mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-19 01:42:58 +01:00
Squashed 'src/secp256k1/' changes from 2f2ccc46954..0cdc758a563
0cdc758a563 Merge bitcoin-core/secp256k1#1631: release: prepare for 0.6.0 39d5dfd542a release: prepare for 0.6.0 df2eceb2790 build: add ellswift.md and musig.md to release tarball a306bb7e903 tools: fix check-abi.sh after cmake out locations were changed 145868a84d2 Do not export `secp256k1_musig_nonce_gen_internal` b161bffb8bf Merge bitcoin-core/secp256k1#1579: Clear sensitive memory without getting optimized out (revival of #636) a38d879a1a6 Merge bitcoin-core/secp256k1#1628: Name public API structs 7d48f5ed02e Merge bitcoin-core/secp256k1#1581: test, ci: Lower default iteration count to 16 694342fdb71 Name public API structs 0f73caf7c62 test, ci: Lower default iteration count to 16 9a8db52f4e9 Merge bitcoin-core/secp256k1#1582: cmake, test: Add `secp256k1_` prefix to test names 765ef53335a Clear _gej instances after point multiplication to avoid potential leaks 349e6ab916b Introduce separate _clear functions for hash module 99cc9fd6d01 Don't rely on memset to set signed integers to 0 97c57f42ba8 Implement various _clear() functions with secp256k1_memclear() 9bb368d1466 Use secp256k1_memclear() to clear stack memory instead of memset() e3497bbf001 Separate between clearing memory and setting to zero in tests d79a6ccd43a Separate secp256k1_fe_set_int( . , 0 ) from secp256k1_fe_clear() 1c081262227 Add secp256k1_memclear() for clearing secret data 1464f15c812 Merge bitcoin-core/secp256k1#1625: util: Remove unused (u)int64_t formatting macros 980c08df80a util: Remove unused (u)int64_t formatting macros 9b7c59cbb90 Merge bitcoin-core/secp256k1#1624: ci: Update macOS image 096e3e23f63 ci: Update macOS image e7d384488e8 Don't clear secrets in pippenger implementation 68b55209f1b Merge bitcoin-core/secp256k1#1619: musig: ctimetests: fix _declassify range for generated nonce points f0868a9b3d8 Merge bitcoin-core/secp256k1#1595: build: 45839th attempt to fix symbol visibility on Windows 1fae76f50c0 Merge bitcoin-core/secp256k1#1620: Remove unused scratch space from API 8be3839fb2e Remove unused scratch space from API 57eda3ba300 musig: ctimetests: fix _declassify range for generated nonce points 87384f5c0f2 cmake, test: Add `secp256k1_` prefix to test names e59158b6eb7 Merge bitcoin-core/secp256k1#1553: cmake: Set top-level target output locations 18f9b967c25 Merge bitcoin-core/secp256k1#1616: examples: do not retry generating seckey randomness in musig 5bab8f6d3c4 examples: make key generation doc consistent e8908221a45 examples: do not retry generating seckey randomness in musig 70b6be1834e extrakeys: improve doc of keypair_create (don't suggest retry) 01b5893389e Merge bitcoin-core/secp256k1#1599: #1570 improve examples: remove key generation loop cd4f84f3ba8 Improve examples/documentation: remove key generation loops a88aa935063 Merge bitcoin-core/secp256k1#1603: f can never equal -m 3660fe5e2a9 Merge bitcoin-core/secp256k1#1479: Add module "musig" that implements MuSig2 multi-signatures (BIP 327) 168c92011f5 build: allow enabling the musig module in cmake f411841a46b Add module "musig" that implements MuSig2 multi-signatures (BIP 327) 0be79660f38 util: add constant-time is_zero_array function c8fbdb1b972 group: add ge_to_bytes_ext and ge_from_bytes_ext ef7ff03407f f can never equal -m c232486d84e Revert "cmake: Set `ENVIRONMENT` property for examples on Windows" 26e4a7c2146 cmake: Set top-level target output locations 4c57c7a5a95 Merge bitcoin-core/secp256k1#1554: cmake: Clean up testing code 447334cb06d include: Avoid visibility("default") on Windows 472faaa8ee6 Merge bitcoin-core/secp256k1#1604: doc: fix typos in `secp256k1_ecdsa_{recoverable_,}signature` API description 292310fbb24 doc: fix typos in `secp256k1_ecdsa_{recoverable_,}signature` API description 85e224dd97f group: add ge_to_bytes and ge_from_bytes 7c987ec89e6 cmake: Call `enable_testing()` unconditionally 6aa576515ef cmake: Delete `CTest` module git-subtree-dir: src/secp256k1 git-subtree-split: 0cdc758a56360bf58a851fe91085a327ec97685a
This commit is contained in:
parent
611562806c
commit
2d46a89386
@ -22,9 +22,10 @@ env:
|
|||||||
RECOVERY: no
|
RECOVERY: no
|
||||||
EXTRAKEYS: no
|
EXTRAKEYS: no
|
||||||
SCHNORRSIG: no
|
SCHNORRSIG: no
|
||||||
|
MUSIG: no
|
||||||
ELLSWIFT: no
|
ELLSWIFT: no
|
||||||
### test options
|
### test options
|
||||||
SECP256K1_TEST_ITERS:
|
SECP256K1_TEST_ITERS: 64
|
||||||
BENCH: yes
|
BENCH: yes
|
||||||
SECP256K1_BENCH_ITERS: 2
|
SECP256K1_BENCH_ITERS: 2
|
||||||
CTIMETESTS: yes
|
CTIMETESTS: yes
|
||||||
@ -69,6 +70,7 @@ task:
|
|||||||
RECOVERY: yes
|
RECOVERY: yes
|
||||||
EXTRAKEYS: yes
|
EXTRAKEYS: yes
|
||||||
SCHNORRSIG: yes
|
SCHNORRSIG: yes
|
||||||
|
MUSIG: yes
|
||||||
ELLSWIFT: yes
|
ELLSWIFT: yes
|
||||||
matrix:
|
matrix:
|
||||||
# Currently only gcc-snapshot, the other compilers are tested on GHA with QEMU
|
# Currently only gcc-snapshot, the other compilers are tested on GHA with QEMU
|
||||||
@ -86,6 +88,7 @@ task:
|
|||||||
RECOVERY: yes
|
RECOVERY: yes
|
||||||
EXTRAKEYS: yes
|
EXTRAKEYS: yes
|
||||||
SCHNORRSIG: yes
|
SCHNORRSIG: yes
|
||||||
|
MUSIG: yes
|
||||||
ELLSWIFT: yes
|
ELLSWIFT: yes
|
||||||
WRAPPER_CMD: 'valgrind --error-exitcode=42'
|
WRAPPER_CMD: 'valgrind --error-exitcode=42'
|
||||||
SECP256K1_TEST_ITERS: 2
|
SECP256K1_TEST_ITERS: 2
|
||||||
|
51
.github/workflows/ci.yml
vendored
51
.github/workflows/ci.yml
vendored
@ -33,9 +33,10 @@ env:
|
|||||||
RECOVERY: 'no'
|
RECOVERY: 'no'
|
||||||
EXTRAKEYS: 'no'
|
EXTRAKEYS: 'no'
|
||||||
SCHNORRSIG: 'no'
|
SCHNORRSIG: 'no'
|
||||||
|
MUSIG: 'no'
|
||||||
ELLSWIFT: 'no'
|
ELLSWIFT: 'no'
|
||||||
### test options
|
### test options
|
||||||
SECP256K1_TEST_ITERS:
|
SECP256K1_TEST_ITERS: 64
|
||||||
BENCH: 'yes'
|
BENCH: 'yes'
|
||||||
SECP256K1_BENCH_ITERS: 2
|
SECP256K1_BENCH_ITERS: 2
|
||||||
CTIMETESTS: 'yes'
|
CTIMETESTS: 'yes'
|
||||||
@ -72,18 +73,18 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
configuration:
|
configuration:
|
||||||
- env_vars: { WIDEMUL: 'int64', RECOVERY: 'yes' }
|
- env_vars: { WIDEMUL: 'int64', RECOVERY: 'yes' }
|
||||||
- env_vars: { WIDEMUL: 'int64', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
|
- env_vars: { WIDEMUL: 'int64', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
|
||||||
- env_vars: { WIDEMUL: 'int128' }
|
- env_vars: { WIDEMUL: 'int128' }
|
||||||
- env_vars: { WIDEMUL: 'int128_struct', ELLSWIFT: 'yes' }
|
- env_vars: { WIDEMUL: 'int128_struct', ELLSWIFT: 'yes' }
|
||||||
- env_vars: { WIDEMUL: 'int128', RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
|
- env_vars: { WIDEMUL: 'int128', RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
|
||||||
- env_vars: { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes' }
|
- env_vars: { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes' }
|
||||||
- env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' }
|
- env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' }
|
||||||
- env_vars: { RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes' }
|
- env_vars: { RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes' }
|
||||||
- env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', CPPFLAGS: '-DVERIFY' }
|
- env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', CPPFLAGS: '-DVERIFY' }
|
||||||
- env_vars: { BUILD: 'distcheck', WITH_VALGRIND: 'no', CTIMETESTS: 'no', BENCH: 'no' }
|
- env_vars: { BUILD: 'distcheck', WITH_VALGRIND: 'no', CTIMETESTS: 'no', BENCH: 'no' }
|
||||||
- env_vars: { CPPFLAGS: '-DDETERMINISTIC' }
|
- env_vars: { CPPFLAGS: '-DDETERMINISTIC' }
|
||||||
- env_vars: { CFLAGS: '-O0', CTIMETESTS: 'no' }
|
- env_vars: { CFLAGS: '-O0', CTIMETESTS: 'no' }
|
||||||
- env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
|
- env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
|
||||||
- env_vars: { ECMULTGENKB: 2, ECMULTWINDOW: 2 }
|
- env_vars: { ECMULTGENKB: 2, ECMULTWINDOW: 2 }
|
||||||
- env_vars: { ECMULTGENKB: 86, ECMULTWINDOW: 4 }
|
- env_vars: { ECMULTGENKB: 86, ECMULTWINDOW: 4 }
|
||||||
cc:
|
cc:
|
||||||
@ -142,6 +143,7 @@ jobs:
|
|||||||
RECOVERY: 'yes'
|
RECOVERY: 'yes'
|
||||||
EXTRAKEYS: 'yes'
|
EXTRAKEYS: 'yes'
|
||||||
SCHNORRSIG: 'yes'
|
SCHNORRSIG: 'yes'
|
||||||
|
MUSIG: 'yes'
|
||||||
ELLSWIFT: 'yes'
|
ELLSWIFT: 'yes'
|
||||||
CC: ${{ matrix.cc }}
|
CC: ${{ matrix.cc }}
|
||||||
|
|
||||||
@ -187,6 +189,7 @@ jobs:
|
|||||||
RECOVERY: 'yes'
|
RECOVERY: 'yes'
|
||||||
EXTRAKEYS: 'yes'
|
EXTRAKEYS: 'yes'
|
||||||
SCHNORRSIG: 'yes'
|
SCHNORRSIG: 'yes'
|
||||||
|
MUSIG: 'yes'
|
||||||
ELLSWIFT: 'yes'
|
ELLSWIFT: 'yes'
|
||||||
CTIMETESTS: 'no'
|
CTIMETESTS: 'no'
|
||||||
|
|
||||||
@ -239,6 +242,7 @@ jobs:
|
|||||||
RECOVERY: 'yes'
|
RECOVERY: 'yes'
|
||||||
EXTRAKEYS: 'yes'
|
EXTRAKEYS: 'yes'
|
||||||
SCHNORRSIG: 'yes'
|
SCHNORRSIG: 'yes'
|
||||||
|
MUSIG: 'yes'
|
||||||
ELLSWIFT: 'yes'
|
ELLSWIFT: 'yes'
|
||||||
CTIMETESTS: 'no'
|
CTIMETESTS: 'no'
|
||||||
|
|
||||||
@ -285,6 +289,7 @@ jobs:
|
|||||||
RECOVERY: 'yes'
|
RECOVERY: 'yes'
|
||||||
EXTRAKEYS: 'yes'
|
EXTRAKEYS: 'yes'
|
||||||
SCHNORRSIG: 'yes'
|
SCHNORRSIG: 'yes'
|
||||||
|
MUSIG: 'yes'
|
||||||
ELLSWIFT: 'yes'
|
ELLSWIFT: 'yes'
|
||||||
CTIMETESTS: 'no'
|
CTIMETESTS: 'no'
|
||||||
|
|
||||||
@ -341,6 +346,7 @@ jobs:
|
|||||||
RECOVERY: 'yes'
|
RECOVERY: 'yes'
|
||||||
EXTRAKEYS: 'yes'
|
EXTRAKEYS: 'yes'
|
||||||
SCHNORRSIG: 'yes'
|
SCHNORRSIG: 'yes'
|
||||||
|
MUSIG: 'yes'
|
||||||
ELLSWIFT: 'yes'
|
ELLSWIFT: 'yes'
|
||||||
CTIMETESTS: 'no'
|
CTIMETESTS: 'no'
|
||||||
|
|
||||||
@ -394,6 +400,7 @@ jobs:
|
|||||||
RECOVERY: 'yes'
|
RECOVERY: 'yes'
|
||||||
EXTRAKEYS: 'yes'
|
EXTRAKEYS: 'yes'
|
||||||
SCHNORRSIG: 'yes'
|
SCHNORRSIG: 'yes'
|
||||||
|
MUSIG: 'yes'
|
||||||
ELLSWIFT: 'yes'
|
ELLSWIFT: 'yes'
|
||||||
CTIMETESTS: 'no'
|
CTIMETESTS: 'no'
|
||||||
SECP256K1_TEST_ITERS: 2
|
SECP256K1_TEST_ITERS: 2
|
||||||
@ -446,6 +453,7 @@ jobs:
|
|||||||
RECOVERY: 'yes'
|
RECOVERY: 'yes'
|
||||||
EXTRAKEYS: 'yes'
|
EXTRAKEYS: 'yes'
|
||||||
SCHNORRSIG: 'yes'
|
SCHNORRSIG: 'yes'
|
||||||
|
MUSIG: 'yes'
|
||||||
ELLSWIFT: 'yes'
|
ELLSWIFT: 'yes'
|
||||||
CTIMETESTS: 'no'
|
CTIMETESTS: 'no'
|
||||||
CFLAGS: '-fsanitize=undefined,address -g'
|
CFLAGS: '-fsanitize=undefined,address -g'
|
||||||
@ -511,6 +519,7 @@ jobs:
|
|||||||
RECOVERY: 'yes'
|
RECOVERY: 'yes'
|
||||||
EXTRAKEYS: 'yes'
|
EXTRAKEYS: 'yes'
|
||||||
SCHNORRSIG: 'yes'
|
SCHNORRSIG: 'yes'
|
||||||
|
MUSIG: 'yes'
|
||||||
ELLSWIFT: 'yes'
|
ELLSWIFT: 'yes'
|
||||||
CC: 'clang'
|
CC: 'clang'
|
||||||
SECP256K1_TEST_ITERS: 32
|
SECP256K1_TEST_ITERS: 32
|
||||||
@ -558,6 +567,7 @@ jobs:
|
|||||||
RECOVERY: 'yes'
|
RECOVERY: 'yes'
|
||||||
EXTRAKEYS: 'yes'
|
EXTRAKEYS: 'yes'
|
||||||
SCHNORRSIG: 'yes'
|
SCHNORRSIG: 'yes'
|
||||||
|
MUSIG: 'yes'
|
||||||
ELLSWIFT: 'yes'
|
ELLSWIFT: 'yes'
|
||||||
CTIMETESTS: 'no'
|
CTIMETESTS: 'no'
|
||||||
|
|
||||||
@ -602,9 +612,9 @@ jobs:
|
|||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
|
|
||||||
x86_64-macos-native:
|
x86_64-macos-native:
|
||||||
name: "x86_64: macOS Monterey, Valgrind"
|
name: "x86_64: macOS Ventura, Valgrind"
|
||||||
# See: https://github.com/actions/runner-images#available-images.
|
# See: https://github.com/actions/runner-images#available-images.
|
||||||
runs-on: macos-12
|
runs-on: macos-13
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CC: 'clang'
|
CC: 'clang'
|
||||||
@ -615,15 +625,15 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
env_vars:
|
env_vars:
|
||||||
- { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
|
- { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
|
||||||
- { WIDEMUL: 'int128_struct', ECMULTGENKB: 2, ECMULTWINDOW: 4 }
|
- { WIDEMUL: 'int128_struct', ECMULTGENKB: 2, ECMULTWINDOW: 4 }
|
||||||
- { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
|
- { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
|
||||||
- { WIDEMUL: 'int128', RECOVERY: 'yes' }
|
- { WIDEMUL: 'int128', RECOVERY: 'yes' }
|
||||||
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
|
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
|
||||||
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' }
|
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' }
|
||||||
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
|
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
|
||||||
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
|
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
|
||||||
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' }
|
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' }
|
||||||
- BUILD: 'distcheck'
|
- BUILD: 'distcheck'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -751,14 +761,14 @@ jobs:
|
|||||||
# Use the bash shell included with Git for Windows.
|
# Use the bash shell included with Git for Windows.
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
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
|
- name: Check
|
||||||
run: |
|
run: |
|
||||||
ctest -C RelWithDebInfo --test-dir build -j ([int]$env:NUMBER_OF_PROCESSORS + 1)
|
ctest -C RelWithDebInfo --test-dir build -j ([int]$env:NUMBER_OF_PROCESSORS + 1)
|
||||||
build\src\RelWithDebInfo\bench_ecmult.exe
|
build\bin\RelWithDebInfo\bench_ecmult.exe
|
||||||
build\src\RelWithDebInfo\bench_internal.exe
|
build\bin\RelWithDebInfo\bench_internal.exe
|
||||||
build\src\RelWithDebInfo\bench.exe
|
build\bin\RelWithDebInfo\bench.exe
|
||||||
|
|
||||||
win64-native-headers:
|
win64-native-headers:
|
||||||
name: "x64 (MSVC): C++ (public headers)"
|
name: "x64 (MSVC): C++ (public headers)"
|
||||||
@ -790,6 +800,7 @@ jobs:
|
|||||||
RECOVERY: 'yes'
|
RECOVERY: 'yes'
|
||||||
EXTRAKEYS: 'yes'
|
EXTRAKEYS: 'yes'
|
||||||
SCHNORRSIG: 'yes'
|
SCHNORRSIG: 'yes'
|
||||||
|
MUSIG: 'yes'
|
||||||
ELLSWIFT: 'yes'
|
ELLSWIFT: 'yes'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,6 +11,7 @@ ecdh_example
|
|||||||
ecdsa_example
|
ecdsa_example
|
||||||
schnorr_example
|
schnorr_example
|
||||||
ellswift_example
|
ellswift_example
|
||||||
|
musig_example
|
||||||
*.exe
|
*.exe
|
||||||
*.so
|
*.so
|
||||||
*.a
|
*.a
|
||||||
|
23
CHANGELOG.md
23
CHANGELOG.md
@ -5,7 +5,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/),
|
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).
|
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
|
## [0.5.1] - 2024-08-01
|
||||||
|
|
||||||
@ -143,7 +162,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).
|
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.
|
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.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.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
|
[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)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
#=============================
|
||||||
|
# Project / Package metadata
|
||||||
|
#=============================
|
||||||
project(libsecp256k1
|
project(libsecp256k1
|
||||||
# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of
|
# 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
|
# the API. All changes in experimental modules are treated as
|
||||||
# backwards-compatible and therefore at most increase the minor version.
|
# 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."
|
DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1."
|
||||||
HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1"
|
HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1"
|
||||||
LANGUAGES C
|
LANGUAGES C
|
||||||
)
|
)
|
||||||
|
enable_testing()
|
||||||
|
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||||
|
|
||||||
if(CMAKE_VERSION VERSION_LESS 3.21)
|
if(CMAKE_VERSION VERSION_LESS 3.21)
|
||||||
# Emulates CMake 3.21+ behavior.
|
# Emulates CMake 3.21+ behavior.
|
||||||
@ -26,15 +31,19 @@ endif()
|
|||||||
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
# 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
|
# All changes in experimental modules are treated as if they don't affect the
|
||||||
# interface and therefore only increase the revision.
|
# interface and therefore only increase the revision.
|
||||||
set(${PROJECT_NAME}_LIB_VERSION_CURRENT 4)
|
set(${PROJECT_NAME}_LIB_VERSION_CURRENT 5)
|
||||||
set(${PROJECT_NAME}_LIB_VERSION_REVISION 2)
|
set(${PROJECT_NAME}_LIB_VERSION_REVISION 0)
|
||||||
set(${PROJECT_NAME}_LIB_VERSION_AGE 2)
|
set(${PROJECT_NAME}_LIB_VERSION_AGE 0)
|
||||||
|
|
||||||
|
#=============================
|
||||||
|
# Language setup
|
||||||
|
#=============================
|
||||||
set(CMAKE_C_STANDARD 90)
|
set(CMAKE_C_STANDARD 90)
|
||||||
set(CMAKE_C_EXTENSIONS OFF)
|
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(BUILD_SHARED_LIBS "Build shared libraries." ON)
|
||||||
option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF)
|
option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF)
|
||||||
if(SECP256K1_DISABLE_SHARED)
|
if(SECP256K1_DISABLE_SHARED)
|
||||||
@ -51,6 +60,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_RECOVERY "Enable ECDSA pubkey recovery module." OFF)
|
||||||
option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
|
option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
|
||||||
option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig 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_ELLSWIFT "Enable ElligatorSwift module." ON)
|
||||||
|
|
||||||
# Processing must be done in a topological sorting of the dependency graph
|
# Processing must be done in a topological sorting of the dependency graph
|
||||||
@ -59,6 +69,14 @@ if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
|||||||
add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
|
add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
|
||||||
endif()
|
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(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||||
if(DEFINED SECP256K1_ENABLE_MODULE_EXTRAKEYS AND NOT SECP256K1_ENABLE_MODULE_EXTRAKEYS)
|
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.")
|
message(FATAL_ERROR "Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.")
|
||||||
@ -262,13 +280,6 @@ if(SECP256K1_BUILD_CTIME_TESTS)
|
|||||||
unset(msan_enabled)
|
unset(msan_enabled)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(CTest)
|
|
||||||
# We do not use CTest's BUILD_TESTING because a single toggle for all tests is too coarse for our needs.
|
|
||||||
mark_as_advanced(BUILD_TESTING)
|
|
||||||
if(SECP256K1_BUILD_BENCHMARK OR SECP256K1_BUILD_TESTS OR SECP256K1_BUILD_EXHAUSTIVE_TESTS OR SECP256K1_BUILD_CTIME_TESTS OR SECP256K1_BUILD_EXAMPLES)
|
|
||||||
enable_testing()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(SECP256K1_APPEND_CFLAGS "" CACHE STRING "Compiler flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.")
|
set(SECP256K1_APPEND_CFLAGS "" CACHE STRING "Compiler flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.")
|
||||||
if(SECP256K1_APPEND_CFLAGS)
|
if(SECP256K1_APPEND_CFLAGS)
|
||||||
# Appending to this low-level rule variable is the only way to
|
# Appending to this low-level rule variable is the only way to
|
||||||
@ -284,6 +295,15 @@ if(SECP256K1_APPEND_LDFLAGS)
|
|||||||
string(APPEND CMAKE_C_LINK_EXECUTABLE " ${SECP256K1_APPEND_LDFLAGS}")
|
string(APPEND CMAKE_C_LINK_EXECUTABLE " ${SECP256K1_APPEND_LDFLAGS}")
|
||||||
endif()
|
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)
|
add_subdirectory(src)
|
||||||
if(SECP256K1_BUILD_EXAMPLES)
|
if(SECP256K1_BUILD_EXAMPLES)
|
||||||
add_subdirectory(examples)
|
add_subdirectory(examples)
|
||||||
@ -305,6 +325,7 @@ message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}
|
|||||||
message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}")
|
message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}")
|
||||||
message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}")
|
message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}")
|
||||||
message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}")
|
message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}")
|
||||||
|
message(" musig ............................... ${SECP256K1_ENABLE_MODULE_MUSIG}")
|
||||||
message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}")
|
message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}")
|
||||||
message("Parameters:")
|
message("Parameters:")
|
||||||
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
|
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
|
||||||
|
16
Makefile.am
16
Makefile.am
@ -195,6 +195,17 @@ ellswift_example_LDFLAGS += -lbcrypt
|
|||||||
endif
|
endif
|
||||||
TESTS += ellswift_example
|
TESTS += ellswift_example
|
||||||
endif
|
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
|
endif
|
||||||
|
|
||||||
### Precomputed tables
|
### Precomputed tables
|
||||||
@ -254,6 +265,7 @@ maintainer-clean-local: clean-testvectors
|
|||||||
### Additional files to distribute
|
### Additional files to distribute
|
||||||
EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md
|
EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md
|
||||||
EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.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 += examples/EXAMPLES_COPYING
|
||||||
EXTRA_DIST += sage/gen_exhaustive_groups.sage
|
EXTRA_DIST += sage/gen_exhaustive_groups.sage
|
||||||
EXTRA_DIST += sage/gen_split_lambda_constants.sage
|
EXTRA_DIST += sage/gen_split_lambda_constants.sage
|
||||||
@ -281,6 +293,10 @@ if ENABLE_MODULE_SCHNORRSIG
|
|||||||
include src/modules/schnorrsig/Makefile.am.include
|
include src/modules/schnorrsig/Makefile.am.include
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if ENABLE_MODULE_MUSIG
|
||||||
|
include src/modules/musig/Makefile.am.include
|
||||||
|
endif
|
||||||
|
|
||||||
if ENABLE_MODULE_ELLSWIFT
|
if ENABLE_MODULE_ELLSWIFT
|
||||||
include src/modules/ellswift/Makefile.am.include
|
include src/modules/ellswift/Makefile.am.include
|
||||||
endif
|
endif
|
||||||
|
@ -21,6 +21,7 @@ Features:
|
|||||||
* Optional module for ECDH key exchange.
|
* Optional module for ECDH key exchange.
|
||||||
* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
||||||
* Optional module for ElligatorSwift key exchange according to [BIP-324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki).
|
* Optional module for ElligatorSwift key exchange according to [BIP-324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki).
|
||||||
|
* Optional module for MuSig2 Schnorr multi-signatures according to [BIP-327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki).
|
||||||
|
|
||||||
Implementation details
|
Implementation details
|
||||||
----------------------
|
----------------------
|
||||||
|
3
ci/ci.sh
3
ci/ci.sh
@ -13,7 +13,7 @@ print_environment() {
|
|||||||
# does not rely on bash.
|
# does not rely on bash.
|
||||||
for var in WERROR_CFLAGS MAKEFLAGS BUILD \
|
for var in WERROR_CFLAGS MAKEFLAGS BUILD \
|
||||||
ECMULTWINDOW ECMULTGENKB ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
|
ECMULTWINDOW ECMULTGENKB ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
|
||||||
EXPERIMENTAL ECDH RECOVERY EXTRAKEYS SCHNORRSIG ELLSWIFT \
|
EXPERIMENTAL ECDH RECOVERY EXTRAKEYS MUSIG SCHNORRSIG ELLSWIFT \
|
||||||
SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
|
SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
|
||||||
EXAMPLES \
|
EXAMPLES \
|
||||||
HOST WRAPPER_CMD \
|
HOST WRAPPER_CMD \
|
||||||
@ -79,6 +79,7 @@ esac
|
|||||||
--enable-module-ellswift="$ELLSWIFT" \
|
--enable-module-ellswift="$ELLSWIFT" \
|
||||||
--enable-module-extrakeys="$EXTRAKEYS" \
|
--enable-module-extrakeys="$EXTRAKEYS" \
|
||||||
--enable-module-schnorrsig="$SCHNORRSIG" \
|
--enable-module-schnorrsig="$SCHNORRSIG" \
|
||||||
|
--enable-module-musig="$MUSIG" \
|
||||||
--enable-examples="$EXAMPLES" \
|
--enable-examples="$EXAMPLES" \
|
||||||
--enable-ctime-tests="$CTIMETESTS" \
|
--enable-ctime-tests="$CTIMETESTS" \
|
||||||
--with-valgrind="$WITH_VALGRIND" \
|
--with-valgrind="$WITH_VALGRIND" \
|
||||||
|
26
configure.ac
26
configure.ac
@ -4,18 +4,18 @@ AC_PREREQ([2.60])
|
|||||||
# the API. All changes in experimental modules are treated as
|
# the API. All changes in experimental modules are treated as
|
||||||
# backwards-compatible and therefore at most increase the minor version.
|
# backwards-compatible and therefore at most increase the minor version.
|
||||||
define(_PKG_VERSION_MAJOR, 0)
|
define(_PKG_VERSION_MAJOR, 0)
|
||||||
define(_PKG_VERSION_MINOR, 5)
|
define(_PKG_VERSION_MINOR, 6)
|
||||||
define(_PKG_VERSION_PATCH, 2)
|
define(_PKG_VERSION_PATCH, 0)
|
||||||
define(_PKG_VERSION_IS_RELEASE, false)
|
define(_PKG_VERSION_IS_RELEASE, true)
|
||||||
|
|
||||||
# The library version is based on libtool versioning of the ABI. The set of
|
# The library version is based on libtool versioning of the ABI. The set of
|
||||||
# rules for updating the version can be found here:
|
# rules for updating the version can be found here:
|
||||||
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
# 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
|
# All changes in experimental modules are treated as if they don't affect the
|
||||||
# interface and therefore only increase the revision.
|
# interface and therefore only increase the revision.
|
||||||
define(_LIB_VERSION_CURRENT, 4)
|
define(_LIB_VERSION_CURRENT, 5)
|
||||||
define(_LIB_VERSION_REVISION, 2)
|
define(_LIB_VERSION_REVISION, 0)
|
||||||
define(_LIB_VERSION_AGE, 2)
|
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])
|
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])
|
||||||
|
|
||||||
@ -184,6 +184,10 @@ AC_ARG_ENABLE(module_schnorrsig,
|
|||||||
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [],
|
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [],
|
||||||
[SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])])
|
[SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(module_musig,
|
||||||
|
AS_HELP_STRING([--enable-module-musig],[enable MuSig2 module [default=yes]]), [],
|
||||||
|
[SECP_SET_DEFAULT([enable_module_musig], [yes], [yes])])
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_ellswift,
|
AC_ARG_ENABLE(module_ellswift,
|
||||||
AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [],
|
AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [],
|
||||||
[SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])])
|
[SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])])
|
||||||
@ -398,6 +402,14 @@ if test x"$enable_module_ellswift" = x"yes"; then
|
|||||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1"
|
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1"
|
||||||
fi
|
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_schnorrsig" = x"yes"; then
|
||||||
if test x"$enable_module_extrakeys" = x"no"; 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.])
|
AC_MSG_ERROR([Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.])
|
||||||
@ -449,6 +461,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_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
||||||
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = 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_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_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"])
|
||||||
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
|
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
|
||||||
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"])
|
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"])
|
||||||
@ -471,6 +484,7 @@ echo " module ecdh = $enable_module_ecdh"
|
|||||||
echo " module recovery = $enable_module_recovery"
|
echo " module recovery = $enable_module_recovery"
|
||||||
echo " module extrakeys = $enable_module_extrakeys"
|
echo " module extrakeys = $enable_module_extrakeys"
|
||||||
echo " module schnorrsig = $enable_module_schnorrsig"
|
echo " module schnorrsig = $enable_module_schnorrsig"
|
||||||
|
echo " module musig = $enable_module_musig"
|
||||||
echo " module ellswift = $enable_module_ellswift"
|
echo " module ellswift = $enable_module_ellswift"
|
||||||
echo
|
echo
|
||||||
echo " asm = $set_asm"
|
echo " asm = $set_asm"
|
||||||
|
54
doc/musig.md
Normal file
54
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>
|
$<$<PLATFORM_ID:Windows>:bcrypt>
|
||||||
)
|
)
|
||||||
set(test_name ${name}_example)
|
set(test_name ${name}_example)
|
||||||
add_test(NAME ${test_name} COMMAND ${target_name})
|
add_test(NAME secp256k1_${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()
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
add_example(ecdsa)
|
add_example(ecdsa)
|
||||||
@ -32,3 +25,7 @@ endif()
|
|||||||
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
||||||
add_example(ellswift)
|
add_example(ellswift)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(SECP256K1_ENABLE_MODULE_MUSIG)
|
||||||
|
add_example(musig)
|
||||||
|
endif()
|
||||||
|
@ -42,18 +42,16 @@ int main(void) {
|
|||||||
assert(return_val);
|
assert(return_val);
|
||||||
|
|
||||||
/*** Key Generation ***/
|
/*** Key Generation ***/
|
||||||
|
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
||||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
printf("Failed to generate randomness\n");
|
||||||
* order), we try to sample a new key. Note that the probability of this
|
return 1;
|
||||||
* happening is negligible. */
|
}
|
||||||
while (1) {
|
/* If the secret key is zero or out of range (greater than secp256k1's
|
||||||
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
* order), we fail. Note that the probability of this occurring is negligible
|
||||||
printf("Failed to generate randomness\n");
|
* with a properly functioning random number generator. */
|
||||||
return 1;
|
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");
|
||||||
if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) {
|
return 1;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Public key creation using a valid context with a verified secret key should never fail */
|
/* 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);
|
assert(return_val);
|
||||||
|
|
||||||
/*** Key Generation ***/
|
/*** Key Generation ***/
|
||||||
|
if (!fill_random(seckey, sizeof(seckey))) {
|
||||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
printf("Failed to generate randomness\n");
|
||||||
* order), we try to sample a new key. Note that the probability of this
|
return 1;
|
||||||
* happening is negligible. */
|
}
|
||||||
while (1) {
|
/* If the secret key is zero or out of range (greater than secp256k1's
|
||||||
if (!fill_random(seckey, sizeof(seckey))) {
|
* order), we fail. Note that the probability of this occurring is negligible
|
||||||
printf("Failed to generate randomness\n");
|
* with a properly functioning random number generator. */
|
||||||
return 1;
|
if (!secp256k1_ec_seckey_verify(ctx, seckey)) {
|
||||||
}
|
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||||
if (secp256k1_ec_seckey_verify(ctx, seckey)) {
|
return 1;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Public key creation using a valid context with a verified secret key should never fail */
|
/* 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);
|
assert(return_val);
|
||||||
|
|
||||||
/*** Generate secret keys ***/
|
/*** Generate secret keys ***/
|
||||||
|
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
||||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
printf("Failed to generate randomness\n");
|
||||||
* order), we try to sample a new key. Note that the probability of this
|
return 1;
|
||||||
* happening is negligible. */
|
}
|
||||||
while (1) {
|
/* If the secret key is zero or out of range (greater than secp256k1's
|
||||||
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
* order), we fail. Note that the probability of this occurring is negligible
|
||||||
printf("Failed to generate randomness\n");
|
* with a properly functioning random number generator. */
|
||||||
return 1;
|
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");
|
||||||
if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) {
|
return 1;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate ElligatorSwift public keys. This should never fail with valid context and
|
/* Generate ElligatorSwift public keys. This should never fail with valid context and
|
||||||
|
260
examples/musig.c
Normal file
260
examples/musig.c
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
* To the extent possible under law, the author(s) have dedicated all *
|
||||||
|
* copyright and related and neighboring rights to the software in this *
|
||||||
|
* file to the public domain worldwide. This software is distributed *
|
||||||
|
* without any warranty. For the CC0 Public Domain Dedication, see *
|
||||||
|
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
/** This file demonstrates how to use the MuSig module to create a
|
||||||
|
* 3-of-3 multisignature. Additionally, see the documentation in
|
||||||
|
* include/secp256k1_musig.h and doc/musig.md.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <secp256k1.h>
|
||||||
|
#include <secp256k1_extrakeys.h>
|
||||||
|
#include <secp256k1_musig.h>
|
||||||
|
#include <secp256k1_schnorrsig.h>
|
||||||
|
|
||||||
|
#include "examples_util.h"
|
||||||
|
|
||||||
|
struct signer_secrets {
|
||||||
|
secp256k1_keypair keypair;
|
||||||
|
secp256k1_musig_secnonce secnonce;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct signer {
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
secp256k1_musig_pubnonce pubnonce;
|
||||||
|
secp256k1_musig_partial_sig partial_sig;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Number of public keys involved in creating the aggregate signature */
|
||||||
|
#define N_SIGNERS 3
|
||||||
|
/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */
|
||||||
|
static int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) {
|
||||||
|
unsigned char seckey[32];
|
||||||
|
|
||||||
|
if (!fill_random(seckey, sizeof(seckey))) {
|
||||||
|
printf("Failed to generate randomness\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* 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, &signer_secrets->keypair, seckey)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!secp256k1_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
secure_erase(seckey, sizeof(seckey));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tweak the pubkey corresponding to the provided keyagg cache, update the cache
|
||||||
|
* and return the tweaked aggregate pk. */
|
||||||
|
static int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache) {
|
||||||
|
secp256k1_pubkey output_pk;
|
||||||
|
/* For BIP 32 tweaking the plain_tweak is set to a hash as defined in BIP
|
||||||
|
* 32. */
|
||||||
|
unsigned char plain_tweak[32] = "this could be a BIP32 tweak....";
|
||||||
|
/* For Taproot tweaking the xonly_tweak is set to the TapTweak hash as
|
||||||
|
* defined in BIP 341 */
|
||||||
|
unsigned char xonly_tweak[32] = "this could be a Taproot tweak..";
|
||||||
|
|
||||||
|
|
||||||
|
/* Plain tweaking which, for example, allows deriving multiple child
|
||||||
|
* public keys from a single aggregate key using BIP32 */
|
||||||
|
if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, cache, plain_tweak)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Note that we did not provide an output_pk argument, because the
|
||||||
|
* resulting pk is also saved in the cache and so if one is just interested
|
||||||
|
* in signing, the output_pk argument is unnecessary. On the other hand, if
|
||||||
|
* one is not interested in signing, the same output_pk can be obtained by
|
||||||
|
* calling `secp256k1_musig_pubkey_get` right after key aggregation to get
|
||||||
|
* the full pubkey and then call `secp256k1_ec_pubkey_tweak_add`. */
|
||||||
|
|
||||||
|
/* Xonly tweaking which, for example, allows creating Taproot commitments */
|
||||||
|
if (!secp256k1_musig_pubkey_xonly_tweak_add(ctx, &output_pk, cache, xonly_tweak)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Note that if we wouldn't care about signing, we can arrive at the same
|
||||||
|
* output_pk by providing the untweaked public key to
|
||||||
|
* `secp256k1_xonly_pubkey_tweak_add` (after converting it to an xonly pubkey
|
||||||
|
* if necessary with `secp256k1_xonly_pubkey_from_pubkey`). */
|
||||||
|
|
||||||
|
/* Now we convert the output_pk to an xonly pubkey to allow to later verify
|
||||||
|
* the Schnorr signature against it. For this purpose we can ignore the
|
||||||
|
* `pk_parity` output argument; we would need it if we would have to open
|
||||||
|
* the Taproot commitment. */
|
||||||
|
if (!secp256k1_xonly_pubkey_from_pubkey(ctx, agg_pk, NULL, &output_pk)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sign a message hash with the given key pairs and store the result in sig */
|
||||||
|
static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const secp256k1_musig_keyagg_cache *cache, const unsigned char *msg32, unsigned char *sig64) {
|
||||||
|
int i;
|
||||||
|
const secp256k1_musig_pubnonce *pubnonces[N_SIGNERS];
|
||||||
|
const secp256k1_musig_partial_sig *partial_sigs[N_SIGNERS];
|
||||||
|
/* The same for all signers */
|
||||||
|
secp256k1_musig_session session;
|
||||||
|
secp256k1_musig_aggnonce agg_pubnonce;
|
||||||
|
|
||||||
|
for (i = 0; i < N_SIGNERS; i++) {
|
||||||
|
unsigned char seckey[32];
|
||||||
|
unsigned char session_secrand[32];
|
||||||
|
/* Create random session ID. It is absolutely necessary that the session ID
|
||||||
|
* is unique for every call of secp256k1_musig_nonce_gen. Otherwise
|
||||||
|
* it's trivial for an attacker to extract the secret key! */
|
||||||
|
if (!fill_random(session_secrand, sizeof(session_secrand))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Initialize session and create secret nonce for signing and public
|
||||||
|
* nonce to send to the other signers. */
|
||||||
|
if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_secrand, seckey, &signer[i].pubkey, msg32, NULL, NULL)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pubnonces[i] = &signer[i].pubnonce;
|
||||||
|
|
||||||
|
secure_erase(seckey, sizeof(seckey));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Communication round 1: Every signer sends their pubnonce to the
|
||||||
|
* coordinator. The coordinator runs secp256k1_musig_nonce_agg and sends
|
||||||
|
* agg_pubnonce to each signer */
|
||||||
|
if (!secp256k1_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Every signer creates a partial signature */
|
||||||
|
for (i = 0; i < N_SIGNERS; i++) {
|
||||||
|
/* Initialize the signing session by processing the aggregate nonce */
|
||||||
|
if (!secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, cache)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* partial_sign will clear the secnonce by setting it to 0. That's because
|
||||||
|
* you must _never_ reuse the secnonce (or use the same session_secrand to
|
||||||
|
* create a secnonce). If you do, you effectively reuse the nonce and
|
||||||
|
* leak the secret key. */
|
||||||
|
if (!secp256k1_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, cache, &session)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
partial_sigs[i] = &signer[i].partial_sig;
|
||||||
|
}
|
||||||
|
/* Communication round 2: Every signer sends their partial signature to the
|
||||||
|
* coordinator, who verifies the partial signatures and aggregates them. */
|
||||||
|
for (i = 0; i < N_SIGNERS; i++) {
|
||||||
|
/* To check whether signing was successful, it suffices to either verify
|
||||||
|
* the aggregate signature with the aggregate public key using
|
||||||
|
* secp256k1_schnorrsig_verify, or verify all partial signatures of all
|
||||||
|
* signers individually. Verifying the aggregate signature is cheaper but
|
||||||
|
* verifying the individual partial signatures has the advantage that it
|
||||||
|
* can be used to determine which of the partial signatures are invalid
|
||||||
|
* (if any), i.e., which of the partial signatures cause the aggregate
|
||||||
|
* signature to be invalid and thus the protocol run to fail. It's also
|
||||||
|
* fine to first verify the aggregate sig, and only verify the individual
|
||||||
|
* sigs if it does not work.
|
||||||
|
*/
|
||||||
|
if (!secp256k1_musig_partial_sig_verify(ctx, &signer[i].partial_sig, &signer[i].pubnonce, &signer[i].pubkey, cache, &session)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return secp256k1_musig_partial_sig_agg(ctx, sig64, &session, partial_sigs, N_SIGNERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
secp256k1_context* ctx;
|
||||||
|
int i;
|
||||||
|
struct signer_secrets signer_secrets[N_SIGNERS];
|
||||||
|
struct signer signers[N_SIGNERS];
|
||||||
|
const secp256k1_pubkey *pubkeys_ptr[N_SIGNERS];
|
||||||
|
secp256k1_xonly_pubkey agg_pk;
|
||||||
|
secp256k1_musig_keyagg_cache cache;
|
||||||
|
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg";
|
||||||
|
unsigned char sig[64];
|
||||||
|
|
||||||
|
/* Create a secp256k1 context */
|
||||||
|
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||||
|
printf("Creating key pairs......");
|
||||||
|
fflush(stdout);
|
||||||
|
for (i = 0; i < N_SIGNERS; i++) {
|
||||||
|
if (!create_keypair(ctx, &signer_secrets[i], &signers[i])) {
|
||||||
|
printf("FAILED\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
pubkeys_ptr[i] = &signers[i].pubkey;
|
||||||
|
}
|
||||||
|
printf("ok\n");
|
||||||
|
|
||||||
|
/* The aggregate public key produced by secp256k1_musig_pubkey_agg depends
|
||||||
|
* on the order of the provided public keys. If there is no canonical order
|
||||||
|
* of the signers, the individual public keys can optionally be sorted with
|
||||||
|
* secp256k1_ec_pubkey_sort to ensure that the aggregate public key is
|
||||||
|
* independent of the order of signers. */
|
||||||
|
printf("Sorting public keys.....");
|
||||||
|
fflush(stdout);
|
||||||
|
if (!secp256k1_ec_pubkey_sort(ctx, pubkeys_ptr, N_SIGNERS)) {
|
||||||
|
printf("FAILED\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("ok\n");
|
||||||
|
|
||||||
|
printf("Combining public keys...");
|
||||||
|
fflush(stdout);
|
||||||
|
/* If you just want to aggregate and not sign, you can call
|
||||||
|
* secp256k1_musig_pubkey_agg with the keyagg_cache argument set to NULL
|
||||||
|
* while providing a non-NULL agg_pk argument. */
|
||||||
|
if (!secp256k1_musig_pubkey_agg(ctx, NULL, &cache, pubkeys_ptr, N_SIGNERS)) {
|
||||||
|
printf("FAILED\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("ok\n");
|
||||||
|
printf("Tweaking................");
|
||||||
|
fflush(stdout);
|
||||||
|
/* Optionally tweak the aggregate key */
|
||||||
|
if (!tweak(ctx, &agg_pk, &cache)) {
|
||||||
|
printf("FAILED\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("ok\n");
|
||||||
|
printf("Signing message.........");
|
||||||
|
fflush(stdout);
|
||||||
|
if (!sign(ctx, signer_secrets, signers, &cache, msg, sig)) {
|
||||||
|
printf("FAILED\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("ok\n");
|
||||||
|
printf("Verifying signature.....");
|
||||||
|
fflush(stdout);
|
||||||
|
if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &agg_pk)) {
|
||||||
|
printf("FAILED\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("ok\n");
|
||||||
|
|
||||||
|
/* It's best practice to try to clear secrets from memory after using them.
|
||||||
|
* This is done because some bugs can allow an attacker to leak memory, for
|
||||||
|
* example through "out of bounds" array access (see Heartbleed), or the OS
|
||||||
|
* swapping them to disk. Hence, we overwrite secret key material with zeros.
|
||||||
|
*
|
||||||
|
* Here we are preventing these writes from being optimized out, as any good compiler
|
||||||
|
* will remove any writes that aren't used. */
|
||||||
|
for (i = 0; i < N_SIGNERS; i++) {
|
||||||
|
secure_erase(&signer_secrets[i], sizeof(signer_secrets[i]));
|
||||||
|
}
|
||||||
|
secp256k1_context_destroy(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
@ -43,20 +43,17 @@ int main(void) {
|
|||||||
assert(return_val);
|
assert(return_val);
|
||||||
|
|
||||||
/*** Key Generation ***/
|
/*** Key Generation ***/
|
||||||
|
if (!fill_random(seckey, sizeof(seckey))) {
|
||||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
printf("Failed to generate randomness\n");
|
||||||
* order), we try to sample a new key. Note that the probability of this
|
return 1;
|
||||||
* happening is negligible. */
|
}
|
||||||
while (1) {
|
/* Try to create a keypair with a valid context. This only fails if the
|
||||||
if (!fill_random(seckey, sizeof(seckey))) {
|
* secret key is zero or out of range (greater than secp256k1's order). Note
|
||||||
printf("Failed to generate randomness\n");
|
* that the probability of this occurring is negligible with a properly
|
||||||
return 1;
|
* functioning random number generator. */
|
||||||
}
|
if (!secp256k1_keypair_create(ctx, &keypair, seckey)) {
|
||||||
/* Try to create a keypair with a valid context, it should only fail if
|
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||||
* the secret key is zero or out of range. */
|
return 1;
|
||||||
if (secp256k1_keypair_create(ctx, &keypair, seckey)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract the X-only public key from the keypair. We pass NULL for
|
/* 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;
|
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.
|
/** Opaque data structure that holds a parsed and valid public key.
|
||||||
*
|
*
|
||||||
* The exact representation of data inside is implementation defined and not
|
* 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
|
* use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. To
|
||||||
* compare keys, use secp256k1_ec_pubkey_cmp.
|
* compare keys, use secp256k1_ec_pubkey_cmp.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct secp256k1_pubkey {
|
||||||
unsigned char data[64];
|
unsigned char data[64];
|
||||||
} secp256k1_pubkey;
|
} 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
|
* The exact representation of data inside is implementation defined and not
|
||||||
* guaranteed to be portable between different platforms or versions. It is
|
* 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
|
* comparison, use the secp256k1_ecdsa_signature_serialize_* and
|
||||||
* secp256k1_ecdsa_signature_parse_* functions.
|
* secp256k1_ecdsa_signature_parse_* functions.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct secp256k1_ecdsa_signature {
|
||||||
unsigned char data[64];
|
unsigned char data[64];
|
||||||
} secp256k1_ecdsa_signature;
|
} secp256k1_ecdsa_signature;
|
||||||
|
|
||||||
@ -147,6 +134,15 @@ typedef int (*secp256k1_nonce_function)(
|
|||||||
* 1. If using Libtool, it defines DLL_EXPORT automatically.
|
* 1. If using Libtool, it defines DLL_EXPORT automatically.
|
||||||
* 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */
|
* 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */
|
||||||
# define SECP256K1_API extern __declspec (dllexport)
|
# 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
|
# endif
|
||||||
/* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static
|
/* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static
|
||||||
* library on Windows. */
|
* library on Windows. */
|
||||||
@ -156,11 +152,12 @@ typedef int (*secp256k1_nonce_function)(
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#ifndef SECP256K1_API
|
#ifndef SECP256K1_API
|
||||||
|
/* All cases not captured by the Windows-specific logic. */
|
||||||
# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
|
# 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")))
|
# define SECP256K1_API extern __attribute__ ((visibility ("default")))
|
||||||
# else
|
# else
|
||||||
/* All cases not captured above. */
|
/* Fall back to standard C's extern. */
|
||||||
# define SECP256K1_API extern
|
# define SECP256K1_API extern
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
@ -392,29 +389,6 @@ SECP256K1_API void secp256k1_context_set_error_callback(
|
|||||||
const void *data
|
const void *data
|
||||||
) SECP256K1_ARG_NONNULL(1);
|
) 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.
|
/** Parse a variable-length public key into the pubkey object.
|
||||||
*
|
*
|
||||||
* Returns: 1 if the public key was fully valid.
|
* Returns: 1 if the public key was fully valid.
|
||||||
@ -679,12 +653,14 @@ SECP256K1_API int secp256k1_ecdsa_sign(
|
|||||||
const void *ndata
|
const void *ndata
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
) 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
|
* 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
|
* when interpreted as an integer (most significant byte first). The
|
||||||
* probability of choosing a 32-byte string uniformly at random which is an
|
* 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
|
* Returns: 1: secret key is valid
|
||||||
* 0: secret key is invalid
|
* 0: secret key is invalid
|
||||||
|
@ -19,7 +19,7 @@ extern "C" {
|
|||||||
* use secp256k1_xonly_pubkey_serialize and secp256k1_xonly_pubkey_parse. To
|
* use secp256k1_xonly_pubkey_serialize and secp256k1_xonly_pubkey_parse. To
|
||||||
* compare keys, use secp256k1_xonly_pubkey_cmp.
|
* compare keys, use secp256k1_xonly_pubkey_cmp.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct secp256k1_xonly_pubkey {
|
||||||
unsigned char data[64];
|
unsigned char data[64];
|
||||||
} secp256k1_xonly_pubkey;
|
} secp256k1_xonly_pubkey;
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ typedef struct {
|
|||||||
* guaranteed to be portable between different platforms or versions. It is
|
* 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.
|
* however guaranteed to be 96 bytes in size, and can be safely copied/moved.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct secp256k1_keypair {
|
||||||
unsigned char data[96];
|
unsigned char data[96];
|
||||||
} secp256k1_keypair;
|
} secp256k1_keypair;
|
||||||
|
|
||||||
@ -155,10 +155,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_
|
|||||||
const unsigned char *tweak32
|
const unsigned char *tweak32
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
) 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
|
* See the documentation of `secp256k1_ec_seckey_verify` for more information
|
||||||
* 0: secret was invalid, try again with a different secret
|
* 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).
|
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||||
* Out: keypair: pointer to the created keypair.
|
* Out: keypair: pointer to the created keypair.
|
||||||
* In: seckey: pointer to a 32-byte secret key.
|
* In: seckey: pointer to a 32-byte secret key.
|
||||||
|
588
include/secp256k1_musig.h
Normal file
588
include/secp256k1_musig.h
Normal file
@ -0,0 +1,588 @@
|
|||||||
|
#ifndef SECP256K1_MUSIG_H
|
||||||
|
#define SECP256K1_MUSIG_H
|
||||||
|
|
||||||
|
#include "secp256k1_extrakeys.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/** This module implements BIP 327 "MuSig2 for BIP340-compatible
|
||||||
|
* Multi-Signatures"
|
||||||
|
* (https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki)
|
||||||
|
* v1.0.0. You can find an example demonstrating the musig module in
|
||||||
|
* examples/musig.c.
|
||||||
|
*
|
||||||
|
* The module also supports BIP 341 ("Taproot") public key tweaking.
|
||||||
|
*
|
||||||
|
* It is recommended to read the documentation in this include file carefully.
|
||||||
|
* Further notes on API usage can be found in doc/musig.md
|
||||||
|
*
|
||||||
|
* Since the first version of MuSig is essentially replaced by MuSig2, we use
|
||||||
|
* MuSig, musig and MuSig2 synonymously unless noted otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Opaque data structures
|
||||||
|
*
|
||||||
|
* The exact representation of data inside the opaque data structures is
|
||||||
|
* implementation defined and not guaranteed to be portable between different
|
||||||
|
* platforms or versions. With the exception of `secp256k1_musig_secnonce`, the
|
||||||
|
* data structures can be safely copied/moved. If you need to convert to a
|
||||||
|
* format suitable for storage, transmission, or comparison, use the
|
||||||
|
* corresponding serialization and parsing functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Opaque data structure that caches information about public key aggregation.
|
||||||
|
*
|
||||||
|
* Guaranteed to be 197 bytes in size. No serialization and parsing functions
|
||||||
|
* (yet).
|
||||||
|
*/
|
||||||
|
typedef struct secp256k1_musig_keyagg_cache {
|
||||||
|
unsigned char data[197];
|
||||||
|
} secp256k1_musig_keyagg_cache;
|
||||||
|
|
||||||
|
/** Opaque data structure that holds a signer's _secret_ nonce.
|
||||||
|
*
|
||||||
|
* Guaranteed to be 132 bytes in size.
|
||||||
|
*
|
||||||
|
* WARNING: This structure MUST NOT be copied or read or written to directly. A
|
||||||
|
* signer who is online throughout the whole process and can keep this
|
||||||
|
* structure in memory can use the provided API functions for a safe standard
|
||||||
|
* workflow.
|
||||||
|
*
|
||||||
|
* Copying this data structure can result in nonce reuse which will leak the
|
||||||
|
* secret signing key.
|
||||||
|
*/
|
||||||
|
typedef struct secp256k1_musig_secnonce {
|
||||||
|
unsigned char data[132];
|
||||||
|
} secp256k1_musig_secnonce;
|
||||||
|
|
||||||
|
/** Opaque data structure that holds a signer's public nonce.
|
||||||
|
*
|
||||||
|
* Guaranteed to be 132 bytes in size. Serialized and parsed with
|
||||||
|
* `musig_pubnonce_serialize` and `musig_pubnonce_parse`.
|
||||||
|
*/
|
||||||
|
typedef struct secp256k1_musig_pubnonce {
|
||||||
|
unsigned char data[132];
|
||||||
|
} secp256k1_musig_pubnonce;
|
||||||
|
|
||||||
|
/** Opaque data structure that holds an aggregate public nonce.
|
||||||
|
*
|
||||||
|
* Guaranteed to be 132 bytes in size. Serialized and parsed with
|
||||||
|
* `musig_aggnonce_serialize` and `musig_aggnonce_parse`.
|
||||||
|
*/
|
||||||
|
typedef struct secp256k1_musig_aggnonce {
|
||||||
|
unsigned char data[132];
|
||||||
|
} secp256k1_musig_aggnonce;
|
||||||
|
|
||||||
|
/** Opaque data structure that holds a MuSig session.
|
||||||
|
*
|
||||||
|
* This structure is not required to be kept secret for the signing protocol to
|
||||||
|
* be secure. Guaranteed to be 133 bytes in size. No serialization and parsing
|
||||||
|
* functions (yet).
|
||||||
|
*/
|
||||||
|
typedef struct secp256k1_musig_session {
|
||||||
|
unsigned char data[133];
|
||||||
|
} secp256k1_musig_session;
|
||||||
|
|
||||||
|
/** Opaque data structure that holds a partial MuSig signature.
|
||||||
|
*
|
||||||
|
* Guaranteed to be 36 bytes in size. Serialized and parsed with
|
||||||
|
* `musig_partial_sig_serialize` and `musig_partial_sig_parse`.
|
||||||
|
*/
|
||||||
|
typedef struct secp256k1_musig_partial_sig {
|
||||||
|
unsigned char data[36];
|
||||||
|
} secp256k1_musig_partial_sig;
|
||||||
|
|
||||||
|
/** Parse a signer's public nonce.
|
||||||
|
*
|
||||||
|
* Returns: 1 when the nonce could be parsed, 0 otherwise.
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: nonce: pointer to a nonce object
|
||||||
|
* In: in66: pointer to the 66-byte nonce to be parsed
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubnonce_parse(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_musig_pubnonce *nonce,
|
||||||
|
const unsigned char *in66
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Serialize a signer's public nonce
|
||||||
|
*
|
||||||
|
* Returns: 1 always
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: out66: pointer to a 66-byte array to store the serialized nonce
|
||||||
|
* In: nonce: pointer to the nonce
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_musig_pubnonce_serialize(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
unsigned char *out66,
|
||||||
|
const secp256k1_musig_pubnonce *nonce
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Parse an aggregate public nonce.
|
||||||
|
*
|
||||||
|
* Returns: 1 when the nonce could be parsed, 0 otherwise.
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: nonce: pointer to a nonce object
|
||||||
|
* In: in66: pointer to the 66-byte nonce to be parsed
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_aggnonce_parse(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_musig_aggnonce *nonce,
|
||||||
|
const unsigned char *in66
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Serialize an aggregate public nonce
|
||||||
|
*
|
||||||
|
* Returns: 1 always
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: out66: pointer to a 66-byte array to store the serialized nonce
|
||||||
|
* In: nonce: pointer to the nonce
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_musig_aggnonce_serialize(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
unsigned char *out66,
|
||||||
|
const secp256k1_musig_aggnonce *nonce
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Parse a MuSig partial signature.
|
||||||
|
*
|
||||||
|
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: sig: pointer to a signature object
|
||||||
|
* In: in32: pointer to the 32-byte signature to be parsed
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_parse(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_musig_partial_sig *sig,
|
||||||
|
const unsigned char *in32
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Serialize a MuSig partial signature
|
||||||
|
*
|
||||||
|
* Returns: 1 always
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: out32: pointer to a 32-byte array to store the serialized signature
|
||||||
|
* In: sig: pointer to the signature
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_musig_partial_sig_serialize(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
unsigned char *out32,
|
||||||
|
const secp256k1_musig_partial_sig *sig
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Computes an aggregate public key and uses it to initialize a keyagg_cache
|
||||||
|
*
|
||||||
|
* Different orders of `pubkeys` result in different `agg_pk`s.
|
||||||
|
*
|
||||||
|
* Before aggregating, the pubkeys can be sorted with `secp256k1_ec_pubkey_sort`
|
||||||
|
* which ensures the same `agg_pk` result for the same multiset of pubkeys.
|
||||||
|
* This is useful to do before `pubkey_agg`, such that the order of pubkeys
|
||||||
|
* does not affect the aggregate public key.
|
||||||
|
*
|
||||||
|
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: agg_pk: the MuSig-aggregated x-only public key. If you do not need it,
|
||||||
|
* this arg can be NULL.
|
||||||
|
* keyagg_cache: if non-NULL, pointer to a musig_keyagg_cache struct that
|
||||||
|
* is required for signing (or observing the signing session
|
||||||
|
* and verifying partial signatures).
|
||||||
|
* In: pubkeys: input array of pointers to public keys to aggregate. The order
|
||||||
|
* is important; a different order will result in a different
|
||||||
|
* aggregate public key.
|
||||||
|
* n_pubkeys: length of pubkeys array. Must be greater than 0.
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_agg(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_xonly_pubkey *agg_pk,
|
||||||
|
secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||||
|
const secp256k1_pubkey * const *pubkeys,
|
||||||
|
size_t n_pubkeys
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
/** Obtain the aggregate public key from a keyagg_cache.
|
||||||
|
*
|
||||||
|
* This is only useful if you need the non-xonly public key, in particular for
|
||||||
|
* plain (non-xonly) tweaking or batch-verifying multiple key aggregations
|
||||||
|
* (not implemented).
|
||||||
|
*
|
||||||
|
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: agg_pk: the MuSig-aggregated public key.
|
||||||
|
* In: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by
|
||||||
|
* `musig_pubkey_agg`
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_pubkey *agg_pk,
|
||||||
|
const secp256k1_musig_keyagg_cache *keyagg_cache
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Apply plain "EC" tweaking to a public key in a given keyagg_cache by adding
|
||||||
|
* the generator multiplied with `tweak32` to it. This is useful for deriving
|
||||||
|
* child keys from an aggregate public key via BIP 32 where `tweak32` is set to
|
||||||
|
* a hash as defined in BIP 32.
|
||||||
|
*
|
||||||
|
* Callers are responsible for deriving `tweak32` in a way that does not reduce
|
||||||
|
* the security of MuSig (for example, by following BIP 32).
|
||||||
|
*
|
||||||
|
* The tweaking method is the same as `secp256k1_ec_pubkey_tweak_add`. So after
|
||||||
|
* the following pseudocode buf and buf2 have identical contents (absent
|
||||||
|
* earlier failures).
|
||||||
|
*
|
||||||
|
* secp256k1_musig_pubkey_agg(..., keyagg_cache, pubkeys, ...)
|
||||||
|
* secp256k1_musig_pubkey_get(..., agg_pk, keyagg_cache)
|
||||||
|
* secp256k1_musig_pubkey_ec_tweak_add(..., output_pk, tweak32, keyagg_cache)
|
||||||
|
* secp256k1_ec_pubkey_serialize(..., buf, ..., output_pk, ...)
|
||||||
|
* secp256k1_ec_pubkey_tweak_add(..., agg_pk, tweak32)
|
||||||
|
* secp256k1_ec_pubkey_serialize(..., buf2, ..., agg_pk, ...)
|
||||||
|
*
|
||||||
|
* This function is required if you want to _sign_ for a tweaked aggregate key.
|
||||||
|
* If you are only computing a public key but not intending to create a
|
||||||
|
* signature for it, use `secp256k1_ec_pubkey_tweak_add` instead.
|
||||||
|
*
|
||||||
|
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: output_pubkey: pointer to a public key to store the result. Will be set
|
||||||
|
* to an invalid value if this function returns 0. If you
|
||||||
|
* do not need it, this arg can be NULL.
|
||||||
|
* In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by
|
||||||
|
* `musig_pubkey_agg`
|
||||||
|
* In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes
|
||||||
|
* `secp256k1_ec_seckey_verify` and is not equal to the
|
||||||
|
* secret key corresponding to the public key represented
|
||||||
|
* by keyagg_cache or its negation. For uniformly random
|
||||||
|
* 32-byte arrays the chance of being invalid is
|
||||||
|
* negligible (around 1 in 2^128).
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_ec_tweak_add(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_pubkey *output_pubkey,
|
||||||
|
secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||||
|
const unsigned char *tweak32
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
/** Apply x-only tweaking to a public key in a given keyagg_cache by adding the
|
||||||
|
* generator multiplied with `tweak32` to it. This is useful for creating
|
||||||
|
* Taproot outputs where `tweak32` is set to a TapTweak hash as defined in BIP
|
||||||
|
* 341.
|
||||||
|
*
|
||||||
|
* Callers are responsible for deriving `tweak32` in a way that does not reduce
|
||||||
|
* the security of MuSig (for example, by following Taproot BIP 341).
|
||||||
|
*
|
||||||
|
* The tweaking method is the same as `secp256k1_xonly_pubkey_tweak_add`. So in
|
||||||
|
* the following pseudocode xonly_pubkey_tweak_add_check (absent earlier
|
||||||
|
* failures) returns 1.
|
||||||
|
*
|
||||||
|
* secp256k1_musig_pubkey_agg(..., agg_pk, keyagg_cache, pubkeys, ...)
|
||||||
|
* secp256k1_musig_pubkey_xonly_tweak_add(..., output_pk, keyagg_cache, tweak32)
|
||||||
|
* secp256k1_xonly_pubkey_serialize(..., buf, output_pk)
|
||||||
|
* secp256k1_xonly_pubkey_tweak_add_check(..., buf, ..., agg_pk, tweak32)
|
||||||
|
*
|
||||||
|
* This function is required if you want to _sign_ for a tweaked aggregate key.
|
||||||
|
* If you are only computing a public key but not intending to create a
|
||||||
|
* signature for it, use `secp256k1_xonly_pubkey_tweak_add` instead.
|
||||||
|
*
|
||||||
|
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: output_pubkey: pointer to a public key to store the result. Will be set
|
||||||
|
* to an invalid value if this function returns 0. If you
|
||||||
|
* do not need it, this arg can be NULL.
|
||||||
|
* In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by
|
||||||
|
* `musig_pubkey_agg`
|
||||||
|
* In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes
|
||||||
|
* `secp256k1_ec_seckey_verify` and is not equal to the
|
||||||
|
* secret key corresponding to the public key represented
|
||||||
|
* by keyagg_cache or its negation. For uniformly random
|
||||||
|
* 32-byte arrays the chance of being invalid is
|
||||||
|
* negligible (around 1 in 2^128).
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_tweak_add(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_pubkey *output_pubkey,
|
||||||
|
secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||||
|
const unsigned char *tweak32
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
/** Starts a signing session by generating a nonce
|
||||||
|
*
|
||||||
|
* This function outputs a secret nonce that will be required for signing and a
|
||||||
|
* corresponding public nonce that is intended to be sent to other signers.
|
||||||
|
*
|
||||||
|
* MuSig differs from regular Schnorr signing in that implementers _must_ take
|
||||||
|
* special care to not reuse a nonce. This can be ensured by following these rules:
|
||||||
|
*
|
||||||
|
* 1. Each call to this function must have a UNIQUE session_secrand32 that must
|
||||||
|
* NOT BE REUSED in subsequent calls to this function and must be KEPT
|
||||||
|
* SECRET (even from other signers).
|
||||||
|
* 2. If you already know the seckey, message or aggregate public key
|
||||||
|
* cache, they can be optionally provided to derive the nonce and increase
|
||||||
|
* misuse-resistance. The extra_input32 argument can be used to provide
|
||||||
|
* additional data that does not repeat in normal scenarios, such as the
|
||||||
|
* current time.
|
||||||
|
* 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
|
||||||
|
* that it is used more than once for signing.
|
||||||
|
*
|
||||||
|
* If you don't have access to good randomness for session_secrand32, but you
|
||||||
|
* have access to a non-repeating counter, then see
|
||||||
|
* secp256k1_musig_nonce_gen_counter.
|
||||||
|
*
|
||||||
|
* Remember that nonce reuse will leak the secret key!
|
||||||
|
* Note that using the same seckey for multiple MuSig sessions is fine.
|
||||||
|
*
|
||||||
|
* Returns: 0 if the arguments are invalid and 1 otherwise
|
||||||
|
* Args: ctx: pointer to a context object (not secp256k1_context_static)
|
||||||
|
* Out: secnonce: pointer to a structure to store the secret nonce
|
||||||
|
* pubnonce: pointer to a structure to store the public nonce
|
||||||
|
* In/Out:
|
||||||
|
* session_secrand32: a 32-byte session_secrand32 as explained above. Must be unique to this
|
||||||
|
* call to secp256k1_musig_nonce_gen and must be uniformly
|
||||||
|
* random. If the function call is successful, the
|
||||||
|
* session_secrand32 buffer is invalidated to prevent reuse.
|
||||||
|
* In:
|
||||||
|
* seckey: the 32-byte secret key that will later be used for signing, if
|
||||||
|
* already known (can be NULL)
|
||||||
|
* pubkey: public key of the signer creating the nonce. The secnonce
|
||||||
|
* output of this function cannot be used to sign for any
|
||||||
|
* other public key. While the public key should correspond
|
||||||
|
* to the provided seckey, a mismatch will not cause the
|
||||||
|
* function to return 0.
|
||||||
|
* msg32: the 32-byte message that will later be signed, if already known
|
||||||
|
* (can be NULL)
|
||||||
|
* keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate
|
||||||
|
* (and potentially tweaked) public key if already known
|
||||||
|
* (can be NULL)
|
||||||
|
* extra_input32: an optional 32-byte array that is input to the nonce
|
||||||
|
* derivation function (can be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_musig_secnonce *secnonce,
|
||||||
|
secp256k1_musig_pubnonce *pubnonce,
|
||||||
|
unsigned char *session_secrand32,
|
||||||
|
const unsigned char *seckey,
|
||||||
|
const secp256k1_pubkey *pubkey,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||||
|
const unsigned char *extra_input32
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6);
|
||||||
|
|
||||||
|
|
||||||
|
/** Alternative way to generate a nonce and start a signing session
|
||||||
|
*
|
||||||
|
* This function outputs a secret nonce that will be required for signing and a
|
||||||
|
* corresponding public nonce that is intended to be sent to other signers.
|
||||||
|
*
|
||||||
|
* This function differs from `secp256k1_musig_nonce_gen` by accepting a
|
||||||
|
* non-repeating counter value instead of a secret random value. This requires
|
||||||
|
* that a secret key is provided to `secp256k1_musig_nonce_gen_counter`
|
||||||
|
* (through the keypair argument), as opposed to `secp256k1_musig_nonce_gen`
|
||||||
|
* where the seckey argument is optional.
|
||||||
|
*
|
||||||
|
* MuSig differs from regular Schnorr signing in that implementers _must_ take
|
||||||
|
* special care to not reuse a nonce. This can be ensured by following these rules:
|
||||||
|
*
|
||||||
|
* 1. The nonrepeating_cnt argument must be a counter value that never repeats,
|
||||||
|
* i.e., you must never call `secp256k1_musig_nonce_gen_counter` twice with
|
||||||
|
* the same keypair and nonrepeating_cnt value. For example, this implies
|
||||||
|
* that if the same keypair is used with `secp256k1_musig_nonce_gen_counter`
|
||||||
|
* on multiple devices, none of the devices should have the same counter
|
||||||
|
* value as any other device.
|
||||||
|
* 2. If the seckey, message or aggregate public key cache is already available
|
||||||
|
* at this stage, any of these can be optionally provided, in which case
|
||||||
|
* they will be used in the derivation of the nonce and increase
|
||||||
|
* misuse-resistance. The extra_input32 argument can be used to provide
|
||||||
|
* additional data that does not repeat in normal scenarios, such as the
|
||||||
|
* current time.
|
||||||
|
* 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
|
||||||
|
* that it is used more than once for signing.
|
||||||
|
*
|
||||||
|
* Remember that nonce reuse will leak the secret key!
|
||||||
|
* Note that using the same keypair for multiple MuSig sessions is fine.
|
||||||
|
*
|
||||||
|
* Returns: 0 if the arguments are invalid and 1 otherwise
|
||||||
|
* Args: ctx: pointer to a context object (not secp256k1_context_static)
|
||||||
|
* Out: secnonce: pointer to a structure to store the secret nonce
|
||||||
|
* pubnonce: pointer to a structure to store the public nonce
|
||||||
|
* In:
|
||||||
|
* nonrepeating_cnt: the value of a counter as explained above. Must be
|
||||||
|
* unique to this call to secp256k1_musig_nonce_gen.
|
||||||
|
* keypair: keypair of the signer creating the nonce. The secnonce
|
||||||
|
* output of this function cannot be used to sign for any
|
||||||
|
* other keypair.
|
||||||
|
* msg32: the 32-byte message that will later be signed, if already known
|
||||||
|
* (can be NULL)
|
||||||
|
* keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate
|
||||||
|
* (and potentially tweaked) public key if already known
|
||||||
|
* (can be NULL)
|
||||||
|
* extra_input32: an optional 32-byte array that is input to the nonce
|
||||||
|
* derivation function (can be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen_counter(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_musig_secnonce *secnonce,
|
||||||
|
secp256k1_musig_pubnonce *pubnonce,
|
||||||
|
uint64_t nonrepeating_cnt,
|
||||||
|
const secp256k1_keypair *keypair,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||||
|
const unsigned char *extra_input32
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||||
|
|
||||||
|
/** Aggregates the nonces of all signers into a single nonce
|
||||||
|
*
|
||||||
|
* This can be done by an untrusted party to reduce the communication
|
||||||
|
* between signers. Instead of everyone sending nonces to everyone else, there
|
||||||
|
* can be one party receiving all nonces, aggregating the nonces with this
|
||||||
|
* function and then sending only the aggregate nonce back to the signers.
|
||||||
|
*
|
||||||
|
* If the aggregator does not compute the aggregate nonce correctly, the final
|
||||||
|
* signature will be invalid.
|
||||||
|
*
|
||||||
|
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: aggnonce: pointer to an aggregate public nonce object for
|
||||||
|
* musig_nonce_process
|
||||||
|
* In: pubnonces: array of pointers to public nonces sent by the
|
||||||
|
* signers
|
||||||
|
* n_pubnonces: number of elements in the pubnonces array. Must be
|
||||||
|
* greater than 0.
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_musig_nonce_agg(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_musig_aggnonce *aggnonce,
|
||||||
|
const secp256k1_musig_pubnonce * const *pubnonces,
|
||||||
|
size_t n_pubnonces
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Takes the aggregate nonce and creates a session that is required for signing
|
||||||
|
* and verification of partial signatures.
|
||||||
|
*
|
||||||
|
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: session: pointer to a struct to store the session
|
||||||
|
* In: aggnonce: pointer to an aggregate public nonce object that is the
|
||||||
|
* output of musig_nonce_agg
|
||||||
|
* msg32: the 32-byte message to sign
|
||||||
|
* keyagg_cache: pointer to the keyagg_cache that was used to create the
|
||||||
|
* aggregate (and potentially tweaked) pubkey
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_process(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_musig_session *session,
|
||||||
|
const secp256k1_musig_aggnonce *aggnonce,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const secp256k1_musig_keyagg_cache *keyagg_cache
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||||
|
|
||||||
|
/** Produces a partial signature
|
||||||
|
*
|
||||||
|
* This function overwrites the given secnonce with zeros and will abort if given a
|
||||||
|
* secnonce that is all zeros. This is a best effort attempt to protect against nonce
|
||||||
|
* reuse. However, this is of course easily defeated if the secnonce has been
|
||||||
|
* copied (or serialized). Remember that nonce reuse will leak the secret key!
|
||||||
|
*
|
||||||
|
* For signing to succeed, the secnonce provided to this function must have
|
||||||
|
* been generated for the provided keypair. This means that when signing for a
|
||||||
|
* keypair consisting of a seckey and pubkey, the secnonce must have been
|
||||||
|
* created by calling musig_nonce_gen with that pubkey. Otherwise, the
|
||||||
|
* illegal_callback is called.
|
||||||
|
*
|
||||||
|
* This function does not verify the output partial signature, deviating from
|
||||||
|
* the BIP 327 specification. It is recommended to verify the output partial
|
||||||
|
* signature with `secp256k1_musig_partial_sig_verify` to prevent random or
|
||||||
|
* adversarially provoked computation errors.
|
||||||
|
*
|
||||||
|
* Returns: 0 if the arguments are invalid or the provided secnonce has already
|
||||||
|
* been used for signing, 1 otherwise
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: partial_sig: pointer to struct to store the partial signature
|
||||||
|
* In/Out: secnonce: pointer to the secnonce struct created in
|
||||||
|
* musig_nonce_gen that has been never used in a
|
||||||
|
* partial_sign call before and has been created for the
|
||||||
|
* keypair
|
||||||
|
* In: keypair: pointer to keypair to sign the message with
|
||||||
|
* keyagg_cache: pointer to the keyagg_cache that was output when the
|
||||||
|
* aggregate public key for this session
|
||||||
|
* session: pointer to the session that was created with
|
||||||
|
* musig_nonce_process
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_musig_partial_sign(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_musig_partial_sig *partial_sig,
|
||||||
|
secp256k1_musig_secnonce *secnonce,
|
||||||
|
const secp256k1_keypair *keypair,
|
||||||
|
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||||
|
const secp256k1_musig_session *session
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
|
||||||
|
|
||||||
|
/** Verifies an individual signer's partial signature
|
||||||
|
*
|
||||||
|
* The signature is verified for a specific signing session. In order to avoid
|
||||||
|
* accidentally verifying a signature from a different or non-existing signing
|
||||||
|
* session, you must ensure the following:
|
||||||
|
* 1. The `keyagg_cache` argument is identical to the one used to create the
|
||||||
|
* `session` with `musig_nonce_process`.
|
||||||
|
* 2. The `pubkey` argument must be identical to the one sent by the signer
|
||||||
|
* before aggregating it with `musig_pubkey_agg` to create the
|
||||||
|
* `keyagg_cache`.
|
||||||
|
* 3. The `pubnonce` argument must be identical to the one sent by the signer
|
||||||
|
* before aggregating it with `musig_nonce_agg` and using the result to
|
||||||
|
* create the `session` with `musig_nonce_process`.
|
||||||
|
*
|
||||||
|
* It is not required to call this function in regular MuSig sessions, because
|
||||||
|
* if any partial signature does not verify, the final signature will not
|
||||||
|
* verify either, so the problem will be caught. However, this function
|
||||||
|
* provides the ability to identify which specific partial signature fails
|
||||||
|
* verification.
|
||||||
|
*
|
||||||
|
* Returns: 0 if the arguments are invalid or the partial signature does not
|
||||||
|
* verify, 1 otherwise
|
||||||
|
* Args ctx: pointer to a context object
|
||||||
|
* In: partial_sig: pointer to partial signature to verify, sent by
|
||||||
|
* the signer associated with `pubnonce` and `pubkey`
|
||||||
|
* pubnonce: public nonce of the signer in the signing session
|
||||||
|
* pubkey: public key of the signer in the signing session
|
||||||
|
* keyagg_cache: pointer to the keyagg_cache that was output when the
|
||||||
|
* aggregate public key for this signing session
|
||||||
|
* session: pointer to the session that was created with
|
||||||
|
* `musig_nonce_process`
|
||||||
|
*/
|
||||||
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
const secp256k1_musig_partial_sig *partial_sig,
|
||||||
|
const secp256k1_musig_pubnonce *pubnonce,
|
||||||
|
const secp256k1_pubkey *pubkey,
|
||||||
|
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||||
|
const secp256k1_musig_session *session
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
|
||||||
|
|
||||||
|
/** Aggregates partial signatures
|
||||||
|
*
|
||||||
|
* Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean
|
||||||
|
* the resulting signature verifies).
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: sig64: complete (but possibly invalid) Schnorr signature
|
||||||
|
* In: session: pointer to the session that was created with
|
||||||
|
* musig_nonce_process
|
||||||
|
* partial_sigs: array of pointers to partial signatures to aggregate
|
||||||
|
* n_sigs: number of elements in the partial_sigs array. Must be
|
||||||
|
* greater than 0.
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_musig_partial_sig_agg(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
unsigned char *sig64,
|
||||||
|
const secp256k1_musig_session *session,
|
||||||
|
const secp256k1_musig_partial_sig * const *partial_sigs,
|
||||||
|
size_t n_sigs
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -7,7 +7,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Opaque data structured that holds a parsed ECDSA signature,
|
/** Opaque data structure that holds a parsed ECDSA signature,
|
||||||
* supporting pubkey recovery.
|
* supporting pubkey recovery.
|
||||||
*
|
*
|
||||||
* The exact representation of data inside is implementation defined and not
|
* 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
|
* recoverability) will have identical representation, so they can be
|
||||||
* memcmp'ed.
|
* memcmp'ed.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct secp256k1_ecdsa_recoverable_signature {
|
||||||
unsigned char data[65];
|
unsigned char data[65];
|
||||||
} secp256k1_ecdsa_recoverable_signature;
|
} 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
|
* secp256k1_nonce_function_bip340 is used, then ndata must be a
|
||||||
* pointer to 32-byte auxiliary randomness as per BIP-340.
|
* pointer to 32-byte auxiliary randomness as per BIP-340.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct secp256k1_schnorrsig_extraparams {
|
||||||
unsigned char magic[4];
|
unsigned char magic[4];
|
||||||
secp256k1_nonce_function_hardened noncefp;
|
secp256k1_nonce_function_hardened noncefp;
|
||||||
void *ndata;
|
void *ndata;
|
||||||
|
@ -87,12 +87,12 @@ endif()
|
|||||||
if(SECP256K1_BUILD_TESTS)
|
if(SECP256K1_BUILD_TESTS)
|
||||||
add_executable(noverify_tests tests.c)
|
add_executable(noverify_tests tests.c)
|
||||||
target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm)
|
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")
|
if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage")
|
||||||
add_executable(tests tests.c)
|
add_executable(tests tests.c)
|
||||||
target_compile_definitions(tests PRIVATE VERIFY)
|
target_compile_definitions(tests PRIVATE VERIFY)
|
||||||
target_link_libraries(tests secp256k1_precomputed secp256k1_asm)
|
target_link_libraries(tests secp256k1_precomputed secp256k1_asm)
|
||||||
add_test(NAME tests COMMAND tests)
|
add_test(NAME secp256k1_tests COMMAND tests)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ if(SECP256K1_BUILD_EXHAUSTIVE_TESTS)
|
|||||||
add_executable(exhaustive_tests tests_exhaustive.c)
|
add_executable(exhaustive_tests tests_exhaustive.c)
|
||||||
target_link_libraries(exhaustive_tests secp256k1_asm)
|
target_link_libraries(exhaustive_tests secp256k1_asm)
|
||||||
target_compile_definitions(exhaustive_tests PRIVATE $<$<NOT:$<CONFIG:Coverage>>:VERIFY>)
|
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()
|
endif()
|
||||||
|
|
||||||
if(SECP256K1_BUILD_CTIME_TESTS)
|
if(SECP256K1_BUILD_CTIME_TESTS)
|
||||||
@ -132,6 +132,9 @@ if(SECP256K1_INSTALL)
|
|||||||
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||||
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h")
|
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h")
|
||||||
endif()
|
endif()
|
||||||
|
if(SECP256K1_ENABLE_MODULE_MUSIG)
|
||||||
|
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_musig.h")
|
||||||
|
endif()
|
||||||
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
||||||
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h")
|
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h")
|
||||||
endif()
|
endif()
|
||||||
|
@ -71,7 +71,7 @@ static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset
|
|||||||
secp256k1_scalar sum_scalars;
|
secp256k1_scalar sum_scalars;
|
||||||
|
|
||||||
secp256k1_gej_set_infinity(&sum_output);
|
secp256k1_gej_set_infinity(&sum_output);
|
||||||
secp256k1_scalar_clear(&sum_scalars);
|
secp256k1_scalar_set_int(&sum_scalars, 0);
|
||||||
for (i = 0; i < iters; ++i) {
|
for (i = 0; i < iters; ++i) {
|
||||||
secp256k1_gej_add_var(&sum_output, &sum_output, &data->output[i], NULL);
|
secp256k1_gej_add_var(&sum_output, &sum_output, &data->output[i], NULL);
|
||||||
if (scalar_gen_offset != NULL) {
|
if (scalar_gen_offset != NULL) {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "../include/secp256k1.h"
|
#include "../include/secp256k1.h"
|
||||||
#include "assumptions.h"
|
#include "assumptions.h"
|
||||||
@ -30,6 +31,10 @@
|
|||||||
#include "../include/secp256k1_schnorrsig.h"
|
#include "../include/secp256k1_schnorrsig.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_MODULE_MUSIG
|
||||||
|
#include "../include/secp256k1_musig.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||||
#include "../include/secp256k1_ellswift.h"
|
#include "../include/secp256k1_ellswift.h"
|
||||||
#endif
|
#endif
|
||||||
@ -180,6 +185,58 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
|||||||
CHECK(ret == 1);
|
CHECK(ret == 1);
|
||||||
#endif
|
#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
|
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||||
ret = secp256k1_ellswift_create(ctx, ellswift, key, NULL);
|
ret = secp256k1_ellswift_create(ctx, ellswift, key, NULL);
|
||||||
|
@ -277,8 +277,8 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
|
|||||||
/* Cleanup. */
|
/* Cleanup. */
|
||||||
secp256k1_fe_clear(&neg);
|
secp256k1_fe_clear(&neg);
|
||||||
secp256k1_ge_clear(&add);
|
secp256k1_ge_clear(&add);
|
||||||
memset(&adds, 0, sizeof(adds));
|
secp256k1_memclear(&adds, sizeof(adds));
|
||||||
memset(&recoded, 0, sizeof(recoded));
|
secp256k1_memclear(&recoded, sizeof(recoded));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup blinding values for secp256k1_ecmult_gen. */
|
/* Setup blinding values for secp256k1_ecmult_gen. */
|
||||||
@ -310,7 +310,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
|
|||||||
VERIFY_CHECK(seed32 != NULL);
|
VERIFY_CHECK(seed32 != NULL);
|
||||||
memcpy(keydata + 32, seed32, 32);
|
memcpy(keydata + 32, seed32, 32);
|
||||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64);
|
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64);
|
||||||
memset(keydata, 0, sizeof(keydata));
|
secp256k1_memclear(keydata, sizeof(keydata));
|
||||||
|
|
||||||
/* Compute projective blinding factor (cannot be 0). */
|
/* Compute projective blinding factor (cannot be 0). */
|
||||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||||
@ -325,16 +325,17 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
|
|||||||
* which secp256k1_gej_add_ge cannot handle. */
|
* which secp256k1_gej_add_ge cannot handle. */
|
||||||
secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b));
|
secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b));
|
||||||
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
||||||
memset(nonce32, 0, 32);
|
|
||||||
secp256k1_ecmult_gen(ctx, &gb, &b);
|
secp256k1_ecmult_gen(ctx, &gb, &b);
|
||||||
secp256k1_scalar_negate(&b, &b);
|
secp256k1_scalar_negate(&b, &b);
|
||||||
secp256k1_scalar_add(&ctx->scalar_offset, &b, &diff);
|
secp256k1_scalar_add(&ctx->scalar_offset, &b, &diff);
|
||||||
secp256k1_ge_set_gej(&ctx->ge_offset, &gb);
|
secp256k1_ge_set_gej(&ctx->ge_offset, &gb);
|
||||||
|
|
||||||
/* Clean up. */
|
/* Clean up. */
|
||||||
|
secp256k1_memclear(nonce32, sizeof(nonce32));
|
||||||
secp256k1_scalar_clear(&b);
|
secp256k1_scalar_clear(&b);
|
||||||
secp256k1_gej_clear(&gb);
|
secp256k1_gej_clear(&gb);
|
||||||
secp256k1_fe_clear(&f);
|
secp256k1_fe_clear(&f);
|
||||||
|
secp256k1_rfc6979_hmac_sha256_clear(&rng);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* SECP256K1_ECMULT_GEN_IMPL_H */
|
#endif /* SECP256K1_ECMULT_GEN_IMPL_H */
|
||||||
|
@ -171,7 +171,9 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
|
|||||||
VERIFY_CHECK(a != NULL);
|
VERIFY_CHECK(a != NULL);
|
||||||
VERIFY_CHECK(2 <= w && w <= 31);
|
VERIFY_CHECK(2 <= w && w <= 31);
|
||||||
|
|
||||||
memset(wnaf, 0, len * sizeof(wnaf[0]));
|
for (bit = 0; bit < len; bit++) {
|
||||||
|
wnaf[bit] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
s = *a;
|
s = *a;
|
||||||
if (secp256k1_scalar_get_bits_limb32(&s, 255, 1)) {
|
if (secp256k1_scalar_get_bits_limb32(&s, 255, 1)) {
|
||||||
@ -179,6 +181,7 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
|
|||||||
sign = -1;
|
sign = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bit = 0;
|
||||||
while (bit < len) {
|
while (bit < len) {
|
||||||
int now;
|
int now;
|
||||||
int word;
|
int word;
|
||||||
@ -660,7 +663,6 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_call
|
|||||||
struct secp256k1_pippenger_state *state_space;
|
struct secp256k1_pippenger_state *state_space;
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
size_t point_idx = 0;
|
size_t point_idx = 0;
|
||||||
int i, j;
|
|
||||||
int bucket_window;
|
int bucket_window;
|
||||||
|
|
||||||
secp256k1_gej_set_infinity(r);
|
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);
|
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);
|
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
|
||||||
return 1;
|
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 secp256k1_fe_impl_normalizes_to_zero
|
||||||
# define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var
|
# 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_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_zero secp256k1_fe_impl_is_zero
|
||||||
# define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd
|
# define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd
|
||||||
# define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var
|
# 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);
|
static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
|
||||||
|
|
||||||
/** Set a field element to 0.
|
/** Clear a field element to prevent leaking sensitive information. */
|
||||||
*
|
|
||||||
* 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);
|
static void secp256k1_fe_clear(secp256k1_fe *a);
|
||||||
|
|
||||||
/** Determine whether a represents field element 0.
|
/** 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;
|
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) {
|
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 9; i >= 0; 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;
|
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) {
|
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 4; i >= 0; i--) {
|
for (i = 4; i >= 0; i--) {
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
#error "Please select wide multiplication implementation"
|
#error "Please select wide multiplication implementation"
|
||||||
#endif
|
#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_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||||
secp256k1_fe na;
|
secp256k1_fe na;
|
||||||
SECP256K1_FE_VERIFY(a);
|
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);
|
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);
|
static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a);
|
||||||
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
|
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
|
||||||
SECP256K1_FE_VERIFY(a);
|
SECP256K1_FE_VERIFY(a);
|
||||||
|
16
src/group.h
16
src/group.h
@ -174,6 +174,22 @@ static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_g
|
|||||||
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */
|
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */
|
||||||
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
|
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
|
||||||
|
|
||||||
|
/** Convert a group element that is not infinity to a 64-byte array. The output
|
||||||
|
* array is platform-dependent. */
|
||||||
|
static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a);
|
||||||
|
|
||||||
|
/** Convert a 64-byte array into group element. This function assumes that the
|
||||||
|
* provided buffer correctly encodes a group element. */
|
||||||
|
static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf);
|
||||||
|
|
||||||
|
/** Convert a group element (that is allowed to be infinity) to a 64-byte
|
||||||
|
* array. The output array is platform-dependent. */
|
||||||
|
static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge);
|
||||||
|
|
||||||
|
/** Convert a 64-byte array into a group element. This function assumes that the
|
||||||
|
* provided buffer is the output of secp256k1_ge_to_bytes_ext. */
|
||||||
|
static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data);
|
||||||
|
|
||||||
/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve.
|
/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve.
|
||||||
*
|
*
|
||||||
* In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the
|
* In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#ifndef SECP256K1_GROUP_IMPL_H
|
#ifndef SECP256K1_GROUP_IMPL_H
|
||||||
#define SECP256K1_GROUP_IMPL_H
|
#define SECP256K1_GROUP_IMPL_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "field.h"
|
#include "field.h"
|
||||||
#include "group.h"
|
#include "group.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -281,36 +283,27 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se
|
|||||||
|
|
||||||
static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
|
static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
|
||||||
r->infinity = 1;
|
r->infinity = 1;
|
||||||
secp256k1_fe_clear(&r->x);
|
secp256k1_fe_set_int(&r->x, 0);
|
||||||
secp256k1_fe_clear(&r->y);
|
secp256k1_fe_set_int(&r->y, 0);
|
||||||
secp256k1_fe_clear(&r->z);
|
secp256k1_fe_set_int(&r->z, 0);
|
||||||
|
|
||||||
SECP256K1_GEJ_VERIFY(r);
|
SECP256K1_GEJ_VERIFY(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
|
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
|
||||||
r->infinity = 1;
|
r->infinity = 1;
|
||||||
secp256k1_fe_clear(&r->x);
|
secp256k1_fe_set_int(&r->x, 0);
|
||||||
secp256k1_fe_clear(&r->y);
|
secp256k1_fe_set_int(&r->y, 0);
|
||||||
|
|
||||||
SECP256K1_GE_VERIFY(r);
|
SECP256K1_GE_VERIFY(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_gej_clear(secp256k1_gej *r) {
|
static void secp256k1_gej_clear(secp256k1_gej *r) {
|
||||||
r->infinity = 0;
|
secp256k1_memclear(r, sizeof(secp256k1_gej));
|
||||||
secp256k1_fe_clear(&r->x);
|
|
||||||
secp256k1_fe_clear(&r->y);
|
|
||||||
secp256k1_fe_clear(&r->z);
|
|
||||||
|
|
||||||
SECP256K1_GEJ_VERIFY(r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_ge_clear(secp256k1_ge *r) {
|
static void secp256k1_ge_clear(secp256k1_ge *r) {
|
||||||
r->infinity = 0;
|
secp256k1_memclear(r, sizeof(secp256k1_ge));
|
||||||
secp256k1_fe_clear(&r->x);
|
|
||||||
secp256k1_fe_clear(&r->y);
|
|
||||||
|
|
||||||
SECP256K1_GE_VERIFY(r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
|
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
|
||||||
@ -941,4 +934,41 @@ static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp25
|
|||||||
return secp256k1_fe_is_square_var(&r);
|
return secp256k1_fe_is_square_var(&r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a) {
|
||||||
|
secp256k1_ge_storage s;
|
||||||
|
|
||||||
|
/* We require that the secp256k1_ge_storage type is exactly 64 bytes.
|
||||||
|
* This is formally not guaranteed by the C standard, but should hold on any
|
||||||
|
* sane compiler in the real world. */
|
||||||
|
STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64);
|
||||||
|
VERIFY_CHECK(!secp256k1_ge_is_infinity(a));
|
||||||
|
secp256k1_ge_to_storage(&s, a);
|
||||||
|
memcpy(buf, &s, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf) {
|
||||||
|
secp256k1_ge_storage s;
|
||||||
|
|
||||||
|
STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64);
|
||||||
|
memcpy(&s, buf, 64);
|
||||||
|
secp256k1_ge_from_storage(r, &s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge) {
|
||||||
|
if (secp256k1_ge_is_infinity(ge)) {
|
||||||
|
memset(data, 0, 64);
|
||||||
|
} else {
|
||||||
|
secp256k1_ge_to_bytes(data, ge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data) {
|
||||||
|
static const unsigned char zeros[64] = { 0 };
|
||||||
|
if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) {
|
||||||
|
secp256k1_ge_set_infinity(ge);
|
||||||
|
} else {
|
||||||
|
secp256k1_ge_from_bytes(ge, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SECP256K1_GROUP_IMPL_H */
|
#endif /* SECP256K1_GROUP_IMPL_H */
|
||||||
|
@ -19,6 +19,7 @@ typedef struct {
|
|||||||
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);
|
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_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_finalize(secp256k1_sha256 *hash, unsigned char *out32);
|
||||||
|
static void secp256k1_sha256_clear(secp256k1_sha256 *hash);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
secp256k1_sha256 inner, outer;
|
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_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_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_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32);
|
||||||
|
static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char v[32];
|
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_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_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_finalize(secp256k1_rfc6979_hmac_sha256 *rng);
|
||||||
|
static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng);
|
||||||
|
|
||||||
#endif /* SECP256K1_HASH_H */
|
#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);
|
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) {
|
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) {
|
||||||
size_t n;
|
size_t n;
|
||||||
unsigned char rkey[64];
|
unsigned char rkey[64];
|
||||||
@ -196,7 +200,7 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const
|
|||||||
rkey[n] ^= 0x5c ^ 0x36;
|
rkey[n] ^= 0x5c ^ 0x36;
|
||||||
}
|
}
|
||||||
secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey));
|
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) {
|
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];
|
unsigned char temp[32];
|
||||||
secp256k1_sha256_finalize(&hash->inner, temp);
|
secp256k1_sha256_finalize(&hash->inner, temp);
|
||||||
secp256k1_sha256_write(&hash->outer, temp, 32);
|
secp256k1_sha256_write(&hash->outer, temp, 32);
|
||||||
memset(temp, 0, 32);
|
secp256k1_memclear(temp, sizeof(temp));
|
||||||
secp256k1_sha256_finalize(&hash->outer, out32);
|
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) {
|
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) {
|
||||||
secp256k1_hmac_sha256 hmac;
|
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) {
|
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng) {
|
||||||
memset(rng->k, 0, 32);
|
(void) rng;
|
||||||
memset(rng->v, 0, 32);
|
}
|
||||||
rng->retry = 0;
|
|
||||||
|
static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng) {
|
||||||
|
secp256k1_memclear(rng, sizeof(*rng));
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef Round
|
#undef Round
|
||||||
|
@ -565,13 +565,12 @@ static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_m
|
|||||||
|
|
||||||
/* g == 0 */
|
/* g == 0 */
|
||||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &SECP256K1_SIGNED30_ONE, 0) == 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 ||
|
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(&f, 9, &SECP256K1_SIGNED30_ONE, 1) == 0 ||
|
||||||
(secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 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(&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. */
|
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||||
secp256k1_modinv32_normalize_30(&d, f.v[8], modinfo);
|
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 */
|
/* g == 0 */
|
||||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &SECP256K1_SIGNED30_ONE, 0) == 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 ||
|
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(&f, len, &SECP256K1_SIGNED30_ONE, 1) == 0 ||
|
||||||
(secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 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(&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. */
|
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||||
secp256k1_modinv32_normalize_30(&d, f.v[len - 1], modinfo);
|
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 */
|
/* g == 0 */
|
||||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &SECP256K1_SIGNED62_ONE, 0) == 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 ||
|
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(&f, 5, &SECP256K1_SIGNED62_ONE, 1) == 0 ||
|
||||||
(secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 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(&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. */
|
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||||
secp256k1_modinv64_normalize_62(&d, f.v[4], modinfo);
|
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 */
|
/* g == 0 */
|
||||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &SECP256K1_SIGNED62_ONE, 0) == 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 ||
|
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(&f, len, &SECP256K1_SIGNED62_ONE, 1) == 0 ||
|
||||||
(secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 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(&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. */
|
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||||
secp256k1_modinv64_normalize_62(&d, f.v[len - 1], modinfo);
|
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, &version, 1);
|
||||||
secp256k1_sha256_write(&sha, x32, 32);
|
secp256k1_sha256_write(&sha, x32, 32);
|
||||||
secp256k1_sha256_finalize(&sha, output);
|
secp256k1_sha256_finalize(&sha, output);
|
||||||
|
secp256k1_sha256_clear(&sha);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -61,9 +62,11 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se
|
|||||||
|
|
||||||
ret = hashfp(output, x, y, data);
|
ret = hashfp(output, x, y, data);
|
||||||
|
|
||||||
memset(x, 0, 32);
|
secp256k1_memclear(x, sizeof(x));
|
||||||
memset(y, 0, 32);
|
secp256k1_memclear(y, sizeof(y));
|
||||||
secp256k1_scalar_clear(&s);
|
secp256k1_scalar_clear(&s);
|
||||||
|
secp256k1_ge_clear(&pt);
|
||||||
|
secp256k1_gej_clear(&res);
|
||||||
|
|
||||||
return !!ret & !overflow;
|
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, ell_b64, 64);
|
||||||
secp256k1_sha256_write(&sha, x32, 32);
|
secp256k1_sha256_write(&sha, x32, 32);
|
||||||
secp256k1_sha256_finalize(&sha, output);
|
secp256k1_sha256_finalize(&sha, output);
|
||||||
|
secp256k1_sha256_clear(&sha);
|
||||||
|
|
||||||
return 1;
|
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, ell_b64, 64);
|
||||||
secp256k1_sha256_write(&sha, x32, 32);
|
secp256k1_sha256_write(&sha, x32, 32);
|
||||||
secp256k1_sha256_finalize(&sha, output);
|
secp256k1_sha256_finalize(&sha, output);
|
||||||
|
secp256k1_sha256_clear(&sha);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -580,7 +582,7 @@ int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output,
|
|||||||
/* Invoke hasher */
|
/* Invoke hasher */
|
||||||
ret = hashfp(output, sx, ell_a64, ell_b64, data);
|
ret = hashfp(output, sx, ell_a64, ell_b64, data);
|
||||||
|
|
||||||
memset(sx, 0, 32);
|
secp256k1_memclear(sx, sizeof(sx));
|
||||||
secp256k1_fe_clear(&px);
|
secp256k1_fe_clear(&px);
|
||||||
secp256k1_scalar_clear(&s);
|
secp256k1_scalar_clear(&s);
|
||||||
|
|
||||||
|
8
src/modules/musig/Makefile.am.include
Normal file
8
src/modules/musig/Makefile.am.include
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
include_HEADERS += include/secp256k1_musig.h
|
||||||
|
noinst_HEADERS += src/modules/musig/main_impl.h
|
||||||
|
noinst_HEADERS += src/modules/musig/keyagg.h
|
||||||
|
noinst_HEADERS += src/modules/musig/keyagg_impl.h
|
||||||
|
noinst_HEADERS += src/modules/musig/session.h
|
||||||
|
noinst_HEADERS += src/modules/musig/session_impl.h
|
||||||
|
noinst_HEADERS += src/modules/musig/tests_impl.h
|
||||||
|
noinst_HEADERS += src/modules/musig/vectors.h
|
32
src/modules/musig/keyagg.h
Normal file
32
src/modules/musig/keyagg.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/***********************************************************************
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_H
|
||||||
|
#define SECP256K1_MODULE_MUSIG_KEYAGG_H
|
||||||
|
|
||||||
|
#include "../../../include/secp256k1.h"
|
||||||
|
#include "../../../include/secp256k1_musig.h"
|
||||||
|
|
||||||
|
#include "../../group.h"
|
||||||
|
#include "../../scalar.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
secp256k1_ge pk;
|
||||||
|
/* If there is no "second" public key, second_pk is set to the point at
|
||||||
|
* infinity */
|
||||||
|
secp256k1_ge second_pk;
|
||||||
|
unsigned char pks_hash[32];
|
||||||
|
/* tweak is identical to value tacc[v] in the specification. */
|
||||||
|
secp256k1_scalar tweak;
|
||||||
|
/* parity_acc corresponds to (1 - gacc[v])/2 in the spec. So if gacc[v] is
|
||||||
|
* -1, parity_acc is 1. Otherwise, parity_acc is 0. */
|
||||||
|
int parity_acc;
|
||||||
|
} secp256k1_keyagg_cache_internal;
|
||||||
|
|
||||||
|
static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache);
|
||||||
|
|
||||||
|
static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk);
|
||||||
|
|
||||||
|
#endif
|
291
src/modules/musig/keyagg_impl.h
Normal file
291
src/modules/musig/keyagg_impl.h
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
/***********************************************************************
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H
|
||||||
|
#define SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "keyagg.h"
|
||||||
|
#include "../../eckey.h"
|
||||||
|
#include "../../ecmult.h"
|
||||||
|
#include "../../field.h"
|
||||||
|
#include "../../group.h"
|
||||||
|
#include "../../hash.h"
|
||||||
|
#include "../../util.h"
|
||||||
|
|
||||||
|
static const unsigned char secp256k1_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf };
|
||||||
|
|
||||||
|
/* A keyagg cache consists of
|
||||||
|
* - 4 byte magic set during initialization to allow detecting an uninitialized
|
||||||
|
* object.
|
||||||
|
* - 64 byte aggregate (and potentially tweaked) public key
|
||||||
|
* - 64 byte "second" public key (set to the point at infinity if not present)
|
||||||
|
* - 32 byte hash of all public keys
|
||||||
|
* - 1 byte the parity of the internal key (if tweaked, otherwise 0)
|
||||||
|
* - 32 byte tweak
|
||||||
|
*/
|
||||||
|
/* Requires that cache_i->pk is not infinity. */
|
||||||
|
static void secp256k1_keyagg_cache_save(secp256k1_musig_keyagg_cache *cache, const secp256k1_keyagg_cache_internal *cache_i) {
|
||||||
|
unsigned char *ptr = cache->data;
|
||||||
|
memcpy(ptr, secp256k1_musig_keyagg_cache_magic, 4);
|
||||||
|
ptr += 4;
|
||||||
|
secp256k1_ge_to_bytes(ptr, &cache_i->pk);
|
||||||
|
ptr += 64;
|
||||||
|
secp256k1_ge_to_bytes_ext(ptr, &cache_i->second_pk);
|
||||||
|
ptr += 64;
|
||||||
|
memcpy(ptr, cache_i->pks_hash, 32);
|
||||||
|
ptr += 32;
|
||||||
|
*ptr = cache_i->parity_acc;
|
||||||
|
ptr += 1;
|
||||||
|
secp256k1_scalar_get_b32(ptr, &cache_i->tweak);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache) {
|
||||||
|
const unsigned char *ptr = cache->data;
|
||||||
|
ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_keyagg_cache_magic, 4) == 0);
|
||||||
|
ptr += 4;
|
||||||
|
secp256k1_ge_from_bytes(&cache_i->pk, ptr);
|
||||||
|
ptr += 64;
|
||||||
|
secp256k1_ge_from_bytes_ext(&cache_i->second_pk, ptr);
|
||||||
|
ptr += 64;
|
||||||
|
memcpy(cache_i->pks_hash, ptr, 32);
|
||||||
|
ptr += 32;
|
||||||
|
cache_i->parity_acc = *ptr & 1;
|
||||||
|
ptr += 1;
|
||||||
|
secp256k1_scalar_set_b32(&cache_i->tweak, ptr, NULL);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||||
|
* SHA256 to SHA256("KeyAgg list")||SHA256("KeyAgg list"). */
|
||||||
|
static void secp256k1_musig_keyagglist_sha256(secp256k1_sha256 *sha) {
|
||||||
|
secp256k1_sha256_initialize(sha);
|
||||||
|
|
||||||
|
sha->s[0] = 0xb399d5e0ul;
|
||||||
|
sha->s[1] = 0xc8fff302ul;
|
||||||
|
sha->s[2] = 0x6badac71ul;
|
||||||
|
sha->s[3] = 0x07c5b7f1ul;
|
||||||
|
sha->s[4] = 0x9701e2eful;
|
||||||
|
sha->s[5] = 0x2a72ecf8ul;
|
||||||
|
sha->s[6] = 0x201a4c7bul;
|
||||||
|
sha->s[7] = 0xab148a38ul;
|
||||||
|
sha->bytes = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Computes pks_hash = tagged_hash(pk[0], ..., pk[np-1]) */
|
||||||
|
static int secp256k1_musig_compute_pks_hash(const secp256k1_context *ctx, unsigned char *pks_hash, const secp256k1_pubkey * const* pks, size_t np) {
|
||||||
|
secp256k1_sha256 sha;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
secp256k1_musig_keyagglist_sha256(&sha);
|
||||||
|
for (i = 0; i < np; i++) {
|
||||||
|
unsigned char ser[33];
|
||||||
|
size_t ser_len = sizeof(ser);
|
||||||
|
if (!secp256k1_ec_pubkey_serialize(ctx, ser, &ser_len, pks[i], SECP256K1_EC_COMPRESSED)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
VERIFY_CHECK(ser_len == sizeof(ser));
|
||||||
|
secp256k1_sha256_write(&sha, ser, sizeof(ser));
|
||||||
|
}
|
||||||
|
secp256k1_sha256_finalize(&sha, pks_hash);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||||
|
* SHA256 to SHA256("KeyAgg coefficient")||SHA256("KeyAgg coefficient"). */
|
||||||
|
static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) {
|
||||||
|
secp256k1_sha256_initialize(sha);
|
||||||
|
|
||||||
|
sha->s[0] = 0x6ef02c5aul;
|
||||||
|
sha->s[1] = 0x06a480deul;
|
||||||
|
sha->s[2] = 0x1f298665ul;
|
||||||
|
sha->s[3] = 0x1d1134f2ul;
|
||||||
|
sha->s[4] = 0x56a0b063ul;
|
||||||
|
sha->s[5] = 0x52da4147ul;
|
||||||
|
sha->s[6] = 0xf280d9d4ul;
|
||||||
|
sha->s[7] = 0x4484be15ul;
|
||||||
|
sha->bytes = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and
|
||||||
|
* otherwise tagged_hash(pks_hash, pk) where pks_hash is the hash of public keys.
|
||||||
|
* second_pk is the point at infinity in case there is no second_pk. Assumes
|
||||||
|
* that pk is not the point at infinity and that the Y-coordinates of pk and
|
||||||
|
* second_pk are normalized. */
|
||||||
|
static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pks_hash, secp256k1_ge *pk, const secp256k1_ge *second_pk) {
|
||||||
|
VERIFY_CHECK(!secp256k1_ge_is_infinity(pk));
|
||||||
|
|
||||||
|
if (!secp256k1_ge_is_infinity(second_pk)
|
||||||
|
&& secp256k1_ge_eq_var(pk, second_pk)) {
|
||||||
|
secp256k1_scalar_set_int(r, 1);
|
||||||
|
} else {
|
||||||
|
secp256k1_sha256 sha;
|
||||||
|
unsigned char buf[33];
|
||||||
|
size_t buflen = sizeof(buf);
|
||||||
|
int ret;
|
||||||
|
secp256k1_musig_keyaggcoef_sha256(&sha);
|
||||||
|
secp256k1_sha256_write(&sha, pks_hash, 32);
|
||||||
|
ret = secp256k1_eckey_pubkey_serialize(pk, buf, &buflen, 1);
|
||||||
|
#ifdef VERIFY
|
||||||
|
/* Serialization does not fail since the pk is not the point at infinity
|
||||||
|
* (according to this function's precondition). */
|
||||||
|
VERIFY_CHECK(ret && buflen == sizeof(buf));
|
||||||
|
#else
|
||||||
|
(void) ret;
|
||||||
|
#endif
|
||||||
|
secp256k1_sha256_write(&sha, buf, sizeof(buf));
|
||||||
|
secp256k1_sha256_finalize(&sha, buf);
|
||||||
|
secp256k1_scalar_set_b32(r, buf, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assumes that pk is not the point at infinity and that the Y-coordinates of pk
|
||||||
|
* and cache_i->second_pk are normalized. */
|
||||||
|
static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk) {
|
||||||
|
secp256k1_musig_keyaggcoef_internal(r, cache_i->pks_hash, pk, &cache_i->second_pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const secp256k1_context *ctx;
|
||||||
|
/* pks_hash is the hash of the public keys */
|
||||||
|
unsigned char pks_hash[32];
|
||||||
|
const secp256k1_pubkey * const* pks;
|
||||||
|
secp256k1_ge second_pk;
|
||||||
|
} secp256k1_musig_pubkey_agg_ecmult_data;
|
||||||
|
|
||||||
|
/* Callback for batch EC multiplication to compute keyaggcoef_0*P0 + keyaggcoef_1*P1 + ... */
|
||||||
|
static int secp256k1_musig_pubkey_agg_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
|
||||||
|
secp256k1_musig_pubkey_agg_ecmult_data *ctx = (secp256k1_musig_pubkey_agg_ecmult_data *) data;
|
||||||
|
int ret;
|
||||||
|
ret = secp256k1_pubkey_load(ctx->ctx, pt, ctx->pks[idx]);
|
||||||
|
#ifdef VERIFY
|
||||||
|
/* pubkey_load can't fail because the same pks have already been loaded in
|
||||||
|
* `musig_compute_pks_hash` (and we test this). */
|
||||||
|
VERIFY_CHECK(ret);
|
||||||
|
#else
|
||||||
|
(void) ret;
|
||||||
|
#endif
|
||||||
|
secp256k1_musig_keyaggcoef_internal(sc, ctx->pks_hash, pt, &ctx->second_pk);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_pubkey * const* pubkeys, size_t n_pubkeys) {
|
||||||
|
secp256k1_musig_pubkey_agg_ecmult_data ecmult_data;
|
||||||
|
secp256k1_gej pkj;
|
||||||
|
secp256k1_ge pkp;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
if (agg_pk != NULL) {
|
||||||
|
memset(agg_pk, 0, sizeof(*agg_pk));
|
||||||
|
}
|
||||||
|
ARG_CHECK(pubkeys != NULL);
|
||||||
|
ARG_CHECK(n_pubkeys > 0);
|
||||||
|
|
||||||
|
ecmult_data.ctx = ctx;
|
||||||
|
ecmult_data.pks = pubkeys;
|
||||||
|
|
||||||
|
secp256k1_ge_set_infinity(&ecmult_data.second_pk);
|
||||||
|
for (i = 1; i < n_pubkeys; i++) {
|
||||||
|
if (secp256k1_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) {
|
||||||
|
secp256k1_ge pk;
|
||||||
|
if (!secp256k1_pubkey_load(ctx, &pk, pubkeys[i])) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ecmult_data.second_pk = pk;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!secp256k1_musig_compute_pks_hash(ctx, ecmult_data.pks_hash, pubkeys, n_pubkeys)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* TODO: actually use optimized ecmult_multi algorithms by providing a
|
||||||
|
* scratch space */
|
||||||
|
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &pkj, NULL, secp256k1_musig_pubkey_agg_callback, (void *) &ecmult_data, n_pubkeys)) {
|
||||||
|
/* In order to reach this line with the current implementation of
|
||||||
|
* ecmult_multi_var one would need to provide a callback that can
|
||||||
|
* fail. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_ge_set_gej(&pkp, &pkj);
|
||||||
|
secp256k1_fe_normalize_var(&pkp.y);
|
||||||
|
/* The resulting public key is infinity with negligible probability */
|
||||||
|
VERIFY_CHECK(!secp256k1_ge_is_infinity(&pkp));
|
||||||
|
if (keyagg_cache != NULL) {
|
||||||
|
secp256k1_keyagg_cache_internal cache_i = { 0 };
|
||||||
|
cache_i.pk = pkp;
|
||||||
|
cache_i.second_pk = ecmult_data.second_pk;
|
||||||
|
memcpy(cache_i.pks_hash, ecmult_data.pks_hash, sizeof(cache_i.pks_hash));
|
||||||
|
secp256k1_keyagg_cache_save(keyagg_cache, &cache_i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (agg_pk != NULL) {
|
||||||
|
secp256k1_extrakeys_ge_even_y(&pkp);
|
||||||
|
secp256k1_xonly_pubkey_save(agg_pk, &pkp);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_pubkey_get(const secp256k1_context* ctx, secp256k1_pubkey *agg_pk, const secp256k1_musig_keyagg_cache *keyagg_cache) {
|
||||||
|
secp256k1_keyagg_cache_internal cache_i;
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(agg_pk != NULL);
|
||||||
|
memset(agg_pk, 0, sizeof(*agg_pk));
|
||||||
|
ARG_CHECK(keyagg_cache != NULL);
|
||||||
|
|
||||||
|
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_pubkey_save(agg_pk, &cache_i.pk);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_musig_pubkey_tweak_add_internal(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32, int xonly) {
|
||||||
|
secp256k1_keyagg_cache_internal cache_i;
|
||||||
|
int overflow = 0;
|
||||||
|
secp256k1_scalar tweak;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
if (output_pubkey != NULL) {
|
||||||
|
memset(output_pubkey, 0, sizeof(*output_pubkey));
|
||||||
|
}
|
||||||
|
ARG_CHECK(keyagg_cache != NULL);
|
||||||
|
ARG_CHECK(tweak32 != NULL);
|
||||||
|
|
||||||
|
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_scalar_set_b32(&tweak, tweak32, &overflow);
|
||||||
|
if (overflow) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (xonly && secp256k1_extrakeys_ge_even_y(&cache_i.pk)) {
|
||||||
|
cache_i.parity_acc ^= 1;
|
||||||
|
secp256k1_scalar_negate(&cache_i.tweak, &cache_i.tweak);
|
||||||
|
}
|
||||||
|
secp256k1_scalar_add(&cache_i.tweak, &cache_i.tweak, &tweak);
|
||||||
|
if (!secp256k1_eckey_pubkey_tweak_add(&cache_i.pk, &tweak)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* eckey_pubkey_tweak_add fails if cache_i.pk is infinity */
|
||||||
|
VERIFY_CHECK(!secp256k1_ge_is_infinity(&cache_i.pk));
|
||||||
|
secp256k1_keyagg_cache_save(keyagg_cache, &cache_i);
|
||||||
|
if (output_pubkey != NULL) {
|
||||||
|
secp256k1_pubkey_save(output_pubkey, &cache_i.pk);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_pubkey_ec_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) {
|
||||||
|
return secp256k1_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_pubkey_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) {
|
||||||
|
return secp256k1_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
12
src/modules/musig/main_impl.h
Normal file
12
src/modules/musig/main_impl.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/**********************************************************************
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SECP256K1_MODULE_MUSIG_MAIN_H
|
||||||
|
#define SECP256K1_MODULE_MUSIG_MAIN_H
|
||||||
|
|
||||||
|
#include "keyagg_impl.h"
|
||||||
|
#include "session_impl.h"
|
||||||
|
|
||||||
|
#endif
|
24
src/modules/musig/session.h
Normal file
24
src/modules/musig/session.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/***********************************************************************
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SECP256K1_MODULE_MUSIG_SESSION_H
|
||||||
|
#define SECP256K1_MODULE_MUSIG_SESSION_H
|
||||||
|
|
||||||
|
#include "../../../include/secp256k1.h"
|
||||||
|
#include "../../../include/secp256k1_musig.h"
|
||||||
|
|
||||||
|
#include "../../scalar.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int fin_nonce_parity;
|
||||||
|
unsigned char fin_nonce[32];
|
||||||
|
secp256k1_scalar noncecoef;
|
||||||
|
secp256k1_scalar challenge;
|
||||||
|
secp256k1_scalar s_part;
|
||||||
|
} secp256k1_musig_session_internal;
|
||||||
|
|
||||||
|
static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session);
|
||||||
|
|
||||||
|
#endif
|
816
src/modules/musig/session_impl.h
Normal file
816
src/modules/musig/session_impl.h
Normal file
@ -0,0 +1,816 @@
|
|||||||
|
/***********************************************************************
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SECP256K1_MODULE_MUSIG_SESSION_IMPL_H
|
||||||
|
#define SECP256K1_MODULE_MUSIG_SESSION_IMPL_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../../../include/secp256k1.h"
|
||||||
|
#include "../../../include/secp256k1_extrakeys.h"
|
||||||
|
#include "../../../include/secp256k1_musig.h"
|
||||||
|
|
||||||
|
#include "keyagg.h"
|
||||||
|
#include "session.h"
|
||||||
|
#include "../../eckey.h"
|
||||||
|
#include "../../hash.h"
|
||||||
|
#include "../../scalar.h"
|
||||||
|
#include "../../util.h"
|
||||||
|
|
||||||
|
/* Outputs 33 zero bytes if the given group element is the point at infinity and
|
||||||
|
* otherwise outputs the compressed serialization */
|
||||||
|
static void secp256k1_musig_ge_serialize_ext(unsigned char *out33, secp256k1_ge* ge) {
|
||||||
|
if (secp256k1_ge_is_infinity(ge)) {
|
||||||
|
memset(out33, 0, 33);
|
||||||
|
} else {
|
||||||
|
int ret;
|
||||||
|
size_t size = 33;
|
||||||
|
ret = secp256k1_eckey_pubkey_serialize(ge, out33, &size, 1);
|
||||||
|
#ifdef VERIFY
|
||||||
|
/* Serialize must succeed because the point is not at infinity */
|
||||||
|
VERIFY_CHECK(ret && size == 33);
|
||||||
|
#else
|
||||||
|
(void) ret;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Outputs the point at infinity if the given byte array is all zero, otherwise
|
||||||
|
* attempts to parse compressed point serialization. */
|
||||||
|
static int secp256k1_musig_ge_parse_ext(secp256k1_ge* ge, const unsigned char *in33) {
|
||||||
|
unsigned char zeros[33] = { 0 };
|
||||||
|
|
||||||
|
if (secp256k1_memcmp_var(in33, zeros, sizeof(zeros)) == 0) {
|
||||||
|
secp256k1_ge_set_infinity(ge);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!secp256k1_eckey_pubkey_parse(ge, in33, 33)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return secp256k1_ge_is_in_correct_subgroup(ge);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const unsigned char secp256k1_musig_secnonce_magic[4] = { 0x22, 0x0e, 0xdc, 0xf1 };
|
||||||
|
|
||||||
|
static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, const secp256k1_scalar *k, const secp256k1_ge *pk) {
|
||||||
|
memcpy(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4);
|
||||||
|
secp256k1_scalar_get_b32(&secnonce->data[4], &k[0]);
|
||||||
|
secp256k1_scalar_get_b32(&secnonce->data[36], &k[1]);
|
||||||
|
secp256k1_ge_to_bytes(&secnonce->data[68], pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_ge *pk, const secp256k1_musig_secnonce *secnonce) {
|
||||||
|
int is_zero;
|
||||||
|
ARG_CHECK(secp256k1_memcmp_var(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4) == 0);
|
||||||
|
/* We make very sure that the nonce isn't invalidated by checking the values
|
||||||
|
* in addition to the magic. */
|
||||||
|
is_zero = secp256k1_is_zero_array(&secnonce->data[4], 2 * 32);
|
||||||
|
secp256k1_declassify(ctx, &is_zero, sizeof(is_zero));
|
||||||
|
ARG_CHECK(!is_zero);
|
||||||
|
|
||||||
|
secp256k1_scalar_set_b32(&k[0], &secnonce->data[4], NULL);
|
||||||
|
secp256k1_scalar_set_b32(&k[1], &secnonce->data[36], NULL);
|
||||||
|
secp256k1_ge_from_bytes(pk, &secnonce->data[68]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If flag is true, invalidate the secnonce; otherwise leave it. Constant-time. */
|
||||||
|
static void secp256k1_musig_secnonce_invalidate(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, int flag) {
|
||||||
|
secp256k1_memczero(secnonce->data, sizeof(secnonce->data), flag);
|
||||||
|
/* The flag argument is usually classified. So, the line above makes the
|
||||||
|
* magic and public key classified. However, we need both to be
|
||||||
|
* declassified. Note that we don't declassify the entire object, because if
|
||||||
|
* flag is 0, then k[0] and k[1] have not been zeroed. */
|
||||||
|
secp256k1_declassify(ctx, secnonce->data, sizeof(secp256k1_musig_secnonce_magic));
|
||||||
|
secp256k1_declassify(ctx, &secnonce->data[68], 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const unsigned char secp256k1_musig_pubnonce_magic[4] = { 0xf5, 0x7a, 0x3d, 0xa0 };
|
||||||
|
|
||||||
|
/* Saves two group elements into a pubnonce. Requires that none of the provided
|
||||||
|
* group elements is infinity. */
|
||||||
|
static void secp256k1_musig_pubnonce_save(secp256k1_musig_pubnonce* nonce, const secp256k1_ge* ges) {
|
||||||
|
int i;
|
||||||
|
memcpy(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4);
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
secp256k1_ge_to_bytes(nonce->data + 4+64*i, &ges[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loads two group elements from a pubnonce. Returns 1 unless the nonce wasn't
|
||||||
|
* properly initialized */
|
||||||
|
static int secp256k1_musig_pubnonce_load(const secp256k1_context* ctx, secp256k1_ge* ges, const secp256k1_musig_pubnonce* nonce) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4) == 0);
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
secp256k1_ge_from_bytes(&ges[i], nonce->data + 4 + 64*i);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const unsigned char secp256k1_musig_aggnonce_magic[4] = { 0xa8, 0xb7, 0xe4, 0x67 };
|
||||||
|
|
||||||
|
static void secp256k1_musig_aggnonce_save(secp256k1_musig_aggnonce* nonce, const secp256k1_ge* ges) {
|
||||||
|
int i;
|
||||||
|
memcpy(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4);
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
secp256k1_ge_to_bytes_ext(&nonce->data[4 + 64*i], &ges[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_musig_aggnonce_load(const secp256k1_context* ctx, secp256k1_ge* ges, const secp256k1_musig_aggnonce* nonce) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4) == 0);
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
secp256k1_ge_from_bytes_ext(&ges[i], &nonce->data[4 + 64*i]);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const unsigned char secp256k1_musig_session_cache_magic[4] = { 0x9d, 0xed, 0xe9, 0x17 };
|
||||||
|
|
||||||
|
/* A session consists of
|
||||||
|
* - 4 byte session cache magic
|
||||||
|
* - 1 byte the parity of the final nonce
|
||||||
|
* - 32 byte serialized x-only final nonce
|
||||||
|
* - 32 byte nonce coefficient b
|
||||||
|
* - 32 byte signature challenge hash e
|
||||||
|
* - 32 byte scalar s that is added to the partial signatures of the signers
|
||||||
|
*/
|
||||||
|
static void secp256k1_musig_session_save(secp256k1_musig_session *session, const secp256k1_musig_session_internal *session_i) {
|
||||||
|
unsigned char *ptr = session->data;
|
||||||
|
|
||||||
|
memcpy(ptr, secp256k1_musig_session_cache_magic, 4);
|
||||||
|
ptr += 4;
|
||||||
|
*ptr = session_i->fin_nonce_parity;
|
||||||
|
ptr += 1;
|
||||||
|
memcpy(ptr, session_i->fin_nonce, 32);
|
||||||
|
ptr += 32;
|
||||||
|
secp256k1_scalar_get_b32(ptr, &session_i->noncecoef);
|
||||||
|
ptr += 32;
|
||||||
|
secp256k1_scalar_get_b32(ptr, &session_i->challenge);
|
||||||
|
ptr += 32;
|
||||||
|
secp256k1_scalar_get_b32(ptr, &session_i->s_part);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session) {
|
||||||
|
const unsigned char *ptr = session->data;
|
||||||
|
|
||||||
|
ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_session_cache_magic, 4) == 0);
|
||||||
|
ptr += 4;
|
||||||
|
session_i->fin_nonce_parity = *ptr;
|
||||||
|
ptr += 1;
|
||||||
|
memcpy(session_i->fin_nonce, ptr, 32);
|
||||||
|
ptr += 32;
|
||||||
|
secp256k1_scalar_set_b32(&session_i->noncecoef, ptr, NULL);
|
||||||
|
ptr += 32;
|
||||||
|
secp256k1_scalar_set_b32(&session_i->challenge, ptr, NULL);
|
||||||
|
ptr += 32;
|
||||||
|
secp256k1_scalar_set_b32(&session_i->s_part, ptr, NULL);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const unsigned char secp256k1_musig_partial_sig_magic[4] = { 0xeb, 0xfb, 0x1a, 0x32 };
|
||||||
|
|
||||||
|
static void secp256k1_musig_partial_sig_save(secp256k1_musig_partial_sig* sig, secp256k1_scalar *s) {
|
||||||
|
memcpy(&sig->data[0], secp256k1_musig_partial_sig_magic, 4);
|
||||||
|
secp256k1_scalar_get_b32(&sig->data[4], s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_musig_partial_sig_load(const secp256k1_context* ctx, secp256k1_scalar *s, const secp256k1_musig_partial_sig* sig) {
|
||||||
|
int overflow;
|
||||||
|
|
||||||
|
ARG_CHECK(secp256k1_memcmp_var(&sig->data[0], secp256k1_musig_partial_sig_magic, 4) == 0);
|
||||||
|
secp256k1_scalar_set_b32(s, &sig->data[4], &overflow);
|
||||||
|
/* Parsed signatures can not overflow */
|
||||||
|
VERIFY_CHECK(!overflow);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_pubnonce_parse(const secp256k1_context* ctx, secp256k1_musig_pubnonce* nonce, const unsigned char *in66) {
|
||||||
|
secp256k1_ge ges[2];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(nonce != NULL);
|
||||||
|
ARG_CHECK(in66 != NULL);
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
if (!secp256k1_eckey_pubkey_parse(&ges[i], &in66[33*i], 33)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!secp256k1_ge_is_in_correct_subgroup(&ges[i])) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
secp256k1_musig_pubnonce_save(nonce, ges);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_pubnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_pubnonce* nonce) {
|
||||||
|
secp256k1_ge ges[2];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(out66 != NULL);
|
||||||
|
memset(out66, 0, 66);
|
||||||
|
ARG_CHECK(nonce != NULL);
|
||||||
|
|
||||||
|
if (!secp256k1_musig_pubnonce_load(ctx, ges, nonce)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
int ret;
|
||||||
|
size_t size = 33;
|
||||||
|
ret = secp256k1_eckey_pubkey_serialize(&ges[i], &out66[33*i], &size, 1);
|
||||||
|
#ifdef VERIFY
|
||||||
|
/* serialize must succeed because the point was just loaded */
|
||||||
|
VERIFY_CHECK(ret && size == 33);
|
||||||
|
#else
|
||||||
|
(void) ret;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_aggnonce_parse(const secp256k1_context* ctx, secp256k1_musig_aggnonce* nonce, const unsigned char *in66) {
|
||||||
|
secp256k1_ge ges[2];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(nonce != NULL);
|
||||||
|
ARG_CHECK(in66 != NULL);
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
if (!secp256k1_musig_ge_parse_ext(&ges[i], &in66[33*i])) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
secp256k1_musig_aggnonce_save(nonce, ges);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_aggnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_aggnonce* nonce) {
|
||||||
|
secp256k1_ge ges[2];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(out66 != NULL);
|
||||||
|
memset(out66, 0, 66);
|
||||||
|
ARG_CHECK(nonce != NULL);
|
||||||
|
|
||||||
|
if (!secp256k1_musig_aggnonce_load(ctx, ges, nonce)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
secp256k1_musig_ge_serialize_ext(&out66[33*i], &ges[i]);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_partial_sig_parse(const secp256k1_context* ctx, secp256k1_musig_partial_sig* sig, const unsigned char *in32) {
|
||||||
|
secp256k1_scalar tmp;
|
||||||
|
int overflow;
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(sig != NULL);
|
||||||
|
ARG_CHECK(in32 != NULL);
|
||||||
|
|
||||||
|
/* Ensure that using the signature will fail if parsing fails (and the user
|
||||||
|
* doesn't check the return value). */
|
||||||
|
memset(sig, 0, sizeof(*sig));
|
||||||
|
|
||||||
|
secp256k1_scalar_set_b32(&tmp, in32, &overflow);
|
||||||
|
if (overflow) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_musig_partial_sig_save(sig, &tmp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_partial_sig_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_sig* sig) {
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(out32 != NULL);
|
||||||
|
ARG_CHECK(sig != NULL);
|
||||||
|
ARG_CHECK(secp256k1_memcmp_var(&sig->data[0], secp256k1_musig_partial_sig_magic, 4) == 0);
|
||||||
|
|
||||||
|
memcpy(out32, &sig->data[4], 32);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write optional inputs into the hash */
|
||||||
|
static void secp256k1_nonce_function_musig_helper(secp256k1_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) {
|
||||||
|
unsigned char zero[7] = { 0 };
|
||||||
|
/* The spec requires length prefixes to be between 1 and 8 bytes
|
||||||
|
* (inclusive) */
|
||||||
|
VERIFY_CHECK(prefix_size >= 1 && prefix_size <= 8);
|
||||||
|
/* Since the length of all input data fits in a byte, we can always pad the
|
||||||
|
* length prefix with prefix_size - 1 zero bytes. */
|
||||||
|
secp256k1_sha256_write(sha, zero, prefix_size - 1);
|
||||||
|
if (data != NULL) {
|
||||||
|
secp256k1_sha256_write(sha, &len, 1);
|
||||||
|
secp256k1_sha256_write(sha, data, len);
|
||||||
|
} else {
|
||||||
|
len = 0;
|
||||||
|
secp256k1_sha256_write(sha, &len, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||||
|
* SHA256 to SHA256("MuSig/aux")||SHA256("MuSig/aux"). */
|
||||||
|
static void secp256k1_nonce_function_musig_sha256_tagged_aux(secp256k1_sha256 *sha) {
|
||||||
|
secp256k1_sha256_initialize(sha);
|
||||||
|
sha->s[0] = 0xa19e884bul;
|
||||||
|
sha->s[1] = 0xf463fe7eul;
|
||||||
|
sha->s[2] = 0x2f18f9a2ul;
|
||||||
|
sha->s[3] = 0xbeb0f9fful;
|
||||||
|
sha->s[4] = 0x0f37e8b0ul;
|
||||||
|
sha->s[5] = 0x06ebd26ful;
|
||||||
|
sha->s[6] = 0xe3b243d2ul;
|
||||||
|
sha->s[7] = 0x522fb150ul;
|
||||||
|
sha->bytes = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||||
|
* SHA256 to SHA256("MuSig/nonce")||SHA256("MuSig/nonce"). */
|
||||||
|
static void secp256k1_nonce_function_musig_sha256_tagged(secp256k1_sha256 *sha) {
|
||||||
|
secp256k1_sha256_initialize(sha);
|
||||||
|
sha->s[0] = 0x07101b64ul;
|
||||||
|
sha->s[1] = 0x18003414ul;
|
||||||
|
sha->s[2] = 0x0391bc43ul;
|
||||||
|
sha->s[3] = 0x0e6258eeul;
|
||||||
|
sha->s[4] = 0x29d26b72ul;
|
||||||
|
sha->s[5] = 0x8343937eul;
|
||||||
|
sha->s[6] = 0xb7a0a4fbul;
|
||||||
|
sha->s[7] = 0xff568a30ul;
|
||||||
|
sha->bytes = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_secrand, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) {
|
||||||
|
secp256k1_sha256 sha;
|
||||||
|
unsigned char rand[32];
|
||||||
|
unsigned char i;
|
||||||
|
unsigned char msg_present;
|
||||||
|
|
||||||
|
if (seckey32 != NULL) {
|
||||||
|
secp256k1_nonce_function_musig_sha256_tagged_aux(&sha);
|
||||||
|
secp256k1_sha256_write(&sha, session_secrand, 32);
|
||||||
|
secp256k1_sha256_finalize(&sha, rand);
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
rand[i] ^= seckey32[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(rand, session_secrand, sizeof(rand));
|
||||||
|
}
|
||||||
|
|
||||||
|
secp256k1_nonce_function_musig_sha256_tagged(&sha);
|
||||||
|
secp256k1_sha256_write(&sha, rand, sizeof(rand));
|
||||||
|
secp256k1_nonce_function_musig_helper(&sha, 1, pk33, 33);
|
||||||
|
secp256k1_nonce_function_musig_helper(&sha, 1, agg_pk32, 32);
|
||||||
|
msg_present = msg32 != NULL;
|
||||||
|
secp256k1_sha256_write(&sha, &msg_present, 1);
|
||||||
|
if (msg_present) {
|
||||||
|
secp256k1_nonce_function_musig_helper(&sha, 8, msg32, 32);
|
||||||
|
}
|
||||||
|
secp256k1_nonce_function_musig_helper(&sha, 4, extra_input32, 32);
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
unsigned char buf[32];
|
||||||
|
secp256k1_sha256 sha_tmp = sha;
|
||||||
|
secp256k1_sha256_write(&sha_tmp, &i, 1);
|
||||||
|
secp256k1_sha256_finalize(&sha_tmp, buf);
|
||||||
|
secp256k1_scalar_set_b32(&k[i], buf, NULL);
|
||||||
|
|
||||||
|
/* Attempt to erase secret data */
|
||||||
|
secp256k1_memclear(buf, sizeof(buf));
|
||||||
|
secp256k1_sha256_clear(&sha_tmp);
|
||||||
|
}
|
||||||
|
secp256k1_memclear(rand, sizeof(rand));
|
||||||
|
secp256k1_sha256_clear(&sha);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *input_nonce, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) {
|
||||||
|
secp256k1_scalar k[2];
|
||||||
|
secp256k1_ge nonce_pts[2];
|
||||||
|
int i;
|
||||||
|
unsigned char pk_ser[33];
|
||||||
|
size_t pk_ser_len = sizeof(pk_ser);
|
||||||
|
unsigned char aggpk_ser[32];
|
||||||
|
unsigned char *aggpk_ser_ptr = NULL;
|
||||||
|
secp256k1_ge pk;
|
||||||
|
int pk_serialize_success;
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
ARG_CHECK(pubnonce != NULL);
|
||||||
|
memset(pubnonce, 0, sizeof(*pubnonce));
|
||||||
|
ARG_CHECK(pubkey != NULL);
|
||||||
|
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||||
|
|
||||||
|
/* Check that the seckey is valid to be able to sign for it later. */
|
||||||
|
if (seckey != NULL) {
|
||||||
|
secp256k1_scalar sk;
|
||||||
|
ret &= secp256k1_scalar_set_b32_seckey(&sk, seckey);
|
||||||
|
secp256k1_scalar_clear(&sk);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyagg_cache != NULL) {
|
||||||
|
secp256k1_keyagg_cache_internal cache_i;
|
||||||
|
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* The loaded point cache_i.pk can not be the point at infinity. */
|
||||||
|
secp256k1_fe_get_b32(aggpk_ser, &cache_i.pk.x);
|
||||||
|
aggpk_ser_ptr = aggpk_ser;
|
||||||
|
}
|
||||||
|
if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pk_serialize_success = secp256k1_eckey_pubkey_serialize(&pk, pk_ser, &pk_ser_len, 1);
|
||||||
|
|
||||||
|
#ifdef VERIFY
|
||||||
|
/* A pubkey cannot be the point at infinity */
|
||||||
|
VERIFY_CHECK(pk_serialize_success);
|
||||||
|
VERIFY_CHECK(pk_ser_len == sizeof(pk_ser));
|
||||||
|
#else
|
||||||
|
(void) pk_serialize_success;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
secp256k1_nonce_function_musig(k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32);
|
||||||
|
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0]));
|
||||||
|
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1]));
|
||||||
|
secp256k1_musig_secnonce_save(secnonce, k, &pk);
|
||||||
|
secp256k1_musig_secnonce_invalidate(ctx, secnonce, !ret);
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
secp256k1_gej nonce_ptj;
|
||||||
|
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj, &k[i]);
|
||||||
|
secp256k1_ge_set_gej(&nonce_pts[i], &nonce_ptj);
|
||||||
|
secp256k1_declassify(ctx, &nonce_pts[i], sizeof(nonce_pts[i]));
|
||||||
|
secp256k1_scalar_clear(&k[i]);
|
||||||
|
secp256k1_gej_clear(&nonce_ptj);
|
||||||
|
}
|
||||||
|
/* None of the nonce_pts will be infinity because k != 0 with overwhelming
|
||||||
|
* probability */
|
||||||
|
secp256k1_musig_pubnonce_save(pubnonce, nonce_pts);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, unsigned char *session_secrand32, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) {
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(secnonce != NULL);
|
||||||
|
memset(secnonce, 0, sizeof(*secnonce));
|
||||||
|
ARG_CHECK(session_secrand32 != NULL);
|
||||||
|
|
||||||
|
/* Check in constant time that the session_secrand32 is not 0 as a
|
||||||
|
* defense-in-depth measure that may protect against a faulty RNG. */
|
||||||
|
ret &= !secp256k1_is_zero_array(session_secrand32, 32);
|
||||||
|
|
||||||
|
/* We can declassify because branching on ret is only relevant when this
|
||||||
|
* function called with an invalid session_secrand32 argument */
|
||||||
|
secp256k1_declassify(ctx, &ret, sizeof(ret));
|
||||||
|
if (ret == 0) {
|
||||||
|
secp256k1_musig_secnonce_invalidate(ctx, secnonce, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret &= secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, session_secrand32, seckey, pubkey, msg32, keyagg_cache, extra_input32);
|
||||||
|
|
||||||
|
/* Set the session_secrand32 buffer to zero to prevent the caller from using
|
||||||
|
* nonce_gen multiple times with the same buffer. */
|
||||||
|
secp256k1_memczero(session_secrand32, 32, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_nonce_gen_counter(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, uint64_t nonrepeating_cnt, const secp256k1_keypair *keypair, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) {
|
||||||
|
unsigned char buf[32] = { 0 };
|
||||||
|
unsigned char seckey[32];
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(secnonce != NULL);
|
||||||
|
memset(secnonce, 0, sizeof(*secnonce));
|
||||||
|
ARG_CHECK(keypair != NULL);
|
||||||
|
|
||||||
|
secp256k1_write_be64(buf, nonrepeating_cnt);
|
||||||
|
/* keypair_sec and keypair_pub do not fail if the arguments are not NULL */
|
||||||
|
ret = secp256k1_keypair_sec(ctx, seckey, keypair);
|
||||||
|
VERIFY_CHECK(ret);
|
||||||
|
ret = secp256k1_keypair_pub(ctx, &pubkey, keypair);
|
||||||
|
VERIFY_CHECK(ret);
|
||||||
|
#ifndef VERIFY
|
||||||
|
(void) ret;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, buf, seckey, &pubkey, msg32, keyagg_cache, extra_input32)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_memclear(seckey, sizeof(seckey));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_musig_sum_pubnonces(const secp256k1_context* ctx, secp256k1_gej *summed_pubnonces, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) {
|
||||||
|
size_t i;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
secp256k1_gej_set_infinity(&summed_pubnonces[0]);
|
||||||
|
secp256k1_gej_set_infinity(&summed_pubnonces[1]);
|
||||||
|
|
||||||
|
for (i = 0; i < n_pubnonces; i++) {
|
||||||
|
secp256k1_ge nonce_pts[2];
|
||||||
|
if (!secp256k1_musig_pubnonce_load(ctx, nonce_pts, pubnonces[i])) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (j = 0; j < 2; j++) {
|
||||||
|
secp256k1_gej_add_ge_var(&summed_pubnonces[j], &summed_pubnonces[j], &nonce_pts[j], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_nonce_agg(const secp256k1_context* ctx, secp256k1_musig_aggnonce *aggnonce, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) {
|
||||||
|
secp256k1_gej aggnonce_ptsj[2];
|
||||||
|
secp256k1_ge aggnonce_pts[2];
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(aggnonce != NULL);
|
||||||
|
ARG_CHECK(pubnonces != NULL);
|
||||||
|
ARG_CHECK(n_pubnonces > 0);
|
||||||
|
|
||||||
|
if (!secp256k1_musig_sum_pubnonces(ctx, aggnonce_ptsj, pubnonces, n_pubnonces)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_ge_set_all_gej_var(aggnonce_pts, aggnonce_ptsj, 2);
|
||||||
|
secp256k1_musig_aggnonce_save(aggnonce, aggnonce_pts);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||||
|
* SHA256 to SHA256("MuSig/noncecoef")||SHA256("MuSig/noncecoef"). */
|
||||||
|
static void secp256k1_musig_compute_noncehash_sha256_tagged(secp256k1_sha256 *sha) {
|
||||||
|
secp256k1_sha256_initialize(sha);
|
||||||
|
sha->s[0] = 0x2c7d5a45ul;
|
||||||
|
sha->s[1] = 0x06bf7e53ul;
|
||||||
|
sha->s[2] = 0x89be68a6ul;
|
||||||
|
sha->s[3] = 0x971254c0ul;
|
||||||
|
sha->s[4] = 0x60ac12d2ul;
|
||||||
|
sha->s[5] = 0x72846dcdul;
|
||||||
|
sha->s[6] = 0x6c81212ful;
|
||||||
|
sha->s[7] = 0xde7a2500ul;
|
||||||
|
sha->bytes = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tagged_hash(aggnonce[0], aggnonce[1], agg_pk, msg) */
|
||||||
|
static void secp256k1_musig_compute_noncehash(unsigned char *noncehash, secp256k1_ge *aggnonce, const unsigned char *agg_pk32, const unsigned char *msg) {
|
||||||
|
unsigned char buf[33];
|
||||||
|
secp256k1_sha256 sha;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
secp256k1_musig_compute_noncehash_sha256_tagged(&sha);
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
secp256k1_musig_ge_serialize_ext(buf, &aggnonce[i]);
|
||||||
|
secp256k1_sha256_write(&sha, buf, sizeof(buf));
|
||||||
|
}
|
||||||
|
secp256k1_sha256_write(&sha, agg_pk32, 32);
|
||||||
|
secp256k1_sha256_write(&sha, msg, 32);
|
||||||
|
secp256k1_sha256_finalize(&sha, noncehash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* out_nonce = nonce_pts[0] + b*nonce_pts[1] */
|
||||||
|
static void secp256k1_effective_nonce(secp256k1_gej *out_nonce, const secp256k1_ge *nonce_pts, const secp256k1_scalar *b) {
|
||||||
|
secp256k1_gej tmp;
|
||||||
|
|
||||||
|
secp256k1_gej_set_ge(&tmp, &nonce_pts[1]);
|
||||||
|
secp256k1_ecmult(out_nonce, &tmp, b, NULL);
|
||||||
|
secp256k1_gej_add_ge_var(out_nonce, out_nonce, &nonce_pts[0], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_ge *aggnonce_pts, const unsigned char *agg_pk32, const unsigned char *msg) {
|
||||||
|
unsigned char noncehash[32];
|
||||||
|
secp256k1_ge fin_nonce_pt;
|
||||||
|
secp256k1_gej fin_nonce_ptj;
|
||||||
|
|
||||||
|
secp256k1_musig_compute_noncehash(noncehash, aggnonce_pts, agg_pk32, msg);
|
||||||
|
secp256k1_scalar_set_b32(b, noncehash, NULL);
|
||||||
|
/* fin_nonce = aggnonce_pts[0] + b*aggnonce_pts[1] */
|
||||||
|
secp256k1_effective_nonce(&fin_nonce_ptj, aggnonce_pts, b);
|
||||||
|
secp256k1_ge_set_gej(&fin_nonce_pt, &fin_nonce_ptj);
|
||||||
|
if (secp256k1_ge_is_infinity(&fin_nonce_pt)) {
|
||||||
|
fin_nonce_pt = secp256k1_ge_const_g;
|
||||||
|
}
|
||||||
|
/* fin_nonce_pt is not the point at infinity */
|
||||||
|
secp256k1_fe_normalize_var(&fin_nonce_pt.x);
|
||||||
|
secp256k1_fe_get_b32(fin_nonce, &fin_nonce_pt.x);
|
||||||
|
secp256k1_fe_normalize_var(&fin_nonce_pt.y);
|
||||||
|
*fin_nonce_parity = secp256k1_fe_is_odd(&fin_nonce_pt.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_nonce_process(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_aggnonce *aggnonce, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache) {
|
||||||
|
secp256k1_keyagg_cache_internal cache_i;
|
||||||
|
secp256k1_ge aggnonce_pts[2];
|
||||||
|
unsigned char fin_nonce[32];
|
||||||
|
secp256k1_musig_session_internal session_i;
|
||||||
|
unsigned char agg_pk32[32];
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(session != NULL);
|
||||||
|
ARG_CHECK(aggnonce != NULL);
|
||||||
|
ARG_CHECK(msg32 != NULL);
|
||||||
|
ARG_CHECK(keyagg_cache != NULL);
|
||||||
|
|
||||||
|
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_fe_get_b32(agg_pk32, &cache_i.pk.x);
|
||||||
|
|
||||||
|
if (!secp256k1_musig_aggnonce_load(ctx, aggnonce_pts, aggnonce)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
secp256k1_musig_nonce_process_internal(&session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_pts, agg_pk32, msg32);
|
||||||
|
secp256k1_schnorrsig_challenge(&session_i.challenge, fin_nonce, msg32, 32, agg_pk32);
|
||||||
|
|
||||||
|
/* If there is a tweak then set `challenge` times `tweak` to the `s`-part.*/
|
||||||
|
secp256k1_scalar_set_int(&session_i.s_part, 0);
|
||||||
|
if (!secp256k1_scalar_is_zero(&cache_i.tweak)) {
|
||||||
|
secp256k1_scalar e_tmp;
|
||||||
|
secp256k1_scalar_mul(&e_tmp, &session_i.challenge, &cache_i.tweak);
|
||||||
|
if (secp256k1_fe_is_odd(&cache_i.pk.y)) {
|
||||||
|
secp256k1_scalar_negate(&e_tmp, &e_tmp);
|
||||||
|
}
|
||||||
|
session_i.s_part = e_tmp;
|
||||||
|
}
|
||||||
|
memcpy(session_i.fin_nonce, fin_nonce, sizeof(session_i.fin_nonce));
|
||||||
|
secp256k1_musig_session_save(session, &session_i);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_musig_partial_sign_clear(secp256k1_scalar *sk, secp256k1_scalar *k) {
|
||||||
|
secp256k1_scalar_clear(sk);
|
||||||
|
secp256k1_scalar_clear(&k[0]);
|
||||||
|
secp256k1_scalar_clear(&k[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_partial_sig *partial_sig, secp256k1_musig_secnonce *secnonce, const secp256k1_keypair *keypair, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) {
|
||||||
|
secp256k1_scalar sk;
|
||||||
|
secp256k1_ge pk, keypair_pk;
|
||||||
|
secp256k1_scalar k[2];
|
||||||
|
secp256k1_scalar mu, s;
|
||||||
|
secp256k1_keyagg_cache_internal cache_i;
|
||||||
|
secp256k1_musig_session_internal session_i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
|
||||||
|
ARG_CHECK(secnonce != NULL);
|
||||||
|
/* Fails if the magic doesn't match */
|
||||||
|
ret = secp256k1_musig_secnonce_load(ctx, k, &pk, secnonce);
|
||||||
|
/* Set nonce to zero to avoid nonce reuse. This will cause subsequent calls
|
||||||
|
* of this function to fail */
|
||||||
|
memset(secnonce, 0, sizeof(*secnonce));
|
||||||
|
if (!ret) {
|
||||||
|
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ARG_CHECK(partial_sig != NULL);
|
||||||
|
ARG_CHECK(keypair != NULL);
|
||||||
|
ARG_CHECK(keyagg_cache != NULL);
|
||||||
|
ARG_CHECK(session != NULL);
|
||||||
|
|
||||||
|
if (!secp256k1_keypair_load(ctx, &sk, &keypair_pk, keypair)) {
|
||||||
|
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ARG_CHECK(secp256k1_fe_equal(&pk.x, &keypair_pk.x)
|
||||||
|
&& secp256k1_fe_equal(&pk.y, &keypair_pk.y));
|
||||||
|
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||||
|
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Negate sk if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc.
|
||||||
|
* This corresponds to the line "Let d = g⋅gacc⋅d' mod n" in the
|
||||||
|
* specification. */
|
||||||
|
if ((secp256k1_fe_is_odd(&cache_i.pk.y)
|
||||||
|
!= cache_i.parity_acc)) {
|
||||||
|
secp256k1_scalar_negate(&sk, &sk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Multiply KeyAgg coefficient */
|
||||||
|
secp256k1_musig_keyaggcoef(&mu, &cache_i, &pk);
|
||||||
|
secp256k1_scalar_mul(&sk, &sk, &mu);
|
||||||
|
|
||||||
|
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
|
||||||
|
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_i.fin_nonce_parity) {
|
||||||
|
secp256k1_scalar_negate(&k[0], &k[0]);
|
||||||
|
secp256k1_scalar_negate(&k[1], &k[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sign */
|
||||||
|
secp256k1_scalar_mul(&s, &session_i.challenge, &sk);
|
||||||
|
secp256k1_scalar_mul(&k[1], &session_i.noncecoef, &k[1]);
|
||||||
|
secp256k1_scalar_add(&k[0], &k[0], &k[1]);
|
||||||
|
secp256k1_scalar_add(&s, &s, &k[0]);
|
||||||
|
secp256k1_musig_partial_sig_save(partial_sig, &s);
|
||||||
|
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_pubkey *pubkey, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) {
|
||||||
|
secp256k1_keyagg_cache_internal cache_i;
|
||||||
|
secp256k1_musig_session_internal session_i;
|
||||||
|
secp256k1_scalar mu, e, s;
|
||||||
|
secp256k1_gej pkj;
|
||||||
|
secp256k1_ge nonce_pts[2];
|
||||||
|
secp256k1_gej rj;
|
||||||
|
secp256k1_gej tmp;
|
||||||
|
secp256k1_ge pkp;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(partial_sig != NULL);
|
||||||
|
ARG_CHECK(pubnonce != NULL);
|
||||||
|
ARG_CHECK(pubkey != NULL);
|
||||||
|
ARG_CHECK(keyagg_cache != NULL);
|
||||||
|
ARG_CHECK(session != NULL);
|
||||||
|
|
||||||
|
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!secp256k1_musig_pubnonce_load(ctx, nonce_pts, pubnonce)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Compute "effective" nonce rj = nonce_pts[0] + b*nonce_pts[1] */
|
||||||
|
/* TODO: use multiexp to compute -s*G + e*mu*pubkey + nonce_pts[0] + b*nonce_pts[1] */
|
||||||
|
secp256k1_effective_nonce(&rj, nonce_pts, &session_i.noncecoef);
|
||||||
|
|
||||||
|
if (!secp256k1_pubkey_load(ctx, &pkp, pubkey)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Multiplying the challenge by the KeyAgg coefficient is equivalent
|
||||||
|
* to multiplying the signer's public key by the coefficient, except
|
||||||
|
* much easier to do. */
|
||||||
|
secp256k1_musig_keyaggcoef(&mu, &cache_i, &pkp);
|
||||||
|
secp256k1_scalar_mul(&e, &session_i.challenge, &mu);
|
||||||
|
|
||||||
|
/* Negate e if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc.
|
||||||
|
* This corresponds to the line "Let g' = g⋅gacc mod n" and the multiplication "g'⋅e"
|
||||||
|
* in the specification. */
|
||||||
|
if (secp256k1_fe_is_odd(&cache_i.pk.y)
|
||||||
|
!= cache_i.parity_acc) {
|
||||||
|
secp256k1_scalar_negate(&e, &e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!secp256k1_musig_partial_sig_load(ctx, &s, partial_sig)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Compute -s*G + e*pkj + rj (e already includes the keyagg coefficient mu) */
|
||||||
|
secp256k1_scalar_negate(&s, &s);
|
||||||
|
secp256k1_gej_set_ge(&pkj, &pkp);
|
||||||
|
secp256k1_ecmult(&tmp, &pkj, &e, &s);
|
||||||
|
if (session_i.fin_nonce_parity) {
|
||||||
|
secp256k1_gej_neg(&rj, &rj);
|
||||||
|
}
|
||||||
|
secp256k1_gej_add_var(&tmp, &tmp, &rj, NULL);
|
||||||
|
|
||||||
|
return secp256k1_gej_is_infinity(&tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_musig_partial_sig_agg(const secp256k1_context* ctx, unsigned char *sig64, const secp256k1_musig_session *session, const secp256k1_musig_partial_sig * const* partial_sigs, size_t n_sigs) {
|
||||||
|
size_t i;
|
||||||
|
secp256k1_musig_session_internal session_i;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(sig64 != NULL);
|
||||||
|
ARG_CHECK(session != NULL);
|
||||||
|
ARG_CHECK(partial_sigs != NULL);
|
||||||
|
ARG_CHECK(n_sigs > 0);
|
||||||
|
|
||||||
|
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < n_sigs; i++) {
|
||||||
|
secp256k1_scalar term;
|
||||||
|
if (!secp256k1_musig_partial_sig_load(ctx, &term, partial_sigs[i])) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
secp256k1_scalar_add(&session_i.s_part, &session_i.s_part, &term);
|
||||||
|
}
|
||||||
|
secp256k1_scalar_get_b32(&sig64[32], &session_i.s_part);
|
||||||
|
memcpy(&sig64[0], session_i.fin_nonce, 32);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
1143
src/modules/musig/tests_impl.h
Normal file
1143
src/modules/musig/tests_impl.h
Normal file
File diff suppressed because it is too large
Load Diff
346
src/modules/musig/vectors.h
Normal file
346
src/modules/musig/vectors.h
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
/**
|
||||||
|
* Automatically generated by ./tools/test_vectors_musig2_generate.py.
|
||||||
|
*
|
||||||
|
* The test vectors for the KeySort function are included in this file. They can
|
||||||
|
* be found in src/modules/extrakeys/tests_impl.h. */
|
||||||
|
|
||||||
|
enum MUSIG_ERROR {
|
||||||
|
MUSIG_PUBKEY,
|
||||||
|
MUSIG_TWEAK,
|
||||||
|
MUSIG_PUBNONCE,
|
||||||
|
MUSIG_AGGNONCE,
|
||||||
|
MUSIG_SECNONCE,
|
||||||
|
MUSIG_SIG,
|
||||||
|
MUSIG_SIG_VERIFY,
|
||||||
|
MUSIG_OTHER
|
||||||
|
};
|
||||||
|
|
||||||
|
struct musig_key_agg_valid_test_case {
|
||||||
|
size_t key_indices_len;
|
||||||
|
size_t key_indices[4];
|
||||||
|
unsigned char expected[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct musig_key_agg_error_test_case {
|
||||||
|
size_t key_indices_len;
|
||||||
|
size_t key_indices[4];
|
||||||
|
size_t tweak_indices_len;
|
||||||
|
size_t tweak_indices[1];
|
||||||
|
int is_xonly[1];
|
||||||
|
enum MUSIG_ERROR error;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct musig_key_agg_vector {
|
||||||
|
unsigned char pubkeys[7][33];
|
||||||
|
unsigned char tweaks[2][32];
|
||||||
|
struct musig_key_agg_valid_test_case valid_case[4];
|
||||||
|
struct musig_key_agg_error_test_case error_case[5];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct musig_key_agg_vector musig_key_agg_vector = {
|
||||||
|
{
|
||||||
|
{ 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
|
||||||
|
{ 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 },
|
||||||
|
{ 0x02, 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, 0x15, 0xC2, 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, 0x14, 0x93, 0x16, 0xC3, 0x51, 0x8C, 0xE7, 0xB7, 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 },
|
||||||
|
{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 },
|
||||||
|
{ 0x02, 0xFF, 0xFF, 0xFF, 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 },
|
||||||
|
{ 0x04, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
|
||||||
|
{ 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 },
|
||||||
|
{ 0x25, 0x2E, 0x4B, 0xD6, 0x74, 0x10, 0xA7, 0x6C, 0xDF, 0x93, 0x3D, 0x30, 0xEA, 0xA1, 0x60, 0x82, 0x14, 0x03, 0x7F, 0x1B, 0x10, 0x5A, 0x01, 0x3E, 0xCC, 0xD3, 0xC5, 0xC1, 0x84, 0xA6, 0x11, 0x0B }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 3, { 0, 1, 2 }, { 0x90, 0x53, 0x9E, 0xED, 0xE5, 0x65, 0xF5, 0xD0, 0x54, 0xF3, 0x2C, 0xC0, 0xC2, 0x20, 0x12, 0x68, 0x89, 0xED, 0x1E, 0x5D, 0x19, 0x3B, 0xAF, 0x15, 0xAE, 0xF3, 0x44, 0xFE, 0x59, 0xD4, 0x61, 0x0C }},
|
||||||
|
{ 3, { 2, 1, 0 }, { 0x62, 0x04, 0xDE, 0x8B, 0x08, 0x34, 0x26, 0xDC, 0x6E, 0xAF, 0x95, 0x02, 0xD2, 0x70, 0x24, 0xD5, 0x3F, 0xC8, 0x26, 0xBF, 0x7D, 0x20, 0x12, 0x14, 0x8A, 0x05, 0x75, 0x43, 0x5D, 0xF5, 0x4B, 0x2B }},
|
||||||
|
{ 3, { 0, 0, 0 }, { 0xB4, 0x36, 0xE3, 0xBA, 0xD6, 0x2B, 0x8C, 0xD4, 0x09, 0x96, 0x9A, 0x22, 0x47, 0x31, 0xC1, 0x93, 0xD0, 0x51, 0x16, 0x2D, 0x8C, 0x5A, 0xE8, 0xB1, 0x09, 0x30, 0x61, 0x27, 0xDA, 0x3A, 0xA9, 0x35 }},
|
||||||
|
{ 4, { 0, 0, 1, 1 }, { 0x69, 0xBC, 0x22, 0xBF, 0xA5, 0xD1, 0x06, 0x30, 0x6E, 0x48, 0xA2, 0x06, 0x79, 0xDE, 0x1D, 0x73, 0x89, 0x38, 0x61, 0x24, 0xD0, 0x75, 0x71, 0xD0, 0xD8, 0x72, 0x68, 0x60, 0x28, 0xC2, 0x6A, 0x3E }},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 2, { 0, 3 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY },
|
||||||
|
{ 2, { 0, 4 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY },
|
||||||
|
{ 2, { 5, 0 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY },
|
||||||
|
{ 2, { 0, 1 }, 1, { 0 }, { 1 }, MUSIG_TWEAK },
|
||||||
|
{ 1, { 6 }, 1, { 1 }, { 0 }, MUSIG_TWEAK },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct musig_nonce_gen_vector {
|
||||||
|
struct musig_nonce_gen_test_case test_case[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct musig_nonce_gen_vector musig_nonce_gen_vector = {
|
||||||
|
{
|
||||||
|
{ { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 1 , { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }, { 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 }, 1 , { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 }, 1 , { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, 1 , { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, { 0xB1, 0x14, 0xE5, 0x02, 0xBE, 0xAA, 0x4E, 0x30, 0x1D, 0xD0, 0x8A, 0x50, 0x26, 0x41, 0x72, 0xC8, 0x4E, 0x41, 0x65, 0x0E, 0x6C, 0xB7, 0x26, 0xB4, 0x10, 0xC0, 0x69, 0x4D, 0x59, 0xEF, 0xFB, 0x64, 0x95, 0xB5, 0xCA, 0xF2, 0x8D, 0x04, 0x5B, 0x97, 0x3D, 0x63, 0xE3, 0xC9, 0x9A, 0x44, 0xB8, 0x07, 0xBD, 0xE3, 0x75, 0xFD, 0x6C, 0xB3, 0x9E, 0x46, 0xDC, 0x4A, 0x51, 0x17, 0x08, 0xD0, 0xE9, 0xD2, 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 }, { 0x02, 0xF7, 0xBE, 0x70, 0x89, 0xE8, 0x37, 0x6E, 0xB3, 0x55, 0x27, 0x23, 0x68, 0x76, 0x6B, 0x17, 0xE8, 0x8E, 0x7D, 0xB7, 0x20, 0x47, 0xD0, 0x5E, 0x56, 0xAA, 0x88, 0x1E, 0xA5, 0x2B, 0x3B, 0x35, 0xDF, 0x02, 0xC2, 0x9C, 0x80, 0x46, 0xFD, 0xD0, 0xDE, 0xD4, 0xC7, 0xE5, 0x58, 0x69, 0x13, 0x72, 0x00, 0xFB, 0xDB, 0xFE, 0x2E, 0xB6, 0x54, 0x26, 0x7B, 0x6D, 0x70, 0x13, 0x60, 0x2C, 0xAE, 0xD3, 0x11, 0x5A } },
|
||||||
|
{ { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 0 , { 0 }, { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, 0 , { 0 }, 0 , { 0 }, 0 , { 0 }, { 0x89, 0xBD, 0xD7, 0x87, 0xD0, 0x28, 0x4E, 0x5E, 0x4D, 0x5F, 0xC5, 0x72, 0xE4, 0x9E, 0x31, 0x6B, 0xAB, 0x7E, 0x21, 0xE3, 0xB1, 0x83, 0x0D, 0xE3, 0x7D, 0xFE, 0x80, 0x15, 0x6F, 0xA4, 0x1A, 0x6D, 0x0B, 0x17, 0xAE, 0x8D, 0x02, 0x4C, 0x53, 0x67, 0x96, 0x99, 0xA6, 0xFD, 0x79, 0x44, 0xD9, 0xC4, 0xA3, 0x66, 0xB5, 0x14, 0xBA, 0xF4, 0x30, 0x88, 0xE0, 0x70, 0x8B, 0x10, 0x23, 0xDD, 0x28, 0x97, 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, { 0x02, 0xC9, 0x6E, 0x7C, 0xB1, 0xE8, 0xAA, 0x5D, 0xAC, 0x64, 0xD8, 0x72, 0x94, 0x79, 0x14, 0x19, 0x8F, 0x60, 0x7D, 0x90, 0xEC, 0xDE, 0x52, 0x00, 0xDE, 0x52, 0x97, 0x8A, 0xD5, 0xDE, 0xD6, 0x3C, 0x00, 0x02, 0x99, 0xEC, 0x51, 0x17, 0xC2, 0xD2, 0x9E, 0xDE, 0xE8, 0xA2, 0x09, 0x25, 0x87, 0xC3, 0x90, 0x9B, 0xE6, 0x94, 0xD5, 0xCF, 0xF0, 0x66, 0x7D, 0x6C, 0x02, 0xEA, 0x40, 0x59, 0xF7, 0xCD, 0x97, 0x86 } },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct musig_nonce_agg_vector {
|
||||||
|
unsigned char pnonces[7][66];
|
||||||
|
struct musig_nonce_agg_test_case valid_case[2];
|
||||||
|
struct musig_nonce_agg_test_case error_case[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct musig_nonce_agg_vector musig_nonce_agg_vector = {
|
||||||
|
{
|
||||||
|
{ 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x03, 0xBA, 0x47, 0xFB, 0xC1, 0x83, 0x44, 0x37, 0xB3, 0x21, 0x2E, 0x89, 0xA8, 0x4D, 0x84, 0x25, 0xE7, 0xBF, 0x12, 0xE0, 0x24, 0x5D, 0x98, 0x26, 0x22, 0x68, 0xEB, 0xDC, 0xB3, 0x85, 0xD5, 0x06, 0x41 },
|
||||||
|
{ 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 },
|
||||||
|
{ 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 },
|
||||||
|
{ 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x03, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 },
|
||||||
|
{ 0x04, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 },
|
||||||
|
{ 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x31 },
|
||||||
|
{ 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0xFF, 0xFF, 0xFF, 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 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ { 0, 1 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x02, 0x47, 0x25, 0x37, 0x73, 0x45, 0xBD, 0xE0, 0xE9, 0xC3, 0x3A, 0xF3, 0xC4, 0x3C, 0x0A, 0x29, 0xA9, 0x24, 0x9F, 0x2F, 0x29, 0x56, 0xFA, 0x8C, 0xFE, 0xB5, 0x5C, 0x85, 0x73, 0xD0, 0x26, 0x2D, 0xC8 }, 0 },
|
||||||
|
{ { 2, 3 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ { 0, 4 }, { 0 }, 1 },
|
||||||
|
{ { 5, 1 }, { 0 }, 0 },
|
||||||
|
{ { 6, 1 }, { 0 }, 0 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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[3];
|
||||||
|
size_t aggnonce_index;
|
||||||
|
size_t msg_index;
|
||||||
|
size_t signer_index;
|
||||||
|
unsigned char expected[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct musig_sign_error_case {
|
||||||
|
size_t key_indices_len;
|
||||||
|
size_t key_indices[3];
|
||||||
|
size_t aggnonce_index;
|
||||||
|
size_t msg_index;
|
||||||
|
size_t secnonce_index;
|
||||||
|
enum MUSIG_ERROR error;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct musig_verify_fail_error_case {
|
||||||
|
unsigned char sig[32];
|
||||||
|
size_t key_indices_len;
|
||||||
|
size_t key_indices[3];
|
||||||
|
size_t nonce_indices_len;
|
||||||
|
size_t nonce_indices[3];
|
||||||
|
size_t msg_index;
|
||||||
|
size_t signer_index;
|
||||||
|
enum MUSIG_ERROR error;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct musig_sign_verify_vector {
|
||||||
|
unsigned char sk[32];
|
||||||
|
unsigned char pubkeys[4][33];
|
||||||
|
unsigned char secnonces[2][194];
|
||||||
|
unsigned char pubnonces[5][194];
|
||||||
|
unsigned char aggnonces[5][66];
|
||||||
|
unsigned char msgs[1][32];
|
||||||
|
struct musig_valid_case valid_case[4];
|
||||||
|
struct musig_sign_error_case sign_error_case[6];
|
||||||
|
struct musig_verify_fail_error_case verify_fail_case[3];
|
||||||
|
struct musig_verify_fail_error_case verify_error_case[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct musig_sign_verify_vector musig_sign_verify_vector = {
|
||||||
|
{ 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE, 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB, 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE, 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71 },
|
||||||
|
{
|
||||||
|
{ 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
|
||||||
|
{ 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
|
||||||
|
{ 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x61 },
|
||||||
|
{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6, 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98, 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF, 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61, 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85, 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5, 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5, 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 },
|
||||||
|
{ 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 },
|
||||||
|
{ 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 },
|
||||||
|
{ 0x02, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x03, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 },
|
||||||
|
{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 },
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||||
|
{ 0x04, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 },
|
||||||
|
{ 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09 },
|
||||||
|
{ 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x02, 0xFF, 0xFF, 0xFF, 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 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68, 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5, 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5, 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 3, { 0, 1, 2 }, 0, 0, 0, { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }},
|
||||||
|
{ 3, { 1, 0, 2 }, 0, 0, 1, { 0x9F, 0xF2, 0xF7, 0xAA, 0xA8, 0x56, 0x15, 0x0C, 0xC8, 0x81, 0x92, 0x54, 0x21, 0x8D, 0x3A, 0xDE, 0xEB, 0x05, 0x35, 0x26, 0x90, 0x51, 0x89, 0x77, 0x24, 0xF9, 0xDB, 0x37, 0x89, 0x51, 0x3A, 0x52 }},
|
||||||
|
{ 3, { 1, 2, 0 }, 0, 0, 2, { 0xFA, 0x23, 0xC3, 0x59, 0xF6, 0xFA, 0xC4, 0xE7, 0x79, 0x6B, 0xB9, 0x3B, 0xC9, 0xF0, 0x53, 0x2A, 0x95, 0x46, 0x8C, 0x53, 0x9B, 0xA2, 0x0F, 0xF8, 0x6D, 0x7C, 0x76, 0xED, 0x92, 0x22, 0x79, 0x00 }},
|
||||||
|
{ 2, { 0, 1 }, 1, 0, 0, { 0xAE, 0x38, 0x60, 0x64, 0xB2, 0x61, 0x05, 0x40, 0x47, 0x98, 0xF7, 0x5D, 0xE2, 0xEB, 0x9A, 0xF5, 0xED, 0xA5, 0x38, 0x7B, 0x06, 0x4B, 0x83, 0xD0, 0x49, 0xCB, 0x7C, 0x5E, 0x08, 0x87, 0x95, 0x31 }},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 2, { 1, 2 }, 0, 0, 0, MUSIG_PUBKEY },
|
||||||
|
{ 3, { 1, 0, 3 }, 0, 0, 0, MUSIG_PUBKEY },
|
||||||
|
{ 3, { 1, 2, 0 }, 2, 0, 0, MUSIG_AGGNONCE },
|
||||||
|
{ 3, { 1, 2, 0 }, 3, 0, 0, MUSIG_AGGNONCE },
|
||||||
|
{ 3, { 1, 2, 0 }, 4, 0, 0, MUSIG_AGGNONCE },
|
||||||
|
{ 3, { 0, 1, 2 }, 0, 0, 1, MUSIG_SECNONCE },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ { 0xFE, 0xD5, 0x44, 0x34, 0xAD, 0x4C, 0xFE, 0x95, 0x3F, 0xC5, 0x27, 0xDC, 0x6A, 0x5E, 0x5B, 0xE8, 0xF6, 0x23, 0x49, 0x07, 0xB7, 0xC1, 0x87, 0x55, 0x95, 0x57, 0xCE, 0x87, 0xA0, 0x54, 0x1C, 0x46 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG_VERIFY },
|
||||||
|
{ { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 1, MUSIG_SIG_VERIFY },
|
||||||
|
{ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 0, 1, 2 }, 3, { 4, 1, 2 }, 0, 0, MUSIG_PUBNONCE },
|
||||||
|
{ { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 3, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_PUBKEY },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct musig_tweak_case {
|
||||||
|
size_t key_indices_len;
|
||||||
|
size_t key_indices[3];
|
||||||
|
size_t nonce_indices_len;
|
||||||
|
size_t nonce_indices[3];
|
||||||
|
size_t tweak_indices_len;
|
||||||
|
size_t tweak_indices[4];
|
||||||
|
int is_xonly[4];
|
||||||
|
size_t signer_index;
|
||||||
|
unsigned char expected[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct musig_tweak_vector {
|
||||||
|
unsigned char sk[32];
|
||||||
|
unsigned char secnonce[97];
|
||||||
|
unsigned char aggnonce[66];
|
||||||
|
unsigned char msg[32];
|
||||||
|
unsigned char pubkeys[3][33];
|
||||||
|
unsigned char pubnonces[3][194];
|
||||||
|
unsigned char tweaks[5][32];
|
||||||
|
struct musig_tweak_case valid_case[5];
|
||||||
|
struct musig_tweak_case error_case[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct musig_tweak_vector musig_tweak_vector = {
|
||||||
|
{ 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE, 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB, 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE, 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71 },
|
||||||
|
{ 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6, 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98, 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF, 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61, 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85, 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5, 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5, 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
|
||||||
|
{ 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 },
|
||||||
|
{ 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68, 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5, 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5, 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF },
|
||||||
|
{
|
||||||
|
{ 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
|
||||||
|
{ 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
|
||||||
|
{ 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 },
|
||||||
|
{ 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 },
|
||||||
|
{ 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 0xE8, 0xF7, 0x91, 0xFF, 0x92, 0x25, 0xA2, 0xAF, 0x01, 0x02, 0xAF, 0xFF, 0x4A, 0x9A, 0x72, 0x3D, 0x96, 0x12, 0xA6, 0x82, 0xA2, 0x5E, 0xBE, 0x79, 0x80, 0x2B, 0x26, 0x3C, 0xDF, 0xCD, 0x83, 0xBB },
|
||||||
|
{ 0xAE, 0x2E, 0xA7, 0x97, 0xCC, 0x0F, 0xE7, 0x2A, 0xC5, 0xB9, 0x7B, 0x97, 0xF3, 0xC6, 0x95, 0x7D, 0x7E, 0x41, 0x99, 0xA1, 0x67, 0xA5, 0x8E, 0xB0, 0x8B, 0xCA, 0xFF, 0xDA, 0x70, 0xAC, 0x04, 0x55 },
|
||||||
|
{ 0xF5, 0x2E, 0xCB, 0xC5, 0x65, 0xB3, 0xD8, 0xBE, 0xA2, 0xDF, 0xD5, 0xB7, 0x5A, 0x4F, 0x45, 0x7E, 0x54, 0x36, 0x98, 0x09, 0x32, 0x2E, 0x41, 0x20, 0x83, 0x16, 0x26, 0xF2, 0x90, 0xFA, 0x87, 0xE0 },
|
||||||
|
{ 0x19, 0x69, 0xAD, 0x73, 0xCC, 0x17, 0x7F, 0xA0, 0xB4, 0xFC, 0xED, 0x6D, 0xF1, 0xF7, 0xBF, 0x99, 0x07, 0xE6, 0x65, 0xFD, 0xE9, 0xBA, 0x19, 0x6A, 0x74, 0xFE, 0xD0, 0xA3, 0xCF, 0x5A, 0xEF, 0x9D },
|
||||||
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 1 }, 2, { 0xE2, 0x8A, 0x5C, 0x66, 0xE6, 0x1E, 0x17, 0x8C, 0x2B, 0xA1, 0x9D, 0xB7, 0x7B, 0x6C, 0xF9, 0xF7, 0xE2, 0xF0, 0xF5, 0x6C, 0x17, 0x91, 0x8C, 0xD1, 0x31, 0x35, 0xE6, 0x0C, 0xC8, 0x48, 0xFE, 0x91 }},
|
||||||
|
{ 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 0 }, 2, { 0x38, 0xB0, 0x76, 0x77, 0x98, 0x25, 0x2F, 0x21, 0xBF, 0x57, 0x02, 0xC4, 0x80, 0x28, 0xB0, 0x95, 0x42, 0x83, 0x20, 0xF7, 0x3A, 0x4B, 0x14, 0xDB, 0x1E, 0x25, 0xDE, 0x58, 0x54, 0x3D, 0x2D, 0x2D }},
|
||||||
|
{ 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 2, { 0, 1 }, { 0, 1 }, 2, { 0x40, 0x8A, 0x0A, 0x21, 0xC4, 0xA0, 0xF5, 0xDA, 0xCA, 0xF9, 0x64, 0x6A, 0xD6, 0xEB, 0x6F, 0xEC, 0xD7, 0xF7, 0xA1, 0x1F, 0x03, 0xED, 0x1F, 0x48, 0xDF, 0xFF, 0x21, 0x85, 0xBC, 0x2C, 0x24, 0x08 }},
|
||||||
|
{ 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 0, 0, 1, 1 }, 2, { 0x45, 0xAB, 0xD2, 0x06, 0xE6, 0x1E, 0x3D, 0xF2, 0xEC, 0x9E, 0x26, 0x4A, 0x6F, 0xEC, 0x82, 0x92, 0x14, 0x1A, 0x63, 0x3C, 0x28, 0x58, 0x63, 0x88, 0x23, 0x55, 0x41, 0xF9, 0xAD, 0xE7, 0x54, 0x35 }},
|
||||||
|
{ 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 1, 0, 1, 0 }, 2, { 0xB2, 0x55, 0xFD, 0xCA, 0xC2, 0x7B, 0x40, 0xC7, 0xCE, 0x78, 0x48, 0xE2, 0xD3, 0xB7, 0xBF, 0x5E, 0xA0, 0xED, 0x75, 0x6D, 0xA8, 0x15, 0x65, 0xAC, 0x80, 0x4C, 0xCC, 0xA3, 0xE1, 0xD5, 0xD2, 0x39 }},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 4 }, { 0 }, 2, { 0 }},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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[2];
|
||||||
|
size_t tweak_indices_len;
|
||||||
|
size_t tweak_indices[3];
|
||||||
|
int is_xonly[3];
|
||||||
|
unsigned char aggnonce[66];
|
||||||
|
size_t psig_indices_len;
|
||||||
|
size_t psig_indices[2];
|
||||||
|
/* if valid case */
|
||||||
|
unsigned char expected[64];
|
||||||
|
/* if error case */
|
||||||
|
int invalid_sig_idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct musig_sig_agg_vector {
|
||||||
|
unsigned char pubkeys[4][33];
|
||||||
|
unsigned char tweaks[3][32];
|
||||||
|
unsigned char psigs[9][32];
|
||||||
|
unsigned char msg[32];
|
||||||
|
struct musig_sig_agg_case valid_case[4];
|
||||||
|
struct musig_sig_agg_case error_case[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct musig_sig_agg_vector musig_sig_agg_vector = {
|
||||||
|
{
|
||||||
|
{ 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
|
||||||
|
{ 0x02, 0xD2, 0xDC, 0x6F, 0x5D, 0xF7, 0xC5, 0x6A, 0xCF, 0x38, 0xC7, 0xFA, 0x0A, 0xE7, 0xA7, 0x59, 0xAE, 0x30, 0xE1, 0x9B, 0x37, 0x35, 0x9D, 0xFD, 0xE0, 0x15, 0x87, 0x23, 0x24, 0xC7, 0xEF, 0x6E, 0x05 },
|
||||||
|
{ 0x03, 0xC7, 0xFB, 0x10, 0x1D, 0x97, 0xFF, 0x93, 0x0A, 0xCD, 0x0C, 0x67, 0x60, 0x85, 0x2E, 0xF6, 0x4E, 0x69, 0x08, 0x3D, 0xE0, 0xB0, 0x6A, 0xC6, 0x33, 0x57, 0x24, 0x75, 0x4B, 0xB4, 0xB0, 0x52, 0x2C },
|
||||||
|
{ 0x02, 0x35, 0x24, 0x33, 0xB2, 0x1E, 0x7E, 0x05, 0xD3, 0xB4, 0x52, 0xB8, 0x1C, 0xAE, 0x56, 0x6E, 0x06, 0xD2, 0xE0, 0x03, 0xEC, 0xE1, 0x6D, 0x10, 0x74, 0xAA, 0xBA, 0x42, 0x89, 0xE0, 0xE3, 0xD5, 0x81 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 0xB5, 0x11, 0xDA, 0x49, 0x21, 0x82, 0xA9, 0x1B, 0x0F, 0xFB, 0x9A, 0x98, 0x02, 0x0D, 0x55, 0xF2, 0x60, 0xAE, 0x86, 0xD7, 0xEC, 0xBD, 0x03, 0x99, 0xC7, 0x38, 0x3D, 0x59, 0xA5, 0xF2, 0xAF, 0x7C },
|
||||||
|
{ 0xA8, 0x15, 0xFE, 0x04, 0x9E, 0xE3, 0xC5, 0xAA, 0xB6, 0x63, 0x10, 0x47, 0x7F, 0xBC, 0x8B, 0xCC, 0xCA, 0xC2, 0xF3, 0x39, 0x5F, 0x59, 0xF9, 0x21, 0xC3, 0x64, 0xAC, 0xD7, 0x8A, 0x2F, 0x48, 0xDC },
|
||||||
|
{ 0x75, 0x44, 0x8A, 0x87, 0x27, 0x4B, 0x05, 0x64, 0x68, 0xB9, 0x77, 0xBE, 0x06, 0xEB, 0x1E, 0x9F, 0x65, 0x75, 0x77, 0xB7, 0x32, 0x0B, 0x0A, 0x33, 0x76, 0xEA, 0x51, 0xFD, 0x42, 0x0D, 0x18, 0xA8 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 0xB1, 0x5D, 0x2C, 0xD3, 0xC3, 0xD2, 0x2B, 0x04, 0xDA, 0xE4, 0x38, 0xCE, 0x65, 0x3F, 0x6B, 0x4E, 0xCF, 0x04, 0x2F, 0x42, 0xCF, 0xDE, 0xD7, 0xC4, 0x1B, 0x64, 0xAA, 0xF9, 0xB4, 0xAF, 0x53, 0xFB },
|
||||||
|
{ 0x61, 0x93, 0xD6, 0xAC, 0x61, 0xB3, 0x54, 0xE9, 0x10, 0x5B, 0xBD, 0xC8, 0x93, 0x7A, 0x34, 0x54, 0xA6, 0xD7, 0x05, 0xB6, 0xD5, 0x73, 0x22, 0xA5, 0xA4, 0x72, 0xA0, 0x2C, 0xE9, 0x9F, 0xCB, 0x64 },
|
||||||
|
{ 0x9A, 0x87, 0xD3, 0xB7, 0x9E, 0xC6, 0x72, 0x28, 0xCB, 0x97, 0x87, 0x8B, 0x76, 0x04, 0x9B, 0x15, 0xDB, 0xD0, 0x5B, 0x81, 0x58, 0xD1, 0x7B, 0x5B, 0x91, 0x14, 0xD3, 0xC2, 0x26, 0x88, 0x75, 0x05 },
|
||||||
|
{ 0x66, 0xF8, 0x2E, 0xA9, 0x09, 0x23, 0x68, 0x9B, 0x85, 0x5D, 0x36, 0xC6, 0xB7, 0xE0, 0x32, 0xFB, 0x99, 0x70, 0x30, 0x14, 0x81, 0xB9, 0x9E, 0x01, 0xCD, 0xB4, 0xD6, 0xAC, 0x7C, 0x34, 0x7A, 0x15 },
|
||||||
|
{ 0x4F, 0x5A, 0xEE, 0x41, 0x51, 0x08, 0x48, 0xA6, 0x44, 0x7D, 0xCD, 0x1B, 0xBC, 0x78, 0x45, 0x7E, 0xF6, 0x90, 0x24, 0x94, 0x4C, 0x87, 0xF4, 0x02, 0x50, 0xD3, 0xEF, 0x2C, 0x25, 0xD3, 0x3E, 0xFE },
|
||||||
|
{ 0xDD, 0xEF, 0x42, 0x7B, 0xBB, 0x84, 0x7C, 0xC0, 0x27, 0xBE, 0xFF, 0x4E, 0xDB, 0x01, 0x03, 0x81, 0x48, 0x91, 0x78, 0x32, 0x25, 0x3E, 0xBC, 0x35, 0x5F, 0xC3, 0x3F, 0x4A, 0x8E, 0x2F, 0xCC, 0xE4 },
|
||||||
|
{ 0x97, 0xB8, 0x90, 0xA2, 0x6C, 0x98, 0x1D, 0xA8, 0x10, 0x2D, 0x3B, 0xC2, 0x94, 0x15, 0x9D, 0x17, 0x1D, 0x72, 0x81, 0x0F, 0xDF, 0x7C, 0x6A, 0x69, 0x1D, 0xEF, 0x02, 0xF0, 0xF7, 0xAF, 0x3F, 0xDC },
|
||||||
|
{ 0x53, 0xFA, 0x9E, 0x08, 0xBA, 0x52, 0x43, 0xCB, 0xCB, 0x0D, 0x79, 0x7C, 0x5E, 0xE8, 0x3B, 0xC6, 0x72, 0x8E, 0x53, 0x9E, 0xB7, 0x6C, 0x2D, 0x0B, 0xF0, 0xF9, 0x71, 0xEE, 0x4E, 0x90, 0x99, 0x71 },
|
||||||
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }
|
||||||
|
},
|
||||||
|
{ 0x59, 0x9C, 0x67, 0xEA, 0x41, 0x0D, 0x00, 0x5B, 0x9D, 0xA9, 0x08, 0x17, 0xCF, 0x03, 0xED, 0x3B, 0x1C, 0x86, 0x8E, 0x4D, 0xA4, 0xED, 0xF0, 0x0A, 0x58, 0x80, 0xB0, 0x08, 0x2C, 0x23, 0x78, 0x69 },
|
||||||
|
{
|
||||||
|
{ 2, { 0, 1 }, 0, { 0 }, { 0 }, { 0x03, 0x41, 0x43, 0x27, 0x22, 0xC5, 0xCD, 0x02, 0x68, 0xD8, 0x29, 0xC7, 0x02, 0xCF, 0x0D, 0x1C, 0xBC, 0xE5, 0x70, 0x33, 0xEE, 0xD2, 0x01, 0xFD, 0x33, 0x51, 0x91, 0x38, 0x52, 0x27, 0xC3, 0x21, 0x0C, 0x03, 0xD3, 0x77, 0xF2, 0xD2, 0x58, 0xB6, 0x4A, 0xAD, 0xC0, 0xE1, 0x6F, 0x26, 0x46, 0x23, 0x23, 0xD7, 0x01, 0xD2, 0x86, 0x04, 0x6A, 0x2E, 0xA9, 0x33, 0x65, 0x65, 0x6A, 0xFD, 0x98, 0x75, 0x98, 0x2B }, 2, { 0, 1 }, { 0x04, 0x1D, 0xA2, 0x22, 0x23, 0xCE, 0x65, 0xC9, 0x2C, 0x9A, 0x0D, 0x6C, 0x2C, 0xAC, 0x82, 0x8A, 0xAF, 0x1E, 0xEE, 0x56, 0x30, 0x4F, 0xEC, 0x37, 0x1D, 0xDF, 0x91, 0xEB, 0xB2, 0xB9, 0xEF, 0x09, 0x12, 0xF1, 0x03, 0x80, 0x25, 0x85, 0x7F, 0xED, 0xEB, 0x3F, 0xF6, 0x96, 0xF8, 0xB9, 0x9F, 0xA4, 0xBB, 0x2C, 0x58, 0x12, 0xF6, 0x09, 0x5A, 0x2E, 0x00, 0x04, 0xEC, 0x99, 0xCE, 0x18, 0xDE, 0x1E }, 0 },
|
||||||
|
{ 2, { 0, 2 }, 0, { 0 }, { 0 }, { 0x02, 0x24, 0xAF, 0xD3, 0x6C, 0x90, 0x20, 0x84, 0x05, 0x8B, 0x51, 0xB5, 0xD3, 0x66, 0x76, 0xBB, 0xA4, 0xDC, 0x97, 0xC7, 0x75, 0x87, 0x37, 0x68, 0xE5, 0x88, 0x22, 0xF8, 0x7F, 0xE4, 0x37, 0xD7, 0x92, 0x02, 0x8C, 0xB1, 0x59, 0x29, 0x09, 0x9E, 0xEE, 0x2F, 0x5D, 0xAE, 0x40, 0x4C, 0xD3, 0x93, 0x57, 0x59, 0x1B, 0xA3, 0x2E, 0x9A, 0xF4, 0xE1, 0x62, 0xB8, 0xD3, 0xE7, 0xCB, 0x5E, 0xFE, 0x31, 0xCB, 0x20 }, 2, { 2, 3 }, { 0x10, 0x69, 0xB6, 0x7E, 0xC3, 0xD2, 0xF3, 0xC7, 0xC0, 0x82, 0x91, 0xAC, 0xCB, 0x17, 0xA9, 0xC9, 0xB8, 0xF2, 0x81, 0x9A, 0x52, 0xEB, 0x5D, 0xF8, 0x72, 0x6E, 0x17, 0xE7, 0xD6, 0xB5, 0x2E, 0x9F, 0x01, 0x80, 0x02, 0x60, 0xA7, 0xE9, 0xDA, 0xC4, 0x50, 0xF4, 0xBE, 0x52, 0x2D, 0xE4, 0xCE, 0x12, 0xBA, 0x91, 0xAE, 0xAF, 0x2B, 0x42, 0x79, 0x21, 0x9E, 0xF7, 0x4B, 0xE1, 0xD2, 0x86, 0xAD, 0xD9 }, 0 },
|
||||||
|
{ 2, { 0, 2 }, 1, { 0 }, { 0 }, { 0x02, 0x08, 0xC5, 0xC4, 0x38, 0xC7, 0x10, 0xF4, 0xF9, 0x6A, 0x61, 0xE9, 0xFF, 0x3C, 0x37, 0x75, 0x88, 0x14, 0xB8, 0xC3, 0xAE, 0x12, 0xBF, 0xEA, 0x0E, 0xD2, 0xC8, 0x7F, 0xF6, 0x95, 0x4F, 0xF1, 0x86, 0x02, 0x0B, 0x18, 0x16, 0xEA, 0x10, 0x4B, 0x4F, 0xCA, 0x2D, 0x30, 0x4D, 0x73, 0x3E, 0x0E, 0x19, 0xCE, 0xAD, 0x51, 0x30, 0x3F, 0xF6, 0x42, 0x0B, 0xFD, 0x22, 0x23, 0x35, 0xCA, 0xA4, 0x02, 0x91, 0x6D }, 2, { 4, 5 }, { 0x5C, 0x55, 0x8E, 0x1D, 0xCA, 0xDE, 0x86, 0xDA, 0x0B, 0x2F, 0x02, 0x62, 0x6A, 0x51, 0x2E, 0x30, 0xA2, 0x2C, 0xF5, 0x25, 0x5C, 0xAE, 0xA7, 0xEE, 0x32, 0xC3, 0x8E, 0x9A, 0x71, 0xA0, 0xE9, 0x14, 0x8B, 0xA6, 0xC0, 0xE6, 0xEC, 0x76, 0x83, 0xB6, 0x42, 0x20, 0xF0, 0x29, 0x86, 0x96, 0xF1, 0xB8, 0x78, 0xCD, 0x47, 0xB1, 0x07, 0xB8, 0x1F, 0x71, 0x88, 0x81, 0x2D, 0x59, 0x39, 0x71, 0xE0, 0xCC }, 0 },
|
||||||
|
{ 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 6, 7 }, { 0x83, 0x9B, 0x08, 0x82, 0x0B, 0x68, 0x1D, 0xBA, 0x8D, 0xAF, 0x4C, 0xC7, 0xB1, 0x04, 0xE8, 0xF2, 0x63, 0x8F, 0x93, 0x88, 0xF8, 0xD7, 0xA5, 0x55, 0xDC, 0x17, 0xB6, 0xE6, 0x97, 0x1D, 0x74, 0x26, 0xCE, 0x07, 0xBF, 0x6A, 0xB0, 0x1F, 0x1D, 0xB5, 0x0E, 0x4E, 0x33, 0x71, 0x92, 0x95, 0xF4, 0x09, 0x45, 0x72, 0xB7, 0x98, 0x68, 0xE4, 0x40, 0xFB, 0x3D, 0xEF, 0xD3, 0xFA, 0xC1, 0xDB, 0x58, 0x9E }, 0 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 7, 8 }, { 0 }, 1 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
enum { MUSIG_VECTORS_MAX_PUBKEYS = 7 };
|
@ -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, xonly_pk32, 32);
|
||||||
secp256k1_sha256_write(&sha, msg, msglen);
|
secp256k1_sha256_write(&sha, msg, msglen);
|
||||||
secp256k1_sha256_finalize(&sha, nonce32);
|
secp256k1_sha256_finalize(&sha, nonce32);
|
||||||
|
secp256k1_sha256_clear(&sha);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +188,8 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi
|
|||||||
secp256k1_memczero(sig64, 64, !ret);
|
secp256k1_memczero(sig64, 64, !ret);
|
||||||
secp256k1_scalar_clear(&k);
|
secp256k1_scalar_clear(&k);
|
||||||
secp256k1_scalar_clear(&sk);
|
secp256k1_scalar_clear(&sk);
|
||||||
memset(seckey, 0, sizeof(seckey));
|
secp256k1_memclear(seckey, sizeof(seckey));
|
||||||
|
secp256k1_gej_clear(&rj);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -29,13 +29,6 @@
|
|||||||
#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL)
|
#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL)
|
||||||
#define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL)
|
#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) {
|
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) {
|
||||||
r->d[0] = v;
|
r->d[0] = v;
|
||||||
r->d[1] = 0;
|
r->d[1] = 0;
|
||||||
|
@ -38,17 +38,6 @@
|
|||||||
#define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL)
|
#define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL)
|
||||||
#define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL)
|
#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) {
|
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) {
|
||||||
r->d[0] = v;
|
r->d[0] = v;
|
||||||
r->d[1] = 0;
|
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_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);
|
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) {
|
static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin) {
|
||||||
int overflow;
|
int overflow;
|
||||||
secp256k1_scalar_set_b32(r, bin, &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);
|
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) {
|
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) {
|
||||||
*r = v % EXHAUSTIVE_TEST_ORDER;
|
*r = v % EXHAUSTIVE_TEST_ORDER;
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ typedef struct secp256k1_scratch_space_struct {
|
|||||||
size_t max_size;
|
size_t max_size;
|
||||||
} secp256k1_scratch;
|
} 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 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);
|
static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch);
|
||||||
|
@ -220,12 +220,12 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co
|
|||||||
ctx->error_callback.data = data;
|
ctx->error_callback.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) {
|
static secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) {
|
||||||
VERIFY_CHECK(ctx != NULL);
|
VERIFY_CHECK(ctx != NULL);
|
||||||
return secp256k1_scratch_create(&ctx->error_callback, max_size);
|
return secp256k1_scratch_create(&ctx->error_callback, max_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) {
|
static void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) {
|
||||||
VERIFY_CHECK(ctx != NULL);
|
VERIFY_CHECK(ctx != NULL);
|
||||||
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
|
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
|
||||||
}
|
}
|
||||||
@ -238,25 +238,13 @@ static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
|
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
|
||||||
secp256k1_ge_storage s;
|
secp256k1_ge_from_bytes(ge, pubkey->data);
|
||||||
|
|
||||||
/* We require that the secp256k1_ge_storage type is exactly 64 bytes.
|
|
||||||
* This is formally not guaranteed by the C standard, but should hold on any
|
|
||||||
* sane compiler in the real world. */
|
|
||||||
STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64);
|
|
||||||
memcpy(&s, &pubkey->data[0], 64);
|
|
||||||
secp256k1_ge_from_storage(ge, &s);
|
|
||||||
ARG_CHECK(!secp256k1_fe_is_zero(&ge->x));
|
ARG_CHECK(!secp256k1_fe_is_zero(&ge->x));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
|
static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
|
||||||
secp256k1_ge_storage s;
|
secp256k1_ge_to_bytes(pubkey->data, ge);
|
||||||
|
|
||||||
STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64);
|
|
||||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));
|
|
||||||
secp256k1_ge_to_storage(&s, ge);
|
|
||||||
memcpy(&pubkey->data[0], &s, 64);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) {
|
int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) {
|
||||||
@ -506,11 +494,13 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
|
|||||||
buffer_append(keydata, &offset, algo16, 16);
|
buffer_append(keydata, &offset, algo16, 16);
|
||||||
}
|
}
|
||||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, offset);
|
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, offset);
|
||||||
memset(keydata, 0, sizeof(keydata));
|
|
||||||
for (i = 0; i <= counter; i++) {
|
for (i = 0; i <= counter; i++) {
|
||||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||||
}
|
}
|
||||||
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
||||||
|
|
||||||
|
secp256k1_memclear(keydata, sizeof(keydata));
|
||||||
|
secp256k1_rfc6979_hmac_sha256_clear(&rng);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,7 +550,7 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc
|
|||||||
* seckey. As a result is_sec_valid is included in ret only after ret was
|
* seckey. As a result is_sec_valid is included in ret only after ret was
|
||||||
* used as a branching variable. */
|
* used as a branching variable. */
|
||||||
ret &= is_sec_valid;
|
ret &= is_sec_valid;
|
||||||
memset(nonce32, 0, 32);
|
secp256k1_memclear(nonce32, sizeof(nonce32));
|
||||||
secp256k1_scalar_clear(&msg);
|
secp256k1_scalar_clear(&msg);
|
||||||
secp256k1_scalar_clear(&non);
|
secp256k1_scalar_clear(&non);
|
||||||
secp256k1_scalar_clear(&sec);
|
secp256k1_scalar_clear(&sec);
|
||||||
@ -607,6 +597,7 @@ static int secp256k1_ec_pubkey_create_helper(const secp256k1_ecmult_gen_context
|
|||||||
|
|
||||||
secp256k1_ecmult_gen(ecmult_gen_ctx, &pj, seckey_scalar);
|
secp256k1_ecmult_gen(ecmult_gen_ctx, &pj, seckey_scalar);
|
||||||
secp256k1_ge_set_gej(p, &pj);
|
secp256k1_ge_set_gej(p, &pj);
|
||||||
|
secp256k1_gej_clear(&pj);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -811,6 +802,7 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32,
|
|||||||
secp256k1_sha256_initialize_tagged(&sha, tag, taglen);
|
secp256k1_sha256_initialize_tagged(&sha, tag, taglen);
|
||||||
secp256k1_sha256_write(&sha, msg, msglen);
|
secp256k1_sha256_write(&sha, msg, msglen);
|
||||||
secp256k1_sha256_finalize(&sha, hash32);
|
secp256k1_sha256_finalize(&sha, hash32);
|
||||||
|
secp256k1_sha256_clear(&sha);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -830,6 +822,10 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32,
|
|||||||
# include "modules/schnorrsig/main_impl.h"
|
# include "modules/schnorrsig/main_impl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_MODULE_MUSIG
|
||||||
|
# include "modules/musig/main_impl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||||
# include "modules/ellswift/main_impl.h"
|
# include "modules/ellswift/main_impl.h"
|
||||||
#endif
|
#endif
|
||||||
|
67
src/tests.c
67
src/tests.c
@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
#define CONDITIONAL_TEST(cnt, nam) if (COUNT < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else
|
#define CONDITIONAL_TEST(cnt, nam) if (COUNT < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else
|
||||||
|
|
||||||
static int COUNT = 64;
|
static int COUNT = 16;
|
||||||
static secp256k1_context *CTX = NULL;
|
static secp256k1_context *CTX = NULL;
|
||||||
static secp256k1_context *STATIC_CTX = NULL;
|
static secp256k1_context *STATIC_CTX = NULL;
|
||||||
|
|
||||||
@ -3671,8 +3671,7 @@ static void test_ge(void) {
|
|||||||
secp256k1_fe zfi2, zfi3;
|
secp256k1_fe zfi2, zfi3;
|
||||||
|
|
||||||
secp256k1_gej_set_infinity(&gej[0]);
|
secp256k1_gej_set_infinity(&gej[0]);
|
||||||
secp256k1_ge_clear(&ge[0]);
|
secp256k1_ge_set_infinity(&ge[0]);
|
||||||
secp256k1_ge_set_gej_var(&ge[0], &gej[0]);
|
|
||||||
for (i = 0; i < runs; i++) {
|
for (i = 0; i < runs; i++) {
|
||||||
int j, k;
|
int j, k;
|
||||||
secp256k1_ge g;
|
secp256k1_ge g;
|
||||||
@ -3982,6 +3981,34 @@ static void test_add_neg_y_diff_x(void) {
|
|||||||
CHECK(secp256k1_gej_eq_ge_var(&sumj, &res));
|
CHECK(secp256k1_gej_eq_ge_var(&sumj, &res));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_ge_bytes(void) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < COUNT + 1; i++) {
|
||||||
|
unsigned char buf[64];
|
||||||
|
secp256k1_ge p, q;
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
secp256k1_ge_set_infinity(&p);
|
||||||
|
} else {
|
||||||
|
testutil_random_ge_test(&p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!secp256k1_ge_is_infinity(&p)) {
|
||||||
|
secp256k1_ge_to_bytes(buf, &p);
|
||||||
|
|
||||||
|
secp256k1_ge_from_bytes(&q, buf);
|
||||||
|
CHECK(secp256k1_ge_eq_var(&p, &q));
|
||||||
|
|
||||||
|
secp256k1_ge_from_bytes_ext(&q, buf);
|
||||||
|
CHECK(secp256k1_ge_eq_var(&p, &q));
|
||||||
|
}
|
||||||
|
secp256k1_ge_to_bytes_ext(buf, &p);
|
||||||
|
secp256k1_ge_from_bytes_ext(&q, buf);
|
||||||
|
CHECK(secp256k1_ge_eq_var(&p, &q));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void run_ge(void) {
|
static void run_ge(void) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < COUNT * 32; i++) {
|
for (i = 0; i < COUNT * 32; i++) {
|
||||||
@ -3989,6 +4016,7 @@ static void run_ge(void) {
|
|||||||
}
|
}
|
||||||
test_add_neg_y_diff_x();
|
test_add_neg_y_diff_x();
|
||||||
test_intialized_inf();
|
test_intialized_inf();
|
||||||
|
test_ge_bytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) {
|
static void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) {
|
||||||
@ -4768,12 +4796,12 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
|
|||||||
testutil_random_ge_test(&pt[ncount]);
|
testutil_random_ge_test(&pt[ncount]);
|
||||||
}
|
}
|
||||||
|
|
||||||
secp256k1_scalar_clear(&sc[0]);
|
secp256k1_scalar_set_int(&sc[0], 0);
|
||||||
CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, 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_set_int(&sc[1], 0);
|
||||||
secp256k1_scalar_clear(&sc[2]);
|
secp256k1_scalar_set_int(&sc[2], 0);
|
||||||
secp256k1_scalar_clear(&sc[3]);
|
secp256k1_scalar_set_int(&sc[3], 0);
|
||||||
secp256k1_scalar_clear(&sc[4]);
|
secp256k1_scalar_set_int(&sc[4], 0);
|
||||||
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, 6));
|
||||||
CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 5));
|
CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 5));
|
||||||
CHECK(secp256k1_gej_is_infinity(&r));
|
CHECK(secp256k1_gej_is_infinity(&r));
|
||||||
@ -5515,7 +5543,7 @@ static void run_ecmult_constants(void) {
|
|||||||
test_ecmult_constants_sha(1607366309u, 2048, expected32_8bit8);
|
test_ecmult_constants_sha(1607366309u, 2048, expected32_8bit8);
|
||||||
}
|
}
|
||||||
|
|
||||||
CONDITIONAL_TEST(35, "test_ecmult_constants_2bit") {
|
CONDITIONAL_TEST(16, "test_ecmult_constants_2bit") {
|
||||||
test_ecmult_constants_2bit();
|
test_ecmult_constants_2bit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7419,6 +7447,10 @@ static void run_ecdsa_wycheproof(void) {
|
|||||||
# include "modules/schnorrsig/tests_impl.h"
|
# include "modules/schnorrsig/tests_impl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_MODULE_MUSIG
|
||||||
|
# include "modules/musig/tests_impl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||||
# include "modules/ellswift/tests_impl.h"
|
# include "modules/ellswift/tests_impl.h"
|
||||||
#endif
|
#endif
|
||||||
@ -7438,6 +7470,18 @@ static void run_secp256k1_memczero_test(void) {
|
|||||||
CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0);
|
CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void run_secp256k1_is_zero_array_test(void) {
|
||||||
|
unsigned char buf1[3] = {0, 1};
|
||||||
|
unsigned char buf2[3] = {1, 0};
|
||||||
|
|
||||||
|
CHECK(secp256k1_is_zero_array(buf1, 0) == 1);
|
||||||
|
CHECK(secp256k1_is_zero_array(buf1, 1) == 1);
|
||||||
|
CHECK(secp256k1_is_zero_array(buf1, 2) == 0);
|
||||||
|
CHECK(secp256k1_is_zero_array(buf2, 1) == 0);
|
||||||
|
CHECK(secp256k1_is_zero_array(buf2, 2) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void run_secp256k1_byteorder_tests(void) {
|
static void run_secp256k1_byteorder_tests(void) {
|
||||||
{
|
{
|
||||||
const uint32_t x = 0xFF03AB45;
|
const uint32_t x = 0xFF03AB45;
|
||||||
@ -7771,12 +7815,17 @@ int main(int argc, char **argv) {
|
|||||||
run_schnorrsig_tests();
|
run_schnorrsig_tests();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_MODULE_MUSIG
|
||||||
|
run_musig_tests();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||||
run_ellswift_tests();
|
run_ellswift_tests();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* util tests */
|
/* util tests */
|
||||||
run_secp256k1_memczero_test();
|
run_secp256k1_memczero_test();
|
||||||
|
run_secp256k1_is_zero_array_test();
|
||||||
run_secp256k1_byteorder_tests();
|
run_secp256k1_byteorder_tests();
|
||||||
|
|
||||||
run_cmov_tests();
|
run_cmov_tests();
|
||||||
|
@ -34,7 +34,7 @@ static void testutil_random_fe_magnitude(secp256k1_fe *fe, int m) {
|
|||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
secp256k1_fe_clear(&zero);
|
secp256k1_fe_set_int(&zero, 0);
|
||||||
secp256k1_fe_negate(&zero, &zero, 0);
|
secp256k1_fe_negate(&zero, &zero, 0);
|
||||||
secp256k1_fe_mul_int_unchecked(&zero, n - 1);
|
secp256k1_fe_mul_int_unchecked(&zero, n - 1);
|
||||||
secp256k1_fe_add(fe, &zero);
|
secp256k1_fe_add(fe, &zero);
|
||||||
|
58
src/util.h
58
src/util.h
@ -8,11 +8,17 @@
|
|||||||
#define SECP256K1_UTIL_H
|
#define SECP256K1_UTIL_H
|
||||||
|
|
||||||
#include "../include/secp256k1.h"
|
#include "../include/secp256k1.h"
|
||||||
|
#include "checkmem.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
/* For SecureZeroMemory */
|
||||||
|
#include <Windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define STR_(x) #x
|
#define STR_(x) #x
|
||||||
#define STR(x) STR_(x)
|
#define STR(x) STR_(x)
|
||||||
@ -192,14 +198,6 @@ static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
# define I64FORMAT "I64d"
|
|
||||||
# define I64uFORMAT "I64u"
|
|
||||||
#else
|
|
||||||
# define I64FORMAT "lld"
|
|
||||||
# define I64uFORMAT "llu"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
# define SECP256K1_GNUC_EXT __extension__
|
# define SECP256K1_GNUC_EXT __extension__
|
||||||
#else
|
#else
|
||||||
@ -221,6 +219,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.
|
/** Semantics like memcmp. Variable-time.
|
||||||
*
|
*
|
||||||
* We use this to avoid possible compiler bugs with memcmp, e.g.
|
* We use this to avoid possible compiler bugs with memcmp, e.g.
|
||||||
@ -239,6 +265,22 @@ static SECP256K1_INLINE int secp256k1_memcmp_var(const void *s1, const void *s2,
|
|||||||
return 0;
|
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.*/
|
/** 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) {
|
static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag) {
|
||||||
unsigned int mask0, mask1, r_masked, a_masked;
|
unsigned int mask0, mask1, r_masked, a_masked;
|
||||||
|
@ -49,7 +49,14 @@ checkout_and_build() {
|
|||||||
-DSECP256K1_BUILD_CTIME_TESTS=OFF \
|
-DSECP256K1_BUILD_CTIME_TESTS=OFF \
|
||||||
-DSECP256K1_BUILD_EXAMPLES=OFF
|
-DSECP256K1_BUILD_EXAMPLES=OFF
|
||||||
cmake --build . -j "$(nproc)"
|
cmake --build . -j "$(nproc)"
|
||||||
abi-dumper src/libsecp256k1.so -o ABI.dump -lver "$2" -public-headers ../include/
|
# FIXME: Just set LIBPATH to lib/libsecp256k1.so once version 0.6.0 is
|
||||||
|
# released.
|
||||||
|
if [ -f "src/libsecp256k1.so" ]; then
|
||||||
|
LIBPATH="src/libsecp256k1.so"
|
||||||
|
else
|
||||||
|
LIBPATH="lib/libsecp256k1.so"
|
||||||
|
fi
|
||||||
|
abi-dumper $LIBPATH -o ABI.dump -lver "$2" -public-headers ../include/
|
||||||
cd "$_orig_dir"
|
cd "$_orig_dir"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
656
tools/test_vectors_musig2_generate.py
Executable file
656
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…
Reference in New Issue
Block a user