mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-18 13:17:55 +02:00
Merge 80cb630bd9 into merged_master (Bitcoin PR bitcoin/bitcoin#31216)
This commit is contained in:
commit
6be1d4093a
40 changed files with 1059 additions and 225 deletions
|
|
@ -38,6 +38,7 @@ message("Configuring secp256k1 subtree...")
|
|||
set(SECP256K1_DISABLE_SHARED ON CACHE BOOL "" FORCE)
|
||||
set(SECP256K1_ENABLE_MODULE_ECDH ON CACHE BOOL "" FORCE)
|
||||
set(SECP256K1_ENABLE_MODULE_RECOVERY ON CACHE BOOL "" FORCE)
|
||||
set(SECP256K1_ENABLE_MODULE_MUSIG OFF CACHE BOOL "" FORCE)
|
||||
set(SECP256K1_BUILD_BENCHMARK OFF CACHE BOOL "" FORCE)
|
||||
set(SECP256K1_BUILD_TESTS ${BUILD_TESTS} CACHE BOOL "" FORCE)
|
||||
set(SECP256K1_BUILD_EXHAUSTIVE_TESTS ${BUILD_TESTS} CACHE BOOL "" FORCE)
|
||||
|
|
|
|||
|
|
@ -22,9 +22,10 @@ env:
|
|||
RECOVERY: no
|
||||
EXTRAKEYS: no
|
||||
SCHNORRSIG: no
|
||||
MUSIG: no
|
||||
ELLSWIFT: no
|
||||
### test options
|
||||
SECP256K1_TEST_ITERS:
|
||||
SECP256K1_TEST_ITERS: 64
|
||||
BENCH: yes
|
||||
SECP256K1_BENCH_ITERS: 2
|
||||
CTIMETESTS: yes
|
||||
|
|
@ -69,6 +70,7 @@ task:
|
|||
RECOVERY: yes
|
||||
EXTRAKEYS: yes
|
||||
SCHNORRSIG: yes
|
||||
MUSIG: yes
|
||||
ELLSWIFT: yes
|
||||
matrix:
|
||||
# Currently only gcc-snapshot, the other compilers are tested on GHA with QEMU
|
||||
|
|
@ -86,6 +88,7 @@ task:
|
|||
RECOVERY: yes
|
||||
EXTRAKEYS: yes
|
||||
SCHNORRSIG: yes
|
||||
MUSIG: yes
|
||||
ELLSWIFT: yes
|
||||
WRAPPER_CMD: 'valgrind --error-exitcode=42'
|
||||
SECP256K1_TEST_ITERS: 2
|
||||
|
|
|
|||
21
src/secp256k1/.github/workflows/ci.yml
vendored
21
src/secp256k1/.github/workflows/ci.yml
vendored
|
|
@ -33,6 +33,7 @@ env:
|
|||
RECOVERY: 'no'
|
||||
EXTRAKEYS: 'no'
|
||||
SCHNORRSIG: 'no'
|
||||
MUSIG: 'no'
|
||||
ELLSWIFT: 'no'
|
||||
ECDSA_S2C: 'no'
|
||||
GENERATOR: 'no'
|
||||
|
|
@ -43,7 +44,7 @@ env:
|
|||
BPPP: 'no'
|
||||
SCHNORRSIG_HALFAGG: 'no'
|
||||
### test options
|
||||
SECP256K1_TEST_ITERS:
|
||||
SECP256K1_TEST_ITERS: 64
|
||||
BENCH: 'yes'
|
||||
SECP256K1_BENCH_ITERS: 2
|
||||
CTIMETESTS: 'yes'
|
||||
|
|
@ -150,6 +151,7 @@ jobs:
|
|||
RECOVERY: 'yes'
|
||||
EXTRAKEYS: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
MUSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
EXPERIMENTAL: 'yes'
|
||||
ECDSA_S2C: 'yes'
|
||||
|
|
@ -204,6 +206,7 @@ jobs:
|
|||
RECOVERY: 'yes'
|
||||
EXTRAKEYS: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
MUSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
EXPERIMENTAL: 'yes'
|
||||
ECDSA_S2C: 'yes'
|
||||
|
|
@ -265,6 +268,7 @@ jobs:
|
|||
RECOVERY: 'yes'
|
||||
EXTRAKEYS: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
MUSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
EXPERIMENTAL: 'yes'
|
||||
ECDSA_S2C: 'yes'
|
||||
|
|
@ -320,6 +324,7 @@ jobs:
|
|||
RECOVERY: 'yes'
|
||||
EXTRAKEYS: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
MUSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
EXPERIMENTAL: 'yes'
|
||||
ECDSA_S2C: 'yes'
|
||||
|
|
@ -385,6 +390,7 @@ jobs:
|
|||
RECOVERY: 'yes'
|
||||
EXTRAKEYS: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
MUSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
EXPERIMENTAL: 'yes'
|
||||
ECDSA_S2C: 'yes'
|
||||
|
|
@ -447,6 +453,7 @@ jobs:
|
|||
RECOVERY: 'yes'
|
||||
EXTRAKEYS: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
MUSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
EXPERIMENTAL: 'yes'
|
||||
ECDSA_S2C: 'yes'
|
||||
|
|
@ -508,6 +515,7 @@ jobs:
|
|||
RECOVERY: 'yes'
|
||||
EXTRAKEYS: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
MUSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
EXPERIMENTAL: 'yes'
|
||||
ECDSA_S2C: 'yes'
|
||||
|
|
@ -575,6 +583,7 @@ jobs:
|
|||
RECOVERY: 'yes'
|
||||
EXTRAKEYS: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
MUSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
EXPERIMENTAL: 'yes'
|
||||
ECDSA_S2C: 'yes'
|
||||
|
|
@ -632,6 +641,7 @@ jobs:
|
|||
RECOVERY: 'yes'
|
||||
EXTRAKEYS: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
MUSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
EXPERIMENTAL: 'yes'
|
||||
ECDSA_S2C: 'yes'
|
||||
|
|
@ -834,14 +844,14 @@ jobs:
|
|||
# Use the bash shell included with Git for Windows.
|
||||
shell: bash
|
||||
run: |
|
||||
cd build/src/RelWithDebInfo && file *tests.exe bench*.exe libsecp256k1-*.dll || true
|
||||
cd build/bin/RelWithDebInfo && file *tests.exe bench*.exe libsecp256k1-*.dll || true
|
||||
|
||||
- name: Check
|
||||
run: |
|
||||
ctest -C RelWithDebInfo --test-dir build -j ([int]$env:NUMBER_OF_PROCESSORS + 1)
|
||||
build\src\RelWithDebInfo\bench_ecmult.exe
|
||||
build\src\RelWithDebInfo\bench_internal.exe
|
||||
build\src\RelWithDebInfo\bench.exe
|
||||
build\bin\RelWithDebInfo\bench_ecmult.exe
|
||||
build\bin\RelWithDebInfo\bench_internal.exe
|
||||
build\bin\RelWithDebInfo\bench.exe
|
||||
|
||||
win64-native-headers:
|
||||
name: "x64 (MSVC): C++ (public headers)"
|
||||
|
|
@ -873,6 +883,7 @@ jobs:
|
|||
RECOVERY: 'yes'
|
||||
EXTRAKEYS: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
MUSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
EXPERIMENTAL: 'yes'
|
||||
ECDSA_S2C: 'yes'
|
||||
|
|
|
|||
1
src/secp256k1/.gitignore
vendored
1
src/secp256k1/.gitignore
vendored
|
|
@ -16,6 +16,7 @@ ecdh_example
|
|||
ecdsa_example
|
||||
schnorr_example
|
||||
ellswift_example
|
||||
musig_example
|
||||
*.exe
|
||||
*.so
|
||||
*.a
|
||||
|
|
|
|||
|
|
@ -8,7 +8,26 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
## [0.6.0] - 2024-11-04
|
||||
|
||||
#### Added
|
||||
- New module `musig` implements the MuSig2 multisignature scheme according to the [BIP 327 specification](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki). See:
|
||||
- Header file `include/secp256k1_musig.h` which defines the new API.
|
||||
- Document `doc/musig.md` for further notes on API usage.
|
||||
- Usage example `examples/musig.c`.
|
||||
- New CMake variable `SECP256K1_APPEND_LDFLAGS` for appending linker flags to the build command.
|
||||
|
||||
#### Changed
|
||||
- API functions now use a significantly more robust method to clear secrets from the stack before returning. However, secret clearing remains a best-effort security measure and cannot guarantee complete removal.
|
||||
- Any type `secp256k1_foo` can now be forward-declared using `typedef struct secp256k1_foo secp256k1_foo;` (or also `struct secp256k1_foo;` in C++).
|
||||
- Organized CMake build artifacts into dedicated directories (`bin/` for executables, `lib/` for libraries) to improve build output structure and Windows shared library compatibility.
|
||||
|
||||
#### Removed
|
||||
- Removed the `secp256k1_scratch_space` struct and its associated functions `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` because the scratch space was unused in the API.
|
||||
|
||||
#### ABI Compatibility
|
||||
The symbols `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` were removed.
|
||||
Otherwise, the library maintains backward compatibility with versions 0.3.x through 0.5.x.
|
||||
|
||||
## [0.5.1] - 2024-08-01
|
||||
|
||||
|
|
@ -146,7 +165,7 @@ 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.5.1...HEAD
|
||||
[0.6.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.1...v0.6.0
|
||||
[0.5.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.0...v0.5.1
|
||||
[0.5.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.1...v0.5.0
|
||||
[0.4.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.0...v0.4.1
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
#=============================
|
||||
# Project / Package metadata
|
||||
#=============================
|
||||
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.5.2
|
||||
VERSION 0.6.0
|
||||
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
|
||||
)
|
||||
enable_testing()
|
||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 3.21)
|
||||
get_directory_property(parent_directory PARENT_DIRECTORY)
|
||||
|
|
@ -27,15 +32,19 @@ endif()
|
|||
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
# All changes in experimental modules are treated as if they don't affect the
|
||||
# interface and therefore only increase the revision.
|
||||
set(${PROJECT_NAME}_LIB_VERSION_CURRENT 4)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_REVISION 2)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_AGE 2)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_CURRENT 5)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_REVISION 0)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_AGE 0)
|
||||
|
||||
#=============================
|
||||
# Language setup
|
||||
#=============================
|
||||
set(CMAKE_C_STANDARD 90)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
|
||||
#=============================
|
||||
# Configurable options
|
||||
#=============================
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries." ON)
|
||||
option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF)
|
||||
if(SECP256K1_DISABLE_SHARED)
|
||||
|
|
@ -52,6 +61,7 @@ option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON)
|
|||
option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF)
|
||||
option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
|
||||
option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON)
|
||||
option(SECP256K1_ENABLE_MODULE_MUSIG "Enable musig module." ON)
|
||||
option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON)
|
||||
|
||||
option(SECP256K1_ENABLE_MODULE_GENERATOR "Enable NUMS generator module." ON)
|
||||
|
|
@ -122,6 +132,14 @@ if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
|||
add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_MUSIG)
|
||||
if(DEFINED SECP256K1_ENABLE_MODULE_SCHNORRSIG AND NOT SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
message(FATAL_ERROR "Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.")
|
||||
endif()
|
||||
set(SECP256K1_ENABLE_MODULE_SCHNORRSIG ON)
|
||||
add_compile_definitions(ENABLE_MODULE_MUSIG=1)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
if(DEFINED SECP256K1_ENABLE_MODULE_EXTRAKEYS AND NOT SECP256K1_ENABLE_MODULE_EXTRAKEYS)
|
||||
message(FATAL_ERROR "Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.")
|
||||
|
|
@ -331,6 +349,15 @@ if(SECP256K1_APPEND_LDFLAGS)
|
|||
string(APPEND CMAKE_C_LINK_EXECUTABLE " ${SECP256K1_APPEND_LDFLAGS}")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
endif()
|
||||
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
||||
endif()
|
||||
if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
||||
endif()
|
||||
add_subdirectory(src)
|
||||
all_targets_compile_options(src "${SECP256K1_LATE_CFLAGS}")
|
||||
if(SECP256K1_BUILD_EXAMPLES)
|
||||
|
|
@ -354,6 +381,7 @@ 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(" musig ............................... ${SECP256K1_ENABLE_MODULE_MUSIG}")
|
||||
message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}")
|
||||
message(" generator ........................... ${SECP256K1_ENABLE_MODULE_GENERATOR}")
|
||||
message(" rangeproof .......................... ${SECP256K1_ENABLE_MODULE_RANGEPROOF}")
|
||||
|
|
|
|||
|
|
@ -206,6 +206,17 @@ ellswift_example_LDFLAGS += -lbcrypt
|
|||
endif
|
||||
TESTS += ellswift_example
|
||||
endif
|
||||
if ENABLE_MODULE_MUSIG
|
||||
noinst_PROGRAMS += musig_example
|
||||
musig_example_SOURCES = examples/musig.c
|
||||
musig_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
|
||||
musig_example_LDADD = libsecp256k1.la
|
||||
musig_example_LDFLAGS = -static
|
||||
if BUILD_WINDOWS
|
||||
musig_example_LDFLAGS += -lbcrypt
|
||||
endif
|
||||
TESTS += musig_example
|
||||
endif
|
||||
endif
|
||||
|
||||
### Precomputed tables
|
||||
|
|
@ -265,6 +276,7 @@ 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 += doc/ellswift.md doc/musig.md
|
||||
EXTRA_DIST += examples/EXAMPLES_COPYING
|
||||
EXTRA_DIST += sage/gen_exhaustive_groups.sage
|
||||
EXTRA_DIST += sage/gen_split_lambda_constants.sage
|
||||
|
|
@ -320,6 +332,10 @@ if ENABLE_MODULE_SCHNORRSIG
|
|||
include src/modules/schnorrsig/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_MUSIG
|
||||
include src/modules/musig/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_ELLSWIFT
|
||||
include src/modules/ellswift/Makefile.am.include
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -4,18 +4,18 @@ AC_PREREQ([2.60])
|
|||
# the API. All changes in experimental modules are treated as
|
||||
# backwards-compatible and therefore at most increase the minor version.
|
||||
define(_PKG_VERSION_MAJOR, 0)
|
||||
define(_PKG_VERSION_MINOR, 5)
|
||||
define(_PKG_VERSION_PATCH, 2)
|
||||
define(_PKG_VERSION_IS_RELEASE, false)
|
||||
define(_PKG_VERSION_MINOR, 6)
|
||||
define(_PKG_VERSION_PATCH, 0)
|
||||
define(_PKG_VERSION_IS_RELEASE, true)
|
||||
|
||||
# The library version is based on libtool versioning of the ABI. The set of
|
||||
# rules for updating the version can be found here:
|
||||
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
# All changes in experimental modules are treated as if they don't affect the
|
||||
# interface and therefore only increase the revision.
|
||||
define(_LIB_VERSION_CURRENT, 4)
|
||||
define(_LIB_VERSION_REVISION, 2)
|
||||
define(_LIB_VERSION_AGE, 2)
|
||||
define(_LIB_VERSION_CURRENT, 5)
|
||||
define(_LIB_VERSION_REVISION, 0)
|
||||
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])
|
||||
|
||||
|
|
@ -510,6 +510,14 @@ if test x"$enable_module_ellswift" = x"yes"; then
|
|||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1"
|
||||
fi
|
||||
|
||||
if test x"$enable_module_musig" = x"yes"; then
|
||||
if test x"$enable_module_schnorrsig" = x"no"; then
|
||||
AC_MSG_ERROR([Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.])
|
||||
fi
|
||||
enable_module_schnorrsig=yes
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_MUSIG=1"
|
||||
fi
|
||||
|
||||
if test x"$enable_module_schnorrsig" = x"yes"; then
|
||||
if test x"$enable_module_extrakeys" = x"no"; then
|
||||
AC_MSG_ERROR([Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.])
|
||||
|
|
@ -601,6 +609,7 @@ 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_MUSIG], [test x"$enable_module_musig" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_GENERATOR], [test x"$enable_module_generator" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" = x"yes"])
|
||||
|
|
@ -637,6 +646,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 musig = $enable_module_musig"
|
||||
echo " module ellswift = $enable_module_ellswift"
|
||||
# libsecp256k1-zkp modules, in the order they were added to the libsecp256k1-zkp
|
||||
echo " module generator = $enable_module_generator"
|
||||
|
|
|
|||
54
src/secp256k1/doc/musig.md
Normal file
54
src/secp256k1/doc/musig.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
Notes on the musig module API
|
||||
===========================
|
||||
|
||||
The following sections contain additional notes on the API of the musig module (`include/secp256k1_musig.h`).
|
||||
A usage example can be found in `examples/musig.c`.
|
||||
|
||||
## API misuse
|
||||
|
||||
The musig API is designed with a focus on misuse resistance.
|
||||
However, due to the interactive nature of the MuSig protocol, there are additional failure modes that are not present in regular (single-party) Schnorr signature creation.
|
||||
While the results can be catastrophic (e.g. leaking of the secret key), it is unfortunately not possible for the musig implementation to prevent all such failure modes.
|
||||
|
||||
Therefore, users of the musig module must take great care to make sure of the following:
|
||||
|
||||
1. A unique nonce per signing session is generated in `secp256k1_musig_nonce_gen`.
|
||||
See the corresponding comment in `include/secp256k1_musig.h` for how to ensure that.
|
||||
2. The `secp256k1_musig_secnonce` structure is never copied or serialized.
|
||||
See also the comment on `secp256k1_musig_secnonce` in `include/secp256k1_musig.h`.
|
||||
3. Opaque data structures are never written to or read from directly.
|
||||
Instead, only the provided accessor functions are used.
|
||||
|
||||
## Key Aggregation and (Taproot) Tweaking
|
||||
|
||||
Given a set of public keys, the aggregate public key is computed with `secp256k1_musig_pubkey_agg`.
|
||||
A plain tweak can be added to the resulting public key with `secp256k1_ec_pubkey_tweak_add` by setting the `tweak32` argument to the hash defined in BIP 32. Similarly, a Taproot tweak can be added with `secp256k1_xonly_pubkey_tweak_add` by setting the `tweak32` argument to the TapTweak hash defined in BIP 341.
|
||||
Both types of tweaking can be combined and invoked multiple times if the specific application requires it.
|
||||
|
||||
## Signing
|
||||
|
||||
This is covered by `examples/musig.c`.
|
||||
Essentially, the protocol proceeds in the following steps:
|
||||
|
||||
1. Generate a keypair with `secp256k1_keypair_create` and obtain the public key with `secp256k1_keypair_pub`.
|
||||
2. Call `secp256k1_musig_pubkey_agg` with the pubkeys of all participants.
|
||||
3. Optionally add a (Taproot) tweak with `secp256k1_musig_pubkey_xonly_tweak_add` and a plain tweak with `secp256k1_musig_pubkey_ec_tweak_add`.
|
||||
4. Generate a pair of secret and public nonce with `secp256k1_musig_nonce_gen` and send the public nonce to the other signers.
|
||||
5. Someone (not necessarily the signer) aggregates the public nonces with `secp256k1_musig_nonce_agg` and sends it to the signers.
|
||||
6. Process the aggregate nonce with `secp256k1_musig_nonce_process`.
|
||||
7. Create a partial signature with `secp256k1_musig_partial_sign`.
|
||||
8. Verify the partial signatures (optional in some scenarios) with `secp256k1_musig_partial_sig_verify`.
|
||||
9. Someone (not necessarily the signer) obtains all partial signatures and aggregates them into the final Schnorr signature using `secp256k1_musig_partial_sig_agg`.
|
||||
|
||||
The aggregate signature can be verified with `secp256k1_schnorrsig_verify`.
|
||||
|
||||
Steps 1 through 5 above can occur before or after the signers are aware of the message to be signed.
|
||||
Whenever possible, it is recommended to generate the nonces only after the message is known.
|
||||
This provides enhanced defense-in-depth measures, protecting against potential API misuse in certain scenarios.
|
||||
However, it does require two rounds of communication during the signing process.
|
||||
The alternative, generating the nonces in a pre-processing step before the message is known, eliminates these additional protective measures but allows for non-interactive signing.
|
||||
Similarly, the API supports an alternative protocol flow where generating the aggregate key (steps 1 to 3) is allowed to happen after exchanging nonces (steps 4 to 5).
|
||||
|
||||
## Verification
|
||||
|
||||
A participant who wants to verify the partial signatures, but does not sign itself may do so using the above instructions except that the verifier skips steps 1, 4 and 7.
|
||||
|
|
@ -9,14 +9,7 @@ function(add_example name)
|
|||
$<$<PLATFORM_ID:Windows>:bcrypt>
|
||||
)
|
||||
set(test_name ${name}_example)
|
||||
add_test(NAME ${test_name} COMMAND ${target_name})
|
||||
if(BUILD_SHARED_LIBS AND MSVC)
|
||||
# The DLL must reside either in the same folder where the executable is
|
||||
# or somewhere in PATH. Using the latter option.
|
||||
set_tests_properties(${test_name} PROPERTIES
|
||||
ENVIRONMENT "PATH=$<TARGET_FILE_DIR:secp256k1>;$ENV{PATH}"
|
||||
)
|
||||
endif()
|
||||
add_test(NAME secp256k1_${test_name} COMMAND ${target_name})
|
||||
endfunction()
|
||||
|
||||
add_example(ecdsa)
|
||||
|
|
@ -32,3 +25,7 @@ endif()
|
|||
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
||||
add_example(ellswift)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_MUSIG)
|
||||
add_example(musig)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -42,18 +42,16 @@ int main(void) {
|
|||
assert(return_val);
|
||||
|
||||
/*** Key Generation ***/
|
||||
|
||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
||||
* order), we try to sample a new key. Note that the probability of this
|
||||
* happening is negligible. */
|
||||
while (1) {
|
||||
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) {
|
||||
break;
|
||||
}
|
||||
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* If the secret key is zero or out of range (greater than secp256k1's
|
||||
* order), we fail. Note that the probability of this occurring is negligible
|
||||
* with a properly functioning random number generator. */
|
||||
if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) {
|
||||
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Public key creation using a valid context with a verified secret key should never fail */
|
||||
|
|
|
|||
|
|
@ -49,18 +49,16 @@ int main(void) {
|
|||
assert(return_val);
|
||||
|
||||
/*** Key Generation ***/
|
||||
|
||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
||||
* order), we try to sample a new key. Note that the probability of this
|
||||
* happening is negligible. */
|
||||
while (1) {
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
if (secp256k1_ec_seckey_verify(ctx, seckey)) {
|
||||
break;
|
||||
}
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* If the secret key is zero or out of range (greater than secp256k1's
|
||||
* order), we fail. Note that the probability of this occurring is negligible
|
||||
* with a properly functioning random number generator. */
|
||||
if (!secp256k1_ec_seckey_verify(ctx, seckey)) {
|
||||
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Public key creation using a valid context with a verified secret key should never fail */
|
||||
|
|
|
|||
|
|
@ -47,18 +47,16 @@ int main(void) {
|
|||
assert(return_val);
|
||||
|
||||
/*** Generate secret keys ***/
|
||||
|
||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
||||
* order), we try to sample a new key. Note that the probability of this
|
||||
* happening is negligible. */
|
||||
while (1) {
|
||||
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) {
|
||||
break;
|
||||
}
|
||||
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* If the secret key is zero or out of range (greater than secp256k1's
|
||||
* order), we fail. Note that the probability of this occurring is negligible
|
||||
* with a properly functioning random number generator. */
|
||||
if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) {
|
||||
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generate ElligatorSwift public keys. This should never fail with valid context and
|
||||
|
|
|
|||
|
|
@ -43,20 +43,17 @@ int main(void) {
|
|||
assert(return_val);
|
||||
|
||||
/*** Key Generation ***/
|
||||
|
||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
||||
* order), we try to sample a new key. Note that the probability of this
|
||||
* happening is negligible. */
|
||||
while (1) {
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* Try to create a keypair with a valid context, it should only fail if
|
||||
* the secret key is zero or out of range. */
|
||||
if (secp256k1_keypair_create(ctx, &keypair, seckey)) {
|
||||
break;
|
||||
}
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* Try to create a keypair with a valid context. This only fails if the
|
||||
* secret key is zero or out of range (greater than secp256k1's order). Note
|
||||
* that the probability of this occurring is negligible with a properly
|
||||
* functioning random number generator. */
|
||||
if (!secp256k1_keypair_create(ctx, &keypair, seckey)) {
|
||||
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Extract the X-only public key from the keypair. We pass NULL for
|
||||
|
|
|
|||
|
|
@ -49,19 +49,6 @@ extern "C" {
|
|||
*/
|
||||
typedef struct secp256k1_context_struct secp256k1_context;
|
||||
|
||||
/** Opaque data structure that holds rewritable "scratch space"
|
||||
*
|
||||
* The purpose of this structure is to replace dynamic memory allocations,
|
||||
* because we target architectures where this may not be available. It is
|
||||
* essentially a resizable (within specified parameters) block of bytes,
|
||||
* which is initially created either by memory allocation or TODO as a pointer
|
||||
* into some fixed rewritable space.
|
||||
*
|
||||
* Unlike the context object, this cannot safely be shared between threads
|
||||
* without additional synchronization logic.
|
||||
*/
|
||||
typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space;
|
||||
|
||||
/** Opaque data structure that holds a parsed and valid public key.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
|
|
@ -71,11 +58,11 @@ typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space;
|
|||
* use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. To
|
||||
* compare keys, use secp256k1_ec_pubkey_cmp.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct secp256k1_pubkey {
|
||||
unsigned char data[64];
|
||||
} secp256k1_pubkey;
|
||||
|
||||
/** Opaque data structured that holds a parsed ECDSA signature.
|
||||
/** Opaque data structure that holds a parsed ECDSA signature.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
|
|
@ -84,7 +71,7 @@ typedef struct {
|
|||
* comparison, use the secp256k1_ecdsa_signature_serialize_* and
|
||||
* secp256k1_ecdsa_signature_parse_* functions.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct secp256k1_ecdsa_signature {
|
||||
unsigned char data[64];
|
||||
} secp256k1_ecdsa_signature;
|
||||
|
||||
|
|
@ -147,6 +134,15 @@ typedef int (*secp256k1_nonce_function)(
|
|||
* 1. If using Libtool, it defines DLL_EXPORT automatically.
|
||||
* 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */
|
||||
# define SECP256K1_API extern __declspec (dllexport)
|
||||
# else
|
||||
/* Building libsecp256k1 as a static library on Windows.
|
||||
* No declspec is needed, and so we would want the non-Windows-specific
|
||||
* logic below take care of this case. However, this may result in setting
|
||||
* __attribute__ ((visibility("default"))), which is supposed to be a noop
|
||||
* on Windows but may trigger warnings when compiling with -flto due to a
|
||||
* bug in GCC, see
|
||||
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116478 . */
|
||||
# define SECP256K1_API extern
|
||||
# endif
|
||||
/* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static
|
||||
* library on Windows. */
|
||||
|
|
@ -156,11 +152,12 @@ typedef int (*secp256k1_nonce_function)(
|
|||
# endif
|
||||
#endif
|
||||
#ifndef SECP256K1_API
|
||||
/* All cases not captured by the Windows-specific logic. */
|
||||
# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
|
||||
/* Building libsecp256k1 on non-Windows using GCC or compatible. */
|
||||
/* Building libsecp256k1 using GCC or compatible. */
|
||||
# define SECP256K1_API extern __attribute__ ((visibility ("default")))
|
||||
# else
|
||||
/* All cases not captured above. */
|
||||
/* Fall back to standard C's extern. */
|
||||
# define SECP256K1_API extern
|
||||
# endif
|
||||
#endif
|
||||
|
|
@ -392,29 +389,6 @@ SECP256K1_API void secp256k1_context_set_error_callback(
|
|||
const void *data
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Create a secp256k1 scratch space object.
|
||||
*
|
||||
* Returns: a newly created scratch space.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In: size: amount of memory to be available as scratch space. Some extra
|
||||
* (<100 bytes) will be allocated for extra accounting.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space *secp256k1_scratch_space_create(
|
||||
const secp256k1_context *ctx,
|
||||
size_t size
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Destroy a secp256k1 scratch space.
|
||||
*
|
||||
* The pointer may not be used afterwards.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* scratch: space to destroy
|
||||
*/
|
||||
SECP256K1_API void secp256k1_scratch_space_destroy(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_scratch_space *scratch
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Parse a variable-length public key into the pubkey object.
|
||||
*
|
||||
* Returns: 1 if the public key was fully valid.
|
||||
|
|
@ -665,12 +639,14 @@ SECP256K1_API int secp256k1_ecdsa_sign(
|
|||
const void *ndata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Verify an ECDSA secret key.
|
||||
/** Verify an elliptic curve secret key.
|
||||
*
|
||||
* A secret key is valid if it is not 0 and less than the secp256k1 curve order
|
||||
* when interpreted as an integer (most significant byte first). The
|
||||
* probability of choosing a 32-byte string uniformly at random which is an
|
||||
* invalid secret key is negligible.
|
||||
* invalid secret key is negligible. However, if it does happen it should
|
||||
* be assumed that the randomness source is severely broken and there should
|
||||
* be no retry.
|
||||
*
|
||||
* Returns: 1: secret key is valid
|
||||
* 0: secret key is invalid
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ extern "C" {
|
|||
* use secp256k1_xonly_pubkey_serialize and secp256k1_xonly_pubkey_parse. To
|
||||
* compare keys, use secp256k1_xonly_pubkey_cmp.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct secp256k1_xonly_pubkey {
|
||||
unsigned char data[64];
|
||||
} secp256k1_xonly_pubkey;
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ typedef struct {
|
|||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 96 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct secp256k1_keypair {
|
||||
unsigned char data[96];
|
||||
} secp256k1_keypair;
|
||||
|
||||
|
|
@ -155,10 +155,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_
|
|||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Compute the keypair for a secret key.
|
||||
/** Compute the keypair for a valid secret key.
|
||||
*
|
||||
* Returns: 1: secret was valid, keypair is ready to use
|
||||
* 0: secret was invalid, try again with a different secret
|
||||
* See the documentation of `secp256k1_ec_seckey_verify` for more information
|
||||
* about the validity of secret keys.
|
||||
*
|
||||
* Returns: 1: secret key is valid
|
||||
* 0: secret key is invalid
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* Out: keypair: pointer to the created keypair.
|
||||
* In: seckey: pointer to a 32-byte secret key.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Opaque data structured that holds a parsed ECDSA signature,
|
||||
/** Opaque data structure that holds a parsed ECDSA signature,
|
||||
* supporting pubkey recovery.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
|
|
@ -21,7 +21,7 @@ extern "C" {
|
|||
* recoverability) will have identical representation, so they can be
|
||||
* memcmp'ed.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct secp256k1_ecdsa_recoverable_signature {
|
||||
unsigned char data[65];
|
||||
} secp256k1_ecdsa_recoverable_signature;
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ SECP256K1_API const secp256k1_nonce_function_hardened secp256k1_nonce_function_b
|
|||
* secp256k1_nonce_function_bip340 is used, then ndata must be a
|
||||
* pointer to 32-byte auxiliary randomness as per BIP-340.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct secp256k1_schnorrsig_extraparams {
|
||||
unsigned char magic[4];
|
||||
secp256k1_nonce_function_hardened noncefp;
|
||||
void *ndata;
|
||||
|
|
|
|||
|
|
@ -87,12 +87,12 @@ endif()
|
|||
if(SECP256K1_BUILD_TESTS)
|
||||
add_executable(noverify_tests tests.c)
|
||||
target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm)
|
||||
add_test(NAME noverify_tests COMMAND noverify_tests)
|
||||
add_test(NAME secp256k1_noverify_tests COMMAND noverify_tests)
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage")
|
||||
add_executable(tests tests.c)
|
||||
target_compile_definitions(tests PRIVATE VERIFY)
|
||||
target_link_libraries(tests secp256k1_precomputed secp256k1_asm)
|
||||
add_test(NAME tests COMMAND tests)
|
||||
add_test(NAME secp256k1_tests COMMAND tests)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ if(SECP256K1_BUILD_EXHAUSTIVE_TESTS)
|
|||
add_executable(exhaustive_tests tests_exhaustive.c)
|
||||
target_link_libraries(exhaustive_tests secp256k1_asm)
|
||||
target_compile_definitions(exhaustive_tests PRIVATE $<$<NOT:$<CONFIG:Coverage>>:VERIFY>)
|
||||
add_test(NAME exhaustive_tests COMMAND exhaustive_tests)
|
||||
add_test(NAME secp256k1_exhaustive_tests COMMAND exhaustive_tests)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_BUILD_CTIME_TESTS)
|
||||
|
|
@ -157,6 +157,9 @@ if(SECP256K1_INSTALL)
|
|||
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h")
|
||||
endif()
|
||||
if(SECP256K1_ENABLE_MODULE_MUSIG)
|
||||
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_musig.h")
|
||||
endif()
|
||||
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
||||
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset
|
|||
secp256k1_scalar sum_scalars;
|
||||
|
||||
secp256k1_gej_set_infinity(&sum_output);
|
||||
secp256k1_scalar_clear(&sum_scalars);
|
||||
secp256k1_scalar_set_int(&sum_scalars, 0);
|
||||
for (i = 0; i < iters; ++i) {
|
||||
secp256k1_gej_add_var(&sum_output, &sum_output, &data->output[i], NULL);
|
||||
if (scalar_gen_offset != NULL) {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@
|
|||
#include "../include/secp256k1_schnorrsig.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_MUSIG
|
||||
#include "../include/secp256k1_musig.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
#include "../include/secp256k1_ellswift.h"
|
||||
#endif
|
||||
|
|
@ -193,6 +197,58 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
|||
CHECK(ret == 1);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_MUSIG
|
||||
{
|
||||
secp256k1_pubkey pk;
|
||||
const secp256k1_pubkey *pk_ptr[1];
|
||||
secp256k1_xonly_pubkey agg_pk;
|
||||
unsigned char session_secrand[32];
|
||||
uint64_t nonrepeating_cnt = 0;
|
||||
secp256k1_musig_secnonce secnonce;
|
||||
secp256k1_musig_pubnonce pubnonce;
|
||||
const secp256k1_musig_pubnonce *pubnonce_ptr[1];
|
||||
secp256k1_musig_aggnonce aggnonce;
|
||||
secp256k1_musig_keyagg_cache cache;
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_musig_partial_sig partial_sig;
|
||||
unsigned char extra_input[32];
|
||||
|
||||
pk_ptr[0] = &pk;
|
||||
pubnonce_ptr[0] = &pubnonce;
|
||||
SECP256K1_CHECKMEM_DEFINE(key, 32);
|
||||
memcpy(session_secrand, key, sizeof(session_secrand));
|
||||
session_secrand[0] = session_secrand[0] + 1;
|
||||
memcpy(extra_input, key, sizeof(extra_input));
|
||||
extra_input[0] = extra_input[0] + 2;
|
||||
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, key));
|
||||
CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair));
|
||||
CHECK(secp256k1_musig_pubkey_agg(ctx, &agg_pk, &cache, pk_ptr, 1));
|
||||
|
||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||
SECP256K1_CHECKMEM_UNDEFINE(session_secrand, sizeof(session_secrand));
|
||||
SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input));
|
||||
ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_secrand, key, &pk, msg, &cache, extra_input);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
ret = secp256k1_musig_nonce_gen_counter(ctx, &secnonce, &pubnonce, nonrepeating_cnt, &keypair, msg, &cache, extra_input);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1));
|
||||
/* Make sure that previous tests don't undefine msg. It's not used as a secret here. */
|
||||
SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg));
|
||||
CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache) == 1);
|
||||
|
||||
ret = secp256k1_keypair_create(ctx, &keypair, key);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
ret = secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &cache, &session);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||
ret = secp256k1_ellswift_create(ctx, ellswift, key, NULL);
|
||||
|
|
|
|||
|
|
@ -171,7 +171,9 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
|
|||
VERIFY_CHECK(a != NULL);
|
||||
VERIFY_CHECK(2 <= w && w <= 31);
|
||||
|
||||
memset(wnaf, 0, len * sizeof(wnaf[0]));
|
||||
for (bit = 0; bit < len; bit++) {
|
||||
wnaf[bit] = 0;
|
||||
}
|
||||
|
||||
s = *a;
|
||||
if (secp256k1_scalar_get_bits(&s, 255, 1)) {
|
||||
|
|
@ -179,6 +181,7 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
|
|||
sign = -1;
|
||||
}
|
||||
|
||||
bit = 0;
|
||||
while (bit < len) {
|
||||
int now;
|
||||
int word;
|
||||
|
|
@ -660,7 +663,6 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_call
|
|||
struct secp256k1_pippenger_state *state_space;
|
||||
size_t idx = 0;
|
||||
size_t point_idx = 0;
|
||||
int i, j;
|
||||
int bucket_window;
|
||||
|
||||
secp256k1_gej_set_infinity(r);
|
||||
|
|
@ -708,18 +710,6 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_call
|
|||
}
|
||||
|
||||
secp256k1_ecmult_pippenger_wnaf(buckets, bucket_window, state_space, r, scalars, points, idx);
|
||||
|
||||
/* Clear data */
|
||||
for(i = 0; (size_t)i < idx; i++) {
|
||||
secp256k1_scalar_clear(&scalars[i]);
|
||||
state_space->ps[i].skew_na = 0;
|
||||
for(j = 0; j < WNAF_SIZE(bucket_window+1); j++) {
|
||||
state_space->wnaf_na[i * WNAF_SIZE(bucket_window+1) + j] = 0;
|
||||
}
|
||||
}
|
||||
for(i = 0; i < 1<<bucket_window; i++) {
|
||||
secp256k1_gej_clear(&buckets[i]);
|
||||
}
|
||||
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST(
|
|||
# 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
|
||||
|
|
@ -144,11 +143,7 @@ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r);
|
|||
*/
|
||||
static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
/** Clear a field element to prevent leaking sensitive information. */
|
||||
static void secp256k1_fe_clear(secp256k1_fe *a);
|
||||
|
||||
/** Determine whether a represents field element 0.
|
||||
|
|
|
|||
|
|
@ -270,13 +270,6 @@ SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) {
|
|||
return a->n[0] & 1;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) {
|
||||
int i;
|
||||
for (i=0; i<10; i++) {
|
||||
a->n[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
int i;
|
||||
for (i = 9; i >= 0; i--) {
|
||||
|
|
|
|||
|
|
@ -212,13 +212,6 @@ SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) {
|
|||
return a->n[0] & 1;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) {
|
||||
int i;
|
||||
for (i=0; i<5; i++) {
|
||||
a->n[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
int i;
|
||||
for (i = 4; i >= 0; i--) {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@
|
|||
#error "Please select wide multiplication implementation"
|
||||
#endif
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
|
||||
secp256k1_memclear(a, sizeof(secp256k1_fe));
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
secp256k1_fe na;
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
|
|
@ -232,15 +236,6 @@ SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ typedef struct {
|
|||
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);
|
||||
static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32);
|
||||
static void secp256k1_sha256_clear(secp256k1_sha256 *hash);
|
||||
|
||||
typedef struct {
|
||||
secp256k1_sha256 inner, outer;
|
||||
|
|
@ -27,6 +28,7 @@ typedef struct {
|
|||
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size);
|
||||
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32);
|
||||
static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash);
|
||||
|
||||
typedef struct {
|
||||
unsigned char v[32];
|
||||
|
|
@ -37,5 +39,6 @@ typedef struct {
|
|||
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng);
|
||||
static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng);
|
||||
|
||||
#endif /* SECP256K1_HASH_H */
|
||||
|
|
|
|||
|
|
@ -171,6 +171,10 @@ static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const uns
|
|||
secp256k1_sha256_write(hash, buf, 32);
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_clear(secp256k1_sha256 *hash) {
|
||||
secp256k1_memclear(hash, sizeof(*hash));
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) {
|
||||
size_t n;
|
||||
unsigned char rkey[64];
|
||||
|
|
@ -196,7 +200,7 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const
|
|||
rkey[n] ^= 0x5c ^ 0x36;
|
||||
}
|
||||
secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey));
|
||||
memset(rkey, 0, sizeof(rkey));
|
||||
secp256k1_memclear(rkey, sizeof(rkey));
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) {
|
||||
|
|
@ -207,10 +211,13 @@ static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned
|
|||
unsigned char temp[32];
|
||||
secp256k1_sha256_finalize(&hash->inner, temp);
|
||||
secp256k1_sha256_write(&hash->outer, temp, 32);
|
||||
memset(temp, 0, 32);
|
||||
secp256k1_memclear(temp, sizeof(temp));
|
||||
secp256k1_sha256_finalize(&hash->outer, out32);
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash) {
|
||||
secp256k1_memclear(hash, sizeof(*hash));
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) {
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
|
|
@ -274,9 +281,11 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256
|
|||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng) {
|
||||
memset(rng->k, 0, 32);
|
||||
memset(rng->v, 0, 32);
|
||||
rng->retry = 0;
|
||||
(void) rng;
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng) {
|
||||
secp256k1_memclear(rng, sizeof(*rng));
|
||||
}
|
||||
|
||||
#undef Round
|
||||
|
|
|
|||
|
|
@ -565,13 +565,12 @@ static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_m
|
|||
|
||||
/* g == 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &SECP256K1_SIGNED30_ONE, 0) == 0);
|
||||
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
|
||||
/* |f| == 1, or (x == 0 and d == 0 and f == modulus) */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, -1) == 0 ||
|
||||
secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, 1) == 0 ||
|
||||
(secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
|
||||
secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
|
||||
(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0 ||
|
||||
secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) == 0)));
|
||||
secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0));
|
||||
|
||||
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||
secp256k1_modinv32_normalize_30(&d, f.v[8], modinfo);
|
||||
|
|
@ -643,13 +642,12 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
|
|||
|
||||
/* g == 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &SECP256K1_SIGNED30_ONE, 0) == 0);
|
||||
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
|
||||
/* |f| == 1, or (x == 0 and d == 0 and f == modulus) */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, -1) == 0 ||
|
||||
secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, 1) == 0 ||
|
||||
(secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
|
||||
secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
|
||||
(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0 ||
|
||||
secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) == 0)));
|
||||
secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0));
|
||||
|
||||
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||
secp256k1_modinv32_normalize_30(&d, f.v[len - 1], modinfo);
|
||||
|
|
|
|||
|
|
@ -621,13 +621,12 @@ static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_m
|
|||
|
||||
/* g == 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &SECP256K1_SIGNED62_ONE, 0) == 0);
|
||||
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
|
||||
/* |f| == 1, or (x == 0 and d == 0 and f == modulus) */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, -1) == 0 ||
|
||||
secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, 1) == 0 ||
|
||||
(secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
|
||||
secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
|
||||
(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0 ||
|
||||
secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) == 0)));
|
||||
secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0));
|
||||
|
||||
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||
secp256k1_modinv64_normalize_62(&d, f.v[4], modinfo);
|
||||
|
|
@ -698,13 +697,12 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
|
|||
|
||||
/* g == 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &SECP256K1_SIGNED62_ONE, 0) == 0);
|
||||
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
|
||||
/* |f| == 1, or (x == 0 and d == 0 and f == modulus) */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, -1) == 0 ||
|
||||
secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, 1) == 0 ||
|
||||
(secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
|
||||
secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
|
||||
(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0 ||
|
||||
secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) == 0)));
|
||||
secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0));
|
||||
|
||||
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||
secp256k1_modinv64_normalize_62(&d, f.v[len - 1], modinfo);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char
|
|||
secp256k1_sha256_write(&sha, &version, 1);
|
||||
secp256k1_sha256_write(&sha, x32, 32);
|
||||
secp256k1_sha256_finalize(&sha, output);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -61,9 +62,11 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se
|
|||
|
||||
ret = hashfp(output, x, y, data);
|
||||
|
||||
memset(x, 0, 32);
|
||||
memset(y, 0, 32);
|
||||
secp256k1_memclear(x, sizeof(x));
|
||||
secp256k1_memclear(y, sizeof(y));
|
||||
secp256k1_scalar_clear(&s);
|
||||
secp256k1_ge_clear(&pt);
|
||||
secp256k1_gej_clear(&res);
|
||||
|
||||
return !!ret & !overflow;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -510,6 +510,7 @@ static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsign
|
|||
secp256k1_sha256_write(&sha, ell_b64, 64);
|
||||
secp256k1_sha256_write(&sha, x32, 32);
|
||||
secp256k1_sha256_finalize(&sha, output);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -539,6 +540,7 @@ static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsign
|
|||
secp256k1_sha256_write(&sha, ell_b64, 64);
|
||||
secp256k1_sha256_write(&sha, x32, 32);
|
||||
secp256k1_sha256_finalize(&sha, output);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -580,7 +582,7 @@ int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output,
|
|||
/* Invoke hasher */
|
||||
ret = hashfp(output, sx, ell_a64, ell_b64, data);
|
||||
|
||||
memset(sx, 0, 32);
|
||||
secp256k1_memclear(sx, sizeof(sx));
|
||||
secp256k1_fe_clear(&px);
|
||||
secp256k1_scalar_clear(&s);
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms
|
|||
secp256k1_sha256_write(&sha, xonly_pk32, 32);
|
||||
secp256k1_sha256_write(&sha, msg, msglen);
|
||||
secp256k1_sha256_finalize(&sha, nonce32);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -187,7 +188,8 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi
|
|||
secp256k1_memczero(sig64, 64, !ret);
|
||||
secp256k1_scalar_clear(&k);
|
||||
secp256k1_scalar_clear(&sk);
|
||||
memset(seckey, 0, sizeof(seckey));
|
||||
secp256k1_memclear(seckey, sizeof(seckey));
|
||||
secp256k1_gej_clear(&rj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,13 +30,6 @@
|
|||
#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL)
|
||||
#define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL)
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) {
|
||||
r->d[0] = 0;
|
||||
r->d[1] = 0;
|
||||
r->d[2] = 0;
|
||||
r->d[3] = 0;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) {
|
||||
r->d[0] = v;
|
||||
r->d[1] = 0;
|
||||
|
|
|
|||
|
|
@ -40,17 +40,6 @@
|
|||
#define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL)
|
||||
#define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL)
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) {
|
||||
r->d[0] = 0;
|
||||
r->d[1] = 0;
|
||||
r->d[2] = 0;
|
||||
r->d[3] = 0;
|
||||
r->d[4] = 0;
|
||||
r->d[5] = 0;
|
||||
r->d[6] = 0;
|
||||
r->d[7] = 0;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) {
|
||||
r->d[0] = v;
|
||||
r->d[1] = 0;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@
|
|||
static const secp256k1_scalar secp256k1_scalar_one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);
|
||||
static const secp256k1_scalar secp256k1_scalar_zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) {
|
||||
secp256k1_memclear(r, sizeof(secp256k1_scalar));
|
||||
}
|
||||
|
||||
static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin) {
|
||||
int overflow;
|
||||
secp256k1_scalar_set_b32(r, bin, &overflow);
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a)
|
|||
return !(*a & 1);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; }
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) {
|
||||
*r = v % EXHAUSTIVE_TEST_ORDER;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ typedef struct secp256k1_scratch_space_struct {
|
|||
size_t max_size;
|
||||
} secp256k1_scratch;
|
||||
|
||||
typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space;
|
||||
|
||||
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size);
|
||||
|
||||
static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch);
|
||||
|
|
|
|||
|
|
@ -8,11 +8,17 @@
|
|||
#define SECP256K1_UTIL_H
|
||||
|
||||
#include "../include/secp256k1.h"
|
||||
#include "checkmem.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#if defined(_MSC_VER)
|
||||
/* For SecureZeroMemory */
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#define STR_(x) #x
|
||||
#define STR(x) STR_(x)
|
||||
|
|
@ -215,14 +221,6 @@ SECP256K1_INLINE static int secp256k1_clz64_var(uint64_t x) {
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define I64FORMAT "I64d"
|
||||
# define I64uFORMAT "I64u"
|
||||
#else
|
||||
# define I64FORMAT "lld"
|
||||
# define I64uFORMAT "llu"
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define SECP256K1_GNUC_EXT __extension__
|
||||
#else
|
||||
|
|
@ -244,6 +242,34 @@ static SECP256K1_INLINE void secp256k1_memczero(void *s, size_t len, int flag) {
|
|||
}
|
||||
}
|
||||
|
||||
/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */
|
||||
static SECP256K1_INLINE void secp256k1_memclear(void *ptr, size_t len) {
|
||||
#if defined(_MSC_VER)
|
||||
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
|
||||
SecureZeroMemory(ptr, len);
|
||||
#elif defined(__GNUC__)
|
||||
/* We use a memory barrier that scares the compiler away from optimizing out the memset.
|
||||
*
|
||||
* Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f
|
||||
* in BoringSSL (ISC License):
|
||||
* As best as we can tell, this is sufficient to break any optimisations that
|
||||
* might try to eliminate "superfluous" memsets.
|
||||
* This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it
|
||||
* is pretty efficient, because the compiler can still implement the memset() efficently,
|
||||
* just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
|
||||
* Yang et al. (USENIX Security 2017) for more background.
|
||||
*/
|
||||
memset(ptr, 0, len);
|
||||
__asm__ __volatile__("" : : "r"(ptr) : "memory");
|
||||
#else
|
||||
void *(*volatile const volatile_memset)(void *, int, size_t) = memset;
|
||||
volatile_memset(ptr, 0, len);
|
||||
#endif
|
||||
#ifdef VERIFY
|
||||
SECP256K1_CHECKMEM_UNDEFINE(ptr, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Semantics like memcmp. Variable-time.
|
||||
*
|
||||
* We use this to avoid possible compiler bugs with memcmp, e.g.
|
||||
|
|
@ -262,6 +288,22 @@ static SECP256K1_INLINE int secp256k1_memcmp_var(const void *s1, const void *s2,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Return 1 if all elements of array s are 0 and otherwise return 0.
|
||||
* Constant-time. */
|
||||
static SECP256K1_INLINE int secp256k1_is_zero_array(const unsigned char *s, size_t len) {
|
||||
unsigned char acc = 0;
|
||||
int ret;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
acc |= s[i];
|
||||
}
|
||||
ret = (acc == 0);
|
||||
/* acc may contain secret values. Try to explicitly clear it. */
|
||||
secp256k1_memclear(&acc, sizeof(acc));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized and non-negative.*/
|
||||
static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag) {
|
||||
unsigned int mask0, mask1, r_masked, a_masked;
|
||||
|
|
|
|||
656
src/secp256k1/tools/test_vectors_musig2_generate.py
Executable file
656
src/secp256k1/tools/test_vectors_musig2_generate.py
Executable file
|
|
@ -0,0 +1,656 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import json
|
||||
import textwrap
|
||||
|
||||
max_pubkeys = 0
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print(
|
||||
"This script converts BIP MuSig2 test vectors in a given directory to a C file that can be used in the test framework."
|
||||
)
|
||||
print("Usage: %s <dir>" % sys.argv[0])
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def hexstr_to_intarray(str):
|
||||
return ", ".join([f"0x{b:02X}" for b in bytes.fromhex(str)])
|
||||
|
||||
|
||||
def create_init(name):
|
||||
return """
|
||||
static const struct musig_%s_vector musig_%s_vector = {
|
||||
""" % (
|
||||
name,
|
||||
name,
|
||||
)
|
||||
|
||||
|
||||
def init_array(key):
|
||||
return textwrap.indent("{ %s },\n" % hexstr_to_intarray(data[key]), 4 * " ")
|
||||
|
||||
|
||||
def init_arrays(key):
|
||||
s = textwrap.indent("{\n", 4 * " ")
|
||||
s += textwrap.indent(
|
||||
",\n".join(["{ %s }" % hexstr_to_intarray(x) for x in data[key]]), 8 * " "
|
||||
)
|
||||
s += textwrap.indent("\n},\n", 4 * " ")
|
||||
return s
|
||||
|
||||
|
||||
def init_indices(array):
|
||||
return " %d, { %s }" % (
|
||||
len(array),
|
||||
", ".join(map(str, array) if len(array) > 0 else "0"),
|
||||
)
|
||||
|
||||
|
||||
def init_is_xonly(case):
|
||||
if len(case["tweak_indices"]) > 0:
|
||||
return ", ".join(map(lambda x: "1" if x else "0", case["is_xonly"]))
|
||||
return "0"
|
||||
|
||||
|
||||
def init_optional_expected(case):
|
||||
return hexstr_to_intarray(case["expected"]) if "expected" in case else 0
|
||||
|
||||
|
||||
def init_cases(cases, f):
|
||||
s = textwrap.indent("{\n", 4 * " ")
|
||||
for (i, case) in enumerate(cases):
|
||||
s += textwrap.indent("%s\n" % f(case), 8 * " ")
|
||||
s += textwrap.indent("},\n", 4 * " ")
|
||||
return s
|
||||
|
||||
|
||||
def finish_init():
|
||||
return "};\n"
|
||||
|
||||
|
||||
s = (
|
||||
"""/**
|
||||
* Automatically generated by %s.
|
||||
*
|
||||
* The test vectors for the KeySort function are included in this file. They can
|
||||
* be found in src/modules/extrakeys/tests_impl.h. */
|
||||
"""
|
||||
% sys.argv[0]
|
||||
)
|
||||
|
||||
|
||||
s += """
|
||||
enum MUSIG_ERROR {
|
||||
MUSIG_PUBKEY,
|
||||
MUSIG_TWEAK,
|
||||
MUSIG_PUBNONCE,
|
||||
MUSIG_AGGNONCE,
|
||||
MUSIG_SECNONCE,
|
||||
MUSIG_SIG,
|
||||
MUSIG_SIG_VERIFY,
|
||||
MUSIG_OTHER
|
||||
};
|
||||
"""
|
||||
|
||||
# key agg vectors
|
||||
with open(sys.argv[1] + "/key_agg_vectors.json", "r") as f:
|
||||
data = json.load(f)
|
||||
|
||||
max_key_indices = max(
|
||||
len(test_case["key_indices"]) for test_case in data["valid_test_cases"]
|
||||
)
|
||||
max_tweak_indices = max(
|
||||
len(test_case["tweak_indices"]) for test_case in data["error_test_cases"]
|
||||
)
|
||||
num_pubkeys = len(data["pubkeys"])
|
||||
max_pubkeys = max(num_pubkeys, max_pubkeys)
|
||||
num_tweaks = len(data["tweaks"])
|
||||
num_valid_cases = len(data["valid_test_cases"])
|
||||
num_error_cases = len(data["error_test_cases"])
|
||||
|
||||
# Add structures for valid and error cases
|
||||
s += (
|
||||
"""
|
||||
struct musig_key_agg_valid_test_case {
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[%d];
|
||||
unsigned char expected[32];
|
||||
};
|
||||
"""
|
||||
% max_key_indices
|
||||
)
|
||||
s += """
|
||||
struct musig_key_agg_error_test_case {
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[%d];
|
||||
size_t tweak_indices_len;
|
||||
size_t tweak_indices[%d];
|
||||
int is_xonly[%d];
|
||||
enum MUSIG_ERROR error;
|
||||
};
|
||||
""" % (
|
||||
max_key_indices,
|
||||
max_tweak_indices,
|
||||
max_tweak_indices,
|
||||
)
|
||||
|
||||
# Add structure for entire vector
|
||||
s += """
|
||||
struct musig_key_agg_vector {
|
||||
unsigned char pubkeys[%d][33];
|
||||
unsigned char tweaks[%d][32];
|
||||
struct musig_key_agg_valid_test_case valid_case[%d];
|
||||
struct musig_key_agg_error_test_case error_case[%d];
|
||||
};
|
||||
""" % (
|
||||
num_pubkeys,
|
||||
num_tweaks,
|
||||
num_valid_cases,
|
||||
num_error_cases,
|
||||
)
|
||||
|
||||
s += create_init("key_agg")
|
||||
# Add pubkeys and tweaks to the vector
|
||||
s += init_arrays("pubkeys")
|
||||
s += init_arrays("tweaks")
|
||||
|
||||
# Add valid cases to the vector
|
||||
s += init_cases(
|
||||
data["valid_test_cases"],
|
||||
lambda case: "{ %s, { %s }},"
|
||||
% (init_indices(case["key_indices"]), hexstr_to_intarray(case["expected"])),
|
||||
)
|
||||
|
||||
def comment_to_error(case):
|
||||
comment = case["comment"]
|
||||
if "public key" in comment.lower():
|
||||
return "MUSIG_PUBKEY"
|
||||
elif "tweak" in comment.lower():
|
||||
return "MUSIG_TWEAK"
|
||||
else:
|
||||
sys.exit("Unknown error")
|
||||
|
||||
# Add error cases to the vector
|
||||
s += init_cases(
|
||||
data["error_test_cases"],
|
||||
lambda case: "{ %s, %s, { %s }, %s },"
|
||||
% (
|
||||
init_indices(case["key_indices"]),
|
||||
init_indices(case["tweak_indices"]),
|
||||
init_is_xonly(case),
|
||||
comment_to_error(case),
|
||||
),
|
||||
)
|
||||
|
||||
s += finish_init()
|
||||
|
||||
# nonce gen vectors
|
||||
with open(sys.argv[1] + "/nonce_gen_vectors.json", "r") as f:
|
||||
data = json.load(f)
|
||||
|
||||
# The MuSig2 implementation only allows messages of length 32
|
||||
data["test_cases"] = list(
|
||||
filter(lambda c: c["msg"] is None or len(c["msg"]) == 64, data["test_cases"])
|
||||
)
|
||||
|
||||
num_tests = len(data["test_cases"])
|
||||
|
||||
s += """
|
||||
struct musig_nonce_gen_test_case {
|
||||
unsigned char rand_[32];
|
||||
int has_sk;
|
||||
unsigned char sk[32];
|
||||
unsigned char pk[33];
|
||||
int has_aggpk;
|
||||
unsigned char aggpk[32];
|
||||
int has_msg;
|
||||
unsigned char msg[32];
|
||||
int has_extra_in;
|
||||
unsigned char extra_in[32];
|
||||
unsigned char expected_secnonce[97];
|
||||
unsigned char expected_pubnonce[66];
|
||||
};
|
||||
"""
|
||||
|
||||
s += (
|
||||
"""
|
||||
struct musig_nonce_gen_vector {
|
||||
struct musig_nonce_gen_test_case test_case[%d];
|
||||
};
|
||||
"""
|
||||
% num_tests
|
||||
)
|
||||
|
||||
s += create_init("nonce_gen")
|
||||
|
||||
def init_array_maybe(array):
|
||||
return "%d , { %s }" % (
|
||||
0 if array is None else 1,
|
||||
hexstr_to_intarray(array) if array is not None else 0,
|
||||
)
|
||||
|
||||
s += init_cases(
|
||||
data["test_cases"],
|
||||
lambda case: "{ { %s }, %s, { %s }, %s, %s, %s, { %s }, { %s } },"
|
||||
% (
|
||||
hexstr_to_intarray(case["rand_"]),
|
||||
init_array_maybe(case["sk"]),
|
||||
hexstr_to_intarray(case["pk"]),
|
||||
init_array_maybe(case["aggpk"]),
|
||||
init_array_maybe(case["msg"]),
|
||||
init_array_maybe(case["extra_in"]),
|
||||
hexstr_to_intarray(case["expected_secnonce"]),
|
||||
hexstr_to_intarray(case["expected_pubnonce"]),
|
||||
),
|
||||
)
|
||||
|
||||
s += finish_init()
|
||||
|
||||
# nonce agg vectors
|
||||
with open(sys.argv[1] + "/nonce_agg_vectors.json", "r") as f:
|
||||
data = json.load(f)
|
||||
|
||||
num_pnonces = len(data["pnonces"])
|
||||
num_valid_cases = len(data["valid_test_cases"])
|
||||
num_error_cases = len(data["error_test_cases"])
|
||||
|
||||
pnonce_indices_len = 2
|
||||
for case in data["valid_test_cases"] + data["error_test_cases"]:
|
||||
assert len(case["pnonce_indices"]) == pnonce_indices_len
|
||||
|
||||
# Add structures for valid and error cases
|
||||
s += """
|
||||
struct musig_nonce_agg_test_case {
|
||||
size_t pnonce_indices[2];
|
||||
/* if valid case */
|
||||
unsigned char expected[66];
|
||||
/* if error case */
|
||||
int invalid_nonce_idx;
|
||||
};
|
||||
"""
|
||||
# Add structure for entire vector
|
||||
s += """
|
||||
struct musig_nonce_agg_vector {
|
||||
unsigned char pnonces[%d][66];
|
||||
struct musig_nonce_agg_test_case valid_case[%d];
|
||||
struct musig_nonce_agg_test_case error_case[%d];
|
||||
};
|
||||
""" % (
|
||||
num_pnonces,
|
||||
num_valid_cases,
|
||||
num_error_cases,
|
||||
)
|
||||
|
||||
s += create_init("nonce_agg")
|
||||
s += init_arrays("pnonces")
|
||||
|
||||
for cases in (data["valid_test_cases"], data["error_test_cases"]):
|
||||
s += init_cases(
|
||||
cases,
|
||||
lambda case: "{ { %s }, { %s }, %d },"
|
||||
% (
|
||||
", ".join(map(str, case["pnonce_indices"])),
|
||||
init_optional_expected(case),
|
||||
case["error"]["signer"] if "error" in case else 0,
|
||||
),
|
||||
)
|
||||
s += finish_init()
|
||||
|
||||
# sign/verify vectors
|
||||
with open(sys.argv[1] + "/sign_verify_vectors.json", "r") as f:
|
||||
data = json.load(f)
|
||||
|
||||
# The MuSig2 implementation only allows messages of length 32
|
||||
assert list(filter(lambda x: len(x) == 64, data["msgs"]))[0] == data["msgs"][0]
|
||||
data["msgs"] = [data["msgs"][0]]
|
||||
|
||||
def filter_msg32(k):
|
||||
return list(filter(lambda x: x["msg_index"] == 0, data[k]))
|
||||
|
||||
data["valid_test_cases"] = filter_msg32("valid_test_cases")
|
||||
data["sign_error_test_cases"] = filter_msg32("sign_error_test_cases")
|
||||
data["verify_error_test_cases"] = filter_msg32("verify_error_test_cases")
|
||||
data["verify_fail_test_cases"] = filter_msg32("verify_fail_test_cases")
|
||||
|
||||
num_pubkeys = len(data["pubkeys"])
|
||||
max_pubkeys = max(num_pubkeys, max_pubkeys)
|
||||
num_secnonces = len(data["secnonces"])
|
||||
num_pubnonces = len(data["pnonces"])
|
||||
num_aggnonces = len(data["aggnonces"])
|
||||
num_msgs = len(data["msgs"])
|
||||
num_valid_cases = len(data["valid_test_cases"])
|
||||
num_sign_error_cases = len(data["sign_error_test_cases"])
|
||||
num_verify_fail_cases = len(data["verify_fail_test_cases"])
|
||||
num_verify_error_cases = len(data["verify_error_test_cases"])
|
||||
|
||||
all_cases = (
|
||||
data["valid_test_cases"]
|
||||
+ data["sign_error_test_cases"]
|
||||
+ data["verify_error_test_cases"]
|
||||
+ data["verify_fail_test_cases"]
|
||||
)
|
||||
max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases)
|
||||
max_nonce_indices = max(
|
||||
len(test_case["nonce_indices"]) if "nonce_indices" in test_case else 0
|
||||
for test_case in all_cases
|
||||
)
|
||||
# Add structures for valid and error cases
|
||||
s += (
|
||||
"""
|
||||
/* Omit pubnonces in the test vectors because our partial signature verification
|
||||
* implementation is able to accept the aggnonce directly. */
|
||||
struct musig_valid_case {
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[%d];
|
||||
size_t aggnonce_index;
|
||||
size_t msg_index;
|
||||
size_t signer_index;
|
||||
unsigned char expected[32];
|
||||
};
|
||||
"""
|
||||
% max_key_indices
|
||||
)
|
||||
|
||||
s += (
|
||||
"""
|
||||
struct musig_sign_error_case {
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[%d];
|
||||
size_t aggnonce_index;
|
||||
size_t msg_index;
|
||||
size_t secnonce_index;
|
||||
enum MUSIG_ERROR error;
|
||||
};
|
||||
"""
|
||||
% max_key_indices
|
||||
)
|
||||
|
||||
s += """
|
||||
struct musig_verify_fail_error_case {
|
||||
unsigned char sig[32];
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[%d];
|
||||
size_t nonce_indices_len;
|
||||
size_t nonce_indices[%d];
|
||||
size_t msg_index;
|
||||
size_t signer_index;
|
||||
enum MUSIG_ERROR error;
|
||||
};
|
||||
""" % (
|
||||
max_key_indices,
|
||||
max_nonce_indices,
|
||||
)
|
||||
|
||||
# Add structure for entire vector
|
||||
s += """
|
||||
struct musig_sign_verify_vector {
|
||||
unsigned char sk[32];
|
||||
unsigned char pubkeys[%d][33];
|
||||
unsigned char secnonces[%d][194];
|
||||
unsigned char pubnonces[%d][194];
|
||||
unsigned char aggnonces[%d][66];
|
||||
unsigned char msgs[%d][32];
|
||||
struct musig_valid_case valid_case[%d];
|
||||
struct musig_sign_error_case sign_error_case[%d];
|
||||
struct musig_verify_fail_error_case verify_fail_case[%d];
|
||||
struct musig_verify_fail_error_case verify_error_case[%d];
|
||||
};
|
||||
""" % (
|
||||
num_pubkeys,
|
||||
num_secnonces,
|
||||
num_pubnonces,
|
||||
num_aggnonces,
|
||||
num_msgs,
|
||||
num_valid_cases,
|
||||
num_sign_error_cases,
|
||||
num_verify_fail_cases,
|
||||
num_verify_error_cases,
|
||||
)
|
||||
|
||||
s += create_init("sign_verify")
|
||||
s += init_array("sk")
|
||||
s += init_arrays("pubkeys")
|
||||
s += init_arrays("secnonces")
|
||||
s += init_arrays("pnonces")
|
||||
s += init_arrays("aggnonces")
|
||||
s += init_arrays("msgs")
|
||||
|
||||
s += init_cases(
|
||||
data["valid_test_cases"],
|
||||
lambda case: "{ %s, %d, %d, %d, { %s }},"
|
||||
% (
|
||||
init_indices(case["key_indices"]),
|
||||
case["aggnonce_index"],
|
||||
case["msg_index"],
|
||||
case["signer_index"],
|
||||
init_optional_expected(case),
|
||||
),
|
||||
)
|
||||
|
||||
def sign_error(case):
|
||||
comment = case["comment"]
|
||||
if "pubkey" in comment or "public key" in comment:
|
||||
return "MUSIG_PUBKEY"
|
||||
elif "Aggregate nonce" in comment:
|
||||
return "MUSIG_AGGNONCE"
|
||||
elif "Secnonce" in comment:
|
||||
return "MUSIG_SECNONCE"
|
||||
else:
|
||||
sys.exit("Unknown sign error")
|
||||
|
||||
s += init_cases(
|
||||
data["sign_error_test_cases"],
|
||||
lambda case: "{ %s, %d, %d, %d, %s },"
|
||||
% (
|
||||
init_indices(case["key_indices"]),
|
||||
case["aggnonce_index"],
|
||||
case["msg_index"],
|
||||
case["secnonce_index"],
|
||||
sign_error(case),
|
||||
),
|
||||
)
|
||||
|
||||
def verify_error(case):
|
||||
comment = case["comment"]
|
||||
if "exceeds" in comment:
|
||||
return "MUSIG_SIG"
|
||||
elif "Wrong signer" in comment or "Wrong signature" in comment:
|
||||
return "MUSIG_SIG_VERIFY"
|
||||
elif "pubnonce" in comment:
|
||||
return "MUSIG_PUBNONCE"
|
||||
elif "pubkey" in comment:
|
||||
return "MUSIG_PUBKEY"
|
||||
else:
|
||||
sys.exit("Unknown verify error")
|
||||
|
||||
for cases in ("verify_fail_test_cases", "verify_error_test_cases"):
|
||||
s += init_cases(
|
||||
data[cases],
|
||||
lambda case: "{ { %s }, %s, %s, %d, %d, %s },"
|
||||
% (
|
||||
hexstr_to_intarray(case["sig"]),
|
||||
init_indices(case["key_indices"]),
|
||||
init_indices(case["nonce_indices"]),
|
||||
case["msg_index"],
|
||||
case["signer_index"],
|
||||
verify_error(case),
|
||||
),
|
||||
)
|
||||
|
||||
s += finish_init()
|
||||
|
||||
# tweak vectors
|
||||
with open(sys.argv[1] + "/tweak_vectors.json", "r") as f:
|
||||
data = json.load(f)
|
||||
|
||||
num_pubkeys = len(data["pubkeys"])
|
||||
max_pubkeys = max(num_pubkeys, max_pubkeys)
|
||||
num_pubnonces = len(data["pnonces"])
|
||||
num_tweaks = len(data["tweaks"])
|
||||
num_valid_cases = len(data["valid_test_cases"])
|
||||
num_error_cases = len(data["error_test_cases"])
|
||||
|
||||
all_cases = data["valid_test_cases"] + data["error_test_cases"]
|
||||
max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases)
|
||||
max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases)
|
||||
max_nonce_indices = max(len(test_case["nonce_indices"]) for test_case in all_cases)
|
||||
# Add structures for valid and error cases
|
||||
s += """
|
||||
struct musig_tweak_case {
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[%d];
|
||||
size_t nonce_indices_len;
|
||||
size_t nonce_indices[%d];
|
||||
size_t tweak_indices_len;
|
||||
size_t tweak_indices[%d];
|
||||
int is_xonly[%d];
|
||||
size_t signer_index;
|
||||
unsigned char expected[32];
|
||||
};
|
||||
""" % (
|
||||
max_key_indices,
|
||||
max_nonce_indices,
|
||||
max_tweak_indices,
|
||||
max_tweak_indices,
|
||||
)
|
||||
|
||||
# Add structure for entire vector
|
||||
s += """
|
||||
struct musig_tweak_vector {
|
||||
unsigned char sk[32];
|
||||
unsigned char secnonce[97];
|
||||
unsigned char aggnonce[66];
|
||||
unsigned char msg[32];
|
||||
unsigned char pubkeys[%d][33];
|
||||
unsigned char pubnonces[%d][194];
|
||||
unsigned char tweaks[%d][32];
|
||||
struct musig_tweak_case valid_case[%d];
|
||||
struct musig_tweak_case error_case[%d];
|
||||
};
|
||||
""" % (
|
||||
num_pubkeys,
|
||||
num_pubnonces,
|
||||
num_tweaks,
|
||||
num_valid_cases,
|
||||
num_error_cases,
|
||||
)
|
||||
s += create_init("tweak")
|
||||
s += init_array("sk")
|
||||
s += init_array("secnonce")
|
||||
s += init_array("aggnonce")
|
||||
s += init_array("msg")
|
||||
s += init_arrays("pubkeys")
|
||||
s += init_arrays("pnonces")
|
||||
s += init_arrays("tweaks")
|
||||
|
||||
s += init_cases(
|
||||
data["valid_test_cases"],
|
||||
lambda case: "{ %s, %s, %s, { %s }, %d, { %s }},"
|
||||
% (
|
||||
init_indices(case["key_indices"]),
|
||||
init_indices(case["nonce_indices"]),
|
||||
init_indices(case["tweak_indices"]),
|
||||
init_is_xonly(case),
|
||||
case["signer_index"],
|
||||
init_optional_expected(case),
|
||||
),
|
||||
)
|
||||
|
||||
s += init_cases(
|
||||
data["error_test_cases"],
|
||||
lambda case: "{ %s, %s, %s, { %s }, %d, { %s }},"
|
||||
% (
|
||||
init_indices(case["key_indices"]),
|
||||
init_indices(case["nonce_indices"]),
|
||||
init_indices(case["tweak_indices"]),
|
||||
init_is_xonly(case),
|
||||
case["signer_index"],
|
||||
init_optional_expected(case),
|
||||
),
|
||||
)
|
||||
|
||||
s += finish_init()
|
||||
|
||||
# sigagg vectors
|
||||
with open(sys.argv[1] + "/sig_agg_vectors.json", "r") as f:
|
||||
data = json.load(f)
|
||||
|
||||
num_pubkeys = len(data["pubkeys"])
|
||||
max_pubkeys = max(num_pubkeys, max_pubkeys)
|
||||
num_tweaks = len(data["tweaks"])
|
||||
num_psigs = len(data["psigs"])
|
||||
num_valid_cases = len(data["valid_test_cases"])
|
||||
num_error_cases = len(data["error_test_cases"])
|
||||
|
||||
all_cases = data["valid_test_cases"] + data["error_test_cases"]
|
||||
max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases)
|
||||
max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases)
|
||||
max_psig_indices = max(len(test_case["psig_indices"]) for test_case in all_cases)
|
||||
|
||||
# Add structures for valid and error cases
|
||||
s += """
|
||||
/* Omit pubnonces in the test vectors because they're only needed for
|
||||
* implementations that do not directly accept an aggnonce. */
|
||||
struct musig_sig_agg_case {
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[%d];
|
||||
size_t tweak_indices_len;
|
||||
size_t tweak_indices[%d];
|
||||
int is_xonly[%d];
|
||||
unsigned char aggnonce[66];
|
||||
size_t psig_indices_len;
|
||||
size_t psig_indices[%d];
|
||||
/* if valid case */
|
||||
unsigned char expected[64];
|
||||
/* if error case */
|
||||
int invalid_sig_idx;
|
||||
};
|
||||
""" % (
|
||||
max_key_indices,
|
||||
max_tweak_indices,
|
||||
max_tweak_indices,
|
||||
max_psig_indices,
|
||||
)
|
||||
|
||||
# Add structure for entire vector
|
||||
s += """
|
||||
struct musig_sig_agg_vector {
|
||||
unsigned char pubkeys[%d][33];
|
||||
unsigned char tweaks[%d][32];
|
||||
unsigned char psigs[%d][32];
|
||||
unsigned char msg[32];
|
||||
struct musig_sig_agg_case valid_case[%d];
|
||||
struct musig_sig_agg_case error_case[%d];
|
||||
};
|
||||
""" % (
|
||||
num_pubkeys,
|
||||
num_tweaks,
|
||||
num_psigs,
|
||||
num_valid_cases,
|
||||
num_error_cases,
|
||||
)
|
||||
|
||||
s += create_init("sig_agg")
|
||||
s += init_arrays("pubkeys")
|
||||
s += init_arrays("tweaks")
|
||||
s += init_arrays("psigs")
|
||||
s += init_array("msg")
|
||||
|
||||
for cases in (data["valid_test_cases"], data["error_test_cases"]):
|
||||
s += init_cases(
|
||||
cases,
|
||||
lambda case: "{ %s, %s, { %s }, { %s }, %s, { %s }, %d },"
|
||||
% (
|
||||
init_indices(case["key_indices"]),
|
||||
init_indices(case["tweak_indices"]),
|
||||
init_is_xonly(case),
|
||||
hexstr_to_intarray(case["aggnonce"]),
|
||||
init_indices(case["psig_indices"]),
|
||||
init_optional_expected(case),
|
||||
case["error"]["signer"] if "error" in case else 0,
|
||||
),
|
||||
)
|
||||
s += finish_init()
|
||||
s += "enum { MUSIG_VECTORS_MAX_PUBKEYS = %d };" % max_pubkeys
|
||||
print(s)
|
||||
Loading…
Add table
Add a link
Reference in a new issue