Compare commits

..

12 Commits

Author SHA1 Message Date
kngako
69d5e6bdc1 Update README
Some checks failed
CI / Valgrind (memcheck) (map[env_vars:map[ASM:no CC:clang ECMULTGENPRECISION:2 ECMULTWINDOW:2]]) (push) Has been skipped
CI / Valgrind (memcheck) (map[env_vars:map[ASM:no CC:i686-linux-gnu-gcc ECMULTGENPRECISION:2 ECMULTWINDOW:2 HOST:i686-linux-gnu]]) (push) Has been skipped
CI / UBSan, ASan, LSan (map[env_vars:map[ASM:auto CC:clang]]) (push) Has been skipped
CI / UBSan, ASan, LSan (map[env_vars:map[ASM:auto CC:i686-linux-gnu-gcc HOST:i686-linux-gnu]]) (push) Has been skipped
CI / UBSan, ASan, LSan (map[env_vars:map[ASM:no CC:clang ECMULTGENPRECISION:2 ECMULTWINDOW:2]]) (push) Has been skipped
CI / UBSan, ASan, LSan (map[env_vars:map[ASM:no CC:i686-linux-gnu-gcc ECMULTGENPRECISION:2 ECMULTWINDOW:2 HOST:i686-linux-gnu]]) (push) Has been skipped
CI / MSan (map[env_vars:map[CFLAGS:-fsanitize=memory -fsanitize-recover=memory -g -O3 ECMULTGENPRECISION:2 ECMULTWINDOW:2]]) (push) Has been skipped
CI / MSan (map[env_vars:map[CFLAGS:-fsanitize=memory -fsanitize-recover=memory -g]]) (push) Has been skipped
CI / ${{ matrix.configuration.job_name }} (map[env_vars:map[HOST:i686-w64-mingw32] job_name:i686 (mingw32-w64): Windows (Debian stable, Wine)]) (push) Has been skipped
CI / ${{ matrix.configuration.job_name }} (map[env_vars:map[HOST:x86_64-w64-mingw32] job_name:x86_64 (mingw32-w64): Windows (Debian stable, Wine)]) (push) Has been skipped
CI / C++ -fpermissive (entire project) (push) Has been skipped
CI / C++ (public headers) (push) Has been skipped
CI / SageMath prover (push) Failing after 2m13s
CI / release (push) Failing after 8m4s
CI / x86_64: macOS Monterey (map[BPPP:yes CC:gcc ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes RECOVERY:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes SECP256K1_TEST_ITERS:2 WHITELIST:yes W… (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BPPP:yes CC:gcc ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes RECOVERY:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes WHITELIST:yes WIDEMUL:int128]) (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BPPP:yes CPPFLAGS:-DVERIFY CTIMETESTS:no ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes RECOVERY:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes WHITELIST:yes… (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BPPP:yes ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes RECOVERY:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes SECP256K1_TEST_ITERS:2 WHITELIST:yes WIDEMUL:… (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BPPP:yes ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes RECOVERY:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes WHITELIST:yes WIDEMUL:int128]) (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BPPP:yes ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes RECOVERY:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes WHITELIST:yes WIDEMUL:int64]) (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BPPP:yes ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes WHITELIST:yes WIDEMUL:int128]) (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BUILD:distcheck]) (push) Has been cancelled
CI / x86_64: macOS Monterey (map[ECMULTGENPRECISION:2 ECMULTWINDOW:4 WIDEMUL:int128_struct]) (push) Has been cancelled
CI / x86_64: macOS Monterey (map[RECOVERY:yes WIDEMUL:int128]) (push) Has been cancelled
CI / ${{ matrix.configuration.job_name }} (map[cmake_options:-A Win32 job_name:x86 (MSVC): Windows (VS 2022)]) (push) Has been cancelled
CI / ${{ matrix.configuration.job_name }} (map[cmake_options:-A x64 -DBUILD_SHARED_LIBS=OFF job_name:x64 (MSVC): Windows (VS 2022, static)]) (push) Has been cancelled
CI / ${{ matrix.configuration.job_name }} (map[cmake_options:-A x64 -DBUILD_SHARED_LIBS=ON job_name:x64 (MSVC): Windows (VS 2022, shared)]) (push) Has been cancelled
CI / ${{ matrix.configuration.job_name }} (map[cmake_options:-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct cpp_flags:/DSECP256K1_MSVC_MULH_TEST_OVERRIDE job_name:x64 (MSVC): Windows (VS 2022, int128_struct with __(u)mulh)]) (push) Has been cancelled
CI / ${{ matrix.configuration.job_name }} (map[cmake_options:-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct job_name:x64 (MSVC): Windows (VS 2022, int128_struct)]) (push) Has been cancelled
CI / x64 (MSVC): C++ (public headers) (push) Has been cancelled
2024-08-23 02:09:22 +02:00
Kgothatso
df0bdeb096 Add xconfigure to gitignore
Some checks failed
CI / Valgrind (memcheck) (map[env_vars:map[ASM:no CC:clang ECMULTGENPRECISION:2 ECMULTWINDOW:2]]) (push) Has been skipped
CI / Valgrind (memcheck) (map[env_vars:map[ASM:no CC:i686-linux-gnu-gcc ECMULTGENPRECISION:2 ECMULTWINDOW:2 HOST:i686-linux-gnu]]) (push) Has been skipped
CI / UBSan, ASan, LSan (map[env_vars:map[ASM:auto CC:clang]]) (push) Has been skipped
CI / UBSan, ASan, LSan (map[env_vars:map[ASM:auto CC:i686-linux-gnu-gcc HOST:i686-linux-gnu]]) (push) Has been skipped
CI / UBSan, ASan, LSan (map[env_vars:map[ASM:no CC:clang ECMULTGENPRECISION:2 ECMULTWINDOW:2]]) (push) Has been skipped
CI / UBSan, ASan, LSan (map[env_vars:map[ASM:no CC:i686-linux-gnu-gcc ECMULTGENPRECISION:2 ECMULTWINDOW:2 HOST:i686-linux-gnu]]) (push) Has been skipped
CI / MSan (map[env_vars:map[CFLAGS:-fsanitize=memory -fsanitize-recover=memory -g -O3 ECMULTGENPRECISION:2 ECMULTWINDOW:2]]) (push) Has been skipped
CI / MSan (map[env_vars:map[CFLAGS:-fsanitize=memory -fsanitize-recover=memory -g]]) (push) Has been skipped
CI / ${{ matrix.configuration.job_name }} (map[env_vars:map[HOST:i686-w64-mingw32] job_name:i686 (mingw32-w64): Windows (Debian stable, Wine)]) (push) Has been skipped
CI / ${{ matrix.configuration.job_name }} (map[env_vars:map[HOST:x86_64-w64-mingw32] job_name:x86_64 (mingw32-w64): Windows (Debian stable, Wine)]) (push) Has been skipped
CI / C++ -fpermissive (entire project) (push) Has been skipped
CI / C++ (public headers) (push) Has been skipped
CI / SageMath prover (push) Has started running
CI / release (push) Failing after 22m11s
CI / x86_64: macOS Monterey (map[BPPP:yes CC:gcc ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes RECOVERY:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes SECP256K1_TEST_ITERS:2 WHITELIST:yes W… (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BPPP:yes CC:gcc ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes RECOVERY:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes WHITELIST:yes WIDEMUL:int128]) (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BPPP:yes CPPFLAGS:-DVERIFY CTIMETESTS:no ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes RECOVERY:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes WHITELIST:yes… (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BPPP:yes ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes RECOVERY:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes SECP256K1_TEST_ITERS:2 WHITELIST:yes WIDEMUL:… (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BPPP:yes ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes RECOVERY:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes WHITELIST:yes WIDEMUL:int128]) (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BPPP:yes ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes RECOVERY:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes WHITELIST:yes WIDEMUL:int64]) (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BPPP:yes ECDH:yes ECDSAADAPTOR:yes ECDSA_S2C:yes ELLSWIFT:yes EXPERIMENTAL:yes FROST:yes GENERATOR:yes MUSIG:yes RANGEPROOF:yes SCHNORRSIG:yes SCHNORRSIG_HALFAGG:yes WHITELIST:yes WIDEMUL:int128]) (push) Has been cancelled
CI / x86_64: macOS Monterey (map[BUILD:distcheck]) (push) Has been cancelled
CI / x86_64: macOS Monterey (map[ECMULTGENPRECISION:2 ECMULTWINDOW:4 WIDEMUL:int128_struct]) (push) Has been cancelled
CI / x86_64: macOS Monterey (map[RECOVERY:yes WIDEMUL:int128]) (push) Has been cancelled
CI / ${{ matrix.configuration.job_name }} (map[cmake_options:-A Win32 job_name:x86 (MSVC): Windows (VS 2022)]) (push) Has been cancelled
CI / ${{ matrix.configuration.job_name }} (map[cmake_options:-A x64 -DBUILD_SHARED_LIBS=OFF job_name:x64 (MSVC): Windows (VS 2022, static)]) (push) Has been cancelled
CI / ${{ matrix.configuration.job_name }} (map[cmake_options:-A x64 -DBUILD_SHARED_LIBS=ON job_name:x64 (MSVC): Windows (VS 2022, shared)]) (push) Has been cancelled
CI / ${{ matrix.configuration.job_name }} (map[cmake_options:-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct cpp_flags:/DSECP256K1_MSVC_MULH_TEST_OVERRIDE job_name:x64 (MSVC): Windows (VS 2022, int128_struct with __(u)mulh)]) (push) Has been cancelled
CI / ${{ matrix.configuration.job_name }} (map[cmake_options:-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct job_name:x64 (MSVC): Windows (VS 2022, int128_struct)]) (push) Has been cancelled
CI / x64 (MSVC): C++ (public headers) (push) Has been cancelled
2024-08-03 19:55:35 +02:00
Jesse Posner
3891388905
frost: add documentation file
This commit adds a documentation file with detailed instructions for how
to use the module properly.
2024-07-23 14:33:22 -07:00
Jesse Posner
36ff5b02da
frost: add tests
Add api tests, nonce tests, tweak tests, sha256 tag tests, and constant
time tests.
2024-07-23 14:33:09 -07:00
Jesse Posner
c2d48a7039
frost: add example file
This commit adds an example file to demonstrate how to use the module.
2024-07-16 23:36:51 -07:00
Jesse Posner
ef15156ffb
frost: signature generation and aggregation
This commit adds signature generation and aggregation, as well as
partial signature serialization and parsing.
2024-07-16 23:36:51 -07:00
Jesse Posner
67c21beadd
frost: nonce aggregation and adaptor signatures
This commit adds nonce aggregation, as well as adaptor signatures.
2024-07-16 23:36:47 -07:00
Jesse Posner
17c47e9708
frost: key tweaking
This commits add BIP-341 ("Taproot") and BIP-32 ("ordinary") public key
tweaking.
2024-07-16 22:13:19 -07:00
Jesse Posner
f606507120
frost: nonce generation
This commits adds nonce generation, as well as serialization and
parsing.
2024-07-16 22:13:19 -07:00
Jesse Posner
197fb7efb9
frost: share aggregation
This commit adds share aggregation and verification, as well as
computation of public verification shares.
2024-07-16 22:13:15 -07:00
Jesse Posner
2336b02fad
frost: share generation
This commit adds share generation, as well as share serialization and
parsing.
2024-07-16 22:01:45 -07:00
Jesse Posner
2f3fa4cace
frost: initialize project
This commit adds the foundational configuration and building scripts
and an initial structure for the project.
2024-07-16 22:01:40 -07:00
12 changed files with 1221 additions and 36 deletions

