Compare commits

..

11 Commits

Author SHA1 Message Date
Jesse Posner
536b0458ad
frost trusted dealer: use set_int instead of clear 2024-05-15 12:53:45 -07:00
Jesse Posner
d3ef472559
frost trusted dealer: improve doc based upon PR feedback 2024-05-15 12:52:48 -07:00
Jesse Posner
e94367c83e
frost trusted dealer: Add documentation file
This commit adds a documentation file with instructions for how to use
the module.
2024-05-14 15:29:07 -07:00
Jesse Posner
1b9567289b
frost trusted dealer: add tests
Add api tests, nonce tests, tweak tests, sha256 tag tests, and constant
time tests.
2024-05-14 15:29:03 -07:00
Jesse Posner
fb34b29d7f
frost trusted dealer: add example file
This commit adds an example file to demonstrate how to use the module.
2024-05-14 15:28:12 -07:00
Jesse Posner
9170dd337c
frost trusted dealer: signature generation and aggregation
This commit adds signature generation and aggregation, as well as
partial signature serialization and parsing.
2024-05-14 15:28:12 -07:00
Jesse Posner
ea059393f0
frost trusted dealer: nonce aggregation and adaptor signatures
This commit adds nonce aggregation, as well as adaptor signatures.
2024-05-14 15:28:12 -07:00
Jesse Posner
5368c81a3c
frost trusted dealer: key tweaking
This commits add BIP-341 ("Taproot") and BIP-32 ("ordinary") public key
tweaking.
2024-05-14 15:28:00 -07:00
Jesse Posner
9b852191de
frost trusted dealer: nonce generation
This commits adds nonce generation, as well as serialization and
parsing.
2024-05-14 15:26:35 -07:00
Jesse Posner
8969cee21c
frost trusted dealer: share generation
This commit adds trusted share generation, as well as share
serialization and parsing.
2024-05-14 14:32:10 -07:00
Jesse Posner
6f47d2eb22
frost trusted dealer: initialize project
This commit adds the foundational configuration and building scripts
and an initial structure for the project.
2024-05-14 14:32:05 -07:00
19 changed files with 358 additions and 1052 deletions

View File

@ -703,7 +703,7 @@ 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' }

1
.gitignore vendored
View File

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

View File

@ -3,7 +3,7 @@ libsecp256k1-zkp
![Dependencies: None](https://img.shields.io/badge/dependencies-none-success) ![Dependencies: None](https://img.shields.io/badge/dependencies-none-success)
A fork of [libsecp256k1](https://github.com/bitcoin-core/secp256k1) with support for advanced and experimental features such as Confidential Assets, 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.

View File

@ -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

View File

@ -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"

View File

@ -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;

View File

@ -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)
@ -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)

View File

@ -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 */

View File

@ -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.*
***********************************************************************/ ***********************************************************************/

View File

@ -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`.

View File

@ -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

View File

@ -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,253 +110,68 @@ 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;
secp256k1_scalar_set_int(&share_i, 0);
for (j = 0; j < threshold; j++) {
unsigned char buf[32];
secp256k1_scalar coeff_i;
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"FROST/trusted-shares-coeffgen", sizeof("FROST/trusted-shares-coeffgen") - 1);
secp256k1_sha256_write(&sha, polygen, 32);
secp256k1_write_be64(&buf[0], j);
secp256k1_sha256_write(&sha, buf, 8);
secp256k1_sha256_finalize(&sha, buf);
secp256k1_scalar_set_b32(&coeff_i, buf, NULL);
/* Horner's method to evaluate polynomial to derive shares */
secp256k1_scalar_add(&share_i, &share_i, &coeff_i);
if (j < threshold - 1) {
secp256k1_scalar_set_int(&idx, i + 1);
secp256k1_scalar_mul(&share_i, &share_i, &idx);
} }
return ret; /* Compute x-only public key for constant term */
} if (i == 0 && j == threshold - 1) {
/* Compute commitment to constant term */
typedef struct { secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &coeff_i);
const secp256k1_context *ctx; secp256k1_ge_set_gej(&rp, &rj);
secp256k1_scalar idx; /* The commitment is non-secret so it can be declassified to
secp256k1_scalar idxn; * allow branching. */
const secp256k1_pubkey * const* vss_commitment; secp256k1_declassify(ctx, &rp, sizeof(rp));
} secp256k1_frost_verify_share_ecmult_data; secp256k1_fe_normalize_var(&rp.y);
pk_parity = secp256k1_extrakeys_ge_even_y(&rp);
typedef struct { secp256k1_xonly_pubkey_save(pk, &rp);
const secp256k1_context *ctx;
secp256k1_scalar idx;
secp256k1_scalar idxn;
const secp256k1_pubkey * const* vss_commitments;
size_t threshold;
} secp256k1_frost_compute_pubshare_ecmult_data;
typedef struct {
const secp256k1_context *ctx;
const secp256k1_pubkey * const* pks;
size_t threshold;
} secp256k1_frost_pubkey_combine_ecmult_data;
static int secp256k1_frost_verify_share_ecmult_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
secp256k1_frost_verify_share_ecmult_data *ctx = (secp256k1_frost_verify_share_ecmult_data *) data;
if (!secp256k1_pubkey_load(ctx->ctx, pt, *(ctx->vss_commitment)+idx)) {
return 0;
} }
*sc = ctx->idxn;
secp256k1_scalar_mul(&ctx->idxn, &ctx->idxn, &ctx->idx);
return 1;
}
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]);
secp256k1_scalar_add(&acc, &acc, &share_i);
}
/* 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) { if (pk_parity == 1) {
secp256k1_scalar_negate(&acc, &acc); 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);
} }
secp256k1_frost_share_save(agg_share, &acc);
return ret; return ret;
} }

View File

@ -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.*
**********************************************************************/ **********************************************************************/

View File

@ -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.*
**********************************************************************/ **********************************************************************/

View File

@ -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);

View File

@ -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)); CHECK_ILLEGAL(CTX, secp256k1_frost_shares_trusted_gen(CTX, shares, pubshares, NULL, seed, 3, 5));
for (j = 0; j < 5; j++) {
CHECK(frost_memcmp_and_randomize(shares[i][j].data, zeros68, sizeof(shares[i][j].data)) == 0);
}
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], NULL, 3, 5, id_ptr));
for (j = 0; j < 5; j++) {
CHECK(frost_memcmp_and_randomize(shares[i][j].data, zeros68, sizeof(shares[i][j].data)) == 0);
}
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 0, 5, id_ptr));
for (j = 0; j < 5; j++) {
CHECK(frost_memcmp_and_randomize(shares[i][j].data, zeros68, sizeof(shares[i][j].data)) == 0);
}
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 3, 0, id_ptr));
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 3, 2, id_ptr));
CHECK_ILLEGAL(CTX, secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 3, 5, NULL));
for (j = 0; j < 5; j++) {
CHECK(frost_memcmp_and_randomize(shares[i][j].data, zeros68, sizeof(shares[i][j].data)) == 0);
}
CHECK(secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 3, 5, id_ptr) == 1);
}
/* Share aggregation */
for (i = 0; i < 5; i++) { for (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_shares_trusted_gen(CTX, shares, pubshares, &pk, NULL, 3, 5));
CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, NULL, &agg_pk, share_ptr, vss_ptr, 5, 3, id_ptr[i])); for (i = 0; i < 5; 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(shares[i].data, zeros68, sizeof(shares[i].data)) == 0);
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, 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);

View File

@ -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;
} }

View File

@ -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));

View File

@ -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