Compare commits
12 Commits
temp-frost
...
frost
Author | SHA1 | Date | |
---|---|---|---|
|
69d5e6bdc1 | ||
|
df0bdeb096 | ||
|
3891388905 | ||
|
36ff5b02da | ||
|
c2d48a7039 | ||
|
ef15156ffb | ||
|
67c21beadd | ||
|
17c47e9708 | ||
|
f606507120 | ||
|
197fb7efb9 | ||
|
2336b02fad | ||
|
2f3fa4cace |
33
.github/workflows/ci.yml
vendored
33
.github/workflows/ci.yml
vendored
@ -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
1
.gitignore
vendored
@ -72,3 +72,4 @@ frost_example
|
|||||||
/CMakeUserPresets.json
|
/CMakeUserPresets.json
|
||||||
# Default CMake build directory.
|
# Default CMake build directory.
|
||||||
/build
|
/build
|
||||||
|
xconfigure.sh
|
||||||
|
@ -3,7 +3,7 @@ libsecp256k1-zkp
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
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.
|
||||||
|
3
ci/ci.sh
3
ci/ci.sh
@ -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" \
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
95
src/modules/frost/frost.md
Normal file
95
src/modules/frost/frost.md
Normal 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.
|
@ -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
|
||||||
|
943
src/modules/frost/tests_impl.h
Normal file
943
src/modules/frost/tests_impl.h
Normal 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
|
@ -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();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user