View File

@ -41,6 +41,7 @@ env:
ECDSAADAPTOR: 'no' ECDSAADAPTOR: 'no'
BPPP: 'no' BPPP: 'no'
SCHNORRSIG_HALFAGG: 'no' SCHNORRSIG_HALFAGG: 'no'
FROST: 'no'
### test options ### test options
SECP256K1_TEST_ITERS: SECP256K1_TEST_ITERS:
BENCH: 'yes' BENCH: 'yes'
@ -79,14 +80,14 @@ jobs:
matrix: matrix:
configuration: configuration:
- env_vars: { WIDEMUL: 'int64', RECOVERY: 'yes' } - env_vars: { WIDEMUL: 'int64', RECOVERY: 'yes' }
- env_vars: { WIDEMUL: 'int64', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes'} - env_vars: { WIDEMUL: 'int64', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', FROST: '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', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } - env_vars: { WIDEMUL: 'int128', RECOVERY: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- env_vars: { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes'} - env_vars: { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', FROST: 'yes' }
- env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' } - env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' }
- env_vars: { RECOVERY: 'yes', SCHNORRSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes'} - env_vars: { RECOVERY: 'yes', SCHNORRSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', FROST: 'yes' }
- env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CPPFLAGS: '-DVERIFY' } - env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', FROST: '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' }
@ -158,6 +159,7 @@ jobs:
ECDSAADAPTOR: 'yes' ECDSAADAPTOR: 'yes'
BPPP: 'yes' BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes' SCHNORRSIG_HALFAGG: 'yes'
FROST: 'yes'
CC: ${{ matrix.cc }} CC: ${{ matrix.cc }}
steps: steps:
@ -211,6 +213,7 @@ jobs:
ECDSAADAPTOR: 'yes' ECDSAADAPTOR: 'yes'
BPPP: 'yes' BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes' SCHNORRSIG_HALFAGG: 'yes'
FROST: 'yes'
CTIMETESTS: 'no' CTIMETESTS: 'no'
steps: steps:
@ -271,6 +274,7 @@ jobs:
ECDSAADAPTOR: 'yes' ECDSAADAPTOR: 'yes'
BPPP: 'yes' BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes' SCHNORRSIG_HALFAGG: 'yes'
FROST: 'yes'
CTIMETESTS: 'no' CTIMETESTS: 'no'
steps: steps:
@ -325,6 +329,7 @@ jobs:
ECDSAADAPTOR: 'yes' ECDSAADAPTOR: 'yes'
BPPP: 'yes' BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes' SCHNORRSIG_HALFAGG: 'yes'
FROST: 'yes'
CTIMETESTS: 'no' CTIMETESTS: 'no'
strategy: strategy:
@ -389,6 +394,7 @@ jobs:
ECDSAADAPTOR: 'yes' ECDSAADAPTOR: 'yes'
BPPP: 'yes' BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes' SCHNORRSIG_HALFAGG: 'yes'
FROST: 'yes'
CTIMETESTS: 'no' CTIMETESTS: 'no'
steps: steps:
@ -450,6 +456,7 @@ jobs:
ECDSAADAPTOR: 'yes' ECDSAADAPTOR: 'yes'
BPPP: 'yes' BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes' SCHNORRSIG_HALFAGG: 'yes'
FROST: 'yes'
CTIMETESTS: 'no' CTIMETESTS: 'no'
SECP256K1_TEST_ITERS: 2 SECP256K1_TEST_ITERS: 2
@ -510,6 +517,7 @@ jobs:
ECDSAADAPTOR: 'yes' ECDSAADAPTOR: 'yes'
BPPP: 'yes' BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes' SCHNORRSIG_HALFAGG: 'yes'
FROST: 'yes'
CTIMETESTS: 'no' CTIMETESTS: 'no'
CFLAGS: '-fsanitize=undefined,address -g' CFLAGS: '-fsanitize=undefined,address -g'
UBSAN_OPTIONS: 'print_stacktrace=1:halt_on_error=1' UBSAN_OPTIONS: 'print_stacktrace=1:halt_on_error=1'
@ -576,6 +584,7 @@ jobs:
ECDSAADAPTOR: 'yes' ECDSAADAPTOR: 'yes'
BPPP: 'yes' BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes' SCHNORRSIG_HALFAGG: 'yes'
FROST: 'yes'
CTIMETESTS: 'yes' CTIMETESTS: 'yes'
CC: 'clang' CC: 'clang'
SECP256K1_TEST_ITERS: 32 SECP256K1_TEST_ITERS: 32
@ -632,6 +641,7 @@ jobs:
ECDSAADAPTOR: 'yes' ECDSAADAPTOR: 'yes'
BPPP: 'yes' BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes' SCHNORRSIG_HALFAGG: 'yes'
FROST: 'yes'
CTIMETESTS: 'no' CTIMETESTS: 'no'
strategy: strategy:
@ -688,15 +698,15 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
env_vars: env_vars:
- { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' } - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', FROST: 'yes' }
- { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 } - { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 }
- { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' } - { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', FROST: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes' } - { WIDEMUL: 'int128', RECOVERY: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' } - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', FROST: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CC: 'gcc' } - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CC: 'gcc', FROST: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', FROST: 'yes', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', FROST: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' } - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', FROST: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' }
- BUILD: 'distcheck' - BUILD: 'distcheck'
steps: steps:
@ -816,6 +826,7 @@ jobs:
ECDSAADAPTOR: 'yes' ECDSAADAPTOR: 'yes'
BPPP: 'yes' BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes' SCHNORRSIG_HALFAGG: 'yes'
FROST: 'yes'
steps: steps:
- name: Checkout - name: Checkout

1
.gitignore vendored
View File

@ -72,3 +72,4 @@ frost_example
/CMakeUserPresets.json /CMakeUserPresets.json
# Default CMake build directory. # Default CMake build directory.
/build /build
xconfigure.sh

View File

@ -3,7 +3,7 @@ libsecp256k1-zkp
![Dependencies: None](https://img.shields.io/badge/dependencies-none-success) ![Dependencies: None](https://img.shields.io/badge/dependencies-none-success)
A fork of [libsecp256k1](https://github.com/bitcoin-core/secp256k1) with support for advanced and experimental features such as Confidential Assets and MuSig2 A fork of [libsecp256k1](https://github.com/bitcoin-core/secp256k1) with support for advanced and experimental features such as Confidential Assets, MuSig2, and FROST.
Added features: Added features:
* Experimental module for ECDSA adaptor signatures. * Experimental module for ECDSA adaptor signatures.

View File

@ -15,7 +15,7 @@ print_environment() {
ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
EXPERIMENTAL ECDH RECOVERY SCHNORRSIG SCHNORRSIG_HALFAGG ELLSWIFT \ EXPERIMENTAL ECDH RECOVERY SCHNORRSIG SCHNORRSIG_HALFAGG ELLSWIFT \
ECDSA_S2C GENERATOR RANGEPROOF WHITELIST MUSIG ECDSAADAPTOR BPPP \ ECDSA_S2C GENERATOR RANGEPROOF WHITELIST MUSIG ECDSAADAPTOR BPPP \
SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\ FROST SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
EXAMPLES \ EXAMPLES \
HOST WRAPPER_CMD \ HOST WRAPPER_CMD \
CC CFLAGS CPPFLAGS AR NM CC CFLAGS CPPFLAGS AR NM
@ -83,6 +83,7 @@ esac
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \ --enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \
--enable-module-schnorrsig="$SCHNORRSIG" \ --enable-module-schnorrsig="$SCHNORRSIG" \
--enable-module-schnorrsig-halfagg="$SCHNORRSIG_HALFAGG" \ --enable-module-schnorrsig-halfagg="$SCHNORRSIG_HALFAGG" \
--enable-module-frost="$FROST" \
--enable-examples="$EXAMPLES" \ --enable-examples="$EXAMPLES" \
--enable-ctime-tests="$CTIMETESTS" \ --enable-ctime-tests="$CTIMETESTS" \
--with-valgrind="$WITH_VALGRIND" \ --with-valgrind="$WITH_VALGRIND" \

View File

@ -1,5 +1,5 @@
/*********************************************************************** /***********************************************************************
* Copyright (c) 2021-2023 Jesse Posner * * Copyright (c) 2021-2024 Jesse Posner *
* Distributed under the MIT software license, see the accompanying * * Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.* * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/ ***********************************************************************/
@ -70,7 +70,7 @@ int create_keypair_and_seed(const secp256k1_context* ctx, struct signer_secrets
} }
/* Create shares and coefficient commitments */ /* Create shares and coefficient commitments */
int create_shares(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, secp256k1_xonly_pubkey *agg_pk) { int create_shares(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, secp256k1_xonly_pubkey *pk) {
int i, j; int i, j;
secp256k1_frost_share shares[N_SIGNERS][N_SIGNERS]; secp256k1_frost_share shares[N_SIGNERS][N_SIGNERS];
const secp256k1_pubkey *vss_commitments[N_SIGNERS]; const secp256k1_pubkey *vss_commitments[N_SIGNERS];
@ -99,7 +99,7 @@ int create_shares(const secp256k1_context* ctx, struct signer_secrets *signer_se
assigned_shares[j] = &shares[j][i]; assigned_shares[j] = &shares[j][i];
} }
/* Each participant aggregates the shares they received. */ /* Each participant aggregates the shares they received. */
if (!secp256k1_frost_share_agg(ctx, &signer_secrets[i].agg_share, agg_pk, assigned_shares, vss_commitments, N_SIGNERS, THRESHOLD, signer[i].id)) { if (!secp256k1_frost_share_agg(ctx, &signer_secrets[i].agg_share, pk, assigned_shares, vss_commitments, N_SIGNERS, THRESHOLD, signer[i].id)) {
return 0; return 0;
} }
for (j = 0; j < N_SIGNERS; j++) { for (j = 0; j < N_SIGNERS; j++) {
@ -123,12 +123,12 @@ int create_shares(const secp256k1_context* ctx, struct signer_secrets *signer_se
/* Tweak the pubkey corresponding to the provided tweak cache, update the cache /* Tweak the pubkey corresponding to the provided tweak cache, update the cache
* and return the tweaked aggregate pk. */ * and return the tweaked aggregate pk. */
int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_frost_tweak_cache *cache) { int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pk, secp256k1_frost_tweak_cache *cache) {
secp256k1_pubkey output_pk; secp256k1_pubkey output_pk;
unsigned char ordinary_tweak[32] = "this could be a BIP32 tweak...."; unsigned char ordinary_tweak[32] = "this could be a BIP32 tweak....";
unsigned char xonly_tweak[32] = "this could be a taproot tweak.."; unsigned char xonly_tweak[32] = "this could be a taproot tweak..";
if (!secp256k1_frost_pubkey_tweak(ctx, cache, agg_pk)) { if (!secp256k1_frost_pubkey_tweak(ctx, cache, pk)) {
return 0; return 0;
} }
@ -154,7 +154,7 @@ int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k
* the Schnorr signature against it. For this purpose we can ignore the * 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 * `pk_parity` output argument; we would need it if we would have to open
* the taproot commitment. */ * the taproot commitment. */
if (!secp256k1_xonly_pubkey_from_pubkey(ctx, agg_pk, NULL, &output_pk)) { if (!secp256k1_xonly_pubkey_from_pubkey(ctx, pk, NULL, &output_pk)) {
return 0; return 0;
} }
return 1; return 1;
@ -162,7 +162,7 @@ int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k
/* Sign a message hash with the given threshold and aggregate shares and store /* Sign a message hash with the given threshold and aggregate shares and store
* the result in sig */ * the result in sig */
int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const unsigned char* msg32, secp256k1_xonly_pubkey *agg_pk, unsigned char *sig64, const secp256k1_frost_tweak_cache *cache) { int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const unsigned char* msg32, secp256k1_xonly_pubkey *pk, unsigned char *sig64, const secp256k1_frost_tweak_cache *cache) {
int i; int i;
int signer_id = 0; int signer_id = 0;
int signers[THRESHOLD]; int signers[THRESHOLD];
@ -181,7 +181,7 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
} }
/* Initialize session and create secret nonce for signing and public /* Initialize session and create secret nonce for signing and public
* nonce to send to the other signers. */ * nonce to send to the other signers. */
if (!secp256k1_frost_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_id, &signer_secrets[i].agg_share, msg32, agg_pk, NULL)) { if (!secp256k1_frost_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_id, &signer_secrets[i].agg_share, msg32, pk, NULL)) {
return 0; return 0;
} }
is_signer[i] = 0; /* Initialize is_signer */ is_signer[i] = 0; /* Initialize is_signer */
@ -210,7 +210,7 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
/* Signing communication round 1: Exchange nonces */ /* Signing communication round 1: Exchange nonces */
for (i = 0; i < THRESHOLD; i++) { for (i = 0; i < THRESHOLD; i++) {
signer_id = signers[i]; signer_id = signers[i];
if (!secp256k1_frost_nonce_process(ctx, &signer[signer_id].session, pubnonces, THRESHOLD, msg32, agg_pk, signer[signer_id].id, ids, cache, NULL)) { if (!secp256k1_frost_nonce_process(ctx, &signer[signer_id].session, pubnonces, THRESHOLD, msg32, pk, signer[signer_id].id, ids, cache, NULL)) {
return 0; return 0;
} }
/* partial_sign will clear the secnonce by setting it to 0. That's because /* partial_sign will clear the secnonce by setting it to 0. That's because
@ -249,7 +249,7 @@ int main(void) {
int i; int i;
struct signer_secrets signer_secrets[N_SIGNERS]; struct signer_secrets signer_secrets[N_SIGNERS];
struct signer signers[N_SIGNERS]; struct signer signers[N_SIGNERS];
secp256k1_xonly_pubkey agg_pk; secp256k1_xonly_pubkey pk;
secp256k1_frost_tweak_cache cache; secp256k1_frost_tweak_cache cache;
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!"; unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!";
unsigned char sig[64]; unsigned char sig[64];
@ -265,26 +265,26 @@ int main(void) {
} }
printf("ok\n"); printf("ok\n");
printf("Creating shares........."); printf("Creating shares.........");
if (!create_shares(ctx, signer_secrets, signers, &agg_pk)) { if (!create_shares(ctx, signer_secrets, signers, &pk)) {
printf("FAILED\n"); printf("FAILED\n");
return 1; return 1;
} }
printf("ok\n"); printf("ok\n");
printf("Tweaking................"); printf("Tweaking................");
/* Optionally tweak the aggregate key */ /* Optionally tweak the aggregate key */
if (!tweak(ctx, &agg_pk, &cache)) { if (!tweak(ctx, &pk, &cache)) {
printf("FAILED\n"); printf("FAILED\n");
return 1; return 1;
} }
printf("ok\n"); printf("ok\n");
printf("Signing message........."); printf("Signing message.........");
if (!sign(ctx, signer_secrets, signers, msg, &agg_pk, sig, &cache)) { if (!sign(ctx, signer_secrets, signers, msg, &pk, sig, &cache)) {
printf("FAILED\n"); printf("FAILED\n");
return 1; return 1;
} }
printf("ok\n"); printf("ok\n");
printf("Verifying signature....."); printf("Verifying signature.....");
if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &agg_pk)) { if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &pk)) {
printf("FAILED\n"); printf("FAILED\n");
return 1; return 1;
} }

