diff --git a/include/secp256k1_musig.h b/include/secp256k1_musig.h index b1c5b912..c5352512 100644 --- a/include/secp256k1_musig.h +++ b/include/secp256k1_musig.h @@ -1,6 +1,8 @@ #ifndef SECP256K1_MUSIG_H #define SECP256K1_MUSIG_H +#include "secp256k1_extrakeys.h" + #ifdef __cplusplus extern "C" { #endif @@ -8,15 +10,30 @@ extern "C" { #include /** This module implements a Schnorr-based multi-signature scheme called MuSig - * (https://eprint.iacr.org/2018/068.pdf). There's an example C source file in the - * module's directory (src/modules/musig/example.c) that demonstrates how it can be - * used. + * (https://eprint.iacr.org/2018/068.pdf). It is compatible with bip-schnorr. + * There's an example C source file in the module's directory + * (src/modules/musig/example.c) that demonstrates how it can be used. * * The documentation in this include file is for reference and may not be sufficient * for users to begin using the library. A full description of API usage can be found * in src/modules/musig/musig.md */ +/** Data structure containing auxiliary data generated in `pubkey_combine` and + * required for `session_*_initialize`. + * Fields: + * magic: Set during initialization in `pubkey_combine` in order to allow + * detecting an uninitialized object. + * pk_hash: The 32-byte hash of the original public keys + * is_negated: Whether the MuSig-aggregated point was negated when + * converting it to the combined xonly pubkey. + */ +typedef struct { + uint64_t magic; + unsigned char pk_hash[32]; + int is_negated; +} secp256k1_musig_pre_session; + /** Data structure containing data related to a signing session resulting in a single * signature. * @@ -28,14 +45,14 @@ extern "C" { * structure. * * Fields: - * combined_pk: MuSig-computed combined public key + * combined_pk: MuSig-computed combined xonly public key + * pre_session: Auxiliary data created in `pubkey_combine` * n_signers: Number of signers - * pk_hash: The 32-byte hash of the original public keys * combined_nonce: Summed combined public nonce (undefined if `nonce_is_set` is false) * nonce_is_set: Whether the above nonce has been set * nonce_is_negated: If `nonce_is_set`, whether the above nonce was negated after * summing the participants' nonces. Needed to ensure the nonce's y - * coordinate has a quadratic-residue y coordinate + * coordinate is even. * msg: The 32-byte message (hash) to be signed * msg_is_set: Whether the above message has been set * has_secret_data: Whether this session object has a signers' secret data; if this @@ -49,9 +66,9 @@ extern "C" { * nonce_commitments_hash has been set */ typedef struct { - secp256k1_pubkey combined_pk; + secp256k1_xonly_pubkey combined_pk; + secp256k1_musig_pre_session pre_session; uint32_t n_signers; - unsigned char pk_hash[32]; secp256k1_pubkey combined_nonce; int nonce_is_set; int nonce_is_negated; @@ -119,9 +136,9 @@ typedef struct { * (cannot be NULL) * scratch: scratch space used to compute the combined pubkey by * multiexponentiation. If NULL, an inefficient algorithm is used. - * Out: combined_pk: the MuSig-combined public key (cannot be NULL) - * pk_hash32: if non-NULL, filled with the 32-byte hash of all input public - * keys in order to be used in `musig_session_initialize`. + * Out: combined_pk: the MuSig-combined xonly public key (cannot be NULL) + * pre_session: if non-NULL, pointer to a musig_pre_session struct to be used in + * `musig_session_initialize`. * In: pubkeys: input array of public keys to combine. The order is important; * a different order will result in a different combined public * key (cannot be NULL) @@ -130,9 +147,9 @@ typedef struct { SECP256K1_API int secp256k1_musig_pubkey_combine( const secp256k1_context* ctx, secp256k1_scratch_space *scratch, - secp256k1_pubkey *combined_pk, - unsigned char *pk_hash32, - const secp256k1_pubkey *pubkeys, + secp256k1_xonly_pubkey *combined_pk, + secp256k1_musig_pre_session *pre_session, + const secp256k1_xonly_pubkey *pubkeys, size_t n_pubkeys ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); @@ -154,9 +171,9 @@ SECP256K1_API int secp256k1_musig_pubkey_combine( * require sharing nonce commitments before the message is known * because it reduces nonce misuse resistance. If NULL, must be * set with `musig_session_get_public_nonce`. - * combined_pk: the combined public key of all signers (cannot be NULL) - * pk_hash32: the 32-byte hash of the signers' individual keys (cannot be - * NULL) + * combined_pk: the combined xonly public key of all signers (cannot be NULL) + * pre_session: pointer to a musig_pre_session struct from + * `musig_pubkey_combine` (cannot be NULL) * n_signers: length of signers array. Number of signers participating in * the MuSig. Must be greater than 0 and at most 2^32 - 1. * my_index: index of this signer in the signers array @@ -169,8 +186,8 @@ SECP256K1_API int secp256k1_musig_session_initialize( unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, - const secp256k1_pubkey *combined_pk, - const unsigned char *pk_hash32, + const secp256k1_xonly_pubkey *combined_pk, + const secp256k1_musig_pre_session *pre_session, size_t n_signers, size_t my_index, const unsigned char *seckey @@ -213,7 +230,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_publi * signers: an array of signers' data to be initialized. Array length must * equal to `n_signers`(cannot be NULL) * In: msg32: the 32-byte message to be signed (cannot be NULL) - * combined_pk: the combined public key of all signers (cannot be NULL) + * combined_pk: the combined xonly public key of all signers (cannot be NULL) + * pre_session: pointer to a musig_pre_session struct from + * `musig_pubkey_combine` (cannot be NULL) * pk_hash32: the 32-byte hash of the signers' individual keys (cannot be NULL) * commitments: array of 32-byte nonce commitments. Array length must equal to * `n_signers` (cannot be NULL) @@ -226,8 +245,8 @@ SECP256K1_API int secp256k1_musig_session_initialize_verifier( secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, const unsigned char *msg32, - const secp256k1_pubkey *combined_pk, - const unsigned char *pk_hash32, + const secp256k1_xonly_pubkey *combined_pk, + const secp256k1_musig_pre_session *pre_session, const unsigned char *const *commitments, size_t n_signers ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7); @@ -343,7 +362,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verif const secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signer, const secp256k1_musig_partial_signature *partial_sig, - const secp256k1_pubkey *pubkey + const secp256k1_xonly_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); /** Combines partial signatures @@ -354,23 +373,16 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verif * Args: ctx: pointer to a context object (cannot be NULL) * session: initialized session for which the combined nonce has been * computed (cannot be NULL) - * Out: sig: complete signature (cannot be NULL) + * Out: sig64: complete signature (cannot be NULL) * In: partial_sigs: array of partial signatures to combine (cannot be NULL) * n_sigs: number of signatures in the partial_sigs array - * tweak32: if `combined_pk` was tweaked with `ec_pubkey_tweak_add` after - * `musig_pubkey_combine` and before `musig_session_initialize` then - * the same tweak must be provided here in order to get a valid - * signature for the tweaked key. Otherwise `tweak` should be NULL. - * If the tweak is larger than the group order or 0 this function will - * return 0. (can be NULL) */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_combine( const secp256k1_context* ctx, const secp256k1_musig_session *session, - secp256k1_schnorrsig *sig, + unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, - size_t n_sigs, - const unsigned char *tweak32 + size_t n_sigs ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Converts a partial signature to an adaptor signature by adding a given secret @@ -403,7 +415,7 @@ SECP256K1_API int secp256k1_musig_partial_sig_adapt( * 0: otherwise * Args: ctx: pointer to a context object (cannot be NULL) * Out:sec_adaptor32: 32-byte secret adaptor (cannot be NULL) - * In: sig: complete 2-of-2 signature (cannot be NULL) + * In: sig64: complete 2-of-2 signature (cannot be NULL) * partial_sigs: array of partial signatures (cannot be NULL) * n_partial_sigs: number of elements in partial_sigs array * nonce_is_negated: the `nonce_is_negated` output of `musig_session_combine_nonces` @@ -411,7 +423,7 @@ SECP256K1_API int secp256k1_musig_partial_sig_adapt( SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_secret_adaptor( const secp256k1_context* ctx, unsigned char *sec_adaptor32, - const secp256k1_schnorrsig *sig, + const unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, size_t n_partial_sigs, int nonce_is_negated diff --git a/src/modules/musig/example.c b/src/modules/musig/example.c index b4c9a95d..4670d442 100644 --- a/src/modules/musig/example.c +++ b/src/modules/musig/example.c @@ -18,8 +18,9 @@ /* Number of public keys involved in creating the aggregate signature */ #define N_SIGNERS 3 /* Create a key pair and store it in seckey and pubkey */ -int create_key(const secp256k1_context* ctx, unsigned char* seckey, secp256k1_pubkey* pubkey) { +int create_keypair(const secp256k1_context* ctx, unsigned char *seckey, secp256k1_xonly_pubkey *pubkey) { int ret; + secp256k1_keypair keypair; FILE *frand = fopen("/dev/urandom", "r"); if (frand == NULL) { return 0; @@ -32,12 +33,14 @@ int create_key(const secp256k1_context* ctx, unsigned char* seckey, secp256k1_pu /* The probability that this not a valid secret key is approximately 2^-128 */ } while (!secp256k1_ec_seckey_verify(ctx, seckey)); fclose(frand); - ret = secp256k1_ec_pubkey_create(ctx, pubkey, seckey); + ret = secp256k1_keypair_create(ctx, &keypair, seckey); + ret &= secp256k1_keypair_xonly_pub(ctx, pubkey, NULL, &keypair); + return ret; } /* Sign a message hash with the given key pairs and store the result in sig */ -int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp256k1_pubkey* pubkeys, const unsigned char* msg32, secp256k1_schnorrsig *sig) { +int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp256k1_xonly_pubkey* pubkeys, const unsigned char* msg32, unsigned char *sig64) { secp256k1_musig_session musig_session[N_SIGNERS]; unsigned char nonce_commitment[N_SIGNERS][32]; const unsigned char *nonce_commitment_ptr[N_SIGNERS]; @@ -49,11 +52,11 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25 for (i = 0; i < N_SIGNERS; i++) { FILE *frand; unsigned char session_id32[32]; - unsigned char pk_hash[32]; - secp256k1_pubkey combined_pk; + secp256k1_xonly_pubkey combined_pk; + secp256k1_musig_pre_session pre_session; /* Create combined pubkey and initialize signer data */ - if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, pk_hash, pubkeys, N_SIGNERS)) { + if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, &pre_session, pubkeys, N_SIGNERS)) { return 0; } /* Create random session ID. It is absolutely necessary that the session ID @@ -69,7 +72,7 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25 } fclose(frand); /* Initialize session */ - if (!secp256k1_musig_session_initialize(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, pk_hash, N_SIGNERS, i, seckeys[i])) { + if (!secp256k1_musig_session_initialize(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, &pre_session, N_SIGNERS, i, seckeys[i])) { return 0; } nonce_commitment_ptr[i] = &nonce_commitment[i][0]; @@ -119,23 +122,23 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25 } } } - return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig, partial_sig, N_SIGNERS, NULL); + return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig64, partial_sig, N_SIGNERS); } int main(void) { secp256k1_context* ctx; int i; unsigned char seckeys[N_SIGNERS][32]; - secp256k1_pubkey pubkeys[N_SIGNERS]; - secp256k1_pubkey combined_pk; + secp256k1_xonly_pubkey pubkeys[N_SIGNERS]; + secp256k1_xonly_pubkey combined_pk; unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!"; - secp256k1_schnorrsig sig; + unsigned char sig[64]; /* Create a context for signing and verification */ ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); printf("Creating key pairs......"); for (i = 0; i < N_SIGNERS; i++) { - if (!create_key(ctx, seckeys[i], &pubkeys[i])) { + if (!create_keypair(ctx, seckeys[i], &pubkeys[i])) { printf("FAILED\n"); return 1; } @@ -148,13 +151,13 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25 } printf("ok\n"); printf("Signing message........."); - if (!sign(ctx, seckeys, pubkeys, msg, &sig)) { + if (!sign(ctx, seckeys, pubkeys, msg, sig)) { printf("FAILED\n"); return 1; } printf("ok\n"); printf("Verifying signature....."); - if (!secp256k1_schnorrsig_verify(ctx, &sig, msg, &combined_pk)) { + if (!secp256k1_schnorrsig_verify(ctx, sig, msg, &combined_pk)) { printf("FAILED\n"); return 1; } diff --git a/src/modules/musig/main_impl.h b/src/modules/musig/main_impl.h index d1123539..5f9cb0d0 100644 --- a/src/modules/musig/main_impl.h +++ b/src/modules/musig/main_impl.h @@ -7,23 +7,23 @@ #ifndef _SECP256K1_MODULE_MUSIG_MAIN_ #define _SECP256K1_MODULE_MUSIG_MAIN_ +#include #include "include/secp256k1.h" #include "include/secp256k1_musig.h" #include "hash.h" /* Computes ell = SHA256(pk[0], ..., pk[np-1]) */ -static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned char *ell, const secp256k1_pubkey *pk, size_t np) { +static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned char *ell, const secp256k1_xonly_pubkey *pk, size_t np) { secp256k1_sha256 sha; size_t i; secp256k1_sha256_initialize(&sha); for (i = 0; i < np; i++) { - unsigned char ser[33]; - size_t serlen = sizeof(ser); - if (!secp256k1_ec_pubkey_serialize(ctx, ser, &serlen, &pk[i], SECP256K1_EC_COMPRESSED)) { + unsigned char ser[32]; + if (!secp256k1_xonly_pubkey_serialize(ctx, ser, &pk[i])) { return 0; } - secp256k1_sha256_write(&sha, ser, serlen); + secp256k1_sha256_write(&sha, ser, 32); } secp256k1_sha256_finalize(&sha, ell); return 1; @@ -77,14 +77,14 @@ static void secp256k1_musig_coefficient(secp256k1_scalar *r, const unsigned char typedef struct { const secp256k1_context *ctx; unsigned char ell[32]; - const secp256k1_pubkey *pks; + const secp256k1_xonly_pubkey *pks; } secp256k1_musig_pubkey_combine_ecmult_data; /* Callback for batch EC multiplication to compute ell_0*P0 + ell_1*P1 + ... */ static int secp256k1_musig_pubkey_combine_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) { secp256k1_musig_pubkey_combine_ecmult_data *ctx = (secp256k1_musig_pubkey_combine_ecmult_data *) data; secp256k1_musig_coefficient(sc, ctx->ell, idx); - return secp256k1_pubkey_load(ctx->ctx, pt, &ctx->pks[idx]); + return secp256k1_xonly_pubkey_load(ctx->ctx, pt, &ctx->pks[idx]); } @@ -97,10 +97,13 @@ static void secp256k1_musig_signers_init(secp256k1_musig_session_signer_data *si } } -int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_pubkey *combined_pk, unsigned char *pk_hash32, const secp256k1_pubkey *pubkeys, size_t n_pubkeys) { +static const uint64_t pre_session_magic = 0xf4adbbdf7c7dd304UL; + +int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, const secp256k1_xonly_pubkey *pubkeys, size_t n_pubkeys) { secp256k1_musig_pubkey_combine_ecmult_data ecmult_data; secp256k1_gej pkj; secp256k1_ge pkp; + int is_negated; VERIFY_CHECK(ctx != NULL); ARG_CHECK(combined_pk != NULL); @@ -117,23 +120,26 @@ int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scrat return 0; } secp256k1_ge_set_gej(&pkp, &pkj); - secp256k1_pubkey_save(combined_pk, &pkp); + secp256k1_fe_normalize(&pkp.y); + is_negated = secp256k1_extrakeys_ge_even_y(&pkp); + secp256k1_xonly_pubkey_save(combined_pk, &pkp); - if (pk_hash32 != NULL) { - memcpy(pk_hash32, ecmult_data.ell, 32); + if (pre_session != NULL) { + pre_session->magic = pre_session_magic; + memcpy(pre_session->pk_hash, ecmult_data.ell, 32); + pre_session->is_negated = is_negated; } return 1; } -int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_pubkey *combined_pk, const unsigned char *pk_hash32, size_t n_signers, size_t my_index, const unsigned char *seckey) { - unsigned char combined_ser[33]; - size_t combined_ser_size = sizeof(combined_ser); +int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, size_t n_signers, size_t my_index, const unsigned char *seckey) { + unsigned char combined_ser[32]; int overflow; secp256k1_scalar secret; secp256k1_scalar mu; secp256k1_sha256 sha; - secp256k1_gej rj; - secp256k1_ge rp; + secp256k1_gej pj; + secp256k1_ge p; VERIFY_CHECK(ctx != NULL); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); @@ -142,7 +148,8 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m ARG_CHECK(nonce_commitment32 != NULL); ARG_CHECK(session_id32 != NULL); ARG_CHECK(combined_pk != NULL); - ARG_CHECK(pk_hash32 != NULL); + ARG_CHECK(pre_session != NULL); + ARG_CHECK(pre_session->magic == pre_session_magic); ARG_CHECK(seckey != NULL); memset(session, 0, sizeof(*session)); @@ -154,7 +161,7 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m session->msg_is_set = 0; } memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk)); - memcpy(session->pk_hash, pk_hash32, 32); + session->pre_session = *pre_session; session->nonce_is_set = 0; session->has_secret_data = 1; if (n_signers == 0 || my_index >= n_signers) { @@ -173,7 +180,25 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m secp256k1_scalar_clear(&secret); return 0; } - secp256k1_musig_coefficient(&mu, pk_hash32, (uint32_t) my_index); + secp256k1_musig_coefficient(&mu, session->pre_session.pk_hash, (uint32_t) my_index); + /* Compute the signers public key point and determine if the secret needs to + * be negated before signing. If the signer's pubkey is negated XOR the + * MuSig-combined pubkey is negated the secret has to be negated. This can + * be seen by looking at the secret key belonging to `combined_pk`. Let's + * define + * P' := mu_0*|P_0| + ... + mu_n*|P_n| where P_i is the i-th public key + * point x_i*G, mu_i is the i-th musig coefficient and |.| is a function + * that normalizes a point to an even Y by negating if necessary similar to + * secp256k1_extrakeys_ge_even_y. Then we have + * P := |P'| the combined xonly public key. Also, P = x*G where x = + * sum_i(b_i*mu_i*x_i) and b_i = -1 if (P != |P'| XOR P_i != |P_i|) and 1 + * otherwise. */ + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret); + secp256k1_ge_set_gej(&p, &pj); + secp256k1_fe_normalize(&p.y); + if (secp256k1_fe_is_odd(&p.y) != session->pre_session.is_negated) { + secp256k1_scalar_negate(&secret, &secret); + } secp256k1_scalar_mul(&secret, &secret, &mu); secp256k1_scalar_get_b32(session->seckey, &secret); @@ -183,8 +208,8 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m if (session->msg_is_set) { secp256k1_sha256_write(&sha, msg32, 32); } - secp256k1_ec_pubkey_serialize(ctx, combined_ser, &combined_ser_size, combined_pk, SECP256K1_EC_COMPRESSED); - secp256k1_sha256_write(&sha, combined_ser, combined_ser_size); + secp256k1_xonly_pubkey_serialize(ctx, combined_ser, combined_pk); + secp256k1_sha256_write(&sha, combined_ser, 32); secp256k1_sha256_write(&sha, seckey, 32); secp256k1_sha256_finalize(&sha, session->secnonce); secp256k1_scalar_set_b32(&secret, session->secnonce, &overflow); @@ -194,9 +219,9 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m } /* Compute public nonce and commitment */ - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &secret); - secp256k1_ge_set_gej(&rp, &rj); - secp256k1_pubkey_save(&session->nonce, &rp); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret); + secp256k1_ge_set_gej(&p, &pj); + secp256k1_pubkey_save(&session->nonce, &p); if (nonce_commitment32 != NULL) { unsigned char commit[33]; @@ -256,7 +281,7 @@ int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp2 return 1; } -int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, const unsigned char *msg32, const secp256k1_pubkey *combined_pk, const unsigned char *pk_hash32, const unsigned char *const *commitments, size_t n_signers) { +int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, const unsigned char *msg32, const secp256k1_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, const unsigned char *const *commitments, size_t n_signers) { size_t i; VERIFY_CHECK(ctx != NULL); @@ -264,7 +289,8 @@ int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, se ARG_CHECK(signers != NULL); ARG_CHECK(msg32 != NULL); ARG_CHECK(combined_pk != NULL); - ARG_CHECK(pk_hash32 != NULL); + ARG_CHECK(pre_session != NULL); + ARG_CHECK(pre_session->magic == pre_session_magic); ARG_CHECK(commitments != NULL); /* Check n_signers before checking commitments to allow testing the case where * n_signers is big without allocating the space. */ @@ -279,13 +305,14 @@ int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, se memset(session, 0, sizeof(*session)); memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk)); + session->pre_session = *pre_session; if (n_signers == 0) { return 0; } session->n_signers = (uint32_t) n_signers; secp256k1_musig_signers_init(signers, session->n_signers); - memcpy(session->pk_hash, pk_hash32, 32); + session->pre_session = *pre_session; session->nonce_is_set = 0; session->msg_is_set = 1; memcpy(session->msg, msg32, 32); @@ -365,7 +392,8 @@ int secp256k1_musig_session_combine_nonces(const secp256k1_context* ctx, secp256 secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL); } secp256k1_ge_set_gej(&combined_noncep, &combined_noncej); - if (secp256k1_fe_is_quad_var(&combined_noncep.y)) { + secp256k1_fe_normalize(&combined_noncep.y); + if (!secp256k1_fe_is_odd(&combined_noncep.y)) { session->nonce_is_negated = 0; } else { session->nonce_is_negated = 1; @@ -397,21 +425,20 @@ int secp256k1_musig_partial_signature_parse(const secp256k1_context* ctx, secp25 /* Compute msghash = SHA256(combined_nonce, combined_pk, msg) */ static int secp256k1_musig_compute_messagehash(const secp256k1_context *ctx, unsigned char *msghash, const secp256k1_musig_session *session) { - unsigned char buf[33]; - size_t bufsize = 33; + unsigned char buf[32]; secp256k1_ge rp; secp256k1_sha256 sha; - secp256k1_sha256_initialize(&sha); + secp256k1_schnorrsig_sha256_tagged(&sha); if (!session->nonce_is_set) { return 0; } secp256k1_pubkey_load(ctx, &rp, &session->combined_nonce); secp256k1_fe_get_b32(buf, &rp.x); secp256k1_sha256_write(&sha, buf, 32); - secp256k1_ec_pubkey_serialize(ctx, buf, &bufsize, &session->combined_pk, SECP256K1_EC_COMPRESSED); - VERIFY_CHECK(bufsize == 33); - secp256k1_sha256_write(&sha, buf, bufsize); + + secp256k1_xonly_pubkey_serialize(ctx, buf, &session->combined_pk); + secp256k1_sha256_write(&sha, buf, 32); if (!session->msg_is_set) { return 0; } @@ -466,14 +493,14 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, const secp256k1_m return 1; } -int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_schnorrsig *sig, const secp256k1_musig_partial_signature *partial_sigs, size_t n_sigs, const unsigned char *tweak32) { +int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp256k1_musig_session *session, unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, size_t n_sigs) { size_t i; secp256k1_scalar s; secp256k1_ge noncep; (void) ctx; VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); + ARG_CHECK(sig64 != NULL); ARG_CHECK(partial_sigs != NULL); ARG_CHECK(session != NULL); @@ -495,40 +522,23 @@ int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp secp256k1_scalar_add(&s, &s, &term); } - /* If there is a tweak then add `msghash` times `tweak` to `s`.*/ - if (tweak32 != NULL) { - unsigned char msghash[32]; - secp256k1_scalar e, scalar_tweak; - int overflow = 0; - - if (!secp256k1_musig_compute_messagehash(ctx, msghash, session)) { - return 0; - } - secp256k1_scalar_set_b32(&e, msghash, NULL); - secp256k1_scalar_set_b32(&scalar_tweak, tweak32, &overflow); - if (overflow || !secp256k1_eckey_privkey_tweak_mul(&e, &scalar_tweak)) { - /* This mimics the behavior of secp256k1_ec_privkey_tweak_mul regarding - * overflow and tweak32 being 0. */ - return 0; - } - secp256k1_scalar_add(&s, &s, &e); - } - secp256k1_pubkey_load(ctx, &noncep, &session->combined_nonce); - VERIFY_CHECK(secp256k1_fe_is_quad_var(&noncep.y)); + VERIFY_CHECK(!secp256k1_fe_is_odd(&noncep.y)); secp256k1_fe_normalize(&noncep.x); - secp256k1_fe_get_b32(&sig->data[0], &noncep.x); - secp256k1_scalar_get_b32(&sig->data[32], &s); + secp256k1_fe_get_b32(&sig64[0], &noncep.x); + secp256k1_scalar_get_b32(&sig64[32], &s); return 1; } -int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signer, const secp256k1_musig_partial_signature *partial_sig, const secp256k1_pubkey *pubkey) { +int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signer, const secp256k1_musig_partial_signature *partial_sig, const secp256k1_xonly_pubkey *pubkey) { unsigned char msghash[32]; secp256k1_scalar s; secp256k1_scalar e; secp256k1_scalar mu; + secp256k1_gej pkj; secp256k1_gej rj; + secp256k1_ge pkp; secp256k1_ge rp; int overflow; @@ -554,16 +564,27 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2 /* Multiplying the messagehash by the musig coefficient is equivalent * to multiplying the signer's public key by the coefficient, except * much easier to do. */ - secp256k1_musig_coefficient(&mu, session->pk_hash, signer->index); + secp256k1_musig_coefficient(&mu, session->pre_session.pk_hash, signer->index); secp256k1_scalar_mul(&e, &e, &mu); if (!secp256k1_pubkey_load(ctx, &rp, &signer->nonce)) { return 0; } + /* If the MuSig-combined point is negated, the signers will sign for the + * negation of their individual xonly public key such that the combined + * signature is valid for the MuSig aggregated xonly key. */ + if (session->pre_session.is_negated) { + secp256k1_scalar_negate(&e, &e); + } - if (!secp256k1_schnorrsig_real_verify(ctx, &rj, &s, &e, pubkey)) { + /* Compute rj = s*G + (-e)*pkj */ + secp256k1_scalar_negate(&e, &e); + if (!secp256k1_xonly_pubkey_load(ctx, &pkp, pubkey)) { return 0; } + secp256k1_gej_set_ge(&pkj, &pkp); + secp256k1_ecmult(&ctx->ecmult_ctx, &rj, &pkj, &e, &s); + if (!session->nonce_is_negated) { secp256k1_ge_neg(&rp, &rp); } @@ -603,7 +624,7 @@ int secp256k1_musig_partial_sig_adapt(const secp256k1_context* ctx, secp256k1_mu return 1; } -int secp256k1_musig_extract_secret_adaptor(const secp256k1_context* ctx, unsigned char *sec_adaptor32, const secp256k1_schnorrsig *sig, const secp256k1_musig_partial_signature *partial_sigs, size_t n_partial_sigs, int nonce_is_negated) { +int secp256k1_musig_extract_secret_adaptor(const secp256k1_context* ctx, unsigned char *sec_adaptor32, const unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, size_t n_partial_sigs, int nonce_is_negated) { secp256k1_scalar t; secp256k1_scalar s; int overflow; @@ -612,10 +633,10 @@ int secp256k1_musig_extract_secret_adaptor(const secp256k1_context* ctx, unsigne (void) ctx; VERIFY_CHECK(ctx != NULL); ARG_CHECK(sec_adaptor32 != NULL); - ARG_CHECK(sig != NULL); + ARG_CHECK(sig64 != NULL); ARG_CHECK(partial_sigs != NULL); - secp256k1_scalar_set_b32(&t, &sig->data[32], &overflow); + secp256k1_scalar_set_b32(&t, &sig64[32], &overflow); if (overflow) { return 0; } diff --git a/src/modules/musig/tests_impl.h b/src/modules/musig/tests_impl.h index ce5b37d0..0930e90a 100644 --- a/src/modules/musig/tests_impl.h +++ b/src/modules/musig/tests_impl.h @@ -9,6 +9,69 @@ #include "secp256k1_musig.h" +int secp256k1_xonly_pubkey_create(secp256k1_xonly_pubkey *pk, const unsigned char *seckey) { + int ret; + secp256k1_keypair keypair; + ret = secp256k1_keypair_create(ctx, &keypair, seckey); + ret &= secp256k1_keypair_xonly_pub(ctx, pk, NULL, &keypair); + return ret; +} + +/* Just a simple (non-adaptor, non-tweaked) 2-of-2 MuSig combine, sign, verify + * test. */ +void musig_simple_test(secp256k1_scratch_space *scratch) { + unsigned char sk[2][32]; + secp256k1_musig_session session[2]; + secp256k1_musig_session_signer_data signer0[2]; + secp256k1_musig_session_signer_data signer1[2]; + unsigned char nonce_commitment[2][32]; + unsigned char msg[32]; + secp256k1_xonly_pubkey combined_pk; + secp256k1_musig_pre_session pre_session; + unsigned char session_id[2][32]; + secp256k1_xonly_pubkey pk[2]; + const unsigned char *ncs[2]; + secp256k1_pubkey public_nonce[3]; + secp256k1_musig_partial_signature partial_sig[2]; + unsigned char final_sig[64]; + + secp256k1_rand256(session_id[0]); + secp256k1_rand256(session_id[1]); + secp256k1_rand256(sk[0]); + secp256k1_rand256(sk[1]); + secp256k1_rand256(msg); + + CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1); + CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1); + + CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk, 2) == 1); + CHECK(secp256k1_musig_session_initialize(ctx, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1); + CHECK(secp256k1_musig_session_initialize(ctx, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1); + + ncs[0] = nonce_commitment[0]; + ncs[1] = nonce_commitment[1]; + + CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signer0, &public_nonce[0], ncs, 2, NULL) == 1); + CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signer1, &public_nonce[1], ncs, 2, NULL) == 1); + + CHECK(secp256k1_musig_set_nonce(ctx, &signer0[0], &public_nonce[0]) == 1); + CHECK(secp256k1_musig_set_nonce(ctx, &signer0[1], &public_nonce[1]) == 1); + CHECK(secp256k1_musig_set_nonce(ctx, &signer1[0], &public_nonce[0]) == 1); + CHECK(secp256k1_musig_set_nonce(ctx, &signer1[1], &public_nonce[1]) == 1); + + CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signer0, 2, NULL, NULL) == 1); + CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signer1, 2, NULL, NULL) == 1); + + CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1); + CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1); + CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1); + CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signer0[1], &partial_sig[1], &pk[1]) == 1); + CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signer1[1], &partial_sig[1], &pk[1]) == 1); + + CHECK(secp256k1_musig_partial_sig_combine(ctx, &session[0], final_sig, partial_sig, 2) == 1); + CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, &combined_pk) == 1); +} + void musig_api_tests(secp256k1_scratch_space *scratch) { secp256k1_scratch_space *scratch_small; secp256k1_musig_session session[2]; @@ -19,8 +82,8 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { secp256k1_musig_partial_signature partial_sig[2]; secp256k1_musig_partial_signature partial_sig_adapted[2]; secp256k1_musig_partial_signature partial_sig_overflow; - secp256k1_schnorrsig final_sig; - secp256k1_schnorrsig final_sig_cmp; + unsigned char final_sig[64]; + unsigned char final_sig_cmp[64]; unsigned char buf[32]; unsigned char sk[2][32]; @@ -31,9 +94,10 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { const unsigned char *ncs[2]; unsigned char msg[32]; unsigned char msghash[32]; - secp256k1_pubkey combined_pk; - unsigned char pk_hash[32]; - secp256k1_pubkey pk[2]; + secp256k1_xonly_pubkey combined_pk; + secp256k1_musig_pre_session pre_session; + secp256k1_musig_pre_session pre_session_uninitialized; + secp256k1_xonly_pubkey pk[2]; unsigned char tweak[32]; unsigned char sec_adaptor[32]; @@ -54,6 +118,10 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); memset(ones, 0xff, 32); + /* Simulate pre_session being uninitialized by setting it to 0s. Actually providing + * an unitialized pre_session object to a initialize_*_session would be undefined + * behavior */ + memset(&pre_session_uninitialized, 0, sizeof(pre_session_uninitialized)); secp256k1_rand256(session_id[0]); secp256k1_rand256(session_id[1]); @@ -63,104 +131,108 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { secp256k1_rand256(sec_adaptor); secp256k1_rand256(tweak); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1); + CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1); + CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1); CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor) == 1); + /** main test body **/ /* Key combination */ ecount = 0; - CHECK(secp256k1_musig_pubkey_combine(none, scratch, &combined_pk, pk_hash, pk, 2) == 0); + CHECK(secp256k1_musig_pubkey_combine(none, scratch, &combined_pk, &pre_session, pk, 2) == 0); CHECK(ecount == 1); - CHECK(secp256k1_musig_pubkey_combine(sign, scratch, &combined_pk, pk_hash, pk, 2) == 0); + CHECK(secp256k1_musig_pubkey_combine(sign, scratch, &combined_pk, &pre_session, pk, 2) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1); + CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1); CHECK(ecount == 2); /* pubkey_combine does not require a scratch space */ - CHECK(secp256k1_musig_pubkey_combine(vrfy, NULL, &combined_pk, pk_hash, pk, 2) == 1); + CHECK(secp256k1_musig_pubkey_combine(vrfy, NULL, &combined_pk, &pre_session, pk, 2) == 1); CHECK(ecount == 2); /* A small scratch space works too, but will result in using an ineffecient algorithm */ scratch_small = secp256k1_scratch_space_create(ctx, 1); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, pk_hash, pk, 2) == 1); + CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, &pre_session, pk, 2) == 1); secp256k1_scratch_space_destroy(ctx, scratch_small); CHECK(ecount == 2); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, NULL, pk_hash, pk, 2) == 0); + CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, NULL, &pre_session, pk, 2) == 0); CHECK(ecount == 3); CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, NULL, pk, 2) == 1); CHECK(ecount == 3); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, NULL, 2) == 0); + CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, NULL, 2) == 0); CHECK(ecount == 4); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 0) == 0); + CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 0) == 0); CHECK(ecount == 5); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, NULL, 0) == 0); + CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, NULL, 0) == 0); CHECK(ecount == 6); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1); + CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1); + CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1); + CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1); /** Session creation **/ ecount = 0; - CHECK(secp256k1_musig_session_initialize(none, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_initialize(none, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0); CHECK(ecount == 1); - CHECK(secp256k1_musig_session_initialize(vrfy, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_initialize(vrfy, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); + CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1); CHECK(ecount == 2); - CHECK(secp256k1_musig_session_initialize(sign, NULL, signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_initialize(sign, NULL, signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0); CHECK(ecount == 3); - CHECK(secp256k1_musig_session_initialize(sign, &session[0], NULL, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_initialize(sign, &session[0], NULL, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0); CHECK(ecount == 4); - CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, NULL, session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, NULL, session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0); CHECK(ecount == 5); - CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], NULL, msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], NULL, msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0); CHECK(ecount == 6); - CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); + CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, &pre_session, 2, 0, sk[0]) == 1); CHECK(ecount == 6); - CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, NULL, pk_hash, 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, NULL, &pre_session, 2, 0, sk[0]) == 0); CHECK(ecount == 7); CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, NULL, 2, 0, sk[0]) == 0); CHECK(ecount == 8); - CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 0, 0, sk[0]) == 0); - CHECK(ecount == 8); + /* Uninitialized pre_session */ + CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session_uninitialized, 2, 0, sk[0]) == 0); + CHECK(ecount == 9); + CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 0, 0, sk[0]) == 0); + CHECK(ecount == 9); /* If more than UINT32_MAX fits in a size_t, test that session_initialize * rejects n_signers that high. */ if (SIZE_MAX > UINT32_MAX) { - CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, ((size_t) UINT32_MAX) + 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, ((size_t) UINT32_MAX) + 2, 0, sk[0]) == 0); } - CHECK(ecount == 8); - CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, NULL) == 0); CHECK(ecount == 9); + CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, NULL) == 0); + CHECK(ecount == 10); /* secret key overflows */ - CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, ones) == 0); - CHECK(ecount == 9); + CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, ones) == 0); + CHECK(ecount == 10); - CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); - CHECK(secp256k1_musig_session_initialize(sign, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, pk_hash, 2, 1, sk[1]) == 1); + CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1); + CHECK(secp256k1_musig_session_initialize(sign, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1); ncs[0] = nonce_commitment[0]; ncs[1] = nonce_commitment[1]; ecount = 0; - CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 1); + CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 1); CHECK(ecount == 0); - CHECK(secp256k1_musig_session_initialize_verifier(none, NULL, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 0); + CHECK(secp256k1_musig_session_initialize_verifier(none, NULL, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 0); CHECK(ecount == 1); - CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, NULL, &combined_pk, pk_hash, ncs, 2) == 0); + CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, NULL, &combined_pk, &pre_session, ncs, 2) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, NULL, pk_hash, ncs, 2) == 0); + CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, NULL, &pre_session, ncs, 2) == 0); CHECK(ecount == 3); CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, NULL, ncs, 2) == 0); CHECK(ecount == 4); - CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, NULL, 2) == 0); + CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, NULL, 2) == 0); CHECK(ecount == 5); - CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 0) == 0); + CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 0) == 0); CHECK(ecount == 5); if (SIZE_MAX > UINT32_MAX) { - CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, ((size_t) UINT32_MAX) + 2) == 0); + CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, ((size_t) UINT32_MAX) + 2) == 0); } CHECK(ecount == 5); - CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 1); + CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 1); CHECK(secp256k1_musig_compute_messagehash(none, msghash, &verifier_session) == 0); CHECK(secp256k1_musig_compute_messagehash(none, msghash, &session[0]) == 0); @@ -306,65 +378,59 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { /** Signing combining and verification */ ecount = 0; - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 2, NULL) == 1); - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2, NULL) == 1); - CHECK(memcmp(&final_sig, &final_sig_cmp, sizeof(final_sig)) == 0); - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2, NULL) == 1); - CHECK(memcmp(&final_sig, &final_sig_cmp, sizeof(final_sig)) == 0); + CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 2) == 1); + CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig_cmp, partial_sig_adapted, 2) == 1); + CHECK(memcmp(final_sig, final_sig_cmp, sizeof(final_sig)) == 0); + CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig_cmp, partial_sig_adapted, 2) == 1); + CHECK(memcmp(final_sig, final_sig_cmp, sizeof(final_sig)) == 0); - CHECK(secp256k1_musig_partial_sig_combine(none, NULL, &final_sig, partial_sig_adapted, 2, tweak) == 0); + CHECK(secp256k1_musig_partial_sig_combine(none, NULL, final_sig, partial_sig_adapted, 2) == 0); CHECK(ecount == 1); - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], NULL, partial_sig_adapted, 2, tweak) == 0); + CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], NULL, partial_sig_adapted, 2) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, NULL, 2, tweak) == 0); + CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, NULL, 2) == 0); CHECK(ecount == 3); { secp256k1_musig_partial_signature partial_sig_tmp[2]; partial_sig_tmp[0] = partial_sig_adapted[0]; partial_sig_tmp[1] = partial_sig_overflow; - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_tmp, 2, tweak) == 0); + CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_tmp, 2) == 0); } CHECK(ecount == 3); /* Wrong number of partial sigs */ - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 1, tweak) == 0); + CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 1) == 0); CHECK(ecount == 3); - { - /* Overflowing tweak */ - unsigned char overflowing_tweak[32]; - memset(overflowing_tweak, 0xff, sizeof(overflowing_tweak)); - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 2, overflowing_tweak) == 0); - CHECK(ecount == 3); - } - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 2, NULL) == 1); + CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 2) == 1); CHECK(ecount == 3); - CHECK(secp256k1_schnorrsig_verify(vrfy, &final_sig, msg, &combined_pk) == 1); + CHECK(secp256k1_schnorrsig_verify(vrfy, final_sig, msg, &combined_pk) == 1); /** Secret adaptor can be extracted from signature */ ecount = 0; - CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 2, nonce_is_negated) == 1); + CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 2, nonce_is_negated) == 1); CHECK(memcmp(sec_adaptor, sec_adaptor1, 32) == 0); - CHECK(secp256k1_musig_extract_secret_adaptor(none, NULL, &final_sig, partial_sig, 2, 0) == 0); + CHECK(secp256k1_musig_extract_secret_adaptor(none, NULL, final_sig, partial_sig, 2, 0) == 0); CHECK(ecount == 1); CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, NULL, partial_sig, 2, 0) == 0); CHECK(ecount == 2); { - secp256k1_schnorrsig final_sig_tmp = final_sig; - memcpy(&final_sig_tmp.data[32], ones, 32); - CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig_tmp, partial_sig, 2, nonce_is_negated) == 0); + unsigned char final_sig_tmp[64]; + memcpy(final_sig_tmp, final_sig, sizeof(final_sig_tmp)); + memcpy(&final_sig_tmp[32], ones, 32); + CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig_tmp, partial_sig, 2, nonce_is_negated) == 0); } CHECK(ecount == 2); - CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, NULL, 2, 0) == 0); + CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, NULL, 2, 0) == 0); CHECK(ecount == 3); { secp256k1_musig_partial_signature partial_sig_tmp[2]; partial_sig_tmp[0] = partial_sig[0]; partial_sig_tmp[1] = partial_sig_overflow; - CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig_tmp, 2, nonce_is_negated) == 0); + CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig_tmp, 2, nonce_is_negated) == 0); } CHECK(ecount == 3); - CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 0, 0) == 1); - CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 2, 1) == 1); + CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 0, 0) == 1); + CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 2, 1) == 1); /** cleanup **/ memset(&session, 0, sizeof(session)); @@ -380,26 +446,26 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { * ones and return the resulting messagehash. This should not result in a different * messagehash because the public keys of the signers are only used during session * initialization. */ -int musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, const unsigned char * const *nonce_commitments, unsigned char *msg, secp256k1_pubkey *nonce_other, unsigned char *sk, unsigned char *session_id) { +int musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp256k1_xonly_pubkey *pks, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, const unsigned char * const *nonce_commitments, unsigned char *msg, secp256k1_pubkey *nonce_other, unsigned char *sk, unsigned char *session_id) { secp256k1_musig_session session; secp256k1_musig_session session_tmp; unsigned char nonce_commitment[32]; secp256k1_musig_session_signer_data signers[2]; secp256k1_musig_session_signer_data signers_tmp[2]; unsigned char sk_dummy[32]; - secp256k1_pubkey pks_tmp[2]; - secp256k1_pubkey combined_pk_tmp; - unsigned char pk_hash_tmp[32]; + secp256k1_xonly_pubkey pks_tmp[2]; + secp256k1_xonly_pubkey combined_pk_tmp; + secp256k1_musig_pre_session pre_session_tmp; secp256k1_pubkey nonce; /* Set up signers with different public keys */ secp256k1_rand256(sk_dummy); pks_tmp[0] = pks[0]; - CHECK(secp256k1_ec_pubkey_create(ctx, &pks_tmp[1], sk_dummy) == 1); - CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk_tmp, pk_hash_tmp, pks_tmp, 2) == 1); - CHECK(secp256k1_musig_session_initialize(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, pk_hash_tmp, 2, 1, sk_dummy) == 1); + CHECK(secp256k1_xonly_pubkey_create(&pks_tmp[1], sk_dummy) == 1); + CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk_tmp, &pre_session_tmp, pks_tmp, 2) == 1); + CHECK(secp256k1_musig_session_initialize(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, &pre_session_tmp, 2, 1, sk_dummy) == 1); - CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1); + CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 0, sk) == 1); CHECK(memcmp(nonce_commitment, nonce_commitments[1], 32) == 0); /* Call get_public_nonce with different signers than the signers the session was * initialized with. */ @@ -417,7 +483,7 @@ int musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp256 * commitments of signers_other do not match the nonce commitments the new session * was initialized with. If do_test is 0, the correct signers are being used and * therefore the function should return 1. */ -int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, unsigned char *msg, unsigned char *sk, secp256k1_musig_session_signer_data *signers_other, int do_test) { +int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, unsigned char *msg, unsigned char *sk, secp256k1_musig_session_signer_data *signers_other, int do_test) { secp256k1_musig_session session; secp256k1_musig_session_signer_data signers[2]; secp256k1_musig_session_signer_data *signers_to_use; @@ -428,7 +494,7 @@ int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_pubkey *combin /* Initialize new signers */ secp256k1_rand256(session_id); - CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 1, sk) == 1); + CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 1, sk) == 1); ncs[0] = nonce_commitment_other; ncs[1] = nonce_commitment; CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2, NULL) == 1); @@ -448,7 +514,7 @@ int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_pubkey *combin * parameters but without a message. Will test that the message must be * provided with `get_public_nonce`. */ -void musig_state_machine_late_msg_test(secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, unsigned char *sk, unsigned char *session_id, unsigned char *msg) { +void musig_state_machine_late_msg_test(secp256k1_xonly_pubkey *pks, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, unsigned char *sk, unsigned char *session_id, unsigned char *msg) { /* Create context for testing ARG_CHECKs by setting an illegal_callback. */ secp256k1_context *ctx_tmp = secp256k1_context_create(SECP256K1_CONTEXT_NONE); int ecount = 0; @@ -460,7 +526,7 @@ void musig_state_machine_late_msg_test(secp256k1_pubkey *pks, secp256k1_pubkey * secp256k1_musig_partial_signature partial_sig; secp256k1_context_set_illegal_callback(ctx_tmp, counting_illegal_callback_fn, &ecount); - CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, NULL, combined_pk, pk_hash, 2, 1, sk) == 1); + CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, NULL, combined_pk, pre_session, 2, 1, sk) == 1); ncs[0] = nonce_commitment_other; ncs[1] = nonce_commitment; @@ -488,17 +554,17 @@ void musig_state_machine_late_msg_test(secp256k1_pubkey *pks, secp256k1_pubkey * * and tries to verify and combine partial sigs. If do_combine is 0, the * combine_nonces step is left out. In that case verify and combine should fail and * this function should return 0. */ -int musig_state_machine_missing_combine_test(secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, secp256k1_musig_partial_signature *partial_sig_other, unsigned char *msg, unsigned char *sk, unsigned char *session_id, secp256k1_musig_partial_signature *partial_sig, int do_combine) { +int musig_state_machine_missing_combine_test(secp256k1_xonly_pubkey *pks, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, secp256k1_musig_partial_signature *partial_sig_other, unsigned char *msg, unsigned char *sk, unsigned char *session_id, secp256k1_musig_partial_signature *partial_sig, int do_combine) { secp256k1_musig_session session; secp256k1_musig_session_signer_data signers[2]; unsigned char nonce_commitment[32]; const unsigned char *ncs[2]; secp256k1_pubkey nonce; secp256k1_musig_partial_signature partial_sigs[2]; - secp256k1_schnorrsig sig; + unsigned char sig[64]; int partial_verify, sig_combine; - CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 1, sk) == 1); + CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 1, sk) == 1); ncs[0] = nonce_commitment_other; ncs[1] = nonce_commitment; CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2, NULL) == 1); @@ -511,7 +577,7 @@ int musig_state_machine_missing_combine_test(secp256k1_pubkey *pks, secp256k1_pu CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1); } partial_verify = secp256k1_musig_partial_sig_verify(ctx, &session, signers, partial_sig_other, &pks[0]); - sig_combine = secp256k1_musig_partial_sig_combine(ctx, &session, &sig, partial_sigs, 2, NULL); + sig_combine = secp256k1_musig_partial_sig_combine(ctx, &session, sig, partial_sigs, 2); if (do_combine != 0) { /* Return 1 if both succeeded */ return partial_verify && sig_combine; @@ -529,9 +595,9 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) { unsigned char session_id[2][32]; unsigned char msg[32]; unsigned char sk[2][32]; - secp256k1_pubkey pk[2]; - secp256k1_pubkey combined_pk; - unsigned char pk_hash[32]; + secp256k1_xonly_pubkey pk[2]; + secp256k1_xonly_pubkey combined_pk; + secp256k1_musig_pre_session pre_session; secp256k1_pubkey nonce[2]; const unsigned char *ncs[2]; secp256k1_musig_partial_signature partial_sig[2]; @@ -547,11 +613,11 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) { secp256k1_rand256(sk[0]); secp256k1_rand256(sk[1]); secp256k1_rand256(msg); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1); - CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, pk_hash, pk, 2) == 1); - CHECK(secp256k1_musig_session_initialize(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); - CHECK(secp256k1_musig_session_initialize(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, &combined_pk, pk_hash, 2, 1, sk[1]) == 1); + CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1); + CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1); + CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk, 2) == 1); + CHECK(secp256k1_musig_session_initialize(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1); + CHECK(secp256k1_musig_session_initialize(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1); /* Set nonce commitments */ ncs[0] = nonce_commitment[0]; @@ -583,8 +649,8 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) { CHECK(secp256k1_musig_set_nonce(ctx, &signers1[1], &nonce[1]) == 1); /* Can't combine nonces from signers of a different session */ - CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, pk_hash, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 1) == 0); - CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, pk_hash, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 0) == 1); + CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, &pre_session, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 1) == 0); + CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, &pre_session, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 0) == 1); /* Partially sign */ CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1); @@ -597,7 +663,7 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) { * with different signers (i.e. they diff in public keys). This is because the * public keys of the signers is set in stone when initializing the session. */ CHECK(secp256k1_musig_compute_messagehash(ctx, msghash1, &session[1]) == 1); - CHECK(musig_state_machine_diff_signer_msghash_test(msghash2, pk, &combined_pk, pk_hash, ncs, msg, &nonce[0], sk[1], session_id[1]) == 1); + CHECK(musig_state_machine_diff_signer_msghash_test(msghash2, pk, &combined_pk, &pre_session, ncs, msg, &nonce[0], sk[1], session_id[1]) == 1); CHECK(memcmp(msghash1, msghash2, 32) == 0); CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1); @@ -605,11 +671,11 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) { /* Wrong signature */ CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[0], &pk[1]) == 0); /* Can't get the public nonce until msg is set */ - musig_state_machine_late_msg_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], sk[1], session_id[1], msg); + musig_state_machine_late_msg_test(pk, &combined_pk, &pre_session, nonce_commitment[0], &nonce[0], sk[1], session_id[1], msg); /* Can't verify and combine partial sigs until nonces are combined */ - CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 0) == 0); - CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 1) == 1); + CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, &pre_session, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 0) == 0); + CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, &pre_session, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 1) == 1); } } @@ -618,8 +684,8 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) { * while the indices 0 and 1 refer to the two signers. Here signer 0 is * sending a-coins to signer 1, while signer 1 is sending b-coins to signer * 0. Signer 0 produces the adaptor signatures. */ - secp256k1_schnorrsig final_sig_a; - secp256k1_schnorrsig final_sig_b; + unsigned char final_sig_a[64]; + unsigned char final_sig_b[64]; secp256k1_musig_partial_signature partial_sig_a[2]; secp256k1_musig_partial_signature partial_sig_b_adapted[2]; secp256k1_musig_partial_signature partial_sig_b[2]; @@ -629,12 +695,12 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) { unsigned char seckey_a[2][32]; unsigned char seckey_b[2][32]; - secp256k1_pubkey pk_a[2]; - secp256k1_pubkey pk_b[2]; - unsigned char pk_hash_a[32]; - unsigned char pk_hash_b[32]; - secp256k1_pubkey combined_pk_a; - secp256k1_pubkey combined_pk_b; + secp256k1_xonly_pubkey pk_a[2]; + secp256k1_xonly_pubkey pk_b[2]; + secp256k1_musig_pre_session pre_session_a; + secp256k1_musig_pre_session pre_session_b; + secp256k1_xonly_pubkey combined_pk_a; + secp256k1_xonly_pubkey combined_pk_b; secp256k1_musig_session musig_session_a[2]; secp256k1_musig_session musig_session_b[2]; unsigned char noncommit_a[2][32]; @@ -659,22 +725,22 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) { secp256k1_rand256(seckey_b[1]); secp256k1_rand256(sec_adaptor); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk_a[0], seckey_a[0])); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk_a[1], seckey_a[1])); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk_b[0], seckey_b[0])); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk_b[1], seckey_b[1])); + CHECK(secp256k1_xonly_pubkey_create(&pk_a[0], seckey_a[0])); + CHECK(secp256k1_xonly_pubkey_create(&pk_a[1], seckey_a[1])); + CHECK(secp256k1_xonly_pubkey_create(&pk_b[0], seckey_b[0])); + CHECK(secp256k1_xonly_pubkey_create(&pk_b[1], seckey_b[1])); CHECK(secp256k1_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor)); - CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_a, pk_hash_a, pk_a, 2)); - CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_b, pk_hash_b, pk_b, 2)); + CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_a, &pre_session_a, pk_a, 2)); + CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_b, &pre_session_b, pk_b, 2)); - CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_a[0], data_a, noncommit_a[0], seed, msg32_a, &combined_pk_a, pk_hash_a, 2, 0, seckey_a[0])); - CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_a[1], data_a, noncommit_a[1], seed, msg32_a, &combined_pk_a, pk_hash_a, 2, 1, seckey_a[1])); + CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_a[0], data_a, noncommit_a[0], seed, msg32_a, &combined_pk_a, &pre_session_a, 2, 0, seckey_a[0])); + CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_a[1], data_a, noncommit_a[1], seed, msg32_a, &combined_pk_a, &pre_session_a, 2, 1, seckey_a[1])); noncommit_a_ptr[0] = noncommit_a[0]; noncommit_a_ptr[1] = noncommit_a[1]; - CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_b[0], data_b, noncommit_b[0], seed, msg32_b, &combined_pk_b, pk_hash_b, 2, 0, seckey_b[0])); - CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_b[1], data_b, noncommit_b[1], seed, msg32_b, &combined_pk_b, pk_hash_b, 2, 1, seckey_b[1])); + CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_b[0], data_b, noncommit_b[0], seed, msg32_b, &combined_pk_b, &pre_session_b, 2, 0, seckey_b[0])); + CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_b[1], data_b, noncommit_b[1], seed, msg32_b, &combined_pk_b, &pre_session_b, 2, 1, seckey_b[1])); noncommit_b_ptr[0] = noncommit_b[0]; noncommit_b_ptr[1] = noncommit_b[1]; @@ -707,17 +773,17 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) { * is broadcasted by signer 0 to take B-coins. */ CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_b_adapted[0], &partial_sig_b[0], sec_adaptor, nonce_is_negated_b)); memcpy(&partial_sig_b_adapted[1], &partial_sig_b[1], sizeof(partial_sig_b_adapted[1])); - CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_b[0], &final_sig_b, partial_sig_b_adapted, 2, NULL) == 1); - CHECK(secp256k1_schnorrsig_verify(ctx, &final_sig_b, msg32_b, &combined_pk_b) == 1); + CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_b[0], final_sig_b, partial_sig_b_adapted, 2) == 1); + CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_b, msg32_b, &combined_pk_b) == 1); /* Step 6: Signer 1 extracts adaptor from the published signature, applies it to * other partial signature, and takes A-coins. */ - CHECK(secp256k1_musig_extract_secret_adaptor(ctx, sec_adaptor_extracted, &final_sig_b, partial_sig_b, 2, nonce_is_negated_b) == 1); + CHECK(secp256k1_musig_extract_secret_adaptor(ctx, sec_adaptor_extracted, final_sig_b, partial_sig_b, 2, nonce_is_negated_b) == 1); CHECK(memcmp(sec_adaptor_extracted, sec_adaptor, sizeof(sec_adaptor)) == 0); /* in real life we couldn't check this, of course */ CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_a[0], &partial_sig_a[0], sec_adaptor_extracted, nonce_is_negated_a)); CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_a[1], &partial_sig_a[1])); - CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_a[1], &final_sig_a, partial_sig_a, 2, NULL) == 1); - CHECK(secp256k1_schnorrsig_verify(ctx, &final_sig_a, msg32_a, &combined_pk_a) == 1); + CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_a[1], final_sig_a, partial_sig_a, 2) == 1); + CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_a, msg32_a, &combined_pk_a) == 1); } /* Checks that hash initialized by secp256k1_musig_sha256_init_tagged has the @@ -753,93 +819,13 @@ void sha256_tag_test(void) { CHECK(memcmp(buf, buf2, 32) == 0); } - -void musig_tweak_test_helper(const secp256k1_pubkey* combined_pubkey, const unsigned char *ec_commit_tweak, const unsigned char *sk0, const unsigned char *sk1, const unsigned char *pk_hash) { - secp256k1_musig_session session[2]; - secp256k1_musig_session_signer_data signers0[2]; - secp256k1_musig_session_signer_data signers1[2]; - secp256k1_pubkey pk[2]; - unsigned char session_id[2][32]; - unsigned char msg[32]; - unsigned char nonce_commitment[2][32]; - secp256k1_pubkey nonce[2]; - const unsigned char *ncs[2]; - secp256k1_musig_partial_signature partial_sig[2]; - secp256k1_schnorrsig final_sig; - - secp256k1_rand256(session_id[0]); - secp256k1_rand256(session_id[1]); - secp256k1_rand256(msg); - - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk0) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk1) == 1); - - /* want to show that can both sign for Q and P */ - CHECK(secp256k1_musig_session_initialize(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, combined_pubkey, pk_hash, 2, 0, sk0) == 1); - CHECK(secp256k1_musig_session_initialize(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, combined_pubkey, pk_hash, 2, 1, sk1) == 1); - /* Set nonce commitments */ - ncs[0] = nonce_commitment[0]; - ncs[1] = nonce_commitment[1]; - CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2, NULL) == 1); - CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signers1, &nonce[1], ncs, 2, NULL) == 1); - /* Set nonces */ - CHECK(secp256k1_musig_set_nonce(ctx, &signers0[0], &nonce[0]) == 1); - CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], &nonce[1]) == 1); - CHECK(secp256k1_musig_set_nonce(ctx, &signers1[0], &nonce[0]) == 1); - CHECK(secp256k1_musig_set_nonce(ctx, &signers1[1], &nonce[1]) == 1); - CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signers0, 2, NULL, NULL) == 1); - CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 1); - CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1); - CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1); - CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signers0[1], &partial_sig[1], &pk[1]) == 1); - CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 1); - CHECK(secp256k1_musig_partial_sig_combine(ctx, &session[0], &final_sig, partial_sig, 2, ec_commit_tweak)); - CHECK(secp256k1_schnorrsig_verify(ctx, &final_sig, msg, combined_pubkey) == 1); -} - -/* In this test we create a combined public key P and a commitment Q = P + - * hash(P, contract)*G. Then we test that we can sign for both public keys. In - * order to sign for Q we use the tweak32 argument of partial_sig_combine. */ -void musig_tweak_test(secp256k1_scratch_space *scratch) { - unsigned char sk[2][32]; - secp256k1_pubkey pk[2]; - unsigned char pk_hash[32]; - secp256k1_pubkey P; - unsigned char P_serialized[33]; - size_t compressed_size = 33; - secp256k1_pubkey Q; - - secp256k1_sha256 sha; - unsigned char contract[32]; - unsigned char ec_commit_tweak[32]; - - /* Setup */ - secp256k1_rand256(sk[0]); - secp256k1_rand256(sk[1]); - secp256k1_rand256(contract); - - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1); - CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &P, pk_hash, pk, 2) == 1); - - CHECK(secp256k1_ec_pubkey_serialize(ctx, P_serialized, &compressed_size, &P, SECP256K1_EC_COMPRESSED) == 1); - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, P_serialized, 33); - secp256k1_sha256_write(&sha, contract, 32); - secp256k1_sha256_finalize(&sha, ec_commit_tweak); - memcpy(&Q, &P, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &Q, ec_commit_tweak)); - - /* Test signing for P */ - musig_tweak_test_helper(&P, NULL, sk[0], sk[1], pk_hash); - /* Test signing for Q */ - musig_tweak_test_helper(&Q, ec_commit_tweak, sk[0], sk[1], pk_hash); -} - void run_musig_tests(void) { int i; secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024); + for (i = 0; i < count; i++) { + musig_simple_test(scratch); + } musig_api_tests(scratch); musig_state_machine_tests(scratch); for (i = 0; i < count; i++) { @@ -847,7 +833,6 @@ void run_musig_tests(void) { scriptless_atomic_swap(scratch); } sha256_tag_test(); - musig_tweak_test(scratch); secp256k1_scratch_space_destroy(ctx, scratch); } diff --git a/src/secp256k1.c b/src/secp256k1.c index dee63ac9..fb4283f1 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -768,14 +768,22 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey * # include "modules/ecdh/main_impl.h" #endif -#ifdef ENABLE_MODULE_MUSIG -# include "modules/musig/main_impl.h" -#endif - #ifdef ENABLE_MODULE_RECOVERY # include "modules/recovery/main_impl.h" #endif +#ifdef ENABLE_MODULE_EXTRAKEYS +# include "modules/extrakeys/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_MUSIG +# include "modules/musig/main_impl.h" +#endif + #ifdef ENABLE_MODULE_GENERATOR # include "modules/generator/main_impl.h" #endif @@ -792,10 +800,3 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey * # include "modules/surjection/main_impl.h" #endif -#ifdef ENABLE_MODULE_EXTRAKEYS -# include "modules/extrakeys/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_SCHNORRSIG -# include "modules/schnorrsig/main_impl.h" -#endif