Compare commits
11 Commits
frost
...
frost-trus
Author | SHA1 | Date | |
---|---|---|---|
|
536b0458ad | ||
|
d3ef472559 | ||
|
e94367c83e | ||
|
1b9567289b | ||
|
fb34b29d7f | ||
|
9170dd337c | ||
|
ea059393f0 | ||
|
5368c81a3c | ||
|
9b852191de | ||
|
8969cee21c | ||
|
6f47d2eb22 |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -703,8 +703,8 @@ jobs:
|
|||||||
- { 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', 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', 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', 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', 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', FROST: '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', 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', 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', 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', 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', FROST: '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'
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -72,4 +72,3 @@ 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, MuSig2, and FROST.
|
A fork of [libsecp256k1](https://github.com/bitcoin-core/secp256k1) with support for advanced and experimental features such as Confidential Assets and MuSig2
|
||||||
|
|
||||||
Added features:
|
Added features:
|
||||||
* Experimental module for ECDSA adaptor signatures.
|
* Experimental module for ECDSA adaptor signatures.
|
||||||
@ -12,7 +12,7 @@ Added features:
|
|||||||
* Experimental module for Confidential Assets (Pedersen commitments, range proofs, and [surjection proofs](src/modules/surjection/surjection.md)).
|
* Experimental module for Confidential Assets (Pedersen commitments, range proofs, and [surjection proofs](src/modules/surjection/surjection.md)).
|
||||||
* Experimental module for Bulletproofs++ range proofs.
|
* Experimental module for Bulletproofs++ range proofs.
|
||||||
* Experimental module for [address whitelisting](src/modules/whitelist/whitelist.md).
|
* Experimental module for [address whitelisting](src/modules/whitelist/whitelist.md).
|
||||||
* Experimental module for [FROST](src/modules/frost/frost.md).
|
* Experimental module for FROST.
|
||||||
|
|
||||||
Experimental features are made available for testing and review by the community. The APIs of these features should not be considered stable.
|
Experimental features are made available for testing and review by the community. The APIs of these features should not be considered stable.
|
||||||
|
|
||||||
|
4
ci/ci.sh
4
ci/ci.sh
@ -14,8 +14,8 @@ print_environment() {
|
|||||||
for var in WERROR_CFLAGS MAKEFLAGS BUILD \
|
for var in WERROR_CFLAGS MAKEFLAGS BUILD \
|
||||||
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 FROST \
|
||||||
FROST SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
|
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
|
||||||
|
34
configure.ac
34
configure.ac
@ -236,15 +236,15 @@ AC_ARG_ENABLE(module_ecdsa-adaptor,
|
|||||||
[],
|
[],
|
||||||
[SECP_SET_DEFAULT([enable_module_ecdsa_adaptor], [no], [yes])])
|
[SECP_SET_DEFAULT([enable_module_ecdsa_adaptor], [no], [yes])])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(module_frost,
|
||||||
|
AS_HELP_STRING([--enable-module-frost],[enable FROST module [default=no]]),
|
||||||
|
[],
|
||||||
|
[SECP_SET_DEFAULT([enable_module_frost], [no], [yes])])
|
||||||
|
|
||||||
AC_ARG_ENABLE(external_default_callbacks,
|
AC_ARG_ENABLE(external_default_callbacks,
|
||||||
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
|
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
|
||||||
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
|
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_frost,
|
|
||||||
AS_HELP_STRING([--enable-module-frost],[enable FROST module (experimental)]),
|
|
||||||
[],
|
|
||||||
[SECP_SET_DEFAULT([enable_module_frost], [no], [yes])])
|
|
||||||
|
|
||||||
# Test-only override of the (autodetected by the C code) "widemul" setting.
|
# Test-only override of the (autodetected by the C code) "widemul" setting.
|
||||||
# Legal values are:
|
# Legal values are:
|
||||||
# * int64 (for [u]int64_t),
|
# * int64 (for [u]int64_t),
|
||||||
@ -475,6 +475,14 @@ if test x"$enable_module_ecdsa_adaptor" = x"yes"; then
|
|||||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDSA_ADAPTOR=1"
|
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDSA_ADAPTOR=1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test x"$enable_module_frost" = x"yes"; then
|
||||||
|
if test x"$enable_module_schnorrsig" = x"no"; then
|
||||||
|
AC_MSG_ERROR([Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.])
|
||||||
|
fi
|
||||||
|
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_FROST=1"
|
||||||
|
enable_module_schnorrsig=yes
|
||||||
|
fi
|
||||||
|
|
||||||
if test x"$enable_module_musig" = x"yes"; then
|
if test x"$enable_module_musig" = x"yes"; then
|
||||||
if test x"$enable_module_schnorrsig" = x"no"; then
|
if test x"$enable_module_schnorrsig" = x"no"; then
|
||||||
AC_MSG_ERROR([Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.])
|
AC_MSG_ERROR([Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.])
|
||||||
@ -535,14 +543,6 @@ if test x"$enable_module_ecdh" = x"yes"; then
|
|||||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1"
|
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test x"$enable_module_frost" = x"yes"; then
|
|
||||||
if test x"$enable_module_schnorrsig" = x"no"; then
|
|
||||||
AC_MSG_ERROR([Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the frost module.])
|
|
||||||
fi
|
|
||||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_FROST=1"
|
|
||||||
enable_module_schnorrsig=yes
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test x"$enable_external_default_callbacks" = x"yes"; then
|
if test x"$enable_external_default_callbacks" = x"yes"; then
|
||||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_DEFAULT_CALLBACKS=1"
|
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_DEFAULT_CALLBACKS=1"
|
||||||
fi
|
fi
|
||||||
@ -592,12 +592,12 @@ else
|
|||||||
if test x"$enable_module_generator" = x"yes"; then
|
if test x"$enable_module_generator" = x"yes"; then
|
||||||
AC_MSG_ERROR([NUMS generator module is experimental. Use --enable-experimental to allow.])
|
AC_MSG_ERROR([NUMS generator module is experimental. Use --enable-experimental to allow.])
|
||||||
fi
|
fi
|
||||||
if test x"$set_asm" = x"arm32"; then
|
|
||||||
AC_MSG_ERROR([ARM32 assembly is experimental. Use --enable-experimental to allow.])
|
|
||||||
fi
|
|
||||||
if test x"$enable_module_frost" = x"yes"; then
|
if test x"$enable_module_frost" = x"yes"; then
|
||||||
AC_MSG_ERROR([FROST module is experimental. Use --enable-experimental to allow.])
|
AC_MSG_ERROR([FROST module is experimental. Use --enable-experimental to allow.])
|
||||||
fi
|
fi
|
||||||
|
if test x"$set_asm" = x"arm32"; then
|
||||||
|
AC_MSG_ERROR([ARM32 assembly is experimental. Use --enable-experimental to allow.])
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
###
|
###
|
||||||
@ -666,9 +666,9 @@ echo " module whitelist = $enable_module_whitelist"
|
|||||||
echo " module musig = $enable_module_musig"
|
echo " module musig = $enable_module_musig"
|
||||||
echo " module ecdsa-s2c = $enable_module_ecdsa_s2c"
|
echo " module ecdsa-s2c = $enable_module_ecdsa_s2c"
|
||||||
echo " module ecdsa-adaptor = $enable_module_ecdsa_adaptor"
|
echo " module ecdsa-adaptor = $enable_module_ecdsa_adaptor"
|
||||||
|
echo " module frost = $enable_module_frost"
|
||||||
echo " module bppp = $enable_module_bppp"
|
echo " module bppp = $enable_module_bppp"
|
||||||
echo " module schnorrsig-halfagg = $enable_module_schnorrsig_halfagg"
|
echo " module schnorrsig-halfagg = $enable_module_schnorrsig_halfagg"
|
||||||
echo " module frost = $enable_module_frost"
|
|
||||||
echo
|
echo
|
||||||
echo " asm = $set_asm"
|
echo " asm = $set_asm"
|
||||||
echo " ecmult window size = $set_ecmult_window"
|
echo " ecmult window size = $set_ecmult_window"
|
||||||
|
118
examples/frost.c
118
examples/frost.c
@ -1,5 +1,5 @@
|
|||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Copyright (c) 2021-2024 Jesse Posner *
|
* Copyright (c) 2021-2023 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.*
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
@ -25,10 +25,8 @@
|
|||||||
#define THRESHOLD 3
|
#define THRESHOLD 3
|
||||||
|
|
||||||
struct signer_secrets {
|
struct signer_secrets {
|
||||||
secp256k1_keypair keypair;
|
secp256k1_frost_share share;
|
||||||
secp256k1_frost_share agg_share;
|
|
||||||
secp256k1_frost_secnonce secnonce;
|
secp256k1_frost_secnonce secnonce;
|
||||||
unsigned char seed[32];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct signer {
|
struct signer {
|
||||||
@ -36,86 +34,26 @@ struct signer {
|
|||||||
secp256k1_frost_pubnonce pubnonce;
|
secp256k1_frost_pubnonce pubnonce;
|
||||||
secp256k1_frost_session session;
|
secp256k1_frost_session session;
|
||||||
secp256k1_frost_partial_sig partial_sig;
|
secp256k1_frost_partial_sig partial_sig;
|
||||||
secp256k1_pubkey vss_commitment[THRESHOLD];
|
|
||||||
unsigned char vss_hash[32];
|
|
||||||
unsigned char pok[64];
|
|
||||||
unsigned char id[33];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Create a key pair and store it in seckey and pubkey */
|
|
||||||
int create_keypair_and_seed(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) {
|
|
||||||
unsigned char seckey[32];
|
|
||||||
secp256k1_pubkey pubkey_tmp;
|
|
||||||
size_t size = 33;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (!fill_random(seckey, sizeof(seckey))) {
|
|
||||||
printf("Failed to generate randomness\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!secp256k1_keypair_pub(ctx, &pubkey_tmp, &signer_secrets->keypair)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!secp256k1_ec_pubkey_serialize(ctx, signer->id, &size, &pubkey_tmp, SECP256K1_EC_COMPRESSED)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!fill_random(signer_secrets->seed, sizeof(signer_secrets->seed))) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 *pk) {
|
int create_shares(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signers, secp256k1_xonly_pubkey *pk) {
|
||||||
int i, j;
|
int i;
|
||||||
secp256k1_frost_share shares[N_SIGNERS][N_SIGNERS];
|
secp256k1_frost_share shares[N_SIGNERS];
|
||||||
const secp256k1_pubkey *vss_commitments[N_SIGNERS];
|
secp256k1_pubkey pubshares[N_SIGNERS];
|
||||||
const unsigned char *ids[N_SIGNERS];
|
unsigned char seed[32];
|
||||||
|
|
||||||
for (i = 0; i < N_SIGNERS; i++) {
|
if (!fill_random(seed, sizeof(seed))) {
|
||||||
vss_commitments[i] = signer[i].vss_commitment;
|
return 0;
|
||||||
ids[i] = signer[i].id;
|
}
|
||||||
|
|
||||||
|
if (!secp256k1_frost_shares_trusted_gen(ctx, shares, pubshares, pk, seed, THRESHOLD, N_SIGNERS)) {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < N_SIGNERS; i++) {
|
for (i = 0; i < N_SIGNERS; i++) {
|
||||||
/* Generate a polynomial share for the participants */
|
signer_secrets[i].share = shares[i];
|
||||||
if (!secp256k1_frost_shares_gen(ctx, shares[i], signer[i].vss_commitment, signer[i].pok, signer_secrets[i].seed, THRESHOLD, N_SIGNERS, ids)) {
|
signers[i].pubshare = pubshares[i];
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* KeyGen communication round 1: exchange shares and coefficient
|
|
||||||
* commitments */
|
|
||||||
for (i = 0; i < N_SIGNERS; i++) {
|
|
||||||
const secp256k1_frost_share *assigned_shares[N_SIGNERS];
|
|
||||||
|
|
||||||
/* Each participant receives a share from each participant (including
|
|
||||||
* themselves) corresponding to their index. */
|
|
||||||
for (j = 0; j < N_SIGNERS; j++) {
|
|
||||||
assigned_shares[j] = &shares[j][i];
|
|
||||||
}
|
|
||||||
/* Each participant aggregates the shares they received. */
|
|
||||||
if (!secp256k1_frost_share_agg(ctx, &signer_secrets[i].agg_share, pk, assigned_shares, vss_commitments, N_SIGNERS, THRESHOLD, signer[i].id)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for (j = 0; j < N_SIGNERS; j++) {
|
|
||||||
/* Each participant verifies their shares. share_agg calls this
|
|
||||||
* internally, so it is only neccessary to call this function if
|
|
||||||
* share_agg returns an error, to determine which participant(s)
|
|
||||||
* submitted faulty data. */
|
|
||||||
if (!secp256k1_frost_share_verify(ctx, THRESHOLD, signer[i].id, assigned_shares[j], &vss_commitments[j])) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* Each participant generates public verification shares that are
|
|
||||||
* used for verifying partial signatures. */
|
|
||||||
if (!secp256k1_frost_compute_pubshare(ctx, &signer[j].pubshare, THRESHOLD, signer[j].id, vss_commitments, N_SIGNERS)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -164,15 +102,16 @@ int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pk, secp256k1_fr
|
|||||||
* 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 *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;
|
size_t signer_id = 0;
|
||||||
int signers[THRESHOLD];
|
int signers[THRESHOLD];
|
||||||
int is_signer[N_SIGNERS];
|
int is_signer[N_SIGNERS];
|
||||||
const secp256k1_frost_pubnonce *pubnonces[THRESHOLD];
|
const secp256k1_frost_pubnonce *pubnonces[THRESHOLD];
|
||||||
const unsigned char *ids[THRESHOLD];
|
size_t ids[THRESHOLD];
|
||||||
const secp256k1_frost_partial_sig *partial_sigs[THRESHOLD];
|
const secp256k1_frost_partial_sig *partial_sigs[THRESHOLD];
|
||||||
|
|
||||||
for (i = 0; i < N_SIGNERS; i++) {
|
for (i = 0; i < N_SIGNERS; i++) {
|
||||||
unsigned char session_id[32];
|
unsigned char session_id[32];
|
||||||
|
|
||||||
/* Create random session ID. It is absolutely necessary that the session ID
|
/* Create random session ID. It is absolutely necessary that the session ID
|
||||||
* is unique for every call of secp256k1_frost_nonce_gen. Otherwise
|
* is unique for every call of secp256k1_frost_nonce_gen. Otherwise
|
||||||
* it's trivial for an attacker to extract the secret key! */
|
* it's trivial for an attacker to extract the secret key! */
|
||||||
@ -181,14 +120,14 @@ 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, pk, NULL)) {
|
if (!secp256k1_frost_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_id, &signer_secrets[i].share, msg32, pk, NULL)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
is_signer[i] = 0; /* Initialize is_signer */
|
is_signer[i] = 0; /* Initialize is_signer */
|
||||||
}
|
}
|
||||||
/* Select a random subset of signers */
|
/* Select a random subset of signers */
|
||||||
for (i = 0; i < THRESHOLD; i++) {
|
for (i = 0; i < THRESHOLD; i++) {
|
||||||
unsigned int subset_seed;
|
size_t subset_seed;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (!fill_random((unsigned char*)&subset_seed, sizeof(subset_seed))) {
|
if (!fill_random((unsigned char*)&subset_seed, sizeof(subset_seed))) {
|
||||||
@ -205,19 +144,19 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
|
|||||||
/* Mark signer as assigned */
|
/* Mark signer as assigned */
|
||||||
pubnonces[i] = &signer[signer_id].pubnonce;
|
pubnonces[i] = &signer[signer_id].pubnonce;
|
||||||
/* pubkeys[i] = &signer[signer_id].pubkey; */
|
/* pubkeys[i] = &signer[signer_id].pubkey; */
|
||||||
ids[i] = signer[signer_id].id;
|
ids[i] = signer_id + 1;
|
||||||
}
|
}
|
||||||
/* 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, pk, signer[signer_id].id, ids, cache, NULL)) {
|
if (!secp256k1_frost_nonce_process(ctx, &signer[signer_id].session, pubnonces, THRESHOLD, msg32, pk, signer_id + 1, 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
|
||||||
* you must _never_ reuse the secnonce (or use the same session_id to
|
* you must _never_ reuse the secnonce (or use the same session_id to
|
||||||
* create a secnonce). If you do, you effectively reuse the nonce and
|
* create a secnonce). If you do, you effectively reuse the nonce and
|
||||||
* leak the secret key. */
|
* leak the secret key. */
|
||||||
if (!secp256k1_frost_partial_sign(ctx, &signer[signer_id].partial_sig, &signer_secrets[signer_id].secnonce, &signer_secrets[signer_id].agg_share, &signer[signer_id].session, cache)) {
|
if (!secp256k1_frost_partial_sign(ctx, &signer[signer_id].partial_sig, &signer_secrets[signer_id].secnonce, &signer_secrets[signer_id].share, &signer[signer_id].session, cache)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
partial_sigs[i] = &signer[signer_id].partial_sig;
|
partial_sigs[i] = &signer[signer_id].partial_sig;
|
||||||
@ -246,7 +185,6 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
|
|||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
secp256k1_context* ctx;
|
secp256k1_context* ctx;
|
||||||
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 pk;
|
secp256k1_xonly_pubkey pk;
|
||||||
@ -256,14 +194,6 @@ int main(void) {
|
|||||||
|
|
||||||
/* Create a context for signing and verification */
|
/* Create a context for signing and verification */
|
||||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||||
printf("Creating key pairs......");
|
|
||||||
for (i = 0; i < N_SIGNERS; i++) {
|
|
||||||
if (!create_keypair_and_seed(ctx, &signer_secrets[i], &signers[i])) {
|
|
||||||
printf("FAILED\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("ok\n");
|
|
||||||
printf("Creating shares.........");
|
printf("Creating shares.........");
|
||||||
if (!create_shares(ctx, signer_secrets, signers, &pk)) {
|
if (!create_shares(ctx, signer_secrets, signers, &pk)) {
|
||||||
printf("FAILED\n");
|
printf("FAILED\n");
|
||||||
@ -271,7 +201,7 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
printf("ok\n");
|
printf("ok\n");
|
||||||
printf("Tweaking................");
|
printf("Tweaking................");
|
||||||
/* Optionally tweak the aggregate key */
|
/* Optionally tweak the key */
|
||||||
if (!tweak(ctx, &pk, &cache)) {
|
if (!tweak(ctx, &pk, &cache)) {
|
||||||
printf("FAILED\n");
|
printf("FAILED\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -9,9 +9,9 @@ extern "C" {
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/** This code is currently a work in progress. It's not secure nor stable.
|
/** This code is currently a work in progress. It's not secure nor stable. IT
|
||||||
* IT IS EXTREMELY DANGEROUS AND RECKLESS TO USE THIS MODULE IN PRODUCTION!
|
* IS EXTREMELY DANGEROUS AND RECKLESS TO USE THIS MODULE IN PRODUCTION!
|
||||||
*
|
|
||||||
* 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
|
||||||
@ -21,9 +21,6 @@ extern "C" {
|
|||||||
* 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.
|
||||||
*/
|
*/
|
||||||
@ -186,14 +183,12 @@ SECP256K1_API int secp256k1_frost_share_parse(
|
|||||||
|
|
||||||
/** Creates key shares
|
/** Creates key shares
|
||||||
*
|
*
|
||||||
* To generate a key, each participant generates a share for each other
|
* To generate a key, a trusted dealer generates a share for each other
|
||||||
* participant. For example, in the case of 2 particpants, Alice and Bob, they
|
|
||||||
* each generate 2 shares, distribute 1 share to each other using a secure
|
|
||||||
* channel, and keep 1 for themselves.
|
|
||||||
*
|
|
||||||
* Each participant must transmit shares over secure channels to each other
|
|
||||||
* participant.
|
* participant.
|
||||||
*
|
*
|
||||||
|
* The trusted dealer must transmit shares over secure channels to
|
||||||
|
* participants.
|
||||||
|
*
|
||||||
* Each call to this function must have a UNIQUE and uniformly RANDOM seed32
|
* Each call to this function must have a UNIQUE and uniformly RANDOM seed32
|
||||||
* that must that must NOT BE REUSED in subsequent calls to this function and
|
* that must that must NOT BE REUSED in subsequent calls to this function and
|
||||||
* must be KEPT SECRET (even from other participants).
|
* must be KEPT SECRET (even from other participants).
|
||||||
@ -201,109 +196,25 @@ SECP256K1_API int secp256k1_frost_share_parse(
|
|||||||
* 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
|
||||||
* Out: shares: pointer to the key shares
|
* Out: shares: pointer to the key shares
|
||||||
* vss_commitment: pointer to the VSS commitment
|
* pubshares: pointer to the public verification shares
|
||||||
* pok64: pointer to the proof of knowledge
|
* pk: pointer to the x-only public key
|
||||||
* In: seed32: 32-byte random seed as explained above. Must be
|
* In: seed32: a 32-byte random seed as explained above. Must be
|
||||||
* unique to this call to secp256k1_frost_shares_gen
|
* unique to this call to
|
||||||
* and must be uniformly random.
|
* secp256k1_frost_shares_trusted_gen and must be
|
||||||
|
* uniformly random.
|
||||||
* threshold: the minimum number of signers required to produce a
|
* threshold: the minimum number of signers required to produce a
|
||||||
* signature
|
* signature
|
||||||
* n_participants: the total number of participants
|
* n_participants: the total number of participants
|
||||||
* ids33: array of 33-byte participant IDs
|
|
||||||
*/
|
*/
|
||||||
SECP256K1_API int secp256k1_frost_shares_gen(
|
SECP256K1_API int secp256k1_frost_shares_trusted_gen(
|
||||||
const secp256k1_context *ctx,
|
const secp256k1_context *ctx,
|
||||||
secp256k1_frost_share *shares,
|
secp256k1_frost_share *shares,
|
||||||
secp256k1_pubkey *vss_commitment,
|
secp256k1_pubkey *pubshares,
|
||||||
unsigned char *pok64,
|
secp256k1_xonly_pubkey *pk,
|
||||||
const unsigned char *seed32,
|
const unsigned char *seed32,
|
||||||
size_t threshold,
|
size_t threshold,
|
||||||
size_t n_participants,
|
|
||||||
const unsigned char * const* ids33
|
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(8);
|
|
||||||
|
|
||||||
/** Aggregates shares
|
|
||||||
*
|
|
||||||
* As part of the key generation protocol, each participant receives a share
|
|
||||||
* from each participant, including a share they "receive" from themselves.
|
|
||||||
* This function verifies those shares against their VSS commitments,
|
|
||||||
* aggregates the shares, and then aggregates the commitments to each
|
|
||||||
* participant's first polynomial coefficient to derive the aggregate public
|
|
||||||
* key.
|
|
||||||
*
|
|
||||||
* If this function returns an error, `secp256k1_frost_share_verify` can be
|
|
||||||
* called on each share to determine which participants submitted faulty
|
|
||||||
* shares.
|
|
||||||
*
|
|
||||||
* Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean
|
|
||||||
* the resulting signature verifies).
|
|
||||||
* Args: ctx: pointer to a context object
|
|
||||||
* Out: agg_share: the aggregated share
|
|
||||||
* agg_pk: the aggregated x-only public key
|
|
||||||
* In: shares: all key generation shares for the partcipant's index
|
|
||||||
* vss_commitments: coefficient commitments of all participants ordered by
|
|
||||||
* the x-only pubkeys of the participants
|
|
||||||
* n_shares: the total number of shares
|
|
||||||
* threshold: the minimum number of shares required to produce a
|
|
||||||
* signature
|
|
||||||
* id33: the 33-byte ID of the participant whose shares are being
|
|
||||||
* aggregated
|
|
||||||
*/
|
|
||||||
SECP256K1_API int secp256k1_frost_share_agg(
|
|
||||||
const secp256k1_context *ctx,
|
|
||||||
secp256k1_frost_share *agg_share,
|
|
||||||
secp256k1_xonly_pubkey *agg_pk,
|
|
||||||
const secp256k1_frost_share * const *shares,
|
|
||||||
const secp256k1_pubkey * const *vss_commitments,
|
|
||||||
size_t n_shares,
|
|
||||||
size_t threshold,
|
|
||||||
const unsigned char *id33
|
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(8);
|
|
||||||
|
|
||||||
/** Verifies a share received during a key generation session
|
|
||||||
*
|
|
||||||
* The signature is verified against the VSS commitment received with the
|
|
||||||
* share. This is only useful for purposes of determining which share(s) are
|
|
||||||
* invalid if share_agg returns an error.
|
|
||||||
*
|
|
||||||
* Returns: 0 if the arguments are invalid or the share does not verify, 1
|
|
||||||
* otherwise
|
|
||||||
* Args ctx: pointer to a context object
|
|
||||||
* In: threshold: the minimum number of signers required to produce a
|
|
||||||
* signature
|
|
||||||
* id33: the 33-byte participant ID of the share recipient
|
|
||||||
* share: pointer to a key generation share
|
|
||||||
* vss_commitment: the VSS commitment associated with the share
|
|
||||||
*/
|
|
||||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_share_verify(
|
|
||||||
const secp256k1_context *ctx,
|
|
||||||
size_t threshold,
|
|
||||||
const unsigned char *id33,
|
|
||||||
const secp256k1_frost_share *share,
|
|
||||||
const secp256k1_pubkey * const *vss_commitment
|
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
|
||||||
|
|
||||||
/** Computes a public verification share used for verifying partial signatures
|
|
||||||
*
|
|
||||||
* Returns: 0 if the arguments are invalid, 1 otherwise
|
|
||||||
* Args: ctx: pointer to a context object
|
|
||||||
* Out: pubshare: pointer to a struct to store the public verification
|
|
||||||
* share
|
|
||||||
* In: threshold: the minimum number of signers required to produce a
|
|
||||||
* signature
|
|
||||||
* id33: the 33-byte participant ID of the participant whose
|
|
||||||
* partial signature will be verified with the pubshare
|
|
||||||
* vss_commitments: coefficient commitments of all participants
|
|
||||||
* n_participants: the total number of participants
|
|
||||||
*/
|
|
||||||
SECP256K1_API int secp256k1_frost_compute_pubshare(
|
|
||||||
const secp256k1_context *ctx,
|
|
||||||
secp256k1_pubkey *pubshare,
|
|
||||||
size_t threshold,
|
|
||||||
const unsigned char *id33,
|
|
||||||
const secp256k1_pubkey * const *vss_commitments,
|
|
||||||
size_t n_participants
|
size_t n_participants
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||||
|
|
||||||
/** Obtain the aggregate public key from a FROST x-only aggregate public key.
|
/** Obtain the aggregate public key from a FROST x-only aggregate public key.
|
||||||
*
|
*
|
||||||
@ -315,7 +226,7 @@ SECP256K1_API int secp256k1_frost_compute_pubshare(
|
|||||||
* Args: ctx: pointer to a context object
|
* Args: ctx: pointer to a context object
|
||||||
* Out: ec_agg_pk: the FROST-aggregated public key.
|
* Out: ec_agg_pk: the FROST-aggregated public key.
|
||||||
* In: xonly_agg_pk: the aggregated x-only public key that is the output of
|
* In: xonly_agg_pk: the aggregated x-only public key that is the output of
|
||||||
* `secp256k1_frost_share_agg`
|
* `secp256k1_frost_shares_gen`
|
||||||
*/
|
*/
|
||||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_get(
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_get(
|
||||||
const secp256k1_context *ctx,
|
const secp256k1_context *ctx,
|
||||||
@ -330,7 +241,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_get(
|
|||||||
* Out: tweak_cache: pointer to a frost_tweak_cache struct that is required
|
* Out: tweak_cache: pointer to a frost_tweak_cache struct that is required
|
||||||
* for key tweaking
|
* for key tweaking
|
||||||
* In: agg_pk: the aggregated x-only public key that is the output of
|
* In: agg_pk: the aggregated x-only public key that is the output of
|
||||||
* `secp256k1_frost_share_agg`
|
* `secp256k1_frost_shares_gen`
|
||||||
*/
|
*/
|
||||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_tweak(
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_tweak(
|
||||||
const secp256k1_context *ctx,
|
const secp256k1_context *ctx,
|
||||||
@ -346,7 +257,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_tweak(
|
|||||||
* the following pseudocode buf and buf2 have identical contents (absent
|
* the following pseudocode buf and buf2 have identical contents (absent
|
||||||
* earlier failures).
|
* earlier failures).
|
||||||
*
|
*
|
||||||
* secp256k1_frost_share_agg(..., xonly_agg_pk, ...)
|
* secp256k1_frost_shares_gen(..., xonly_agg_pk, ...)
|
||||||
* secp256k1_frost_pubkey_tweak(..., tweak_cache, xonly_agg_pk)
|
* secp256k1_frost_pubkey_tweak(..., tweak_cache, xonly_agg_pk)
|
||||||
* secp256k1_frost_pubkey_ec_tweak_add(..., output_pk, tweak_cache, tweak32)
|
* secp256k1_frost_pubkey_ec_tweak_add(..., output_pk, tweak_cache, tweak32)
|
||||||
* secp256k1_ec_pubkey_serialize(..., buf, output_pk)
|
* secp256k1_ec_pubkey_serialize(..., buf, output_pk)
|
||||||
@ -389,7 +300,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_ec_tweak_a
|
|||||||
* the following pseudocode xonly_pubkey_tweak_add_check (absent earlier
|
* the following pseudocode xonly_pubkey_tweak_add_check (absent earlier
|
||||||
* failures) returns 1.
|
* failures) returns 1.
|
||||||
*
|
*
|
||||||
* secp256k1_frost_share_agg(..., agg_pk, ...)
|
* secp256k1_frost_shares_gen(..., agg_pk, ...)
|
||||||
* secp256k1_frost_pubkey_tweak(..., tweak_cache, agg_pk)
|
* secp256k1_frost_pubkey_tweak(..., tweak_cache, agg_pk)
|
||||||
* secp256k1_frost_pubkey_xonly_tweak_add(..., output_pk, tweak_cache, tweak32)
|
* secp256k1_frost_pubkey_xonly_tweak_add(..., output_pk, tweak_cache, tweak32)
|
||||||
* secp256k1_xonly_pubkey_serialize(..., buf, output_pk)
|
* secp256k1_xonly_pubkey_serialize(..., buf, output_pk)
|
||||||
@ -476,10 +387,10 @@ SECP256K1_API int secp256k1_frost_nonce_gen(
|
|||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
/** Takes the public nonces of all signers and computes a session that is
|
/** Takes the public nonces of all signers and computes a session that is
|
||||||
* required for signing and verification of partial signatures. The participant
|
* required for signing and verification of partial signatures. The participant
|
||||||
* IDs can be sorted before combining, but the corresponding pubnonces must be
|
* IDs can be sorted before combining, but the corresponding pubnonces must be
|
||||||
* resorted as well. All signers must use the same sorting of pubnonces,
|
* resorted as well. All signers must use the same sorting of pubnonces,
|
||||||
* otherwise signing will fail.
|
* otherwise signing will fail.
|
||||||
*
|
*
|
||||||
* Returns: 0 if the arguments are invalid or if some signer sent invalid
|
* Returns: 0 if the arguments are invalid or if some signer sent invalid
|
||||||
* pubnonces, 1 otherwise
|
* pubnonces, 1 otherwise
|
||||||
@ -490,9 +401,9 @@ SECP256K1_API int secp256k1_frost_nonce_gen(
|
|||||||
* greater than 0.
|
* greater than 0.
|
||||||
* msg32: the 32-byte message to sign
|
* msg32: the 32-byte message to sign
|
||||||
* agg_pk: the FROST-aggregated public key
|
* agg_pk: the FROST-aggregated public key
|
||||||
* myd_id33: the 33-byte ID of the participant who will use the
|
* my_id: the ID of the participant who will use the session for
|
||||||
* session for signing
|
* signing
|
||||||
* ids33: array of the 33-byte participant IDs of the signers
|
* ids: array of the IDs of the signers
|
||||||
* tweak_cache: pointer to frost_tweak_cache struct (can be NULL)
|
* tweak_cache: pointer to frost_tweak_cache struct (can be NULL)
|
||||||
* adaptor: optional pointer to an adaptor point encoded as a
|
* adaptor: optional pointer to an adaptor point encoded as a
|
||||||
* public key if this signing session is part of an
|
* public key if this signing session is part of an
|
||||||
@ -505,11 +416,11 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_nonce_process(
|
|||||||
size_t n_pubnonces,
|
size_t n_pubnonces,
|
||||||
const unsigned char *msg32,
|
const unsigned char *msg32,
|
||||||
const secp256k1_xonly_pubkey *agg_pk,
|
const secp256k1_xonly_pubkey *agg_pk,
|
||||||
const unsigned char *my_id33,
|
size_t my_id,
|
||||||
const unsigned char * const* ids33,
|
const size_t *ids,
|
||||||
const secp256k1_frost_tweak_cache *tweak_cache,
|
const secp256k1_frost_tweak_cache *tweak_cache,
|
||||||
const secp256k1_pubkey *adaptor
|
const secp256k1_pubkey *adaptor
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(8);
|
||||||
|
|
||||||
/** Produces a partial signature
|
/** Produces a partial signature
|
||||||
*
|
*
|
||||||
@ -547,7 +458,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_compute_pubshare` for the signer's ID.
|
* `secp256k1_frost_shares_trusted_gen` for the signer's 'pk'.
|
||||||
* 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`.
|
||||||
*
|
*
|
||||||
@ -561,7 +472,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_compute_pubshare`
|
* `secp256k1_frost_shares_trusted_gen`
|
||||||
* 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)
|
||||||
|
@ -356,10 +356,8 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
|||||||
|
|
||||||
#ifdef ENABLE_MODULE_FROST
|
#ifdef ENABLE_MODULE_FROST
|
||||||
{
|
{
|
||||||
secp256k1_pubkey pk[2];
|
secp256k1_xonly_pubkey pk;
|
||||||
secp256k1_xonly_pubkey agg_pk;
|
|
||||||
unsigned char session_id[32];
|
unsigned char session_id[32];
|
||||||
unsigned char seed[2][32];
|
|
||||||
secp256k1_frost_secnonce secnonce[2];
|
secp256k1_frost_secnonce secnonce[2];
|
||||||
secp256k1_frost_pubnonce pubnonce[2];
|
secp256k1_frost_pubnonce pubnonce[2];
|
||||||
const secp256k1_frost_pubnonce *pubnonce_ptr[2];
|
const secp256k1_frost_pubnonce *pubnonce_ptr[2];
|
||||||
@ -372,86 +370,48 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
|||||||
secp256k1_pubkey adaptor;
|
secp256k1_pubkey adaptor;
|
||||||
unsigned char pre_sig[64];
|
unsigned char pre_sig[64];
|
||||||
int nonce_parity;
|
int nonce_parity;
|
||||||
secp256k1_frost_share shares[2][2];
|
secp256k1_frost_share shares[2];
|
||||||
const secp256k1_frost_share *share_ptr[2];
|
secp256k1_pubkey pubshares[2];
|
||||||
secp256k1_frost_share agg_share;
|
size_t ids[2];
|
||||||
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[0] = &pubnonce[0];
|
||||||
pubnonce_ptr[1] = &pubnonce[1];
|
pubnonce_ptr[1] = &pubnonce[1];
|
||||||
SECP256K1_CHECKMEM_DEFINE(key, 32);
|
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));
|
memcpy(extra_input, key, sizeof(extra_input));
|
||||||
extra_input[0] = extra_input[0] + 3;
|
extra_input[0] = extra_input[0] + 1;
|
||||||
memcpy(sec_adaptor, key, sizeof(sec_adaptor));
|
memcpy(sec_adaptor, key, sizeof(sec_adaptor));
|
||||||
sec_adaptor[0] = extra_input[0] + 4;
|
sec_adaptor[0] = extra_input[0] + 2;
|
||||||
memcpy(key2, key, sizeof(key2));
|
|
||||||
key2[0] = key2[0] + 5;
|
|
||||||
memcpy(session_id, key, sizeof(session_id));
|
memcpy(session_id, key, sizeof(session_id));
|
||||||
session_id[0] = session_id[0] + 6;
|
session_id[0] = session_id[0] + 3;
|
||||||
partial_sig_ptr[0] = &partial_sig;
|
partial_sig_ptr[0] = &partial_sig;
|
||||||
share_ptr[0] = &shares[0][0];
|
ids[0] = 1;
|
||||||
share_ptr[1] = &shares[1][0];
|
ids[1] = 2;
|
||||||
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 */
|
/* shares_gen */
|
||||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||||
SECP256K1_CHECKMEM_UNDEFINE(key2, 32);
|
ret = secp256k1_frost_shares_trusted_gen(ctx, shares, pubshares, &pk, key, 2, 2);
|
||||||
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));
|
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||||
CHECK(ret == 1);
|
CHECK(ret == 1);
|
||||||
|
SECP256K1_CHECKMEM_UNDEFINE(&shares[0], sizeof(shares[0]));
|
||||||
|
SECP256K1_CHECKMEM_UNDEFINE(&shares[1], sizeof(shares[1]));
|
||||||
/* nonce_gen */
|
/* nonce_gen */
|
||||||
SECP256K1_CHECKMEM_UNDEFINE(session_id, sizeof(session_id));
|
SECP256K1_CHECKMEM_UNDEFINE(session_id, sizeof(session_id));
|
||||||
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor));
|
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor));
|
||||||
SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input));
|
SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input));
|
||||||
SECP256K1_CHECKMEM_UNDEFINE(sec_adaptor, sizeof(sec_adaptor));
|
SECP256K1_CHECKMEM_UNDEFINE(sec_adaptor, sizeof(sec_adaptor));
|
||||||
CHECK(secp256k1_frost_pubkey_tweak(ctx, &cache, &agg_pk) == 1);
|
CHECK(secp256k1_frost_pubkey_tweak(ctx, &cache, &pk) == 1);
|
||||||
ret = secp256k1_frost_nonce_gen(ctx, &secnonce[0], &pubnonce[0], session_id, &agg_share, msg, &agg_pk, extra_input);
|
ret = secp256k1_frost_nonce_gen(ctx, &secnonce[0], &pubnonce[0], session_id, &shares[0], msg, &pk, extra_input);
|
||||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||||
CHECK(ret == 1);
|
CHECK(ret == 1);
|
||||||
ret = secp256k1_frost_nonce_gen(ctx, &secnonce[1], &pubnonce[1], session_id, &agg_share, msg, &agg_pk, extra_input);
|
ret = secp256k1_frost_nonce_gen(ctx, &secnonce[1], &pubnonce[1], session_id, &shares[1], msg, &pk, extra_input);
|
||||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||||
CHECK(ret == 1);
|
CHECK(ret == 1);
|
||||||
/* partial_sign */
|
/* partial_sign */
|
||||||
CHECK(secp256k1_frost_nonce_process(ctx, &session, pubnonce_ptr, 2, msg, &agg_pk, id_ptr[0], id_ptr, &cache, &adaptor) == 1);
|
CHECK(secp256k1_frost_nonce_process(ctx, &session, pubnonce_ptr, 2, msg, &pk, 1, ids, &cache, &adaptor) == 1);
|
||||||
ret = secp256k1_keypair_create(ctx, &keypair, key);
|
ret = secp256k1_keypair_create(ctx, &keypair, key);
|
||||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||||
CHECK(ret == 1);
|
CHECK(ret == 1);
|
||||||
ret = secp256k1_frost_partial_sign(ctx, &partial_sig, &secnonce[0], &agg_share, &session, &cache);
|
ret = secp256k1_frost_partial_sign(ctx, &partial_sig, &secnonce[0], &shares[0], &session, &cache);
|
||||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||||
CHECK(ret == 1);
|
CHECK(ret == 1);
|
||||||
/* adapt */
|
/* adapt */
|
||||||
@ -465,7 +425,7 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
|||||||
/* extract_adaptor */
|
/* extract_adaptor */
|
||||||
ret = secp256k1_frost_extract_adaptor(ctx, sec_adaptor, sig, pre_sig, nonce_parity);
|
ret = secp256k1_frost_extract_adaptor(ctx, sec_adaptor, sig, pre_sig, nonce_parity);
|
||||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||||
CHECK(ret == 1);
|
CHECK(ret == 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Copyright (c) 2022-2024 Jesse Posner *
|
* Copyright (c) 2022-2023 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.*
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
@ -9,50 +9,33 @@ The following sections contain additional notes on the API of the frost module
|
|||||||
|
|
||||||
Users of the frost module must take great care to make sure of the following:
|
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
|
1. The dealer establishes a secure communications channel with each participant
|
||||||
purposes. Partipants must provide the same public key to each other
|
and uses that channel to transmit shares during key generation.
|
||||||
participant.
|
2. A unique set of coefficients per key generation session is generated in
|
||||||
2. Each participant establishes a secure communications channel with each other
|
`secp256k1_frost_share_gen`. See the corresponding comment in
|
||||||
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.
|
`include/secp256k1_frost.h` for how to ensure that.
|
||||||
4. The `pubnonces` provided to `secp256k1_frost_nonce_process` are sorted by
|
3. The `pubnonces` provided to `secp256k1_frost_nonce_process` are sorted by
|
||||||
the corresponding lexicographic ordering of the x-only pubkey of each
|
the corresponding lexicographic ordering of the x-only pubkey of each
|
||||||
participant, and the `ids33` provided to `secp256k1_frost_nonce_process`
|
participant, and the `pubkeys` provided to `secp256k1_frost_nonce_process`
|
||||||
are sorted lexicographically.
|
are sorted lexicographically.
|
||||||
5. A unique nonce per signing session is generated in `secp256k1_frost_nonce_gen`.
|
4. A unique nonce per signing session is generated in
|
||||||
See the corresponding comment in `include/secp256k1_frost.h` for how to ensure that.
|
`secp256k1_frost_nonce_gen`. See the corresponding comment in
|
||||||
6. The `secp256k1_frost_secnonce` structure is never copied or serialized.
|
`include/secp256k1_frost.h` for how to ensure that.
|
||||||
See also the comment on `secp256k1_frost_secnonce` in `include/secp256k1_frost.h`.
|
5. The `secp256k1_frost_secnonce` structure is never copied or serialized. See
|
||||||
7. Opaque data structures are never written to or read from directly.
|
also the comment on `secp256k1_frost_secnonce` in
|
||||||
Instead, only the provided accessor functions are used.
|
`include/secp256k1_frost.h`.
|
||||||
8. If adaptor signatures are used, all partial signatures are verified.
|
6. Opaque data structures are never written to or read from directly. Instead,
|
||||||
|
only the provided accessor functions are used.
|
||||||
|
7. If adaptor signatures are used, all partial signatures are verified.
|
||||||
|
|
||||||
# Key Generation
|
# Key Generation
|
||||||
|
|
||||||
1. Generate a keypair with `secp256k1_keypair_create` and obtain the x-only
|
1. A trusted dealer generates shares with `secp256k1_frost_shares_trusted_gen`
|
||||||
public key with `secp256k1_keypair_xonly_pub`, and distribute it to each
|
and distributes a share and the public key to each participant using a
|
||||||
other participant to be used as an authentication key and identifier.
|
secure channel.
|
||||||
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
|
# Tweaking
|
||||||
|
|
||||||
|
|
||||||
A (Taproot) tweak can be added to the resulting public key with
|
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
|
`secp256k1_xonly_pubkey_tweak_add`, after converting it to an xonly pubkey if
|
||||||
necessary with `secp256k1_xonly_pubkey_from_pubkey`.
|
necessary with `secp256k1_xonly_pubkey_from_pubkey`.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* Copyright (c) 2021-2024 Jesse Posner *
|
* Copyright (c) 2021-2023 Jesse Posner *
|
||||||
* Distributed under the MIT software license, see the accompanying *
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
@ -23,6 +23,4 @@ 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
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* Copyright (c) 2021-2024 Jesse Posner *
|
* Copyright (c) 2021-2023 Jesse Posner *
|
||||||
* Distributed under the MIT software license, see the accompanying *
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
@ -53,24 +53,6 @@ static int secp256k1_tweak_cache_load(const secp256k1_context* ctx, secp256k1_tw
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Computes indexhash = tagged_hash(pk) */
|
|
||||||
static int secp256k1_frost_compute_indexhash(secp256k1_scalar *indexhash, const unsigned char *id33) {
|
|
||||||
secp256k1_sha256 sha;
|
|
||||||
unsigned char buf[32];
|
|
||||||
|
|
||||||
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"FROST/index", sizeof("FROST/index") - 1);
|
|
||||||
secp256k1_sha256_write(&sha, id33, 33);
|
|
||||||
secp256k1_sha256_finalize(&sha, buf);
|
|
||||||
secp256k1_scalar_set_b32(indexhash, buf, NULL);
|
|
||||||
/* The x-coordinate must not be zero (see
|
|
||||||
* draft-irtf-cfrg-frost-08#section-4.2.2) */
|
|
||||||
if (secp256k1_scalar_is_zero(indexhash)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const unsigned char secp256k1_frost_share_magic[4] = { 0xa1, 0x6a, 0x42, 0x03 };
|
static const unsigned char secp256k1_frost_share_magic[4] = { 0xa1, 0x6a, 0x42, 0x03 };
|
||||||
|
|
||||||
static void secp256k1_frost_share_save(secp256k1_frost_share* share, secp256k1_scalar *s) {
|
static void secp256k1_frost_share_save(secp256k1_frost_share* share, secp256k1_scalar *s) {
|
||||||
@ -81,6 +63,8 @@ static void secp256k1_frost_share_save(secp256k1_frost_share* share, secp256k1_s
|
|||||||
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) {
|
||||||
int overflow;
|
int overflow;
|
||||||
|
|
||||||
|
/* The magic is non-secret so it can be declassified to allow branching. */
|
||||||
|
secp256k1_declassify(ctx, &share->data[0], 4);
|
||||||
ARG_CHECK(secp256k1_memcmp_var(&share->data[0], secp256k1_frost_share_magic, 4) == 0);
|
ARG_CHECK(secp256k1_memcmp_var(&share->data[0], secp256k1_frost_share_magic, 4) == 0);
|
||||||
secp256k1_scalar_set_b32(s, &share->data[4], &overflow);
|
secp256k1_scalar_set_b32(s, &share->data[4], &overflow);
|
||||||
/* Parsed shares cannot overflow */
|
/* Parsed shares cannot overflow */
|
||||||
@ -111,82 +95,14 @@ int secp256k1_frost_share_parse(const secp256k1_context* ctx, secp256k1_frost_sh
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_frost_derive_coeff(secp256k1_scalar *coeff, const unsigned char *polygen32, size_t i) {
|
int secp256k1_frost_shares_trusted_gen(const secp256k1_context *ctx, secp256k1_frost_share *shares, secp256k1_pubkey *pubshares, secp256k1_xonly_pubkey *pk, const unsigned char *seed32, size_t threshold, size_t n_participants) {
|
||||||
secp256k1_sha256 sha;
|
secp256k1_sha256 sha;
|
||||||
unsigned char buf[32];
|
|
||||||
|
|
||||||
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"FROST/coeffgen", sizeof("FROST/coeffgen") - 1);
|
|
||||||
secp256k1_sha256_write(&sha, polygen32, 32);
|
|
||||||
secp256k1_write_be64(&buf[0], i);
|
|
||||||
secp256k1_sha256_write(&sha, buf, 8);
|
|
||||||
secp256k1_sha256_finalize(&sha, buf);
|
|
||||||
secp256k1_scalar_set_b32(coeff, buf, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int secp256k1_frost_vss_gen(const secp256k1_context *ctx, secp256k1_pubkey *vss_commitment, unsigned char *pok64, const unsigned char *polygen32, size_t threshold) {
|
|
||||||
secp256k1_sha256 sha;
|
|
||||||
unsigned char buf[32];
|
|
||||||
secp256k1_keypair keypair;
|
|
||||||
secp256k1_gej rj;
|
secp256k1_gej rj;
|
||||||
secp256k1_ge rp;
|
secp256k1_ge rp;
|
||||||
size_t i;
|
|
||||||
int ret = 1;
|
|
||||||
|
|
||||||
for (i = 0; i < threshold; i++) {
|
|
||||||
secp256k1_scalar coeff_i;
|
|
||||||
|
|
||||||
secp256k1_frost_derive_coeff(&coeff_i, polygen32, i);
|
|
||||||
/* Compute proof-of-knowledge for constant term */
|
|
||||||
if (i == threshold - 1) {
|
|
||||||
secp256k1_scalar_get_b32(buf, &coeff_i);
|
|
||||||
ret &= secp256k1_keypair_create(ctx, &keypair, buf);
|
|
||||||
|
|
||||||
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"FROST/KeygenPoK", sizeof("FROST/KeygenPoK") - 1);
|
|
||||||
secp256k1_sha256_finalize(&sha, buf);
|
|
||||||
|
|
||||||
ret &= secp256k1_schnorrsig_sign32(ctx, pok64, buf, &keypair, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compute commitment to each coefficient */
|
|
||||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &coeff_i);
|
|
||||||
secp256k1_ge_set_gej(&rp, &rj);
|
|
||||||
secp256k1_pubkey_save(&vss_commitment[threshold - i - 1], &rp);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int secp256k1_frost_share_gen(secp256k1_frost_share *share, const unsigned char *polygen32, size_t threshold, const unsigned char *id33) {
|
|
||||||
secp256k1_scalar idx;
|
|
||||||
secp256k1_scalar share_i;
|
|
||||||
size_t i;
|
|
||||||
int ret = 1;
|
|
||||||
|
|
||||||
/* Derive share */
|
|
||||||
/* See draft-irtf-cfrg-frost-08#appendix-C.1 */
|
|
||||||
secp256k1_scalar_set_int(&share_i, 0);
|
|
||||||
if (!secp256k1_frost_compute_indexhash(&idx, id33)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for (i = 0; i < threshold; i++) {
|
|
||||||
secp256k1_scalar coeff_i;
|
|
||||||
|
|
||||||
secp256k1_frost_derive_coeff(&coeff_i, polygen32, i);
|
|
||||||
/* Horner's method to evaluate polynomial to derive shares */
|
|
||||||
secp256k1_scalar_add(&share_i, &share_i, &coeff_i);
|
|
||||||
if (i < threshold - 1) {
|
|
||||||
secp256k1_scalar_mul(&share_i, &share_i, &idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
secp256k1_frost_share_save(share, &share_i);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int secp256k1_frost_shares_gen(const secp256k1_context *ctx, secp256k1_frost_share *shares, secp256k1_pubkey *vss_commitment, unsigned char *pok64, const unsigned char *seed32, size_t threshold, size_t n_participants, const unsigned char * const* ids33) {
|
|
||||||
secp256k1_sha256 sha;
|
|
||||||
unsigned char polygen[32];
|
unsigned char polygen[32];
|
||||||
size_t i;
|
size_t i, j;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
|
int pk_parity = 0;
|
||||||
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
VERIFY_CHECK(ctx != NULL);
|
||||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||||
@ -194,254 +110,69 @@ int secp256k1_frost_shares_gen(const secp256k1_context *ctx, secp256k1_frost_sha
|
|||||||
for (i = 0; i < n_participants; i++) {
|
for (i = 0; i < n_participants; i++) {
|
||||||
memset(&shares[i], 0, sizeof(shares[i]));
|
memset(&shares[i], 0, sizeof(shares[i]));
|
||||||
}
|
}
|
||||||
ARG_CHECK(vss_commitment != NULL);
|
ARG_CHECK(pubshares != NULL);
|
||||||
ARG_CHECK(pok64 != NULL);
|
ARG_CHECK(pk != NULL);
|
||||||
ARG_CHECK(seed32 != NULL);
|
ARG_CHECK(seed32 != NULL);
|
||||||
ARG_CHECK(ids33 != NULL);
|
|
||||||
ARG_CHECK(threshold > 1);
|
ARG_CHECK(threshold > 1);
|
||||||
ARG_CHECK(n_participants >= threshold);
|
ARG_CHECK(n_participants >= threshold);
|
||||||
|
|
||||||
/* Commit to all inputs */
|
/* Commit to threshold, n_participants, and seed */
|
||||||
secp256k1_sha256_initialize(&sha);
|
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"FROST/trusted-shares-polygen", sizeof("FROST/trusted-shares-polygen") - 1);
|
||||||
secp256k1_sha256_write(&sha, seed32, 32);
|
secp256k1_sha256_write(&sha, seed32, 32);
|
||||||
secp256k1_write_be64(&polygen[0], threshold);
|
secp256k1_write_be64(&polygen[0], threshold);
|
||||||
secp256k1_write_be64(&polygen[8], n_participants);
|
secp256k1_write_be64(&polygen[8], n_participants);
|
||||||
secp256k1_sha256_write(&sha, polygen, 16);
|
secp256k1_sha256_write(&sha, polygen, 16);
|
||||||
for (i = 0; i < n_participants; i++) {
|
|
||||||
secp256k1_sha256_write(&sha, ids33[i], 33);
|
|
||||||
}
|
|
||||||
secp256k1_sha256_finalize(&sha, polygen);
|
secp256k1_sha256_finalize(&sha, polygen);
|
||||||
|
|
||||||
ret &= secp256k1_frost_vss_gen(ctx, vss_commitment, pok64, polygen, threshold);
|
/* Derive shares */
|
||||||
|
/* See draft-irtf-cfrg-frost-08#appendix-C.1 */
|
||||||
for (i = 0; i < n_participants; i++) {
|
for (i = 0; i < n_participants; i++) {
|
||||||
ret &= secp256k1_frost_share_gen(&shares[i], polygen, threshold, ids33[i]);
|
secp256k1_scalar share_i, idx;
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
secp256k1_scalar_set_int(&share_i, 0);
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
for (j = 0; j < threshold; j++) {
|
||||||
const secp256k1_context *ctx;
|
unsigned char buf[32];
|
||||||
secp256k1_scalar idx;
|
secp256k1_scalar coeff_i;
|
||||||
secp256k1_scalar idxn;
|
|
||||||
const secp256k1_pubkey * const* vss_commitment;
|
|
||||||
} secp256k1_frost_verify_share_ecmult_data;
|
|
||||||
|
|
||||||
typedef struct {
|
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"FROST/trusted-shares-coeffgen", sizeof("FROST/trusted-shares-coeffgen") - 1);
|
||||||
const secp256k1_context *ctx;
|
secp256k1_sha256_write(&sha, polygen, 32);
|
||||||
secp256k1_scalar idx;
|
secp256k1_write_be64(&buf[0], j);
|
||||||
secp256k1_scalar idxn;
|
secp256k1_sha256_write(&sha, buf, 8);
|
||||||
const secp256k1_pubkey * const* vss_commitments;
|
secp256k1_sha256_finalize(&sha, buf);
|
||||||
size_t threshold;
|
secp256k1_scalar_set_b32(&coeff_i, buf, NULL);
|
||||||
} secp256k1_frost_compute_pubshare_ecmult_data;
|
|
||||||
|
|
||||||
typedef struct {
|
/* Horner's method to evaluate polynomial to derive shares */
|
||||||
const secp256k1_context *ctx;
|
secp256k1_scalar_add(&share_i, &share_i, &coeff_i);
|
||||||
const secp256k1_pubkey * const* pks;
|
if (j < threshold - 1) {
|
||||||
size_t threshold;
|
secp256k1_scalar_set_int(&idx, i + 1);
|
||||||
} secp256k1_frost_pubkey_combine_ecmult_data;
|
secp256k1_scalar_mul(&share_i, &share_i, &idx);
|
||||||
|
}
|
||||||
|
|
||||||
static int secp256k1_frost_verify_share_ecmult_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
|
/* Compute x-only public key for constant term */
|
||||||
secp256k1_frost_verify_share_ecmult_data *ctx = (secp256k1_frost_verify_share_ecmult_data *) data;
|
if (i == 0 && j == threshold - 1) {
|
||||||
if (!secp256k1_pubkey_load(ctx->ctx, pt, *(ctx->vss_commitment)+idx)) {
|
/* Compute commitment to constant term */
|
||||||
return 0;
|
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &coeff_i);
|
||||||
}
|
secp256k1_ge_set_gej(&rp, &rj);
|
||||||
*sc = ctx->idxn;
|
/* The commitment is non-secret so it can be declassified to
|
||||||
secp256k1_scalar_mul(&ctx->idxn, &ctx->idxn, &ctx->idx);
|
* allow branching. */
|
||||||
|
secp256k1_declassify(ctx, &rp, sizeof(rp));
|
||||||
return 1;
|
secp256k1_fe_normalize_var(&rp.y);
|
||||||
}
|
pk_parity = secp256k1_extrakeys_ge_even_y(&rp);
|
||||||
|
secp256k1_xonly_pubkey_save(pk, &rp);
|
||||||
static int secp256k1_frost_compute_pubshare_ecmult_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
|
}
|
||||||
secp256k1_frost_compute_pubshare_ecmult_data *ctx = (secp256k1_frost_compute_pubshare_ecmult_data *) data;
|
|
||||||
|
|
||||||
if (!secp256k1_pubkey_load(ctx->ctx, pt, &ctx->vss_commitments[idx/ctx->threshold][idx % ctx->threshold])) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (idx != 0 && idx % ctx->threshold == 0) {
|
|
||||||
secp256k1_scalar_set_int(&ctx->idxn, 1);
|
|
||||||
}
|
|
||||||
*sc = ctx->idxn;
|
|
||||||
secp256k1_scalar_mul(&ctx->idxn, &ctx->idxn, &ctx->idx);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int secp256k1_frost_pubkey_combine_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
|
|
||||||
secp256k1_frost_pubkey_combine_ecmult_data *ctx = (secp256k1_frost_pubkey_combine_ecmult_data *) data;
|
|
||||||
|
|
||||||
secp256k1_scalar_set_int(sc, 1);
|
|
||||||
/* the public key is the first index of each set of coefficients */
|
|
||||||
return secp256k1_pubkey_load(ctx->ctx, pt, &ctx->pks[idx][0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See draft-irtf-cfrg-frost-08#appendix-C.2 */
|
|
||||||
static int secp256k1_frost_vss_verify_internal(const secp256k1_context* ctx, size_t threshold, const unsigned char *id33, const secp256k1_scalar *share, const secp256k1_pubkey * const* vss_commitment) {
|
|
||||||
secp256k1_scalar share_neg;
|
|
||||||
secp256k1_gej tmpj, snj;
|
|
||||||
secp256k1_ge sng;
|
|
||||||
secp256k1_frost_verify_share_ecmult_data verify_share_ecmult_data;
|
|
||||||
|
|
||||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
|
||||||
|
|
||||||
/* Use an EC multi-multiplication to verify the following equation:
|
|
||||||
* 0 = - share_i*G + idx^0*vss_commitment[0]
|
|
||||||
* + ...
|
|
||||||
* + idx^(threshold - 1)*vss_commitment[threshold - 1]*/
|
|
||||||
verify_share_ecmult_data.ctx = ctx;
|
|
||||||
verify_share_ecmult_data.vss_commitment = vss_commitment;
|
|
||||||
/* Evaluate the public polynomial at the idx */
|
|
||||||
if (!secp256k1_frost_compute_indexhash(&verify_share_ecmult_data.idx, id33)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
secp256k1_scalar_set_int(&verify_share_ecmult_data.idxn, 1);
|
|
||||||
/* TODO: add scratch */
|
|
||||||
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &tmpj, NULL, secp256k1_frost_verify_share_ecmult_callback, (void *) &verify_share_ecmult_data, threshold)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
secp256k1_scalar_negate(&share_neg, share);
|
|
||||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &snj, &share_neg);
|
|
||||||
secp256k1_ge_set_gej(&sng, &snj);
|
|
||||||
secp256k1_gej_add_ge(&tmpj, &tmpj, &sng);
|
|
||||||
return secp256k1_gej_is_infinity(&tmpj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See draft-irtf-cfrg-frost-08#appendix-C.2 */
|
|
||||||
int secp256k1_frost_share_verify(const secp256k1_context* ctx, size_t threshold, const unsigned char *id33, const secp256k1_frost_share *share, const secp256k1_pubkey * const* vss_commitment) {
|
|
||||||
secp256k1_scalar share_i;
|
|
||||||
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
|
||||||
ARG_CHECK(id33 != NULL);
|
|
||||||
ARG_CHECK(share != NULL);
|
|
||||||
ARG_CHECK(vss_commitment != NULL);
|
|
||||||
ARG_CHECK(threshold > 1);
|
|
||||||
|
|
||||||
if (!secp256k1_frost_share_load(ctx, &share_i, share)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return secp256k1_frost_vss_verify_internal(ctx, threshold, id33, &share_i, vss_commitment);
|
|
||||||
}
|
|
||||||
|
|
||||||
int secp256k1_frost_compute_pubshare(const secp256k1_context* ctx, secp256k1_pubkey *pubshare, size_t threshold, const unsigned char *id33, const secp256k1_pubkey * const* vss_commitments, size_t n_participants) {
|
|
||||||
secp256k1_gej pkj;
|
|
||||||
secp256k1_ge pkp, tmp;
|
|
||||||
secp256k1_frost_compute_pubshare_ecmult_data compute_pubshare_ecmult_data;
|
|
||||||
secp256k1_frost_pubkey_combine_ecmult_data pubkey_combine_ecmult_data;
|
|
||||||
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
|
||||||
ARG_CHECK(pubshare != NULL);
|
|
||||||
memset(pubshare, 0, sizeof(*pubshare));
|
|
||||||
ARG_CHECK(id33 != NULL);
|
|
||||||
ARG_CHECK(vss_commitments != NULL);
|
|
||||||
ARG_CHECK(n_participants > 1);
|
|
||||||
ARG_CHECK(threshold > 1);
|
|
||||||
|
|
||||||
if (threshold > n_participants) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Use an EC multi-multiplication to compute the following equation:
|
|
||||||
* agg_share_i*G = (
|
|
||||||
* idx^0*vss_commitment[0][0] + ...
|
|
||||||
* + idx^(t - 1)*vss_commitment[0][t - 1]
|
|
||||||
* ) + ...
|
|
||||||
* + (
|
|
||||||
* idx^0*vss_commitment[n - 1][0] + ...
|
|
||||||
* + idx^(t - 1)*vss_commitment[n - 1][t - 1]
|
|
||||||
* )*/
|
|
||||||
compute_pubshare_ecmult_data.ctx = ctx;
|
|
||||||
compute_pubshare_ecmult_data.vss_commitments = vss_commitments;
|
|
||||||
compute_pubshare_ecmult_data.threshold = threshold;
|
|
||||||
/* Evaluate the public polynomial at the idx */
|
|
||||||
if (!secp256k1_frost_compute_indexhash(&compute_pubshare_ecmult_data.idx, id33)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
secp256k1_scalar_set_int(&compute_pubshare_ecmult_data.idxn, 1);
|
|
||||||
/* TODO: add scratch */
|
|
||||||
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &pkj, NULL, secp256k1_frost_compute_pubshare_ecmult_callback, (void *) &compute_pubshare_ecmult_data, n_participants*threshold)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
secp256k1_ge_set_gej(&tmp, &pkj);
|
|
||||||
|
|
||||||
/* Combine pubkeys */
|
|
||||||
pubkey_combine_ecmult_data.ctx = ctx;
|
|
||||||
pubkey_combine_ecmult_data.pks = vss_commitments;
|
|
||||||
pubkey_combine_ecmult_data.threshold = threshold;
|
|
||||||
|
|
||||||
/* TODO: add scratch */
|
|
||||||
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &pkj, NULL, secp256k1_frost_pubkey_combine_callback, (void *) &pubkey_combine_ecmult_data, n_participants)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
secp256k1_ge_set_gej(&pkp, &pkj);
|
|
||||||
secp256k1_fe_normalize_var(&pkp.y);
|
|
||||||
if (secp256k1_fe_is_odd(&pkp.y)) {
|
|
||||||
secp256k1_ge_neg(&tmp, &tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
secp256k1_pubkey_save(pubshare, &tmp);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int secp256k1_frost_share_agg(const secp256k1_context* ctx, secp256k1_frost_share *agg_share, secp256k1_xonly_pubkey *agg_pk, const secp256k1_frost_share * const* shares, const secp256k1_pubkey * const* vss_commitments, size_t n_shares, size_t threshold, const unsigned char *id33) {
|
|
||||||
secp256k1_frost_pubkey_combine_ecmult_data pubkey_combine_ecmult_data;
|
|
||||||
secp256k1_gej pkj;
|
|
||||||
secp256k1_ge pkp;
|
|
||||||
int pk_parity;
|
|
||||||
secp256k1_scalar acc;
|
|
||||||
size_t i;
|
|
||||||
int ret = 1;
|
|
||||||
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
|
||||||
ARG_CHECK(agg_share != NULL);
|
|
||||||
memset(agg_share, 0, sizeof(*agg_share));
|
|
||||||
ARG_CHECK(agg_pk != NULL);
|
|
||||||
memset(agg_pk, 0, sizeof(*agg_pk));
|
|
||||||
ARG_CHECK(shares != NULL);
|
|
||||||
ARG_CHECK(vss_commitments != NULL);
|
|
||||||
ARG_CHECK(id33 != NULL);
|
|
||||||
ARG_CHECK(n_shares > 1);
|
|
||||||
ARG_CHECK(threshold > 1);
|
|
||||||
|
|
||||||
if (threshold > n_shares) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
secp256k1_scalar_clear(&acc);
|
|
||||||
for (i = 0; i < n_shares; i++) {
|
|
||||||
secp256k1_scalar share_i;
|
|
||||||
|
|
||||||
if (!secp256k1_frost_share_load(ctx, &share_i, shares[i])) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
/* Verify share against commitments */
|
|
||||||
ret &= secp256k1_frost_vss_verify_internal(ctx, threshold, id33, &share_i, &vss_commitments[i]);
|
if (pk_parity == 1) {
|
||||||
secp256k1_scalar_add(&acc, &acc, &share_i);
|
secp256k1_scalar_negate(&share_i, &share_i);
|
||||||
|
}
|
||||||
|
secp256k1_frost_share_save(&shares[i], &share_i);
|
||||||
|
/* Compute pubshare */
|
||||||
|
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &share_i);
|
||||||
|
secp256k1_ge_set_gej(&rp, &rj);
|
||||||
|
secp256k1_pubkey_save(&pubshares[i], &rp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Combine pubkeys */
|
|
||||||
pubkey_combine_ecmult_data.ctx = ctx;
|
|
||||||
pubkey_combine_ecmult_data.pks = vss_commitments;
|
|
||||||
pubkey_combine_ecmult_data.threshold = threshold;
|
|
||||||
|
|
||||||
/* TODO: add scratch */
|
|
||||||
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &pkj, NULL, secp256k1_frost_pubkey_combine_callback, (void *) &pubkey_combine_ecmult_data, n_shares)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
secp256k1_ge_set_gej(&pkp, &pkj);
|
|
||||||
secp256k1_fe_normalize_var(&pkp.y);
|
|
||||||
pk_parity = secp256k1_extrakeys_ge_even_y(&pkp);
|
|
||||||
secp256k1_xonly_pubkey_save(agg_pk, &pkp);
|
|
||||||
|
|
||||||
/* Invert the aggregate share if the combined pubkey has an odd Y coordinate. */
|
|
||||||
if (pk_parity == 1) {
|
|
||||||
secp256k1_scalar_negate(&acc, &acc);
|
|
||||||
}
|
|
||||||
secp256k1_frost_share_save(agg_share, &acc);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* Copyright (c) 2021-2024 Jesse Posner *
|
* Copyright (c) 2021-2023 Jesse Posner *
|
||||||
* Distributed under the MIT software license, see the accompanying *
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* Copyright (c) 2021-2024 Jesse Posner *
|
* Copyright (c) 2021-2023 Jesse Posner *
|
||||||
* Distributed under the MIT software license, see the accompanying *
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* Copyright (c) 2021-2024 Jesse Posner *
|
* Copyright (c) 2021-2023 Jesse Posner *
|
||||||
* Distributed under the MIT software license, see the accompanying *
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
@ -313,7 +313,7 @@ int secp256k1_frost_nonce_gen(const secp256k1_context* ctx, secp256k1_frost_secn
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int secp256k1_frost_sum_nonces(const secp256k1_context* ctx, secp256k1_gej *summed_nonces, const secp256k1_frost_pubnonce * const *pubnonces, size_t n_pubnonces) {
|
static int secp256k1_frost_sum_nonces(const secp256k1_context* ctx, secp256k1_gej *summed_nonces, const secp256k1_frost_pubnonce * const* pubnonces, size_t n_pubnonces) {
|
||||||
size_t i;
|
size_t i;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
@ -334,19 +334,16 @@ static int secp256k1_frost_sum_nonces(const secp256k1_context* ctx, secp256k1_ge
|
|||||||
|
|
||||||
/* TODO: consider updating to frost-08 to address maleability at the cost of performance */
|
/* TODO: consider updating to frost-08 to address maleability at the cost of performance */
|
||||||
/* See https://github.com/cfrg/draft-irtf-cfrg-frost/pull/217 */
|
/* See https://github.com/cfrg/draft-irtf-cfrg-frost/pull/217 */
|
||||||
static int secp256k1_frost_compute_noncehash(const secp256k1_context* ctx, unsigned char *noncehash, const unsigned char *msg, const secp256k1_frost_pubnonce * const *pubnonces, size_t n_pubnonces, const unsigned char *pk32, const unsigned char * const *ids33) {
|
static int secp256k1_frost_compute_noncehash(const secp256k1_context* ctx, unsigned char *noncehash, const unsigned char *msg, const secp256k1_frost_pubnonce * const* pubnonces, size_t n_pubnonces, const unsigned char *pk32, const size_t *ids) {
|
||||||
unsigned char buf[66];
|
unsigned char buf[66];
|
||||||
secp256k1_sha256 sha;
|
secp256k1_sha256 sha;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"FROST/noncecoef", sizeof("FROST/noncecoef") - 1);
|
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"FROST/noncecoef", sizeof("FROST/noncecoef") - 1);
|
||||||
/* TODO: sort by index */
|
|
||||||
for (i = 0; i < n_pubnonces; i++) {
|
for (i = 0; i < n_pubnonces; i++) {
|
||||||
secp256k1_scalar idx;
|
secp256k1_scalar idx;
|
||||||
|
|
||||||
if (!secp256k1_frost_compute_indexhash(&idx, ids33[i])) {
|
secp256k1_scalar_set_int(&idx, ids[i]);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
secp256k1_scalar_get_b32(buf, &idx);
|
secp256k1_scalar_get_b32(buf, &idx);
|
||||||
secp256k1_sha256_write(&sha, buf, 32);
|
secp256k1_sha256_write(&sha, buf, 32);
|
||||||
if (!secp256k1_frost_pubnonce_serialize(ctx, buf, pubnonces[i])) {
|
if (!secp256k1_frost_pubnonce_serialize(ctx, buf, pubnonces[i])) {
|
||||||
@ -360,7 +357,7 @@ static int secp256k1_frost_compute_noncehash(const secp256k1_context* ctx, unsig
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int secp256k1_frost_nonce_process_internal(const secp256k1_context* ctx, int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_gej *aggnoncej, const unsigned char *msg, const secp256k1_frost_pubnonce * const *pubnonces, size_t n_pubnonces, const unsigned char *pk32, const unsigned char * const *ids33) {
|
static int secp256k1_frost_nonce_process_internal(const secp256k1_context* ctx, int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_gej *aggnoncej, const unsigned char *msg, const secp256k1_frost_pubnonce * const* pubnonces, size_t n_pubnonces, const unsigned char *pk32, const size_t *ids) {
|
||||||
unsigned char noncehash[32];
|
unsigned char noncehash[32];
|
||||||
secp256k1_ge fin_nonce_pt;
|
secp256k1_ge fin_nonce_pt;
|
||||||
secp256k1_gej fin_nonce_ptj;
|
secp256k1_gej fin_nonce_ptj;
|
||||||
@ -368,7 +365,7 @@ static int secp256k1_frost_nonce_process_internal(const secp256k1_context* ctx,
|
|||||||
|
|
||||||
secp256k1_ge_set_gej(&aggnonce[0], &aggnoncej[0]);
|
secp256k1_ge_set_gej(&aggnonce[0], &aggnoncej[0]);
|
||||||
secp256k1_ge_set_gej(&aggnonce[1], &aggnoncej[1]);
|
secp256k1_ge_set_gej(&aggnonce[1], &aggnoncej[1]);
|
||||||
if (!secp256k1_frost_compute_noncehash(ctx, noncehash, msg, pubnonces, n_pubnonces, pk32, ids33)) {
|
if (!secp256k1_frost_compute_noncehash(ctx, noncehash, msg, pubnonces, n_pubnonces, pk32, ids)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* fin_nonce = aggnonce[0] + b*aggnonce[1] */
|
/* fin_nonce = aggnonce[0] + b*aggnonce[1] */
|
||||||
@ -389,7 +386,7 @@ static int secp256k1_frost_nonce_process_internal(const secp256k1_context* ctx,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int secp256k1_frost_lagrange_coefficient(secp256k1_scalar *r, const unsigned char * const *ids33, size_t n_participants, const unsigned char *my_id33) {
|
static int secp256k1_frost_lagrange_coefficient(secp256k1_scalar *r, const size_t *ids, size_t n_participants, size_t my_id) {
|
||||||
size_t i;
|
size_t i;
|
||||||
secp256k1_scalar num;
|
secp256k1_scalar num;
|
||||||
secp256k1_scalar den;
|
secp256k1_scalar den;
|
||||||
@ -397,15 +394,11 @@ static int secp256k1_frost_lagrange_coefficient(secp256k1_scalar *r, const unsig
|
|||||||
|
|
||||||
secp256k1_scalar_set_int(&num, 1);
|
secp256k1_scalar_set_int(&num, 1);
|
||||||
secp256k1_scalar_set_int(&den, 1);
|
secp256k1_scalar_set_int(&den, 1);
|
||||||
if (!secp256k1_frost_compute_indexhash(&party_idx, my_id33)) {
|
secp256k1_scalar_set_int(&party_idx, my_id);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for (i = 0; i < n_participants; i++) {
|
for (i = 0; i < n_participants; i++) {
|
||||||
secp256k1_scalar mul;
|
secp256k1_scalar mul;
|
||||||
|
|
||||||
if (!secp256k1_frost_compute_indexhash(&mul, ids33[i])) {
|
secp256k1_scalar_set_int(&mul, ids[i]);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (secp256k1_scalar_eq(&mul, &party_idx)) {
|
if (secp256k1_scalar_eq(&mul, &party_idx)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -422,7 +415,7 @@ static int secp256k1_frost_lagrange_coefficient(secp256k1_scalar *r, const unsig
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int secp256k1_frost_nonce_process(const secp256k1_context* ctx, secp256k1_frost_session *session, const secp256k1_frost_pubnonce * const* pubnonces, size_t n_pubnonces, const unsigned char *msg32, const secp256k1_xonly_pubkey *pk, const unsigned char *my_id33, const unsigned char * const *ids33, const secp256k1_frost_tweak_cache *tweak_cache, const secp256k1_pubkey *adaptor) {
|
int secp256k1_frost_nonce_process(const secp256k1_context* ctx, secp256k1_frost_session *session, const secp256k1_frost_pubnonce * const* pubnonces, size_t n_pubnonces, const unsigned char *msg32, const secp256k1_xonly_pubkey *pk, size_t my_id, const size_t *ids, const secp256k1_frost_tweak_cache *tweak_cache, const secp256k1_pubkey *adaptor) {
|
||||||
secp256k1_ge aggnonce_pt[2];
|
secp256k1_ge aggnonce_pt[2];
|
||||||
secp256k1_gej aggnonce_ptj[2];
|
secp256k1_gej aggnonce_ptj[2];
|
||||||
unsigned char fin_nonce[32];
|
unsigned char fin_nonce[32];
|
||||||
@ -435,10 +428,12 @@ int secp256k1_frost_nonce_process(const secp256k1_context* ctx, secp256k1_frost_
|
|||||||
ARG_CHECK(session != NULL);
|
ARG_CHECK(session != NULL);
|
||||||
ARG_CHECK(msg32 != NULL);
|
ARG_CHECK(msg32 != NULL);
|
||||||
ARG_CHECK(pubnonces != NULL);
|
ARG_CHECK(pubnonces != NULL);
|
||||||
ARG_CHECK(ids33 != NULL);
|
ARG_CHECK(ids != NULL);
|
||||||
ARG_CHECK(my_id33 != NULL);
|
|
||||||
ARG_CHECK(pk != NULL);
|
|
||||||
ARG_CHECK(n_pubnonces > 1);
|
ARG_CHECK(n_pubnonces > 1);
|
||||||
|
ARG_CHECK(my_id != 0);
|
||||||
|
for (i = 0; i < n_pubnonces; i++) {
|
||||||
|
ARG_CHECK(ids[i] != 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (!secp256k1_xonly_pubkey_serialize(ctx, pk32, pk)) {
|
if (!secp256k1_xonly_pubkey_serialize(ctx, pk32, pk)) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -453,6 +448,7 @@ int secp256k1_frost_nonce_process(const secp256k1_context* ctx, secp256k1_frost_
|
|||||||
here, we will never be able to determine who it is. Therefore, we
|
here, we will never be able to determine who it is. Therefore, we
|
||||||
should continue such that the culprit is revealed when collecting
|
should continue such that the culprit is revealed when collecting
|
||||||
and verifying partial signatures.
|
and verifying partial signatures.
|
||||||
|
|
||||||
However, dealing with the point at infinity (loading,
|
However, dealing with the point at infinity (loading,
|
||||||
de-/serializing) would require a lot of extra code complexity.
|
de-/serializing) would require a lot of extra code complexity.
|
||||||
Instead, we set the aggregate nonce to some arbitrary point (the
|
Instead, we set the aggregate nonce to some arbitrary point (the
|
||||||
@ -476,7 +472,7 @@ int secp256k1_frost_nonce_process(const secp256k1_context* ctx, secp256k1_frost_
|
|||||||
}
|
}
|
||||||
secp256k1_gej_add_ge_var(&aggnonce_ptj[0], &aggnonce_ptj[0], &adaptorp, NULL);
|
secp256k1_gej_add_ge_var(&aggnonce_ptj[0], &aggnonce_ptj[0], &adaptorp, NULL);
|
||||||
}
|
}
|
||||||
if (!secp256k1_frost_nonce_process_internal(ctx, &session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_ptj, msg32, pubnonces, n_pubnonces, pk32, ids33)) {
|
if (!secp256k1_frost_nonce_process_internal(ctx, &session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_ptj, msg32, pubnonces, n_pubnonces, pk32, ids)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,7 +496,7 @@ int secp256k1_frost_nonce_process(const secp256k1_context* ctx, secp256k1_frost_
|
|||||||
}
|
}
|
||||||
/* Update the challenge by multiplying the Lagrange coefficient to prepare
|
/* Update the challenge by multiplying the Lagrange coefficient to prepare
|
||||||
* for signing. */
|
* for signing. */
|
||||||
if (!secp256k1_frost_lagrange_coefficient(&l, ids33, n_pubnonces, my_id33)) {
|
if (!secp256k1_frost_lagrange_coefficient(&l, ids, n_pubnonces, my_id)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
secp256k1_scalar_mul(&session_i.challenge, &session_i.challenge, &l);
|
secp256k1_scalar_mul(&session_i.challenge, &session_i.challenge, &l);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Copyright (c) 2022-2024 Jesse Posner *
|
* Copyright (c) 2022, 2023 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.*
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
@ -23,77 +23,49 @@
|
|||||||
#include "../../hash.h"
|
#include "../../hash.h"
|
||||||
#include "../../util.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
|
/* Simple (non-adaptor, non-tweaked) 3-of-5 FROST aggregate, sign, verify
|
||||||
* test. */
|
* test. */
|
||||||
void frost_simple_test(void) {
|
void frost_simple_test(void) {
|
||||||
unsigned char sk[5][32];
|
|
||||||
secp256k1_frost_pubnonce pubnonce[5];
|
secp256k1_frost_pubnonce pubnonce[5];
|
||||||
const secp256k1_frost_pubnonce *pubnonce_ptr[5];
|
const secp256k1_frost_pubnonce *pubnonce_ptr[5];
|
||||||
unsigned char msg[32];
|
unsigned char msg[32];
|
||||||
secp256k1_pubkey vss_commitment[5][3];
|
secp256k1_xonly_pubkey pk;
|
||||||
const secp256k1_pubkey *vss_ptr[5];
|
unsigned char seed[32];
|
||||||
unsigned char pok[5][64];
|
secp256k1_frost_share shares[5];
|
||||||
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_frost_secnonce secnonce[5];
|
||||||
secp256k1_pubkey pubshare[5];
|
secp256k1_pubkey pubshares[5];
|
||||||
secp256k1_frost_partial_sig partial_sig[5];
|
secp256k1_frost_partial_sig partial_sig[5];
|
||||||
const secp256k1_frost_partial_sig *partial_sig_ptr[5];
|
const secp256k1_frost_partial_sig *partial_sig_ptr[5];
|
||||||
unsigned char final_sig[64];
|
unsigned char final_sig[64];
|
||||||
secp256k1_frost_session session;
|
secp256k1_frost_session session;
|
||||||
int i, j;
|
int i;
|
||||||
unsigned char id[5][33];
|
size_t ids[5];
|
||||||
const unsigned char *id_ptr[5];
|
|
||||||
|
secp256k1_testrand256(seed);
|
||||||
|
|
||||||
for (i = 0; i < 5; i++) {
|
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];
|
pubnonce_ptr[i] = &pubnonce[i];
|
||||||
partial_sig_ptr[i] = &partial_sig[i];
|
partial_sig_ptr[i] = &partial_sig[i];
|
||||||
id_ptr[i] = id[i];
|
ids[i] = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
CHECK(frost_create_pk(id[i], sk[i]));
|
CHECK(secp256k1_frost_shares_trusted_gen(CTX, shares, pubshares, &pk, seed, 3, 5) == 1);
|
||||||
}
|
|
||||||
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);
|
secp256k1_testrand256(msg);
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
secp256k1_testrand256(buf[i]);
|
unsigned char session_id[32];
|
||||||
|
|
||||||
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[i], &pubnonce[i], buf[i], &agg_share[i], NULL, NULL, NULL) == 1);
|
secp256k1_testrand256(session_id);
|
||||||
|
|
||||||
|
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[i], &pubnonce[i], session_id, &shares[i], NULL, NULL, NULL) == 1);
|
||||||
}
|
}
|
||||||
for (i = 0; i < 3; i++) {
|
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_nonce_process(CTX, &session, pubnonce_ptr, 3, msg, &pk, ids[i], ids, NULL, NULL) == 1);
|
||||||
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[i], &secnonce[i], &agg_share[i], &session, NULL) == 1);
|
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[i], &secnonce[i], &shares[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_verify(CTX, &partial_sig[i], &pubnonce[i], &pubshares[i], &session, NULL) == 1);
|
||||||
}
|
}
|
||||||
CHECK(secp256k1_frost_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, 3) == 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);
|
CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), &pk) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void frost_pubnonce_summing_to_inf(secp256k1_frost_pubnonce *pubnonce) {
|
void frost_pubnonce_summing_to_inf(secp256k1_frost_pubnonce *pubnonce) {
|
||||||
@ -135,11 +107,11 @@ void frost_api_tests(void) {
|
|||||||
unsigned char final_sig[64];
|
unsigned char final_sig[64];
|
||||||
unsigned char pre_sig[64];
|
unsigned char pre_sig[64];
|
||||||
unsigned char buf[32];
|
unsigned char buf[32];
|
||||||
unsigned char sk[5][32];
|
/* unsigned char sk[5][32]; */
|
||||||
unsigned char max64[64];
|
unsigned char max64[64];
|
||||||
unsigned char zeros68[68] = { 0 };
|
unsigned char zeros68[68] = { 0 };
|
||||||
unsigned char session_id[5][32];
|
unsigned char session_id[5][32];
|
||||||
unsigned char seed[5][32];
|
unsigned char seed[32];
|
||||||
secp256k1_frost_secnonce secnonce[5];
|
secp256k1_frost_secnonce secnonce[5];
|
||||||
secp256k1_frost_secnonce secnonce_tmp;
|
secp256k1_frost_secnonce secnonce_tmp;
|
||||||
secp256k1_frost_secnonce invalid_secnonce;
|
secp256k1_frost_secnonce invalid_secnonce;
|
||||||
@ -150,8 +122,8 @@ void frost_api_tests(void) {
|
|||||||
secp256k1_frost_pubnonce invalid_pubnonce;
|
secp256k1_frost_pubnonce invalid_pubnonce;
|
||||||
const secp256k1_frost_pubnonce *invalid_pubnonce_ptr[5];
|
const secp256k1_frost_pubnonce *invalid_pubnonce_ptr[5];
|
||||||
unsigned char msg[32];
|
unsigned char msg[32];
|
||||||
secp256k1_xonly_pubkey agg_pk;
|
secp256k1_xonly_pubkey pk;
|
||||||
secp256k1_pubkey full_agg_pk;
|
secp256k1_pubkey full_pk;
|
||||||
secp256k1_frost_tweak_cache tweak_cache;
|
secp256k1_frost_tweak_cache tweak_cache;
|
||||||
secp256k1_frost_tweak_cache invalid_tweak_cache;
|
secp256k1_frost_tweak_cache invalid_tweak_cache;
|
||||||
secp256k1_frost_session session[5];
|
secp256k1_frost_session session[5];
|
||||||
@ -162,21 +134,13 @@ void frost_api_tests(void) {
|
|||||||
unsigned char sec_adaptor[32];
|
unsigned char sec_adaptor[32];
|
||||||
unsigned char sec_adaptor1[32];
|
unsigned char sec_adaptor1[32];
|
||||||
secp256k1_pubkey adaptor;
|
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_pubkey invalid_vss_pk;
|
||||||
secp256k1_frost_share shares[5][5];
|
|
||||||
secp256k1_frost_share invalid_share;
|
secp256k1_frost_share invalid_share;
|
||||||
secp256k1_frost_share agg_share[5];
|
secp256k1_frost_share shares[5];
|
||||||
unsigned char pok[5][64];
|
secp256k1_pubkey pubshares[5];
|
||||||
const secp256k1_frost_share *share_ptr[5];
|
int i;
|
||||||
const secp256k1_frost_share *invalid_share_ptr[5];
|
size_t ids[5];
|
||||||
secp256k1_pubkey pubshare[5];
|
size_t invalid_ids[5];
|
||||||
int i, j;
|
|
||||||
unsigned char id[5][33];
|
|
||||||
const unsigned char *id_ptr[5];
|
|
||||||
|
|
||||||
/** setup **/
|
/** setup **/
|
||||||
memset(max64, 0xff, sizeof(max64));
|
memset(max64, 0xff, sizeof(max64));
|
||||||
@ -196,158 +160,68 @@ void frost_api_tests(void) {
|
|||||||
secp256k1_testrand256(sec_adaptor);
|
secp256k1_testrand256(sec_adaptor);
|
||||||
secp256k1_testrand256(msg);
|
secp256k1_testrand256(msg);
|
||||||
secp256k1_testrand256(tweak);
|
secp256k1_testrand256(tweak);
|
||||||
|
secp256k1_testrand256(seed);
|
||||||
CHECK(secp256k1_ec_pubkey_create(CTX, &adaptor, sec_adaptor) == 1);
|
CHECK(secp256k1_ec_pubkey_create(CTX, &adaptor, sec_adaptor) == 1);
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
pubnonce_ptr[i] = &pubnonce[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];
|
partial_sig_ptr[i] = &partial_sig[i];
|
||||||
invalid_partial_sig_ptr[i] = &partial_sig[i];
|
invalid_partial_sig_ptr[i] = &partial_sig[i];
|
||||||
id_ptr[i] = id[i];
|
ids[i] = i + 1;
|
||||||
|
invalid_ids[i] = i + 1;
|
||||||
secp256k1_testrand256(session_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_pubnonce_ptr[0] = &invalid_pubnonce;
|
||||||
invalid_share_ptr[0] = &invalid_share;
|
|
||||||
invalid_partial_sig_ptr[0] = &invalid_partial_sig;
|
invalid_partial_sig_ptr[0] = &invalid_partial_sig;
|
||||||
for (i = 0; i < 5; i++) {
|
invalid_ids[2] = 0;
|
||||||
for (j = 0; j < 3; j++) {
|
|
||||||
invalid_vss_commitment[i][j] = invalid_vss_pk;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** main test body **/
|
/** main test body **/
|
||||||
|
|
||||||
/** Key generation **/
|
/** Key generation **/
|
||||||
|
CHECK(secp256k1_frost_shares_trusted_gen(CTX, shares, pubshares, &pk, seed, 3, 5) == 1);
|
||||||
|
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_trusted_gen(CTX, NULL, pubshares, &pk, seed, 3, 5));
|
||||||
|
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_trusted_gen(CTX, shares, NULL, &pk, seed, 3, 5));
|
||||||
for (i = 0; i < 5; 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);
|
CHECK(frost_memcmp_and_randomize(shares[i].data, zeros68, sizeof(shares[i].data)) == 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_trusted_gen(CTX, shares, pubshares, NULL, seed, 3, 5));
|
||||||
/* Share aggregation */
|
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
for (j = 0; j < 5; j++) {
|
CHECK(frost_memcmp_and_randomize(shares[i].data, zeros68, sizeof(shares[i].data)) == 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_trusted_gen(CTX, shares, pubshares, &pk, NULL, 3, 5));
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
CHECK(frost_memcmp_and_randomize(shares[i].data, zeros68, sizeof(shares[i].data)) == 0);
|
||||||
|
}
|
||||||
|
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_trusted_gen(CTX, shares, pubshares, &pk, seed, 0, 5));
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
CHECK(frost_memcmp_and_randomize(shares[i].data, zeros68, sizeof(shares[i].data)) == 0);
|
||||||
|
}
|
||||||
|
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_trusted_gen(CTX, shares, pubshares, &pk, seed, 3, 0));
|
||||||
|
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_trusted_gen(CTX, shares, pubshares, &pk, seed, 3, 2));
|
||||||
|
|
||||||
/* Share verification */
|
CHECK(secp256k1_frost_shares_trusted_gen(CTX, shares, pubshares, &pk, seed, 3, 5) == 1);
|
||||||
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 */
|
/* pubkey_get */
|
||||||
CHECK(secp256k1_frost_pubkey_get(CTX, &full_agg_pk, &agg_pk) == 1);
|
CHECK(secp256k1_frost_pubkey_get(CTX, &full_pk, &pk) == 1);
|
||||||
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_get(CTX, NULL, &agg_pk));
|
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_get(CTX, NULL, &pk));
|
||||||
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_get(CTX, &full_agg_pk, NULL));
|
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_get(CTX, &full_pk, NULL));
|
||||||
CHECK(secp256k1_memcmp_var(&full_agg_pk, zeros68, sizeof(full_agg_pk)) == 0);
|
CHECK(secp256k1_memcmp_var(&full_pk, zeros68, sizeof(full_pk)) == 0);
|
||||||
|
|
||||||
/** Tweaking **/
|
/** Tweaking **/
|
||||||
|
|
||||||
/* pubkey_tweak */
|
/* pubkey_tweak */
|
||||||
CHECK(secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &agg_pk) == 1);
|
CHECK(secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &pk) == 1);
|
||||||
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_tweak(CTX, NULL, &agg_pk));
|
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_tweak(CTX, NULL, &pk));
|
||||||
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, NULL));
|
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, NULL));
|
||||||
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &invalid_pk));
|
CHECK_ILLEGAL(CTX, secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &invalid_pk));
|
||||||
|
|
||||||
CHECK(secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &agg_pk) == 1);
|
CHECK(secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &pk) == 1);
|
||||||
|
|
||||||
/* tweak_add */
|
/* tweak_add */
|
||||||
{
|
{
|
||||||
int (*tweak_func[2]) (const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_frost_tweak_cache *tweak_cache, const unsigned char *tweak32);
|
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[0] = secp256k1_frost_pubkey_ec_tweak_add;
|
||||||
tweak_func[1] = secp256k1_frost_pubkey_xonly_tweak_add;
|
tweak_func[1] = secp256k1_frost_pubkey_xonly_tweak_add;
|
||||||
CHECK(secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &agg_pk) == 1);
|
CHECK(secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &pk) == 1);
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
secp256k1_pubkey tmp_output_pk;
|
secp256k1_pubkey tmp_output_pk;
|
||||||
secp256k1_frost_tweak_cache tmp_tweak_cache = tweak_cache;
|
secp256k1_frost_tweak_cache tmp_tweak_cache = tweak_cache;
|
||||||
@ -374,31 +248,31 @@ void frost_api_tests(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Session creation **/
|
/** Session creation **/
|
||||||
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &agg_share[0], msg, &agg_pk, max64) == 1);
|
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &shares[0], msg, &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(STATIC_CTX, secp256k1_frost_nonce_gen(STATIC_CTX, &secnonce[0], &pubnonce[0], session_id[0], &shares[0], msg, &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, NULL, &pubnonce[0], session_id[0], &shares[0], msg, &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], NULL, session_id[0], &shares[0], msg, &pk, max64));
|
||||||
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], NULL, &agg_share[0], msg, &agg_pk, max64));
|
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], NULL, &shares[0], msg, &pk, max64));
|
||||||
CHECK(frost_memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0);
|
CHECK(frost_memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0);
|
||||||
/* no seckey and session_id is 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(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], zeros68, NULL, msg, &pk, max64) == 0);
|
||||||
CHECK(frost_memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 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 */
|
/* 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], zeros68, &shares[0], msg, &pk, max64) == 1);
|
||||||
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], NULL, msg, &agg_pk, max64) == 1);
|
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], NULL, msg, &pk, max64) == 1);
|
||||||
/* invalid agg_share */
|
/* invalid share */
|
||||||
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &invalid_share, msg, &agg_pk, max64));
|
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &invalid_share, msg, &pk, max64));
|
||||||
CHECK(frost_memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0);
|
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], &shares[0], NULL, &pk, max64) == 1);
|
||||||
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &agg_share[0], msg, NULL, max64) == 1);
|
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &shares[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_ILLEGAL(CTX, secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &shares[0], msg, &invalid_pk, max64));
|
||||||
CHECK(frost_memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0);
|
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);
|
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], &shares[0], msg, &pk, NULL) == 1);
|
||||||
|
|
||||||
/* Every in-argument except session_id can be NULL */
|
/* 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[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[1], &pubnonce[1], session_id[1], &shares[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);
|
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[2], &pubnonce[2], session_id[2], &shares[2], NULL, NULL, NULL) == 1);
|
||||||
|
|
||||||
/** Serialize and parse public nonces **/
|
/** Serialize and parse public nonces **/
|
||||||
CHECK_ILLEGAL(CTX, secp256k1_frost_pubnonce_serialize(CTX, NULL, &pubnonce[0]));
|
CHECK_ILLEGAL(CTX, secp256k1_frost_pubnonce_serialize(CTX, NULL, &pubnonce[0]));
|
||||||
@ -423,50 +297,51 @@ void frost_api_tests(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Process nonces **/
|
/** 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(secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, msg, &pk, ids[0], ids, &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, NULL, pubnonce_ptr, 3, msg, &pk, ids[0], ids, &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], NULL, 3, msg, &pk, ids[0], ids, &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], pubnonce_ptr, 0, msg, &pk, ids[0], ids, &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], invalid_pubnonce_ptr, 3, msg, &pk, ids[0], ids, &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, NULL, &pk, ids[0], ids, &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, NULL, ids[0], ids, &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, &pk, 0, ids, &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_ILLEGAL(CTX, secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, msg, &pk, ids[0], invalid_ids, &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, &pk, ids[0], NULL, &tweak_cache, &adaptor));
|
||||||
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, &pk, ids[0], ids, NULL, &adaptor) == 1);
|
||||||
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, &pk, ids[0], ids, &invalid_tweak_cache, &adaptor));
|
||||||
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, &pk, ids[0], ids, &tweak_cache, NULL) == 1);
|
||||||
|
CHECK_ILLEGAL(CTX, secp256k1_frost_nonce_process(CTX, &session[0], pubnonce_ptr, 3, msg, &pk, ids[0], ids, &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[0], pubnonce_ptr, 3, msg, &pk, ids[0], ids, &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[1], pubnonce_ptr, 3, msg, &pk, ids[1], ids, &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);
|
CHECK(secp256k1_frost_nonce_process(CTX, &session[2], pubnonce_ptr, 3, msg, &pk, ids[2], ids, &tweak_cache, &adaptor) == 1);
|
||||||
|
|
||||||
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
|
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);
|
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &shares[0], &session[0], &tweak_cache) == 1);
|
||||||
/* The secnonce is set to 0 and subsequent signing attempts fail */
|
/* The secnonce is set to 0 and subsequent signing attempts fail */
|
||||||
CHECK(secp256k1_memcmp_var(&secnonce_tmp, zeros68, sizeof(secnonce_tmp)) == 0);
|
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));
|
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &shares[0], &session[0], &tweak_cache));
|
||||||
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
|
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));
|
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, NULL, &secnonce_tmp, &shares[0], &session[0], &tweak_cache));
|
||||||
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
|
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], NULL, &shares[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], &invalid_secnonce, &shares[0], &session[0], &tweak_cache));
|
||||||
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, NULL, &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));
|
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));
|
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));
|
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));
|
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &shares[0], NULL, &tweak_cache));
|
||||||
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
|
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));
|
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &shares[0], &invalid_session, &tweak_cache));
|
||||||
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
|
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);
|
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &shares[0], &session[0], NULL) == 1);
|
||||||
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
|
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));
|
CHECK_ILLEGAL(CTX, secp256k1_frost_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &shares[0], &session[0], &invalid_tweak_cache));
|
||||||
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
|
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[0], &secnonce[0], &shares[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[1], &secnonce[1], &shares[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_sign(CTX, &partial_sig[2], &secnonce[2], &shares[2], &session[2], &tweak_cache) == 1);
|
||||||
|
|
||||||
CHECK(secp256k1_frost_partial_sig_serialize(CTX, buf, &partial_sig[0]) == 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, NULL, &partial_sig[0]));
|
||||||
@ -485,22 +360,22 @@ void frost_api_tests(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Partial signature verification */
|
/** 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[0], &pubnonce[0], &pubshares[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(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[0], &pubshares[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, NULL, &pubnonce[0], &pubshares[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, &invalid_partial_sig, &pubnonce[0], &pubshares[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], NULL, &pubshares[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], &invalid_pubnonce, &pubshares[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], 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], &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], &pubshares[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_ILLEGAL(CTX, secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pubshares[0], &invalid_session, &tweak_cache));
|
||||||
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pubshare[0], &session[0], NULL) == 1);
|
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pubshares[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_ILLEGAL(CTX, secp256k1_frost_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pubshares[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[0], &pubnonce[0], &pubshares[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[1], &pubnonce[1], &pubshares[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);
|
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[2], &pubnonce[2], &pubshares[2], &session[2], &tweak_cache) == 1);
|
||||||
|
|
||||||
/** Signature aggregation and verification */
|
/** Signature aggregation and verification */
|
||||||
CHECK(secp256k1_frost_partial_sig_agg(CTX, pre_sig, &session[0], partial_sig_ptr, 3) == 1);
|
CHECK(secp256k1_frost_partial_sig_agg(CTX, pre_sig, &session[0], partial_sig_ptr, 3) == 1);
|
||||||
@ -530,10 +405,10 @@ void frost_api_tests(void) {
|
|||||||
/* sig and pre_sig argument point to the same location */
|
/* sig and pre_sig argument point to the same location */
|
||||||
memcpy(final_sig, pre_sig, sizeof(final_sig));
|
memcpy(final_sig, pre_sig, sizeof(final_sig));
|
||||||
CHECK(secp256k1_frost_adapt(CTX, final_sig, final_sig, sec_adaptor, nonce_parity) == 1);
|
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_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), &pk) == 1);
|
||||||
|
|
||||||
CHECK(secp256k1_frost_adapt(CTX, final_sig, pre_sig, sec_adaptor, nonce_parity) == 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);
|
CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), &pk) == 1);
|
||||||
|
|
||||||
/** Secret adaptor can be extracted from signature */
|
/** Secret adaptor can be extracted from signature */
|
||||||
CHECK(secp256k1_frost_extract_adaptor(CTX, sec_adaptor1, final_sig, pre_sig, nonce_parity) == 1);
|
CHECK(secp256k1_frost_extract_adaptor(CTX, sec_adaptor1, final_sig, pre_sig, nonce_parity) == 1);
|
||||||
@ -607,37 +482,9 @@ void frost_nonce_test(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
/* Attempts to create a signature for the aggregate public key using given secret
|
||||||
* keys and tweak_cache. */
|
* 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) {
|
void frost_tweak_test_helper(const secp256k1_xonly_pubkey* pk, const secp256k1_frost_share *sr0, const secp256k1_frost_share *sr1, const secp256k1_frost_share *sr2, secp256k1_frost_tweak_cache *tweak_cache, const size_t *ids, const secp256k1_pubkey *sr_pk0, const secp256k1_pubkey *sr_pk1, const secp256k1_pubkey *sr_pk2) {
|
||||||
unsigned char session_id[3][32];
|
unsigned char session_id[3][32];
|
||||||
unsigned char msg[32];
|
unsigned char msg[32];
|
||||||
secp256k1_frost_secnonce secnonce[3];
|
secp256k1_frost_secnonce secnonce[3];
|
||||||
@ -662,9 +509,9 @@ void frost_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const secp256
|
|||||||
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[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_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[0], pubnonce_ptr, 3, msg, pk, ids[0], ids, 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[1], pubnonce_ptr, 3, msg, pk, ids[1], ids, 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_nonce_process(CTX, &session[2], pubnonce_ptr, 3, msg, pk, ids[2], ids, 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[0], &secnonce[0], sr0, &session[0], tweak_cache) == 1);
|
||||||
@ -676,51 +523,31 @@ void frost_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const secp256
|
|||||||
CHECK(secp256k1_frost_partial_sig_verify(CTX, &partial_sig[2], &pubnonce[2], sr_pk2, &session[2], 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_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);
|
CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), pk) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create aggregate public key P[0], tweak multiple times (using xonly and
|
/* Create aggregate public key P[0], tweak multiple times (using xonly and
|
||||||
* ordinary tweaking) and test signing. */
|
* ordinary tweaking) and test signing. */
|
||||||
void frost_tweak_test(void) {
|
void frost_tweak_test(void) {
|
||||||
unsigned char sk[5][32];
|
secp256k1_pubkey pubshares[5];
|
||||||
secp256k1_pubkey pubshare[5];
|
|
||||||
secp256k1_frost_tweak_cache tweak_cache;
|
secp256k1_frost_tweak_cache tweak_cache;
|
||||||
enum { N_TWEAKS = 8 };
|
enum { N_TWEAKS = 8 };
|
||||||
secp256k1_pubkey P[N_TWEAKS + 1];
|
secp256k1_pubkey P[N_TWEAKS + 1];
|
||||||
secp256k1_xonly_pubkey P_xonly[N_TWEAKS + 1];
|
secp256k1_xonly_pubkey P_xonly[N_TWEAKS + 1];
|
||||||
unsigned char seed[5][32];
|
unsigned char seed[32];
|
||||||
secp256k1_pubkey vss_commitment[5][3];
|
secp256k1_frost_share shares[5];
|
||||||
const secp256k1_pubkey *vss_ptr[5];
|
int i;
|
||||||
unsigned char pok[5][64];
|
size_t ids[5];
|
||||||
secp256k1_frost_share shares[5][5];
|
|
||||||
const secp256k1_frost_share *share_ptr[5];
|
secp256k1_testrand256(seed);
|
||||||
secp256k1_frost_share agg_share[5];
|
|
||||||
int i, j;
|
|
||||||
unsigned char id[5][33];
|
|
||||||
const unsigned char *id_ptr[5];
|
|
||||||
|
|
||||||
/* Key Setup */
|
/* Key Setup */
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
secp256k1_testrand256(seed[i]);
|
ids[i] = i + 1;
|
||||||
secp256k1_testrand256(sk[i]);
|
}
|
||||||
vss_ptr[i] = vss_commitment[i];
|
CHECK(secp256k1_frost_shares_trusted_gen(CTX, shares, pubshares, &P_xonly[0], seed, 3, 5) == 1);
|
||||||
id_ptr[i] = id[i];
|
|
||||||
|
|
||||||
CHECK(frost_create_pk(id[i], sk[i]));
|
frost_tweak_test_helper(&P_xonly[0], &shares[0], &shares[1], &shares[2], NULL, ids, &pubshares[0], &pubshares[1], &pubshares[2]);
|
||||||
}
|
|
||||||
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_get(CTX, &P[0], &P_xonly[0]));
|
||||||
CHECK(secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &P_xonly[0]) == 1);
|
CHECK(secp256k1_frost_pubkey_tweak(CTX, &tweak_cache, &P_xonly[0]) == 1);
|
||||||
|
|
||||||
@ -752,37 +579,22 @@ void frost_tweak_test(void) {
|
|||||||
CHECK(secp256k1_memcmp_var(&tmp_key, &P[i], sizeof(tmp_key)) == 0);
|
CHECK(secp256k1_memcmp_var(&tmp_key, &P[i], sizeof(tmp_key)) == 0);
|
||||||
}
|
}
|
||||||
/* Test signing for P[i] */
|
/* 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]);
|
frost_tweak_test_helper(&P_xonly[i], &shares[0], &shares[1], &shares[2], &tweak_cache, ids, &pubshares[0], &pubshares[1], &pubshares[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Performs a FROST DKG */
|
/* Performs a FROST DKG */
|
||||||
void frost_dkg_test_helper(secp256k1_frost_share *agg_share, secp256k1_xonly_pubkey *agg_pk, const unsigned char * const* ids33) {
|
void frost_dkg_test_helper(secp256k1_frost_share *shares, secp256k1_xonly_pubkey *pk) {
|
||||||
secp256k1_pubkey vss_commitment[5][3];
|
unsigned char seed[32];
|
||||||
const secp256k1_pubkey *vss_ptr[5];
|
secp256k1_pubkey pubshares[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);
|
||||||
secp256k1_testrand256(seed[i]);
|
|
||||||
vss_ptr[i] = vss_commitment[i];
|
CHECK(secp256k1_frost_shares_trusted_gen(CTX, shares, pubshares, pk, seed, 3, 5) == 1);
|
||||||
}
|
|
||||||
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 */
|
/* 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) {
|
int frost_sign_test_helper(unsigned char *final_sig, const secp256k1_frost_share *share, const secp256k1_xonly_pubkey *pk, const unsigned char *msg, const secp256k1_pubkey *adaptor) {
|
||||||
unsigned char session_id[3][32];
|
unsigned char session_id[3][32];
|
||||||
secp256k1_frost_secnonce secnonce[3];
|
secp256k1_frost_secnonce secnonce[3];
|
||||||
secp256k1_frost_pubnonce pubnonce[3];
|
secp256k1_frost_pubnonce pubnonce[3];
|
||||||
@ -793,20 +605,22 @@ int frost_sign_test_helper(unsigned char *final_sig, const secp256k1_frost_share
|
|||||||
int i;
|
int i;
|
||||||
int nonce_parity;
|
int nonce_parity;
|
||||||
secp256k1_frost_session_internal session_i;
|
secp256k1_frost_session_internal session_i;
|
||||||
|
size_t ids[5];
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
pubnonce_ptr[i] = &pubnonce[i];
|
pubnonce_ptr[i] = &pubnonce[i];
|
||||||
partial_sig_ptr[i] = &partial_sig[i];
|
partial_sig_ptr[i] = &partial_sig[i];
|
||||||
|
ids[i] = i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
secp256k1_testrand256(session_id[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);
|
CHECK(secp256k1_frost_nonce_gen(CTX, &secnonce[i], &pubnonce[i], session_id[i], &share[i], NULL, NULL, NULL) == 1);
|
||||||
}
|
}
|
||||||
for (i = 0; i < 3; i++) {
|
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_nonce_process(CTX, &session, pubnonce_ptr, 3, msg, pk, i + 1, ids, NULL, adaptor) == 1);
|
||||||
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[i], &secnonce[i], &agg_share[i], &session, NULL) == 1);
|
CHECK(secp256k1_frost_partial_sign(CTX, &partial_sig[i], &secnonce[i], &share[i], &session, NULL) == 1);
|
||||||
}
|
}
|
||||||
CHECK(secp256k1_frost_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, 3) == 1);
|
CHECK(secp256k1_frost_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, 3) == 1);
|
||||||
|
|
||||||
@ -824,12 +638,10 @@ void frost_rand_scalar(secp256k1_scalar *scalar) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void frost_multi_hop_lock_tests(void) {
|
void frost_multi_hop_lock_tests(void) {
|
||||||
secp256k1_frost_share agg_share_a[5];
|
secp256k1_frost_share share_a[5];
|
||||||
secp256k1_frost_share agg_share_b[5];
|
secp256k1_frost_share share_b[5];
|
||||||
secp256k1_xonly_pubkey agg_pk_a;
|
secp256k1_xonly_pubkey agg_pk_a;
|
||||||
secp256k1_xonly_pubkey agg_pk_b;
|
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_ab[64];
|
||||||
unsigned char asig_bc[64];
|
unsigned char asig_bc[64];
|
||||||
unsigned char pop[32];
|
unsigned char pop[32];
|
||||||
@ -845,29 +657,12 @@ void frost_multi_hop_lock_tests(void) {
|
|||||||
unsigned char sig_bc[64];
|
unsigned char sig_bc[64];
|
||||||
int nonce_parity_ab;
|
int nonce_parity_ab;
|
||||||
int nonce_parity_bc;
|
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 */
|
/* Alice DKG */
|
||||||
for (i = 0; i < 5; i++) {
|
frost_dkg_test_helper(share_a, &agg_pk_a);
|
||||||
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 */
|
/* Bob DKG */
|
||||||
for (i = 0; i < 5; i++) {
|
frost_dkg_test_helper(share_b, &agg_pk_b);
|
||||||
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 */
|
/* Carol setup */
|
||||||
/* Proof of payment */
|
/* Proof of payment */
|
||||||
@ -888,13 +683,13 @@ void frost_multi_hop_lock_tests(void) {
|
|||||||
CHECK(secp256k1_eckey_pubkey_tweak_add(&r_ge, &tp));
|
CHECK(secp256k1_eckey_pubkey_tweak_add(&r_ge, &tp));
|
||||||
secp256k1_pubkey_save(&r, &r_ge);
|
secp256k1_pubkey_save(&r, &r_ge);
|
||||||
/* Encrypt Alice's signature with the left lock as the encryption key */
|
/* 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);
|
nonce_parity_ab = frost_sign_test_helper(asig_ab, share_a, &agg_pk_a, tx_ab, &l);
|
||||||
|
|
||||||
/* Bob setup */
|
/* Bob setup */
|
||||||
CHECK(secp256k1_frost_verify_adaptor(CTX, asig_ab, tx_ab, &agg_pk_a, &l, nonce_parity_ab) == 1);
|
CHECK(secp256k1_frost_verify_adaptor(CTX, asig_ab, tx_ab, &agg_pk_a, &l, nonce_parity_ab) == 1);
|
||||||
secp256k1_testrand256(tx_bc);
|
secp256k1_testrand256(tx_bc);
|
||||||
/* Encrypt Bob's signature with the right lock as the encryption key */
|
/* 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);
|
nonce_parity_bc = frost_sign_test_helper(asig_bc, share_b, &agg_pk_b, tx_bc, &r);
|
||||||
|
|
||||||
/* Carol decrypt */
|
/* Carol decrypt */
|
||||||
CHECK(secp256k1_frost_verify_adaptor(CTX, asig_bc, tx_bc, &agg_pk_b, &r, nonce_parity_bc) == 1);
|
CHECK(secp256k1_frost_verify_adaptor(CTX, asig_bc, tx_bc, &agg_pk_b, &r, nonce_parity_bc) == 1);
|
||||||
|
@ -276,6 +276,7 @@ static void secp256k1_pedersen_commitment_save(secp256k1_pedersen_commitment* co
|
|||||||
|
|
||||||
int secp256k1_pedersen_commitment_parse(const secp256k1_context* ctx, secp256k1_pedersen_commitment* commit, const unsigned char *input) {
|
int secp256k1_pedersen_commitment_parse(const secp256k1_context* ctx, secp256k1_pedersen_commitment* commit, const unsigned char *input) {
|
||||||
secp256k1_fe x;
|
secp256k1_fe x;
|
||||||
|
secp256k1_ge ge;
|
||||||
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
VERIFY_CHECK(ctx != NULL);
|
||||||
ARG_CHECK(commit != NULL);
|
ARG_CHECK(commit != NULL);
|
||||||
@ -284,20 +285,28 @@ int secp256k1_pedersen_commitment_parse(const secp256k1_context* ctx, secp256k1_
|
|||||||
|
|
||||||
if ((input[0] & 0xFE) != 8 ||
|
if ((input[0] & 0xFE) != 8 ||
|
||||||
!secp256k1_fe_set_b32_limit(&x, &input[1]) ||
|
!secp256k1_fe_set_b32_limit(&x, &input[1]) ||
|
||||||
!secp256k1_ge_x_on_curve_var(&x)) {
|
!secp256k1_ge_set_xquad(&ge, &x)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (input[0] & 1) {
|
||||||
memcpy(commit->data, input, 33);
|
secp256k1_ge_neg(&ge, &ge);
|
||||||
|
}
|
||||||
|
secp256k1_pedersen_commitment_save(commit, &ge);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int secp256k1_pedersen_commitment_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pedersen_commitment* commit) {
|
int secp256k1_pedersen_commitment_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pedersen_commitment* commit) {
|
||||||
|
secp256k1_ge ge;
|
||||||
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
VERIFY_CHECK(ctx != NULL);
|
||||||
ARG_CHECK(output != NULL);
|
ARG_CHECK(output != NULL);
|
||||||
ARG_CHECK(commit != NULL);
|
ARG_CHECK(commit != NULL);
|
||||||
|
|
||||||
memcpy(output, commit->data, 33);
|
secp256k1_pedersen_commitment_load(&ge, commit);
|
||||||
|
|
||||||
|
output[0] = 9 ^ secp256k1_fe_is_square_var(&ge.y);
|
||||||
|
secp256k1_fe_normalize_var(&ge.x);
|
||||||
|
secp256k1_fe_get_b32(&output[1], &ge.x);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,13 +264,7 @@ static void test_pedersen(void) {
|
|||||||
}
|
}
|
||||||
CHECK(secp256k1_pedersen_blind_sum(CTX, &blinds[(total - 1) * 32], bptr, total - 1, inputs));
|
CHECK(secp256k1_pedersen_blind_sum(CTX, &blinds[(total - 1) * 32], bptr, total - 1, inputs));
|
||||||
for (i = 0; i < total; i++) {
|
for (i = 0; i < total; i++) {
|
||||||
unsigned char result[33];
|
|
||||||
secp256k1_pedersen_commitment parse;
|
|
||||||
|
|
||||||
CHECK(secp256k1_pedersen_commit(CTX, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
|
CHECK(secp256k1_pedersen_commit(CTX, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
|
||||||
CHECK(secp256k1_pedersen_commitment_serialize(CTX, result, &commits[i]));
|
|
||||||
CHECK(secp256k1_pedersen_commitment_parse(CTX, &parse, result));
|
|
||||||
CHECK(secp256k1_memcmp_var(&commits[i], &parse, 33) == 0);
|
|
||||||
}
|
}
|
||||||
CHECK(secp256k1_pedersen_verify_tally(CTX, cptr, inputs, &cptr[inputs], outputs));
|
CHECK(secp256k1_pedersen_verify_tally(CTX, cptr, inputs, &cptr[inputs], outputs));
|
||||||
CHECK(secp256k1_pedersen_verify_tally(CTX, &cptr[inputs], outputs, cptr, inputs));
|
CHECK(secp256k1_pedersen_verify_tally(CTX, &cptr[inputs], outputs, cptr, inputs));
|
||||||
|
@ -889,6 +889,10 @@ static int secp256k1_ge_parse_ext(secp256k1_ge* ge, const unsigned char *in33) {
|
|||||||
# include "modules/ecdsa_adaptor/main_impl.h"
|
# include "modules/ecdsa_adaptor/main_impl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_MODULE_FROST
|
||||||
|
# include "modules/frost/main_impl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_MODULE_MUSIG
|
#ifdef ENABLE_MODULE_MUSIG
|
||||||
# include "modules/musig/main_impl.h"
|
# include "modules/musig/main_impl.h"
|
||||||
#endif
|
#endif
|
||||||
@ -908,7 +912,3 @@ static int secp256k1_ge_parse_ext(secp256k1_ge* ge, const unsigned char *in33) {
|
|||||||
#ifdef ENABLE_MODULE_SURJECTIONPROOF
|
#ifdef ENABLE_MODULE_SURJECTIONPROOF
|
||||||
# include "modules/surjection/main_impl.h"
|
# include "modules/surjection/main_impl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_MODULE_FROST
|
|
||||||
# include "modules/frost/main_impl.h"
|
|
||||||
#endif
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user