View File

@ -15,11 +15,15 @@ extern "C" {
* This module implements a variant of Flexible Round-Optimized Schnorr * This module implements a variant of Flexible Round-Optimized Schnorr
* Threshold Signatures (FROST) by Chelsea Komlo and Ian Goldberg * Threshold Signatures (FROST) by Chelsea Komlo and Ian Goldberg
* (https://crysp.uwaterloo.ca/software/frost/). Signatures are compatible with * (https://crysp.uwaterloo.ca/software/frost/). Signatures are compatible with
* BIP-340 ("Schnorr"). * BIP-340 ("Schnorr"). There's an example C source file in the module's
* directory (examples/frost.c) that demonstrates how it can be used.
* *
* The module also supports BIP-341 ("Taproot") and BIP-32 ("ordinary") public * The module also supports BIP-341 ("Taproot") and BIP-32 ("ordinary") public
* key tweaking, and adaptor signatures. * key tweaking, and adaptor signatures.
* *
* It is recommended to read the documentation in this include file carefully.
* Further notes on API usage can be found in src/modules/frost/frost.md
*
* Following the convention used in the MuSig module, the API uses the singular * Following the convention used in the MuSig module, the API uses the singular
* term "nonce" to refer to the two "nonces" used by the FROST scheme. * term "nonce" to refer to the two "nonces" used by the FROST scheme.
*/ */
@ -283,9 +287,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_share_verify(
* *
* Returns: 0 if the arguments are invalid, 1 otherwise * Returns: 0 if the arguments are invalid, 1 otherwise
* Args: ctx: pointer to a context object * Args: ctx: pointer to a context object
* In: pubshare: pointer to a struct to store the public verification * Out: pubshare: pointer to a struct to store the public verification
* share * share
* threshold: the minimum number of signers required to produce a * In: threshold: the minimum number of signers required to produce a
* signature * signature
* id33: the 33-byte participant ID of the participant whose * id33: the 33-byte participant ID of the participant whose
* partial signature will be verified with the pubshare * partial signature will be verified with the pubshare
@ -472,10 +476,10 @@ SECP256K1_API int secp256k1_frost_nonce_gen(
) 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);
/** Takes the public nonces of all signers and computes a session that is /** Takes the public nonces of all signers and computes a session that is
* required for signing and verification of partial signatures. The participant * required for signing and verification of partial signatures. The participant
* IDs can be sorted before combining, but the corresponding pubnonces must be * IDs can be sorted before combining, but the corresponding pubnonces must be
* resorted as well. All signers must use the same sorting of pubnonces, * resorted as well. All signers must use the same sorting of pubnonces,
* otherwise signing will fail. * otherwise signing will fail.
* *
* Returns: 0 if the arguments are invalid or if some signer sent invalid * Returns: 0 if the arguments are invalid or if some signer sent invalid
* pubnonces, 1 otherwise * pubnonces, 1 otherwise
@ -543,7 +547,7 @@ SECP256K1_API int secp256k1_frost_partial_sign(
* 1. The `tweak_cache` argument is identical to the one used to create the * 1. The `tweak_cache` argument is identical to the one used to create the
* `session` with `frost_nonce_process`. * `session` with `frost_nonce_process`.
* 2. The `pubshare` argument must be the output of * 2. The `pubshare` argument must be the output of
* `secp256k1_frost_shares_trusted_gen` for the signer's 'pk'. * `secp256k1_frost_compute_pubshare` for the signer's ID.
* 3. The `pubnonce` argument must be identical to the one sent by the * 3. The `pubnonce` argument must be identical to the one sent by the
* signer and used to create the `session` with `frost_nonce_process`. * signer and used to create the `session` with `frost_nonce_process`.
* *
@ -557,7 +561,7 @@ SECP256K1_API int secp256k1_frost_partial_sign(
* pubnonce: public nonce of the signer in the signing session * pubnonce: public nonce of the signer in the signing session
* pubshare: public verification share of the signer in the signing * pubshare: public verification share of the signer in the signing
* session that is the output of * session that is the output of
* `secp256k1_frost_shares_trusted_gen` * `secp256k1_frost_compute_pubshare`
* session: pointer to the session that was created with * session: pointer to the session that was created with
* `frost_nonce_process` * `frost_nonce_process`
* tweak_cache: pointer to frost_tweak_cache struct (can be NULL) * tweak_cache: pointer to frost_tweak_cache struct (can be NULL)

View File

@ -47,6 +47,10 @@
#include "../include/secp256k1_musig.h" #include "../include/secp256k1_musig.h"
#endif #endif
#ifdef ENABLE_MODULE_FROST
#include "include/secp256k1_frost.h"
#endif
static void run_tests(secp256k1_context *ctx, unsigned char *key); static void run_tests(secp256k1_context *ctx, unsigned char *key);
int main(void) { int main(void) {
@ -349,4 +353,119 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
CHECK(ret == 1); CHECK(ret == 1);
} }
#endif #endif
#ifdef ENABLE_MODULE_FROST
{
secp256k1_pubkey pk[2];
secp256k1_xonly_pubkey agg_pk;
unsigned char session_id[32];
unsigned char seed[2][32];
secp256k1_frost_secnonce secnonce[2];
secp256k1_frost_pubnonce pubnonce[2];
const secp256k1_frost_pubnonce *pubnonce_ptr[2];
secp256k1_frost_tweak_cache cache;
secp256k1_frost_session session;
secp256k1_frost_partial_sig partial_sig;
const secp256k1_frost_partial_sig *partial_sig_ptr[1];
unsigned char extra_input[32];
unsigned char sec_adaptor[32];
secp256k1_pubkey adaptor;
unsigned char pre_sig[64];
int nonce_parity;
secp256k1_frost_share shares[2][2];
const secp256k1_frost_share *share_ptr[2];
secp256k1_frost_share agg_share;
const secp256k1_pubkey *vss_ptr[2];
unsigned char pok[2][64];
secp256k1_pubkey vss_commitment[2][2];
unsigned char key2[32];
secp256k1_keypair keypair2;
unsigned char id[2][33];
const unsigned char *id_ptr[2];
size_t size = 33;
id_ptr[0] = id[0];
id_ptr[1] = id[1];
pubnonce_ptr[0] = &pubnonce[0];
pubnonce_ptr[1] = &pubnonce[1];
SECP256K1_CHECKMEM_DEFINE(key, 32);
memcpy(seed[0], key, 32);
seed[0][0] = seed[0][0] + 1;
memcpy(seed[0], key, 32);
seed[1][0] = seed[1][0] + 2;
memcpy(extra_input, key, sizeof(extra_input));
extra_input[0] = extra_input[0] + 3;
memcpy(sec_adaptor, key, sizeof(sec_adaptor));
sec_adaptor[0] = extra_input[0] + 4;
memcpy(key2, key, sizeof(key2));
key2[0] = key2[0] + 5;
memcpy(session_id, key, sizeof(session_id));
session_id[0] = session_id[0] + 6;
partial_sig_ptr[0] = &partial_sig;
share_ptr[0] = &shares[0][0];
share_ptr[1] = &shares[1][0];
vss_ptr[0] = vss_commitment[0];
vss_ptr[1] = vss_commitment[1];
CHECK(secp256k1_keypair_create(ctx, &keypair, key));
CHECK(secp256k1_keypair_create(ctx, &keypair2, key2));
CHECK(secp256k1_keypair_pub(ctx, &pk[0], &keypair));
CHECK(secp256k1_keypair_pub(ctx, &pk[1], &keypair2));
CHECK(secp256k1_ec_pubkey_serialize(ctx, id[0], &size, &pk[0], SECP256K1_EC_COMPRESSED));
CHECK(secp256k1_ec_pubkey_serialize(ctx, id[1], &size, &pk[1], SECP256K1_EC_COMPRESSED));
/* shares_gen */
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(key2, 32);
SECP256K1_CHECKMEM_UNDEFINE(seed[0], 32);
SECP256K1_CHECKMEM_UNDEFINE(seed[1], 32);
ret = secp256k1_frost_shares_gen(ctx, shares[0], vss_commitment[0], pok[0], seed[0], 2, 2, id_ptr);
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
ret = secp256k1_frost_shares_gen(ctx, shares[1], vss_commitment[1], pok[1], seed[1], 2, 2, id_ptr);
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
/* share_agg */
SECP256K1_CHECKMEM_DEFINE(&vss_commitment[0][0], sizeof(secp256k1_pubkey));
SECP256K1_CHECKMEM_DEFINE(&vss_commitment[0][1], sizeof(secp256k1_pubkey));
SECP256K1_CHECKMEM_DEFINE(&vss_commitment[1][0], sizeof(secp256k1_pubkey));
SECP256K1_CHECKMEM_DEFINE(&vss_commitment[1][1], sizeof(secp256k1_pubkey));
SECP256K1_CHECKMEM_DEFINE(pok[0], 64);
ret = secp256k1_frost_share_agg(ctx, &agg_share, &agg_pk, share_ptr, vss_ptr, 2, 2, id_ptr[0]);
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
/* nonce_gen */
SECP256K1_CHECKMEM_UNDEFINE(session_id, sizeof(session_id));
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor));
SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input));
SECP256K1_CHECKMEM_UNDEFINE(sec_adaptor, sizeof(sec_adaptor));
CHECK(secp256k1_frost_pubkey_tweak(ctx, &cache, &agg_pk) == 1);
ret = secp256k1_frost_nonce_gen(ctx, &secnonce[0], &pubnonce[0], session_id, &agg_share, msg, &agg_pk, extra_input);
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
ret = secp256k1_frost_nonce_gen(ctx, &secnonce[1], &pubnonce[1], session_id, &agg_share, msg, &agg_pk, extra_input);
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
/* partial_sign */
CHECK(secp256k1_frost_nonce_process(ctx, &session, pubnonce_ptr, 2, msg, &agg_pk, id_ptr[0], id_ptr, &cache, &adaptor) == 1);
ret = secp256k1_keypair_create(ctx, &keypair, key);
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
ret = secp256k1_frost_partial_sign(ctx, &partial_sig, &secnonce[0], &agg_share, &session, &cache);
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
/* adapt */
SECP256K1_CHECKMEM_DEFINE(&partial_sig, sizeof(partial_sig));
CHECK(secp256k1_frost_partial_sig_agg(ctx, pre_sig, &session, partial_sig_ptr, 1));
SECP256K1_CHECKMEM_DEFINE(pre_sig, sizeof(pre_sig));
CHECK(secp256k1_frost_nonce_parity(ctx, &nonce_parity, &session));
ret = secp256k1_frost_adapt(ctx, sig, pre_sig, sec_adaptor, nonce_parity);
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
/* extract_adaptor */
ret = secp256k1_frost_extract_adaptor(ctx, sec_adaptor, sig, pre_sig, nonce_parity);
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
}
#endif
} }

View File

@ -5,3 +5,4 @@ noinst_HEADERS += src/modules/frost/keygen_impl.h
noinst_HEADERS += src/modules/frost/session.h noinst_HEADERS += src/modules/frost/session.h
noinst_HEADERS += src/modules/frost/session_impl.h noinst_HEADERS += src/modules/frost/session_impl.h
noinst_HEADERS += src/modules/frost/adaptor_impl.h noinst_HEADERS += src/modules/frost/adaptor_impl.h
noinst_HEADERS += src/modules/frost/tests_impl.h

View File

@ -0,0 +1,95 @@
Notes on the frost module API
===========================
The following sections contain additional notes on the API of the frost module
(`include/secp256k1_frost.h`). A usage example can be found in
`examples/frost.c`.
# API misuse
Users of the frost module must take great care to make sure of the following:
1. Each participant exchanges public keys for identification and authentication
purposes. Partipants must provide the same public key to each other
participant.
2. Each participant establishes a secure communications channel with each other
participant and uses that channel to transmit shares and commitments during
key generation.
3. A unique set of coefficients per key generation session is generated in
`secp256k1_frost_shares_gen`. See the corresponding comment in
`include/secp256k1_frost.h` for how to ensure that.
4. The `pubnonces` provided to `secp256k1_frost_nonce_process` are sorted by
the corresponding lexicographic ordering of the x-only pubkey of each
participant, and the `ids33` provided to `secp256k1_frost_nonce_process`
are sorted lexicographically.
5. A unique nonce per signing session is generated in `secp256k1_frost_nonce_gen`.
See the corresponding comment in `include/secp256k1_frost.h` for how to ensure that.
6. The `secp256k1_frost_secnonce` structure is never copied or serialized.
See also the comment on `secp256k1_frost_secnonce` in `include/secp256k1_frost.h`.
7. Opaque data structures are never written to or read from directly.
Instead, only the provided accessor functions are used.
8. If adaptor signatures are used, all partial signatures are verified.
# Key Generation
1. Generate a keypair with `secp256k1_keypair_create` and obtain the x-only
public key with `secp256k1_keypair_xonly_pub`, and distribute it to each
other participant to be used as an authentication key and identifier.
2. Generate a VSS commitment, proof-of-knowledge, and shares with
`secp256k1_frost_shares_gen`. The VSS commitment and proof-of-knowledge must
be broadcast to all participants. Assign each participant a share according
to the order of `ids33` and distribute the shares to the participants using
a secure channel.
3. After receiving a share and commitment set from each participant, call
`secp256k1_frost_share_agg` to compute the aggregate share, group public
key, and VSS hash. If this function returns an error,
`secp256k1_frost_share_verify` is called on each share to determine which
participants submitted faulty shares.
4. Optionally compute the public verification share by calling
`secp256k1_frost_compute_pubshare` with the x-only public key of each
participant. This share is required by `secp256k1_frost_partial_sig_verify`
to verify partial signatures generated by `secp256k1_frost_partial_sign`.
# Tweaking
A (Taproot) tweak can be added to the resulting public key with
`secp256k1_xonly_pubkey_tweak_add`, after converting it to an xonly pubkey if
necessary with `secp256k1_xonly_pubkey_from_pubkey`.
An ordinary tweak can be added to the resulting public key with
`secp256k1_ec_pubkey_tweak_add`, after converting it to an ordinary pubkey if
necessary with `secp256k1_frost_pubkey_get`.
Tweaks can also be chained together by tweaking an already tweaked key.
# Signing
1. Optionally add a tweak by calling `secp256k1_frost_pubkey_tweak` and then
`secp256k1_frost_pubkey_xonly_tweak_add` for a Taproot tweak and
`secp256k1_frost_pubkey_ec_tweak_add` for an ordinary tweak.
2. Generate a pair of secret and public nonce with `secp256k1_frost_nonce_gen`
and send the public nonce to the other signers.
3. Process the aggregate nonce with `secp256k1_frost_nonce_process`.
4. Create a partial signature with `secp256k1_frost_partial_sign`.
5. Verify the partial signatures (optional in some scenarios) with
`secp256k1_frost_partial_sig_verify`.
6. Someone (not necessarily the signer) obtains all partial signatures and
aggregates them into the final Schnorr signature using
`secp256k1_frost_partial_sig_agg`.
The aggregate signature can be verified with `secp256k1_schnorrsig_verify`.
Note that steps 1 to 3 can happen before the message to be signed is known to
the signers. Therefore, the communication round to exchange nonces can be
viewed as a pre-processing step that is run whenever convenient to the signers.
This disables some of the defense-in-depth measures that may protect against
API misuse in some cases. Similarly, the API supports an alternative protocol
flow where generating the key (see Key Generation above) is allowed to happen
after exchanging nonces (step 2).
# 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 2 and 4.

View File

@ -23,4 +23,6 @@ static int secp256k1_tweak_cache_load(const secp256k1_context* ctx, secp256k1_tw
static int secp256k1_frost_share_load(const secp256k1_context* ctx, secp256k1_scalar *s, const secp256k1_frost_share* share); static int secp256k1_frost_share_load(const secp256k1_context* ctx, secp256k1_scalar *s, const secp256k1_frost_share* share);
static int secp256k1_frost_compute_indexhash(secp256k1_scalar *indexhash, const unsigned char *id33);
#endif #endif

View File

@ -0,0 +1,943 @@
/***********************************************************************
* Copyright (c) 2022-2024 Jesse Posner *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_MODULE_FROST_TESTS_IMPL_H
#define SECP256K1_MODULE_FROST_TESTS_IMPL_H
#include <stdlib.h>
#include <string.h>
#include "../../../include/secp256k1.h"
#include "../../../include/secp256k1_extrakeys.h"
#include "../../../include/secp256k1_frost.h"
#include "session.h"
#include "keygen.h"
#include "../../scalar.h"
#include "../../scratch.h"
#include "../../field.h"
#include "../../group.h"
#include "../../hash.h"
#include "../../util.h"
static int frost_create_pk(unsigned char *id, const unsigned char *sk) {
int ret;
secp256k1_pubkey pubkey_tmp;
size_t size = 33;
ret = secp256k1_ec_pubkey_create(CTX, &pubkey_tmp, sk);
ret &= secp256k1_ec_pubkey_serialize(CTX, id, &size, &pubkey_tmp, SECP256K1_EC_COMPRESSED);
return ret;
}
/* Simple (non-adaptor, non-tweaked) 3-of-5 FROST aggregate, sign, verify
* test. */
void frost_simple_test(void) {
unsigned char sk[5][32];
secp256k1_frost_pubnonce pubnonce[5];
const secp256k1_frost_pubnonce *pubnonce_ptr[5];
unsigned char msg[32];
secp256k1_pubkey vss_commitment[5][3];
const secp256k1_pubkey *vss_ptr[5];
unsigned char pok[5][64];
secp256k1_xonly_pubkey agg_pk;
unsigned char buf[5][32];
secp256k1_frost_share shares[5][5];
const secp256k1_frost_share *share_ptr[5];
secp256k1_frost_share agg_share[5];
secp256k1_frost_secnonce secnonce[5];
secp256k1_pubkey pubshare[5];
secp256k1_frost_partial_sig partial_sig[5];
const secp256k1_frost_partial_sig *partial_sig_ptr[5];
unsigned char final_sig[64];
secp256k1_frost_session session;
int i, j;
unsigned char id[5][33];
const unsigned char *id_ptr[5];
for (i = 0; i < 5; i++) {
secp256k1_testrand256(buf[i]);
secp256k1_testrand256(sk[i]);
vss_ptr[i] = vss_commitment[i];
pubnonce_ptr[i] = &pubnonce[i];
partial_sig_ptr[i] = &partial_sig[i];
id_ptr[i] = id[i];
CHECK(frost_create_pk(id[i], sk[i]));
}
for (i = 0; i < 5; i++) {
CHECK(secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], buf[i], 3, 5, id_ptr) == 1);
}
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
share_ptr[j] = &shares[j][i];
CHECK(secp256k1_frost_share_verify(CTX, 3, id_ptr[i], share_ptr[j], &vss_ptr[j]) == 1);
CHECK(secp256k1_frost_compute_pubshare(CTX, &pubshare[j], 3, id_ptr[j], vss_ptr, 5) == 1);
}
CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, 5, 3, id_ptr[i]) == 1);
}
secp256k1_testrand256(msg);
for (i = 0; i < 3; i++) {
secp256k1_testrand256(buf[i]);
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[i], &pubnonce[i], buf[i], &agg_share[i], NULL, NULL, NULL) == 1);
}
for (i = 0; i < 3; i++) {
CHECK(secp256k1_frost_nonce_process(CTX, &session, pubnonce_ptr, 3, msg, &agg_pk, id_ptr[i], id_ptr, NULL, NULL) == 1);
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[i], &secnonce[i], &agg_share[i], &session, NULL) == 1);
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[i], &pubnonce[i], &pubshare[i], &session, NULL) == 1);
}
CHECK(secp256k1_frost_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, 3) == 1);
CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), &agg_pk) == 1);
}
void frost_pubnonce_summing_to_inf(secp256k1_frost_pubnonce *pubnonce) {
secp256k1_ge ge[2];
int i;
secp256k1_gej summed_nonces[2];
const secp256k1_frost_pubnonce *pubnonce_ptr[2];
ge[0] = secp256k1_ge_const_g;
ge[1] = secp256k1_ge_const_g;
for (i = 0; i < 2; i++) {
secp256k1_frost_pubnonce_save(&pubnonce[i], ge);
pubnonce_ptr[i] = &pubnonce[i];
secp256k1_ge_neg(&ge[0], &ge[0]);
secp256k1_ge_neg(&ge[1], &ge[1]);
}
secp256k1_frost_sum_nonces(CTX, summed_nonces, pubnonce_ptr, 2);
CHECK(secp256k1_gej_is_infinity(&summed_nonces[0]));
CHECK(secp256k1_gej_is_infinity(&summed_nonces[1]));
}
int frost_memcmp_and_randomize(unsigned char *value, const unsigned char *expected, size_t len) {
int ret;
size_t i;
ret = secp256k1_memcmp_var(value, expected, len);
for (i = 0; i < len; i++) {
value[i] = secp256k1_testrand_bits(8);
}
return ret;
}
void frost_api_tests(void) {
secp256k1_frost_partial_sig partial_sig[5];
const secp256k1_frost_partial_sig *partial_sig_ptr[5];
secp256k1_frost_partial_sig invalid_partial_sig;
const secp256k1_frost_partial_sig *invalid_partial_sig_ptr[5];
unsigned char final_sig[64];
unsigned char pre_sig[64];
unsigned char buf[32];
unsigned char sk[5][32];
unsigned char max64[64];
unsigned char zeros68[68] = { 0 };
unsigned char session_id[5][32];
unsigned char seed[5][32];
secp256k1_frost_secnonce secnonce[5];
secp256k1_frost_secnonce secnonce_tmp;
secp256k1_frost_secnonce invalid_secnonce;
secp256k1_frost_pubnonce pubnonce[5];
const secp256k1_frost_pubnonce *pubnonce_ptr[5];
unsigned char pubnonce_ser[66];
secp256k1_frost_pubnonce inf_pubnonce[5];
secp256k1_frost_pubnonce invalid_pubnonce;
const secp256k1_frost_pubnonce *invalid_pubnonce_ptr[5];
unsigned char msg[32];
secp256k1_xonly_pubkey agg_pk;
secp256k1_pubkey full_agg_pk;
secp256k1_frost_tweak_cache tweak_cache;
secp256k1_frost_tweak_cache invalid_tweak_cache;
secp256k1_frost_session session[5];
secp256k1_frost_session invalid_session;
secp256k1_xonly_pubkey invalid_pk;
unsigned char tweak[32];
int nonce_parity;
unsigned char sec_adaptor[32];
unsigned char sec_adaptor1[32];
secp256k1_pubkey adaptor;
secp256k1_pubkey vss_commitment[5][3];
secp256k1_pubkey invalid_vss_commitment[5][3];
const secp256k1_pubkey *vss_ptr[5];
const secp256k1_pubkey *invalid_vss_ptr[5];
secp256k1_pubkey invalid_vss_pk;
secp256k1_frost_share shares[5][5];
secp256k1_frost_share invalid_share;
secp256k1_frost_share agg_share[5];
unsigned char pok[5][64];
const secp256k1_frost_share *share_ptr[5];
const secp256k1_frost_share *invalid_share_ptr[5];
secp256k1_pubkey pubshare[5];
int i, j;
unsigned char id[5][33];
const unsigned char *id_ptr[5];
/** setup **/
memset(max64, 0xff, sizeof(max64));
memset(&invalid_share, 0xff, sizeof(invalid_share));
/* Simulate structs being uninitialized by setting it to 0s. We don't want
* to produce undefined behavior by actually providing uninitialized
* structs. */
memset(&invalid_pk, 0, sizeof(invalid_pk));
memset(&invalid_secnonce, 0, sizeof(invalid_secnonce));
memset(&invalid_partial_sig, 0, sizeof(invalid_partial_sig));
memset(&invalid_pubnonce, 0, sizeof(invalid_pubnonce));
memset(&invalid_vss_pk, 0, sizeof(invalid_vss_pk));
memset(&invalid_tweak_cache, 0, sizeof(invalid_tweak_cache));
memset(&invalid_session, 0, sizeof(invalid_session));
frost_pubnonce_summing_to_inf(inf_pubnonce);
secp256k1_testrand256(sec_adaptor);
secp256k1_testrand256(msg);
secp256k1_testrand256(tweak);
CHECK(secp256k1_ec_pubkey_create(CTX, &adaptor, sec_adaptor) == 1);
for (i = 0; i < 5; i++) {
pubnonce_ptr[i] = &pubnonce[i];
vss_ptr[i] = vss_commitment[i];
invalid_vss_ptr[i] = invalid_vss_commitment[i];
partial_sig_ptr[i] = &partial_sig[i];
invalid_partial_sig_ptr[i] = &partial_sig[i];
id_ptr[i] = id[i];
secp256k1_testrand256(session_id[i]);
secp256k1_testrand256(seed[i]);
secp256k1_testrand256(sk[i]);
CHECK(frost_create_pk(id[i], sk[i]));
}
invalid_pubnonce_ptr[0] = &invalid_pubnonce;
invalid_share_ptr[0] = &invalid_share;
invalid_partial_sig_ptr[0] = &invalid_partial_sig;
for (i = 0; i < 5; i++) {
for (j = 0; j < 3; j++) {
invalid_vss_commitment[i][j] = invalid_vss_pk;
}
}
/** main test body **/
/** Key generation **/
for (i = 0; i < 5; i++) {
CHECK(secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 3, 5, id_ptr) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_gen(CTX, NULL, vss_commitment[i], pok[i], seed[i], 3, 5, id_ptr));
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_gen(CTX, shares[i], NULL, pok[i], seed[i], 3, 5, id_ptr));
for (j = 0; j < 5; j++) {
CHECK(frost_memcmp_and_randomize(shares[i][j].data, zeros68, sizeof(shares[i][j].data)) == 0);
}
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], NULL, seed[i], 3, 5, id_ptr));
for (j = 0; j < 5; j++) {
CHECK(frost_memcmp_and_randomize(shares[i][j].data, zeros68, sizeof(shares[i][j].data)) == 0);
}
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], NULL, 3, 5, id_ptr));
for (j = 0; j < 5; j++) {
CHECK(frost_memcmp_and_randomize(shares[i][j].data, zeros68, sizeof(shares[i][j].data)) == 0);
}
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 0, 5, id_ptr));
for (j = 0; j < 5; j++) {
CHECK(frost_memcmp_and_randomize(shares[i][j].data, zeros68, sizeof(shares[i][j].data)) == 0);
}
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 3, 0, id_ptr));
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 3, 2, id_ptr));
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 3, 5, NULL));
for (j = 0; j < 5; j++) {
CHECK(frost_memcmp_and_randomize(shares[i][j].data, zeros68, sizeof(shares[i][j].data)) == 0);
}
CHECK(secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 3, 5, id_ptr) == 1);
}
/* Share aggregation */
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
share_ptr[j] = &shares[j][i];
}
CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, 5, 3, id_ptr[i]) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, NULL, &agg_pk, share_ptr, vss_ptr, 5, 3, id_ptr[i]));
CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], NULL, share_ptr, vss_ptr, 5, 3, id_ptr[i]));
CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, NULL, vss_ptr, 5, 3, id_ptr[i]));
CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0);
CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, NULL, 5, 3, id_ptr[i]));
CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0);
CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0);
/* TODO: fix test */
/* CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, invalid_vss_ptr, 5, 3, id_ptr[i])); */
/* CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); */
/* CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); */
CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, 5, 3, NULL));
CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0);
CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, invalid_share_ptr, vss_ptr, 5, 3, id_ptr[i]));
CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0);
CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, 0, 3, id_ptr[i]));
CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0);
CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, NULL, vss_ptr, 0, 3, id_ptr[i]));
CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0);
CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, 5, 0, id_ptr[i]));
CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0);
CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, NULL, 5, 0, id_ptr[i]));
CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0);
CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0);
CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, 5, 3, id_ptr[i]) == 1);
}
/* Share verification */
CHECK(secp256k1_frost_share_verify(CTX, 3, id_ptr[4], share_ptr[0], &vss_ptr[0]) == 1);
CHECK(secp256k1_frost_share_verify(CTX, 3, id_ptr[4], share_ptr[0], &vss_ptr[1]) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_share_verify(CTX, 3, NULL, share_ptr[0], &vss_ptr[0]));
CHECK_ILLEGAL(CTX, secp256k1_frost_share_verify(CTX, 3, id_ptr[4], NULL, &vss_ptr[1]));
CHECK_ILLEGAL(CTX, secp256k1_frost_share_verify(CTX, 3, id_ptr[4], &invalid_share, &vss_ptr[0]));
CHECK_ILLEGAL(CTX, secp256k1_frost_share_verify(CTX, 3, id_ptr[4], share_ptr[0], NULL));
CHECK_ILLEGAL(CTX, secp256k1_frost_share_verify(CTX, 3, id_ptr[4], share_ptr[0], &invalid_vss_ptr[0]));
CHECK_ILLEGAL(CTX, secp256k1_frost_share_verify(CTX, 0, id_ptr[4], share_ptr[0], &vss_ptr[0]));
CHECK(secp256k1_frost_share_verify(CTX, 3, id_ptr[4], share_ptr[0], &vss_ptr[0]) == 1);
CHECK(secp256k1_frost_share_verify(CTX, 3, id_ptr[4], share_ptr[1], &vss_ptr[1]) == 1);
/* Compute public verification share */
CHECK(secp256k1_frost_compute_pubshare(CTX, &pubshare[0], 3, id_ptr[0], vss_ptr, 5) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_compute_pubshare(CTX, NULL, 3, id_ptr[0], vss_ptr, 5));
CHECK_ILLEGAL(CTX, secp256k1_frost_compute_pubshare(CTX, &pubshare[0], 3, NULL, vss_ptr, 5));
CHECK(frost_memcmp_and_randomize(pubshare[0].data, zeros68, sizeof(pubshare[0].data)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_compute_pubshare(CTX, &pubshare[0], 3, id_ptr[0], NULL, 5));
CHECK(frost_memcmp_and_randomize(pubshare[0].data, zeros68, sizeof(pubshare[0].data)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_compute_pubshare(CTX, &pubshare[0], 3, id_ptr[0], invalid_vss_ptr, 5));
CHECK(frost_memcmp_and_randomize(pubshare[0].data, zeros68, sizeof(pubshare[0].data)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_compute_pubshare(CTX, &pubshare[0], 0, id_ptr[0], invalid_vss_ptr, 5));
CHECK(frost_memcmp_and_randomize(pubshare[0].data, zeros68, sizeof(pubshare[0].data)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_compute_pubshare(CTX, &pubshare[0], 0, id_ptr[0], NULL, 5));
CHECK(frost_memcmp_and_randomize(pubshare[0].data, zeros68, sizeof(pubshare[0].data)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_compute_pubshare(CTX, &pubshare[0], 3, id_ptr[0], invalid_vss_ptr, 0));
CHECK(frost_memcmp_and_randomize(pubshare[0].data, zeros68, sizeof(pubshare[0].data)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_compute_pubshare(CTX, &pubshare[0], 3, id_ptr[0], NULL, 0));
CHECK(frost_memcmp_and_randomize(pubshare[0].data, zeros68, sizeof(pubshare[0].data)) == 0);
CHECK(secp256k1_frost_compute_pubshare(CTX, &pubshare[0], 3, id_ptr[0], vss_ptr, 5) == 1);
CHECK(secp256k1_frost_compute_pubshare(CTX, &pubshare[1], 3, id_ptr[1], vss_ptr, 5) == 1);
CHECK(secp256k1_frost_compute_pubshare(CTX, &pubshare[2], 3, id_ptr[2], vss_ptr, 5) == 1);
/* pubkey_get */
CHECK(secp256k1_frost_pubkey_get(CTX, &full_agg_pk, &agg_pk) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_get(CTX, NULL, &agg_pk));
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_get(CTX, &full_agg_pk, NULL));
CHECK(secp256k1_memcmp_var(&full_agg_pk, zeros68, sizeof(full_agg_pk)) == 0);
/** Tweaking **/
/* pubkey_tweak */
CHECK(secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &agg_pk) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_tweak(CTX, NULL, &agg_pk));
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, NULL));
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &invalid_pk));
CHECK(secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &agg_pk) == 1);
/* tweak_add */
{
int (*tweak_func[2]) (const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_frost_tweak_cache *tweak_cache, const unsigned char *tweak32);
tweak_func[0] = secp256k1_frost_pubkey_ec_tweak_add;
tweak_func[1] = secp256k1_frost_pubkey_xonly_tweak_add;
CHECK(secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &agg_pk) == 1);
for (i = 0; i < 2; i++) {
secp256k1_pubkey tmp_output_pk;
secp256k1_frost_tweak_cache tmp_tweak_cache = tweak_cache;
CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_tweak_cache, tweak) == 1);
/* Reset tweak_cache */
tmp_tweak_cache = tweak_cache;
CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_tweak_cache, tweak) == 1);
tmp_tweak_cache = tweak_cache;
CHECK((*tweak_func[i])(CTX, NULL, &tmp_tweak_cache, tweak) == 1);
tmp_tweak_cache = tweak_cache;
CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, NULL, tweak));
CHECK(frost_memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0);
tmp_tweak_cache = tweak_cache;
CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, &tmp_tweak_cache, NULL));
CHECK(frost_memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0);
tmp_tweak_cache = tweak_cache;
CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_tweak_cache, max64) == 0);
CHECK(frost_memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0);
tmp_tweak_cache = tweak_cache;
/* Uninitialized tweak_cache */
CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, &invalid_tweak_cache, tweak));
CHECK(frost_memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0);
}
}
/** Session creation **/
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &agg_share[0], msg, &agg_pk, max64) == 1);
CHECK_ILLEGAL(STATIC_CTX, secp256k1_frost_nonce_gen(STATIC_CTX, &secnonce[0], &pubnonce[0], session_id[0], &agg_share[0], msg, &agg_pk, max64));
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_gen(CTX, NULL, &pubnonce[0], session_id[0], &agg_share[0], msg, &agg_pk, max64));
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_gen(CTX, &secnonce[0], NULL, session_id[0], &agg_share[0], msg, &agg_pk, max64));
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], NULL, &agg_share[0], msg, &agg_pk, max64));
CHECK(frost_memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0);
/* no seckey and session_id is 0 */
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], zeros68, NULL, msg, &agg_pk, max64) == 0);
CHECK(frost_memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0);
/* session_id 0 is fine when a seckey is provided */
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], zeros68, &agg_share[0], msg, &agg_pk, max64) == 1);
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], NULL, msg, &agg_pk, max64) == 1);
/* invalid agg_share */
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &invalid_share, msg, &agg_pk, max64));
CHECK(frost_memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0);
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &agg_share[0], NULL, &agg_pk, max64) == 1);
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &agg_share[0], msg, NULL, max64) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &agg_share[0], msg, &invalid_pk, max64));
CHECK(frost_memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0);
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &agg_share[0], msg, &agg_pk, NULL) == 1);
/* Every in-argument except session_id can be NULL */
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], NULL, NULL, NULL, NULL) == 1);
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_id[1], &agg_share[1], NULL, NULL, NULL) == 1);
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[2], &pubnonce[2], session_id[2], &agg_share[2], NULL, NULL, NULL) == 1);
/** Serialize and parse public nonces **/
CHECK_ILLEGAL(CTX, secp256k1_frost_pubnonce_serialize(CTX, NULL, &pubnonce[0]));
CHECK_ILLEGAL(CTX, secp256k1_frost_pubnonce_serialize(CTX, pubnonce_ser, NULL));
CHECK(frost_memcmp_and_randomize(pubnonce_ser, zeros68, sizeof(pubnonce_ser)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_pubnonce_serialize(CTX, pubnonce_ser, &invalid_pubnonce));
CHECK(frost_memcmp_and_randomize(pubnonce_ser, zeros68, sizeof(pubnonce_ser)) == 0);
CHECK(secp256k1_frost_pubnonce_serialize(CTX, pubnonce_ser, &pubnonce[0]) == 1);
CHECK(secp256k1_frost_pubnonce_parse(CTX, &pubnonce[0], pubnonce_ser) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_pubnonce_parse(CTX, NULL, pubnonce_ser));
CHECK_ILLEGAL(CTX, secp256k1_frost_pubnonce_parse(CTX, &pubnonce[0], NULL));
CHECK(secp256k1_frost_pubnonce_parse(CTX, &pubnonce[0], zeros68) == 0);
CHECK(secp256k1_frost_pubnonce_parse(CTX, &pubnonce[0], pubnonce_ser) == 1);
{
/* Check that serialize and parse results in the same value */
secp256k1_frost_pubnonce tmp;
CHECK(secp256k1_frost_pubnonce_serialize(CTX, pubnonce_ser, &pubnonce[0]) == 1);
CHECK(secp256k1_frost_pubnonce_parse(CTX, &tmp, pubnonce_ser) == 1);
CHECK(secp256k1_memcmp_var(&tmp, &pubnonce[0], sizeof(tmp)) == 0);
}
/** Process nonces **/
CHECK(secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, msg, &agg_pk, id_ptr[0], id_ptr, &tweak_cache, &adaptor) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_process(CTX, NULL, pubnonce_ptr, 3, msg, &agg_pk, id_ptr[0], id_ptr, &tweak_cache, &adaptor));
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_process(CTX, &session[0], NULL, 3, msg, &agg_pk, id_ptr[0], id_ptr, &tweak_cache, &adaptor));
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 0, msg, &agg_pk, id_ptr[0], id_ptr, &tweak_cache, &adaptor));
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_process(CTX, &session[0], invalid_pubnonce_ptr, 3, msg, &agg_pk, id_ptr[0], id_ptr, &tweak_cache, &adaptor));
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, NULL, &agg_pk, id_ptr[0], id_ptr, &tweak_cache, &adaptor));
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, msg, NULL, id_ptr[0], id_ptr, &tweak_cache, &adaptor));
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, msg, &agg_pk, NULL, id_ptr, &tweak_cache, &adaptor));
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, msg, &agg_pk, id_ptr[0], NULL, &tweak_cache, &adaptor));
CHECK(secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, msg, &agg_pk, id_ptr[0], id_ptr, NULL, &adaptor) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, msg, &agg_pk, id_ptr[0], id_ptr, &invalid_tweak_cache, &adaptor));
CHECK(secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, msg, &agg_pk, id_ptr[0], id_ptr, &tweak_cache, NULL) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, msg, &agg_pk, id_ptr[0], id_ptr, &tweak_cache, (secp256k1_pubkey *)&invalid_pk));
CHECK(secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, msg, &agg_pk, id_ptr[0], id_ptr, &tweak_cache, &adaptor) == 1);
CHECK(secp256k1_frost_nonce_process(CTX, &session[1], pubnonce_ptr, 3, msg, &agg_pk, id_ptr[1], id_ptr, &tweak_cache, &adaptor) == 1);
CHECK(secp256k1_frost_nonce_process(CTX, &session[2], pubnonce_ptr, 3, msg, &agg_pk, id_ptr[2], id_ptr, &tweak_cache, &adaptor) == 1);
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &agg_share[0], &session[0], &tweak_cache) == 1);
/* The secnonce is set to 0 and subsequent signing attempts fail */
CHECK(secp256k1_memcmp_var(&secnonce_tmp, zeros68, sizeof(secnonce_tmp)) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &agg_share[0], &session[0], &tweak_cache));
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, NULL, &secnonce_tmp, &agg_share[0], &session[0], &tweak_cache));
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, &partial_sig[0], NULL, &agg_share[0], &session[0], &tweak_cache));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, &partial_sig[0], &invalid_secnonce, &agg_share[0], &session[0], &tweak_cache));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, NULL, &session[0], &tweak_cache));
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &invalid_share, &session[0], &tweak_cache));
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &agg_share[0], NULL, &tweak_cache));
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &agg_share[0], &invalid_session, &tweak_cache));
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &agg_share[0], &session[0], NULL) == 1);
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &agg_share[0], &session[0], &invalid_tweak_cache));
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce[0], &agg_share[0], &session[0], &tweak_cache) == 1);
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[1], &secnonce[1], &agg_share[1], &session[1], &tweak_cache) == 1);
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[2], &secnonce[2], &agg_share[2], &session[2], &tweak_cache) == 1);
CHECK(secp256k1_frost_partial_sig_serialize(CTX, buf, &partial_sig[0]) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_serialize(CTX, NULL, &partial_sig[0]));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_serialize(CTX, buf, NULL));
CHECK(secp256k1_frost_partial_sig_parse(CTX, &partial_sig[0], buf) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_parse(CTX, NULL, buf));
CHECK(secp256k1_frost_partial_sig_parse(CTX, &partial_sig[0], max64) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_parse(CTX, &partial_sig[0], NULL));
{
/* Check that serialize and parse results in the same value */
secp256k1_frost_partial_sig tmp;
CHECK(secp256k1_frost_partial_sig_serialize(CTX, buf, &partial_sig[0]) == 1);
CHECK(secp256k1_frost_partial_sig_parse(CTX, &tmp, buf) == 1);
CHECK(secp256k1_memcmp_var(&tmp, &partial_sig[0], sizeof(tmp)) == 0);
}
/** Partial signature verification */
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pubshare[0], &session[0], &tweak_cache) == 1);
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[0], &pubshare[0], &session[0], &tweak_cache) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_verify(CTX, NULL, &pubnonce[0], &pubshare[0], &session[0], &tweak_cache));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_verify(CTX, &invalid_partial_sig, &pubnonce[0], &pubshare[0], &session[0], &tweak_cache));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], NULL, &pubshare[0], &session[0], &tweak_cache));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &invalid_pubnonce, &pubshare[0], &session[0], &tweak_cache));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], NULL, &session[0], &tweak_cache));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &invalid_vss_pk, &session[0], &tweak_cache));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pubshare[0], NULL, &tweak_cache));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pubshare[0], &invalid_session, &tweak_cache));
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pubshare[0], &session[0], NULL) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pubshare[0], &session[0], &invalid_tweak_cache));
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pubshare[0], &session[0], &tweak_cache) == 1);
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[1], &pubshare[1], &session[1], &tweak_cache) == 1);
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[2], &pubnonce[2], &pubshare[2], &session[2], &tweak_cache) == 1);
/** Signature aggregation and verification */
CHECK(secp256k1_frost_partial_sig_agg(CTX, pre_sig, &session[0], partial_sig_ptr, 3) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_agg(CTX, NULL, &session[0], partial_sig_ptr, 3));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_agg(CTX, pre_sig, NULL, partial_sig_ptr, 3));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_agg(CTX, pre_sig, &invalid_session, partial_sig_ptr, 3));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_agg(CTX, pre_sig, &session[0], NULL, 3));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_agg(CTX, pre_sig, &session[0], invalid_partial_sig_ptr, 3));
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sig_agg(CTX, pre_sig, &session[0], partial_sig_ptr, 0));
CHECK(secp256k1_frost_partial_sig_agg(CTX, pre_sig, &session[0], partial_sig_ptr, 1) == 1);
CHECK(secp256k1_frost_partial_sig_agg(CTX, pre_sig, &session[1], partial_sig_ptr, 2) == 1);
CHECK(secp256k1_frost_partial_sig_agg(CTX, pre_sig, &session[2], partial_sig_ptr, 3) == 1);
/** Adaptor signature verification */
CHECK(secp256k1_frost_nonce_parity(CTX, &nonce_parity, &session[0]) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_parity(CTX, NULL, &session[0]));
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_parity(CTX, &nonce_parity, NULL));
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_parity(CTX, &nonce_parity, &invalid_session));
CHECK(secp256k1_frost_adapt(CTX, final_sig, pre_sig, sec_adaptor, nonce_parity) == 1);
CHECK_ILLEGAL(CTX, secp256k1_frost_adapt(CTX, NULL, pre_sig, sec_adaptor, 0));
CHECK_ILLEGAL(CTX, secp256k1_frost_adapt(CTX, final_sig, NULL, sec_adaptor, 0));
CHECK(secp256k1_frost_adapt(CTX, final_sig, max64, sec_adaptor, 0) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_adapt(CTX, final_sig, pre_sig, NULL, 0));
CHECK(secp256k1_frost_adapt(CTX, final_sig, pre_sig, max64, 0) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_adapt(CTX, final_sig, pre_sig, sec_adaptor, 2));
/* sig and pre_sig argument point to the same location */
memcpy(final_sig, pre_sig, sizeof(final_sig));
CHECK(secp256k1_frost_adapt(CTX, final_sig, final_sig, sec_adaptor, nonce_parity) == 1);
CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), &agg_pk) == 1);
CHECK(secp256k1_frost_adapt(CTX, final_sig, pre_sig, sec_adaptor, nonce_parity) == 1);
CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), &agg_pk) == 1);
/** Secret adaptor can be extracted from signature */
CHECK(secp256k1_frost_extract_adaptor(CTX, sec_adaptor1, final_sig, pre_sig, nonce_parity) == 1);
CHECK(secp256k1_memcmp_var(sec_adaptor, sec_adaptor1, 32) == 0);
/* wrong nonce parity */
CHECK(secp256k1_frost_extract_adaptor(CTX, sec_adaptor1, final_sig, pre_sig, !nonce_parity) == 1);
CHECK(secp256k1_memcmp_var(sec_adaptor, sec_adaptor1, 32) != 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_extract_adaptor(CTX, NULL, final_sig, pre_sig, 0));
CHECK_ILLEGAL(CTX, secp256k1_frost_extract_adaptor(CTX, sec_adaptor1, NULL, pre_sig, 0));
CHECK(secp256k1_frost_extract_adaptor(CTX, sec_adaptor1, max64, pre_sig, 0) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_extract_adaptor(CTX, sec_adaptor1, final_sig, NULL, 0));
CHECK(secp256k1_frost_extract_adaptor(CTX, sec_adaptor1, final_sig, max64, 0) == 0);
CHECK_ILLEGAL(CTX, secp256k1_frost_extract_adaptor(CTX, sec_adaptor1, final_sig, pre_sig, 2));
}
void frost_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) {
secp256k1_scalar k1[2], k2[2];
secp256k1_nonce_function_frost(k1, args[0], args[1], args[2], args[3], args[4]);
secp256k1_testrand_flip(args[n_flip], n_bytes);
secp256k1_nonce_function_frost(k2, args[0], args[1], args[2], args[3], args[4]);
CHECK(secp256k1_scalar_eq(&k1[0], &k2[0]) == 0);
CHECK(secp256k1_scalar_eq(&k1[1], &k2[1]) == 0);
}
void frost_nonce_test(void) {
unsigned char *args[5];
unsigned char session_id[32];
unsigned char sk[32];
unsigned char msg[32];
unsigned char agg_pk[32];
unsigned char extra_input[32];
int i, j;
secp256k1_scalar k[5][2];
secp256k1_testrand_bytes_test(session_id, sizeof(session_id));
secp256k1_testrand_bytes_test(sk, sizeof(sk));
secp256k1_testrand_bytes_test(msg, sizeof(msg));
secp256k1_testrand_bytes_test(agg_pk, sizeof(agg_pk));
secp256k1_testrand_bytes_test(extra_input, sizeof(extra_input));
/* Check that a bitflip in an argument results in different nonces. */
args[0] = session_id;
args[1] = msg;
args[2] = sk;
args[3] = agg_pk;
args[4] = extra_input;
for (i = 0; i < COUNT; i++) {
frost_nonce_bitflip(args, 0, sizeof(session_id));
frost_nonce_bitflip(args, 1, sizeof(msg));
frost_nonce_bitflip(args, 2, sizeof(sk));
frost_nonce_bitflip(args, 3, sizeof(agg_pk));
frost_nonce_bitflip(args, 4, sizeof(extra_input));
}
/* Check that if any argument is NULL, a different nonce is produced than if
* any other argument is NULL. */
memcpy(msg, session_id, sizeof(msg));
memcpy(sk, session_id, sizeof(sk));
memcpy(agg_pk, session_id, sizeof(agg_pk));
memcpy(extra_input, session_id, sizeof(extra_input));
secp256k1_nonce_function_frost(k[0], args[0], args[1], args[2], args[3], args[4]);
secp256k1_nonce_function_frost(k[1], args[0], NULL, args[2], args[3], args[4]);
secp256k1_nonce_function_frost(k[2], args[0], args[1], NULL, args[3], args[4]);
secp256k1_nonce_function_frost(k[3], args[0], args[1], args[2], NULL, args[4]);
secp256k1_nonce_function_frost(k[4], args[0], args[1], args[2], args[3], NULL);
for (i = 0; i < 4; i++) {
for (j = i+1; j < 5; j++) {
CHECK(secp256k1_scalar_eq(&k[i][0], &k[j][0]) == 0);
CHECK(secp256k1_scalar_eq(&k[i][1], &k[j][1]) == 0);
}
}
}
void frost_sha256_tag_test_internal(secp256k1_sha256 *sha_tagged, unsigned char *tag, size_t taglen) {
secp256k1_sha256 sha;
unsigned char buf[32];
unsigned char buf2[32];
size_t i;
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, tag, taglen);
secp256k1_sha256_finalize(&sha, buf);
/* buf = SHA256(tag) */
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, buf, 32);
secp256k1_sha256_write(&sha, buf, 32);
/* Is buffer fully consumed? */
CHECK((sha.bytes & 0x3F) == 0);
/* Compare with tagged SHA */
for (i = 0; i < 8; i++) {
CHECK(sha_tagged->s[i] == sha.s[i]);
}
secp256k1_sha256_write(&sha, buf, 32);
secp256k1_sha256_write(sha_tagged, buf, 32);
secp256k1_sha256_finalize(&sha, buf);
secp256k1_sha256_finalize(sha_tagged, buf2);
CHECK(secp256k1_memcmp_var(buf, buf2, 32) == 0);
}
/* Attempts to create a signature for the aggregate public key using given secret
* keys and tweak_cache. */
void frost_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const secp256k1_frost_share *sr0, const secp256k1_frost_share *sr1, const secp256k1_frost_share *sr2, secp256k1_frost_tweak_cache *tweak_cache, const unsigned char * const* ids33, const secp256k1_pubkey *sr_pk0, const secp256k1_pubkey *sr_pk1, const secp256k1_pubkey *sr_pk2) {
unsigned char session_id[3][32];
unsigned char msg[32];
secp256k1_frost_secnonce secnonce[3];
secp256k1_frost_pubnonce pubnonce[3];
const secp256k1_frost_pubnonce *pubnonce_ptr[3];
secp256k1_frost_session session[5];
secp256k1_frost_partial_sig partial_sig[3];
const secp256k1_frost_partial_sig *partial_sig_ptr[3];
unsigned char final_sig[64];
int i;
for (i = 0; i < 3; i++) {
pubnonce_ptr[i] = &pubnonce[i];
partial_sig_ptr[i] = &partial_sig[i];
secp256k1_testrand256(session_id[i]);
}
secp256k1_testrand256(msg);
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sr0, NULL, NULL, NULL) == 1);
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_id[1], sr1, NULL, NULL, NULL) == 1);
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[2], &pubnonce[2], session_id[2], sr2, NULL, NULL, NULL) == 1);
CHECK(secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, msg, agg_pk, ids33[0], ids33, tweak_cache, NULL) == 1);
CHECK(secp256k1_frost_nonce_process(CTX, &session[1], pubnonce_ptr, 3, msg, agg_pk, ids33[1], ids33, tweak_cache, NULL) == 1);
CHECK(secp256k1_frost_nonce_process(CTX, &session[2], pubnonce_ptr, 3, msg, agg_pk, ids33[2], ids33, tweak_cache, NULL) == 1);
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce[0], sr0, &session[0], tweak_cache) == 1);
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[1], &secnonce[1], sr1, &session[1], tweak_cache) == 1);
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[2], &secnonce[2], sr2, &session[2], tweak_cache) == 1);
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], sr_pk0, &session[0], tweak_cache) == 1);
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[1], sr_pk1, &session[1], tweak_cache) == 1);
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[2], &pubnonce[2], sr_pk2, &session[2], tweak_cache) == 1);
CHECK(secp256k1_frost_partial_sig_agg(CTX, final_sig, &session[0], partial_sig_ptr, 3) == 1);
CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), agg_pk) == 1);
}
/* Create aggregate public key P[0], tweak multiple times (using xonly and
* ordinary tweaking) and test signing. */
void frost_tweak_test(void) {
unsigned char sk[5][32];
secp256k1_pubkey pubshare[5];
secp256k1_frost_tweak_cache tweak_cache;
enum { N_TWEAKS = 8 };
secp256k1_pubkey P[N_TWEAKS + 1];
secp256k1_xonly_pubkey P_xonly[N_TWEAKS + 1];
unsigned char seed[5][32];
secp256k1_pubkey vss_commitment[5][3];
const secp256k1_pubkey *vss_ptr[5];
unsigned char pok[5][64];
secp256k1_frost_share shares[5][5];
const secp256k1_frost_share *share_ptr[5];
secp256k1_frost_share agg_share[5];
int i, j;
unsigned char id[5][33];
const unsigned char *id_ptr[5];
/* Key Setup */
for (i = 0; i < 5; i++) {
secp256k1_testrand256(seed[i]);
secp256k1_testrand256(sk[i]);
vss_ptr[i] = vss_commitment[i];
id_ptr[i] = id[i];
CHECK(frost_create_pk(id[i], sk[i]));
}
for (i = 0; i < 5; i++) {
CHECK(secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 3, 5, id_ptr) == 1);
}
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
share_ptr[j] = &shares[j][i];
CHECK(secp256k1_frost_share_verify(CTX, 3, id_ptr[i], share_ptr[j], &vss_ptr[j]) == 1);
CHECK(secp256k1_frost_compute_pubshare(CTX, &pubshare[j], 3, id_ptr[j], vss_ptr, 5) == 1);
}
CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], &P_xonly[0], share_ptr, vss_ptr, 5, 3, id_ptr[i]) == 1);
}
frost_tweak_test_helper(&P_xonly[0], &agg_share[0], &agg_share[1], &agg_share[2], NULL, id_ptr, &pubshare[0], &pubshare[1], &pubshare[2]);
CHECK(secp256k1_frost_pubkey_get(CTX, &P[0], &P_xonly[0]));
CHECK(secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &P_xonly[0]) == 1);
/* Compute Pi = f(Pj) + tweaki*G where where j = i-1 and try signing for */
/* that key. If xonly is set to true, the function f is normalizes the input */
/* point to have an even X-coordinate ("xonly-tweaking"). */
/* Otherwise, the function f is the identity function. */
for (i = 1; i <= N_TWEAKS; i++) {
unsigned char tweak[32];
int P_parity;
int xonly = secp256k1_testrand_bits(1);
secp256k1_testrand256(tweak);
if (xonly) {
CHECK(secp256k1_frost_pubkey_xonly_tweak_add(CTX, &P[i], &tweak_cache, tweak) == 1);
} else {
CHECK(secp256k1_frost_pubkey_ec_tweak_add(CTX, &P[i], &tweak_cache, tweak) == 1);
}
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &P_xonly[i], &P_parity, &P[i]));
/* Check that frost_pubkey_tweak_add produces same result as */
/* xonly_pubkey_tweak_add or ec_pubkey_tweak_add. */
if (xonly) {
unsigned char P_serialized[32];
CHECK(secp256k1_xonly_pubkey_serialize(CTX, P_serialized, &P_xonly[i]));
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, P_serialized, P_parity, &P_xonly[i-1], tweak) == 1);
} else {
secp256k1_pubkey tmp_key = P[i-1];
CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &tmp_key, tweak));
CHECK(secp256k1_memcmp_var(&tmp_key, &P[i], sizeof(tmp_key)) == 0);
}
/* Test signing for P[i] */
frost_tweak_test_helper(&P_xonly[i], &agg_share[0], &agg_share[1], &agg_share[2], &tweak_cache, id_ptr, &pubshare[0], &pubshare[1], &pubshare[2]);
}
}
/* Performs a FROST DKG */
void frost_dkg_test_helper(secp256k1_frost_share *agg_share, secp256k1_xonly_pubkey *agg_pk, const unsigned char * const* ids33) {
secp256k1_pubkey vss_commitment[5][3];
const secp256k1_pubkey *vss_ptr[5];
unsigned char pok[5][64];
unsigned char seed[5][32];
secp256k1_frost_share shares[5][5];
const secp256k1_frost_share *share_ptr[5];
int i, j;
for (i = 0; i < 5; i++) {
secp256k1_testrand256(seed[i]);
vss_ptr[i] = vss_commitment[i];
}
for (i = 0; i < 5; i++) {
CHECK(secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 3, 5, ids33) == 1);
}
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
share_ptr[j] = &shares[j][i];
}
CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], agg_pk, share_ptr, vss_ptr, 5, 3, ids33[i]) == 1);
}
}
/* Signs a message with a FROST keypair */
int frost_sign_test_helper(unsigned char *final_sig, const secp256k1_frost_share *agg_share, const secp256k1_xonly_pubkey *agg_pk, const unsigned char * const* ids33, const unsigned char *msg, const secp256k1_pubkey *adaptor) {
unsigned char session_id[3][32];
secp256k1_frost_secnonce secnonce[3];
secp256k1_frost_pubnonce pubnonce[3];
const secp256k1_frost_pubnonce *pubnonce_ptr[3];
secp256k1_frost_partial_sig partial_sig[5];
const secp256k1_frost_partial_sig *partial_sig_ptr[5];
secp256k1_frost_session session;
int i;
int nonce_parity;
secp256k1_frost_session_internal session_i;
for (i = 0; i < 3; i++) {
pubnonce_ptr[i] = &pubnonce[i];
partial_sig_ptr[i] = &partial_sig[i];
}
for (i = 0; i < 3; i++) {
secp256k1_testrand256(session_id[i]);
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[i], &pubnonce[i], session_id[i], agg_share, NULL, NULL, NULL) == 1);
}
for (i = 0; i < 3; i++) {
CHECK(secp256k1_frost_nonce_process(CTX, &session, pubnonce_ptr, 3, msg, agg_pk, ids33[i], ids33, NULL, adaptor) == 1);
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[i], &secnonce[i], &agg_share[i], &session, NULL) == 1);
}
CHECK(secp256k1_frost_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, 3) == 1);
CHECK(secp256k1_frost_nonce_parity(CTX, &nonce_parity, &session));
secp256k1_frost_session_load(CTX, &session_i, &session);
return nonce_parity;
}
void frost_rand_scalar(secp256k1_scalar *scalar) {
unsigned char buf32[32];
secp256k1_testrand256(buf32);
secp256k1_scalar_set_b32(scalar, buf32, NULL);
}
void frost_multi_hop_lock_tests(void) {
secp256k1_frost_share agg_share_a[5];
secp256k1_frost_share agg_share_b[5];
secp256k1_xonly_pubkey agg_pk_a;
secp256k1_xonly_pubkey agg_pk_b;
unsigned char sk_a[5][32];
unsigned char sk_b[5][32];
unsigned char asig_ab[64];
unsigned char asig_bc[64];
unsigned char pop[32];
secp256k1_pubkey pubkey_pop;
unsigned char tx_ab[32];
unsigned char tx_bc[32];
unsigned char buf[32];
secp256k1_scalar t1, t2, tp;
secp256k1_pubkey l, r;
secp256k1_ge l_ge, r_ge;
secp256k1_scalar deckey;
unsigned char sig_ab[64];
unsigned char sig_bc[64];
int nonce_parity_ab;
int nonce_parity_bc;
int i;
unsigned char id_a[5][33];
const unsigned char *id_ptr_a[5];
unsigned char id_b[5][33];
const unsigned char *id_ptr_b[5];
/* Alice DKG */
for (i = 0; i < 5; i++) {
secp256k1_testrand256(sk_a[i]);
id_ptr_a[i] = id_a[i];
CHECK(frost_create_pk(id_a[i], sk_a[i]));
}
frost_dkg_test_helper(agg_share_a, &agg_pk_a, id_ptr_a);
/* Bob DKG */
for (i = 0; i < 5; i++) {
secp256k1_testrand256(sk_b[i]);
id_ptr_b[i] = id_b[i];
CHECK(frost_create_pk(id_b[i], sk_b[i]));
}
frost_dkg_test_helper(agg_share_b, &agg_pk_b, id_ptr_b);
/* Carol setup */
/* Proof of payment */
secp256k1_testrand256(pop);
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey_pop, pop));
/* Alice setup */
secp256k1_testrand256(tx_ab);
frost_rand_scalar(&t1);
frost_rand_scalar(&t2);
secp256k1_scalar_add(&tp, &t1, &t2);
/* Left lock */
secp256k1_pubkey_load(CTX, &l_ge, &pubkey_pop);
CHECK(secp256k1_eckey_pubkey_tweak_add(&l_ge, &t1));
secp256k1_pubkey_save(&l, &l_ge);
/* Right lock */
secp256k1_pubkey_load(CTX, &r_ge, &pubkey_pop);
CHECK(secp256k1_eckey_pubkey_tweak_add(&r_ge, &tp));
secp256k1_pubkey_save(&r, &r_ge);
/* Encrypt Alice's signature with the left lock as the encryption key */
nonce_parity_ab = frost_sign_test_helper(asig_ab, agg_share_a, &agg_pk_a, id_ptr_a, tx_ab, &l);
/* Bob setup */
CHECK(secp256k1_frost_verify_adaptor(CTX, asig_ab, tx_ab, &agg_pk_a, &l, nonce_parity_ab) == 1);
secp256k1_testrand256(tx_bc);
/* Encrypt Bob's signature with the right lock as the encryption key */
nonce_parity_bc = frost_sign_test_helper(asig_bc, agg_share_b, &agg_pk_b, id_ptr_b, tx_bc, &r);
/* Carol decrypt */
CHECK(secp256k1_frost_verify_adaptor(CTX, asig_bc, tx_bc, &agg_pk_b, &r, nonce_parity_bc) == 1);
secp256k1_scalar_set_b32(&deckey, pop, NULL);
secp256k1_scalar_add(&deckey, &deckey, &tp);
secp256k1_scalar_get_b32(buf, &deckey);
CHECK(secp256k1_frost_adapt(CTX, sig_bc, asig_bc, buf, nonce_parity_bc));
CHECK(secp256k1_schnorrsig_verify(CTX, sig_bc, tx_bc, sizeof(tx_bc), &agg_pk_b) == 1);
/* Bob recover and decrypt */
CHECK(secp256k1_frost_extract_adaptor(CTX, buf, sig_bc, asig_bc, nonce_parity_bc));
secp256k1_scalar_set_b32(&deckey, buf, NULL);
secp256k1_scalar_negate(&t2, &t2);
secp256k1_scalar_add(&deckey, &deckey, &t2);
secp256k1_scalar_get_b32(buf, &deckey);
CHECK(secp256k1_frost_adapt(CTX, sig_ab, asig_ab, buf, nonce_parity_ab));
CHECK(secp256k1_schnorrsig_verify(CTX, sig_ab, tx_ab, sizeof(tx_ab), &agg_pk_a) == 1);
/* Alice recover and derive proof of payment */
CHECK(secp256k1_frost_extract_adaptor(CTX, buf, sig_ab, asig_ab, nonce_parity_ab));
secp256k1_scalar_set_b32(&deckey, buf, NULL);
secp256k1_scalar_negate(&t1, &t1);
secp256k1_scalar_add(&deckey, &deckey, &t1);
secp256k1_scalar_get_b32(buf, &deckey);
CHECK(secp256k1_memcmp_var(buf, pop, 32) == 0);
}
void run_frost_tests(void) {
int i;
for (i = 0; i < COUNT; i++) {
frost_simple_test();
}
frost_api_tests();
frost_nonce_test();
for (i = 0; i < COUNT; i++) {
/* Run multiple times to ensure that pk and nonce have different y
* parities */
frost_tweak_test();
}
for (i = 0; i < COUNT; i++) {
frost_multi_hop_lock_tests();
}
}
#endif

View File

@ -7502,6 +7502,10 @@ static void run_ecdsa_wycheproof(void) {
# include "modules/ecdsa_adaptor/tests_impl.h" # include "modules/ecdsa_adaptor/tests_impl.h"
#endif #endif
#ifdef ENABLE_MODULE_FROST
# include "modules/frost/tests_impl.h"
#endif
static void run_secp256k1_memczero_test(void) { static void run_secp256k1_memczero_test(void) {
unsigned char buf1[6] = {1, 2, 3, 4, 5, 6}; unsigned char buf1[6] = {1, 2, 3, 4, 5, 6};
unsigned char buf2[sizeof(buf1)]; unsigned char buf2[sizeof(buf1)];
@ -7892,6 +7896,10 @@ int main(int argc, char **argv) {
run_ecdsa_adaptor_tests(); run_ecdsa_adaptor_tests();
#endif #endif
#ifdef ENABLE_MODULE_FROST
run_frost_tests();
#endif
/* util tests */ /* util tests */
run_secp256k1_memczero_test(); run_secp256k1_memczero_test();
run_secp256k1_byteorder_tests(); run_secp256k1_byteorder_tests();