diff --git a/.travis.yml b/.travis.yml index 2ace5be9..9b7fe6f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,9 +22,9 @@ env: - WIDEMUL=int64 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes - WIDEMUL=int128 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes - WIDEMUL=int64 RECOVERY=yes - - WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes + - WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes - WIDEMUL=int128 - - WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes + - WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes - WIDEMUL=int128 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes - WIDEMUL=int128 ASM=x86_64 - BIGNUM=no @@ -33,10 +33,10 @@ env: - BUILD=distcheck WITH_VALGRIND=no CTIMETEST=no BENCH=no - CPPFLAGS=-DDETERMINISTIC - CFLAGS=-O0 CTIMETEST=no - - CFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" LDFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1" BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes CTIMETEST=no + - CFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" LDFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1" BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes CTIMETEST=no - ECMULTGENPRECISION=2 - ECMULTGENPRECISION=8 - - RUN_VALGRIND=yes BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes EXTRAFLAGS="--disable-openssl-tests" BUILD= + - RUN_VALGRIND=yes BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes EXTRAFLAGS="--disable-openssl-tests" BUILD= matrix: fast_finish: true include: @@ -84,7 +84,7 @@ matrix: - libc6-dbg:i386 # S390x build (big endian system) - compiler: gcc - env: HOST=s390x-unknown-linux-gnu ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes CTIMETEST= + env: HOST=s390x-unknown-linux-gnu ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes CTIMETEST= arch: s390x # We use this to install macOS dependencies instead of the built in `homebrew` plugin, diff --git a/include/secp256k1_musig.h b/include/secp256k1_musig.h index c5352512..46fe6c28 100644 --- a/include/secp256k1_musig.h +++ b/include/secp256k1_musig.h @@ -20,18 +20,25 @@ extern "C" { */ /** Data structure containing auxiliary data generated in `pubkey_combine` and - * required for `session_*_initialize`. + * required for `session_*_init`. * 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. + * magic: Set during initialization in `pubkey_combine` to allow + * detecting an uninitialized object. + * pk_hash: The 32-byte hash of the original public keys + * pk_parity: Whether the MuSig-aggregated point was negated when + * converting it to the combined xonly pubkey. + * is_tweaked: Whether the combined pubkey was tweaked + * tweak: If is_tweaked, array with the 32-byte tweak + * internal_key_parity: If is_tweaked, the parity of the combined pubkey + * before tweaking */ typedef struct { uint64_t magic; unsigned char pk_hash[32]; - int is_negated; + int pk_parity; + int is_tweaked; + unsigned char tweak[32]; + int internal_key_parity; } secp256k1_musig_pre_session; /** Data structure containing data related to a signing session resulting in a single @@ -45,49 +52,49 @@ typedef struct { * structure. * * Fields: - * combined_pk: MuSig-computed combined xonly public key + * magic: Set in `musig_session_init` to allow detecting an + * uninitialized object. + * round: Current round of the session * pre_session: Auxiliary data created in `pubkey_combine` + * combined_pk: MuSig-computed combined xonly public key * n_signers: Number of signers - * 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 is even. * msg: The 32-byte message (hash) to be signed - * msg_is_set: Whether the above message has been set + * is_msg_set: Whether the above message has been set * has_secret_data: Whether this session object has a signers' secret data; if this * is `false`, it may still be used for verification purposes. * seckey: If `has_secret_data`, the signer's secret key * secnonce: If `has_secret_data`, the signer's secret nonce * nonce: If `has_secret_data`, the signer's public nonce - * nonce_commitments_hash: If `has_secret_data` and `nonce_commitments_hash_is_set`, - * the hash of all signers' commitments - * nonce_commitments_hash_is_set: If `has_secret_data`, whether the - * nonce_commitments_hash has been set + * nonce_commitments_hash: If `has_secret_data` and round >= 1, the hash of all + * signers' commitments + * combined_nonce: If round >= 2, the summed combined public nonce + * combined_nonce_parity: If round >= 2, the parity of the Y coordinate of above + * nonce. */ typedef struct { - secp256k1_xonly_pubkey combined_pk; + uint64_t magic; + int round; secp256k1_musig_pre_session pre_session; + secp256k1_xonly_pubkey combined_pk; uint32_t n_signers; - secp256k1_pubkey combined_nonce; - int nonce_is_set; - int nonce_is_negated; + int is_msg_set; unsigned char msg[32]; - int msg_is_set; int has_secret_data; unsigned char seckey[32]; unsigned char secnonce[32]; - secp256k1_pubkey nonce; + secp256k1_xonly_pubkey nonce; + int partial_nonce_parity; unsigned char nonce_commitments_hash[32]; - int nonce_commitments_hash_is_set; + secp256k1_xonly_pubkey combined_nonce; + int combined_nonce_parity; } secp256k1_musig_session; /** Data structure containing data on all signers in a single session. * * The workflow for this structure is as follows: * - * 1. This structure is initialized with `musig_session_initialize` or - * `musig_session_initialize_verifier`, which set the `index` field, and zero out + * 1. This structure is initialized with `musig_session_init` or + * `musig_session_init_verifier`, which set the `index` field, and zero out * all other fields. The public session is initialized with the signers' * nonce_commitments. * @@ -112,7 +119,7 @@ typedef struct { typedef struct { int present; uint32_t index; - secp256k1_pubkey nonce; + secp256k1_xonly_pubkey nonce; unsigned char nonce_commitment[32]; } secp256k1_musig_session_signer_data; @@ -129,7 +136,8 @@ typedef struct { unsigned char data[32]; } secp256k1_musig_partial_signature; -/** Computes a combined public key and the hash of the given public keys +/** Computes a combined public key and the hash of the given public keys. + * Different orders of `pubkeys` result in different `combined_pk`s. * * Returns: 1 if the public keys were successfully combined, 0 otherwise * Args: ctx: pointer to a context object initialized for verification @@ -138,11 +146,11 @@ typedef struct { * multiexponentiation. If NULL, an inefficient algorithm is used. * 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`. + * `musig_session_init` or `musig_pubkey_tweak_add`. * 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) - * n_pubkeys: length of pubkeys array + * n_pubkeys: length of pubkeys array. Must be greater than 0. */ SECP256K1_API int secp256k1_musig_pubkey_combine( const secp256k1_context* ctx, @@ -153,6 +161,42 @@ SECP256K1_API int secp256k1_musig_pubkey_combine( size_t n_pubkeys ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); +/** Tweak an x-only public key by adding the generator multiplied with tweak32 + * to it. The resulting output_pubkey with the given internal_pubkey and tweak + * passes `secp256k1_xonly_pubkey_tweak_test`. + * + * This function is only useful before initializing a signing session. If you + * are only computing a public key, but not intending to create a signature for + * it, you can just use `secp256k1_xonly_pubkey_tweak_add`. Can only be called + * once with a given pre_session. + * + * Returns: 0 if the arguments are invalid or the resulting public key would be + * invalid (only when the tweak is the negation of the corresponding + * secret key). 1 otherwise. + * Args: ctx: pointer to a context object initialized for verification + * (cannot be NULL) + * pre_session: pointer to a `musig_pre_session` struct initialized in + * `musig_pubkey_combine` (cannot be NULL) + * Out: output_pubkey: pointer to a public key to store the result. Will be set + * to an invalid value if this function returns 0 (cannot + * be NULL) + * In: internal_pubkey: pointer to the `combined_pk` from + * `musig_pubkey_combine` to which the tweak is applied. + * (cannot be NULL). + * tweak32: pointer to a 32-byte tweak. If the tweak is invalid + * according to secp256k1_ec_seckey_verify, this function + * returns 0. For uniformly random 32-byte arrays the + * chance of being invalid is negligible (around 1 in + * 2^128) (cannot be NULL). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_tweak_add( + const secp256k1_context* ctx, + secp256k1_musig_pre_session *pre_session, + secp256k1_pubkey *output_pubkey, + const secp256k1_xonly_pubkey *internal_pubkey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + /** Initializes a signing session for a signer * * Returns: 1: session is successfully initialized @@ -172,14 +216,16 @@ SECP256K1_API int secp256k1_musig_pubkey_combine( * because it reduces nonce misuse resistance. If NULL, must be * set with `musig_session_get_public_nonce`. * 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) + * pre_session: pointer to a musig_pre_session struct after initializing + * it with `musig_pubkey_combine` and optionally provided to + * `musig_pubkey_tweak_add` (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 + * my_index: index of this signer in the signers array. Must be less + * than `n_signers`. * seckey: the signer's 32-byte secret key (cannot be NULL) */ -SECP256K1_API int secp256k1_musig_session_initialize( +SECP256K1_API int secp256k1_musig_session_init( const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, @@ -193,7 +239,10 @@ SECP256K1_API int secp256k1_musig_session_initialize( const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(11); -/** Gets the signer's public nonce given a list of all signers' data with commitments +/** Gets the signer's public nonce given a list of all signers' data with + * commitments. Called by participating signers after + * `secp256k1_musig_session_init` and after all nonce commitments have + * been collected * * Returns: 1: public nonce is written in nonce * 0: signer data is missing commitments or session isn't initialized @@ -201,20 +250,22 @@ SECP256K1_API int secp256k1_musig_session_initialize( * Args: ctx: pointer to a context object (cannot be NULL) * session: the signing session to get the nonce from (cannot be NULL) * signers: an array of signers' data initialized with - * `musig_session_initialize`. Array length must equal to + * `musig_session_init`. Array length must equal to * `n_commitments` (cannot be NULL) - * Out: nonce: the nonce (cannot be NULL) - * In: commitments: array of 32-byte nonce commitments (cannot be NULL) + * Out: nonce32: filled with a 32-byte public nonce which is supposed to be + * sent to the other signers and then used in `musig_set nonce` + * (cannot be NULL) + * In: commitments: array of pointers to 32-byte nonce commitments (cannot be NULL) * n_commitments: the length of commitments and signers array. Must be the total * number of signers participating in the MuSig. * msg32: the 32-byte message to be signed. Must be NULL if already - * set with `musig_session_initialize` otherwise can not be NULL. + * set with `musig_session_init` otherwise can not be NULL. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_public_nonce( const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, - secp256k1_pubkey *nonce, + unsigned char *nonce32, const unsigned char *const *commitments, size_t n_commitments, const unsigned char *msg32 @@ -234,13 +285,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_publi * 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) + * commitments: array of pointers to 32-byte nonce commitments. Array + * length must equal to `n_signers` (cannot be NULL) * n_signers: length of signers and commitments array. Number of signers * participating in the MuSig. Must be greater than 0 and at most * 2^32 - 1. */ -SECP256K1_API int secp256k1_musig_session_initialize_verifier( +SECP256K1_API int secp256k1_musig_session_init_verifier( const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, @@ -259,13 +310,13 @@ SECP256K1_API int secp256k1_musig_session_initialize_verifier( * Args: ctx: pointer to a context object (cannot be NULL) * signer: pointer to the signer data to update (cannot be NULL). Must have * been used with `musig_session_get_public_nonce` or initialized - * with `musig_session_initialize_verifier`. - * In: nonce: signer's alleged public nonce (cannot be NULL) + * with `musig_session_init_verifier`. + * In: nonce32: signer's alleged public nonce (cannot be NULL) */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_set_nonce( const secp256k1_context* ctx, secp256k1_musig_session_signer_data *signer, - const secp256k1_pubkey *nonce + const unsigned char *nonce32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Updates a session with the combined public nonce of all signers. The combined @@ -281,8 +332,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_set_nonce( * (cannot be NULL) * n_signers: the length of the signers array. Must be the total number of * signers participating in the MuSig. - * Out: nonce_is_negated: a pointer to an integer that indicates if the combined - * public nonce had to be negated. + * Out: nonce_parity: if non-NULL, a pointer to an integer that indicates the + * parity of the combined public nonce. Used for adaptor + * signatures. * adaptor: point to add to the combined public nonce. If NULL, nothing is * added to the combined nonce. */ @@ -291,7 +343,7 @@ SECP256K1_API int secp256k1_musig_session_combine_nonces( secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signers, size_t n_signers, - int *nonce_is_negated, + int *nonce_parity, const secp256k1_pubkey *adaptor ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -369,7 +421,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verif * * Returns: 1: all partial signatures have values in range. Does NOT mean the * resulting signature verifies. - * 0: some partial signature had s/r out of range + * 0: some partial signature are missing or had s or r out of range * Args: ctx: pointer to a context object (cannot be NULL) * session: initialized session for which the combined nonce has been * computed (cannot be NULL) @@ -395,14 +447,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_combi * In: partial_sig: partial signature to tweak with secret adaptor (cannot be NULL) * sec_adaptor32: 32-byte secret adaptor to add to the partial signature (cannot * be NULL) - * nonce_is_negated: the `nonce_is_negated` output of `musig_session_combine_nonces` + * nonce_parity: the `nonce_parity` output of `musig_session_combine_nonces` */ SECP256K1_API int secp256k1_musig_partial_sig_adapt( const secp256k1_context* ctx, secp256k1_musig_partial_signature *adaptor_sig, const secp256k1_musig_partial_signature *partial_sig, const unsigned char *sec_adaptor32, - int nonce_is_negated + int nonce_parity ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Extracts a secret adaptor from a MuSig, given all parties' partial @@ -418,7 +470,7 @@ SECP256K1_API int secp256k1_musig_partial_sig_adapt( * 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` + * nonce_parity: the `nonce_parity` output of `musig_session_combine_nonces` */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_secret_adaptor( const secp256k1_context* ctx, @@ -426,7 +478,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_secret_ad const unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, size_t n_partial_sigs, - int nonce_is_negated + int nonce_parity ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); #ifdef __cplusplus diff --git a/src/modules/musig/example.c b/src/modules/musig/example.c index 4670d442..2c5b7006 100644 --- a/src/modules/musig/example.c +++ b/src/modules/musig/example.c @@ -45,7 +45,7 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25 unsigned char nonce_commitment[N_SIGNERS][32]; const unsigned char *nonce_commitment_ptr[N_SIGNERS]; secp256k1_musig_session_signer_data signer_data[N_SIGNERS][N_SIGNERS]; - secp256k1_pubkey nonce[N_SIGNERS]; + unsigned char nonce[N_SIGNERS][32]; int i, j; secp256k1_musig_partial_signature partial_sig[N_SIGNERS]; @@ -60,7 +60,7 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25 return 0; } /* Create random session ID. It is absolutely necessary that the session ID - * is unique for every call of secp256k1_musig_session_initialize. Otherwise + * is unique for every call of secp256k1_musig_session_init. Otherwise * it's trivial for an attacker to extract the secret key! */ frand = fopen("/dev/urandom", "r"); if(frand == NULL) { @@ -72,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, &pre_session, N_SIGNERS, i, seckeys[i])) { + if (!secp256k1_musig_session_init(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]; @@ -80,14 +80,14 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25 /* Communication round 1: Exchange nonce commitments */ for (i = 0; i < N_SIGNERS; i++) { /* Set nonce commitments in the signer data and get the own public nonce */ - if (!secp256k1_musig_session_get_public_nonce(ctx, &musig_session[i], signer_data[i], &nonce[i], nonce_commitment_ptr, N_SIGNERS, NULL)) { + if (!secp256k1_musig_session_get_public_nonce(ctx, &musig_session[i], signer_data[i], nonce[i], nonce_commitment_ptr, N_SIGNERS, NULL)) { return 0; } } /* Communication round 2: Exchange nonces */ for (i = 0; i < N_SIGNERS; i++) { for (j = 0; j < N_SIGNERS; j++) { - if (!secp256k1_musig_set_nonce(ctx, &signer_data[i][j], &nonce[j])) { + if (!secp256k1_musig_set_nonce(ctx, &signer_data[i][j], nonce[j])) { /* Signer j's nonce does not match the nonce commitment. In this case * abort the protocol. If you make another attempt at finishing the * protocol, create a new session (with a fresh session ID!). */ diff --git a/src/modules/musig/main_impl.h b/src/modules/musig/main_impl.h index 5f9cb0d0..d397eab3 100644 --- a/src/modules/musig/main_impl.h +++ b/src/modules/musig/main_impl.h @@ -87,7 +87,6 @@ static int secp256k1_musig_pubkey_combine_callback(secp256k1_scalar *sc, secp256 return secp256k1_xonly_pubkey_load(ctx->ctx, pt, &ctx->pks[idx]); } - static void secp256k1_musig_signers_init(secp256k1_musig_session_signer_data *signers, uint32_t n_signers) { uint32_t i; for (i = 0; i < n_signers; i++) { @@ -103,7 +102,7 @@ int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scrat secp256k1_musig_pubkey_combine_ecmult_data ecmult_data; secp256k1_gej pkj; secp256k1_ge pkp; - int is_negated; + int pk_parity; VERIFY_CHECK(ctx != NULL); ARG_CHECK(combined_pk != NULL); @@ -121,18 +120,46 @@ int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scrat } secp256k1_ge_set_gej(&pkp, &pkj); secp256k1_fe_normalize(&pkp.y); - is_negated = secp256k1_extrakeys_ge_even_y(&pkp); + pk_parity = secp256k1_extrakeys_ge_even_y(&pkp); secp256k1_xonly_pubkey_save(combined_pk, &pkp); 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; + pre_session->pk_parity = pk_parity; + pre_session->is_tweaked = 0; } 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_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, size_t n_signers, size_t my_index, const unsigned char *seckey) { +int secp256k1_musig_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_musig_pre_session *pre_session, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { + secp256k1_ge pk; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pre_session != NULL); + ARG_CHECK(pre_session->magic == pre_session_magic); + /* This function can only be called once because otherwise signing would not + * succeed */ + ARG_CHECK(pre_session->is_tweaked == 0); + + pre_session->internal_key_parity = pre_session->pk_parity; + if(!secp256k1_xonly_pubkey_tweak_add(ctx, output_pubkey, internal_pubkey, tweak32)) { + return 0; + } + + memcpy(pre_session->tweak, tweak32, 32); + pre_session->is_tweaked = 1; + + if (!secp256k1_pubkey_load(ctx, &pk, output_pubkey)) { + return 0; + } + pre_session->pk_parity = secp256k1_extrakeys_ge_even_y(&pk); + return 1; +} + +static const uint64_t session_magic = 0xd92e6fc1ee41b4cbUL; + +int secp256k1_musig_session_init(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; @@ -140,6 +167,8 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m secp256k1_sha256 sha; secp256k1_gej pj; secp256k1_ge p; + unsigned char nonce_ser[32]; + size_t nonce_ser_size = sizeof(nonce_ser); VERIFY_CHECK(ctx != NULL); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); @@ -152,27 +181,24 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m ARG_CHECK(pre_session->magic == pre_session_magic); ARG_CHECK(seckey != NULL); + ARG_CHECK(n_signers > 0); + ARG_CHECK(n_signers <= UINT32_MAX); + ARG_CHECK(my_index < n_signers); + memset(session, 0, sizeof(*session)); + session->magic = session_magic; if (msg32 != NULL) { memcpy(session->msg, msg32, 32); - session->msg_is_set = 1; + session->is_msg_set = 1; } else { - session->msg_is_set = 0; + session->is_msg_set = 0; } memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk)); session->pre_session = *pre_session; - session->nonce_is_set = 0; session->has_secret_data = 1; - if (n_signers == 0 || my_index >= n_signers) { - return 0; - } - if (n_signers > UINT32_MAX) { - return 0; - } session->n_signers = (uint32_t) n_signers; secp256k1_musig_signers_init(signers, session->n_signers); - session->nonce_commitments_hash_is_set = 0; /* Compute secret key */ secp256k1_scalar_set_b32(&secret, seckey, &overflow); @@ -181,22 +207,33 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m return 0; } 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 + /* Compute the signer's public key point and determine if the secret is + * negated before signing. That happens if if the signer's pubkey has an odd + * Y coordinate XOR the MuSig-combined pubkey has an odd Y coordinate XOR + * (if tweaked) the internal key has an odd Y coordinate. + * + * 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. */ + * P := |P'| + t*G where t is the tweak. + * And the combined xonly public key is + * |P| = x*G + * where x = sum_i(b_i*mu_i*x_i) + b'*t + * b' = -1 if P != |P|, 1 otherwise + * b_i = -1 if (P_i != |P_i| XOR P' != |P'| XOR P != |P|) 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) { + if((secp256k1_fe_is_odd(&p.y) + + session->pre_session.pk_parity + + (session->pre_session.is_tweaked + && session->pre_session.internal_key_parity)) + % 2 == 1) { secp256k1_scalar_negate(&secret, &secret); } secp256k1_scalar_mul(&secret, &secret, &mu); @@ -205,7 +242,7 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m /* Compute secret nonce */ secp256k1_sha256_initialize(&sha); secp256k1_sha256_write(&sha, session_id32, 32); - if (session->msg_is_set) { + if (session->is_msg_set) { secp256k1_sha256_write(&sha, msg32, 32); } secp256k1_xonly_pubkey_serialize(ctx, combined_ser, combined_pk); @@ -221,47 +258,49 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m /* Compute public nonce and commitment */ secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret); secp256k1_ge_set_gej(&p, &pj); - secp256k1_pubkey_save(&session->nonce, &p); + secp256k1_fe_normalize_var(&p.y); + session->partial_nonce_parity = secp256k1_extrakeys_ge_even_y(&p); + secp256k1_xonly_pubkey_save(&session->nonce, &p); - if (nonce_commitment32 != NULL) { - unsigned char commit[33]; - size_t commit_size = sizeof(commit); - secp256k1_sha256_initialize(&sha); - secp256k1_ec_pubkey_serialize(ctx, commit, &commit_size, &session->nonce, SECP256K1_EC_COMPRESSED); - secp256k1_sha256_write(&sha, commit, commit_size); - secp256k1_sha256_finalize(&sha, nonce_commitment32); - } + secp256k1_sha256_initialize(&sha); + secp256k1_xonly_pubkey_serialize(ctx, nonce_ser, &session->nonce); + secp256k1_sha256_write(&sha, nonce_ser, nonce_ser_size); + secp256k1_sha256_finalize(&sha, nonce_commitment32); + session->round = 0; secp256k1_scalar_clear(&secret); return 1; } -int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, secp256k1_pubkey *nonce, const unsigned char *const *commitments, size_t n_commitments, const unsigned char *msg32) { +int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce, const unsigned char *const *commitments, size_t n_commitments, const unsigned char *msg32) { secp256k1_sha256 sha; unsigned char nonce_commitments_hash[32]; size_t i; + unsigned char nonce_ser[32]; + size_t nonce_ser_size = sizeof(nonce_ser); (void) ctx; VERIFY_CHECK(ctx != NULL); ARG_CHECK(session != NULL); + ARG_CHECK(session->magic == session_magic); ARG_CHECK(signers != NULL); ARG_CHECK(nonce != NULL); ARG_CHECK(commitments != NULL); - /* If the message was not set during initialization it must be set now. */ - ARG_CHECK(!(!session->msg_is_set && msg32 == NULL)); - /* The message can only be set once. */ - ARG_CHECK(!(session->msg_is_set && msg32 != NULL)); - if (!session->has_secret_data || n_commitments != session->n_signers) { - return 0; - } + ARG_CHECK(session->round == 0); + /* If the message was not set during initialization it must be set now. */ + ARG_CHECK(!(!session->is_msg_set && msg32 == NULL)); + /* The message can only be set once. */ + ARG_CHECK(!(session->is_msg_set && msg32 != NULL)); + ARG_CHECK(session->has_secret_data); + ARG_CHECK(n_commitments == session->n_signers); for (i = 0; i < n_commitments; i++) { ARG_CHECK(commitments[i] != NULL); } if (msg32 != NULL) { memcpy(session->msg, msg32, 32); - session->msg_is_set = 1; + session->is_msg_set = 1; } secp256k1_sha256_initialize(&sha); for (i = 0; i < n_commitments; i++) { @@ -269,19 +308,15 @@ int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp2 secp256k1_sha256_write(&sha, commitments[i], 32); } secp256k1_sha256_finalize(&sha, nonce_commitments_hash); - if (session->nonce_commitments_hash_is_set - && memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) { - /* Abort if get_public_nonce has been called before with a different array of - * commitments. */ - return 0; - } memcpy(session->nonce_commitments_hash, nonce_commitments_hash, 32); - session->nonce_commitments_hash_is_set = 1; - memcpy(nonce, &session->nonce, sizeof(*nonce)); + + secp256k1_xonly_pubkey_serialize(ctx, nonce_ser, &session->nonce); + memcpy(nonce, &nonce_ser, nonce_ser_size); + session->round = 1; 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_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, const unsigned char *const *commitments, size_t n_signers) { +int secp256k1_musig_session_init_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); @@ -294,9 +329,8 @@ int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, se ARG_CHECK(commitments != NULL); /* Check n_signers before checking commitments to allow testing the case where * n_signers is big without allocating the space. */ - if (n_signers > UINT32_MAX) { - return 0; - } + ARG_CHECK(n_signers > 0); + ARG_CHECK(n_signers <= UINT32_MAX); for (i = 0; i < n_signers; i++) { ARG_CHECK(commitments[i] != NULL); } @@ -304,50 +338,48 @@ int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, se memset(session, 0, sizeof(*session)); + session->magic = session_magic; 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); session->pre_session = *pre_session; - session->nonce_is_set = 0; - session->msg_is_set = 1; + session->is_msg_set = 1; memcpy(session->msg, msg32, 32); session->has_secret_data = 0; - session->nonce_commitments_hash_is_set = 0; for (i = 0; i < n_signers; i++) { memcpy(signers[i].nonce_commitment, commitments[i], 32); } + session->round = 1; return 1; } -int secp256k1_musig_set_nonce(const secp256k1_context* ctx, secp256k1_musig_session_signer_data *signer, const secp256k1_pubkey *nonce) { - unsigned char commit[33]; - size_t commit_size = sizeof(commit); +int secp256k1_musig_set_nonce(const secp256k1_context* ctx, secp256k1_musig_session_signer_data *signer, const unsigned char *nonce) { secp256k1_sha256 sha; + unsigned char commit[32]; VERIFY_CHECK(ctx != NULL); ARG_CHECK(signer != NULL); ARG_CHECK(nonce != NULL); secp256k1_sha256_initialize(&sha); - secp256k1_ec_pubkey_serialize(ctx, commit, &commit_size, nonce, SECP256K1_EC_COMPRESSED); - secp256k1_sha256_write(&sha, commit, commit_size); + secp256k1_sha256_write(&sha, nonce, 32); secp256k1_sha256_finalize(&sha, commit); if (memcmp(commit, signer->nonce_commitment, 32) != 0) { return 0; } memcpy(&signer->nonce, nonce, sizeof(*nonce)); + if (!secp256k1_xonly_pubkey_parse(ctx, &signer->nonce, nonce)) { + return 0; + } signer->present = 1; return 1; } -int secp256k1_musig_session_combine_nonces(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signers, size_t n_signers, int *nonce_is_negated, const secp256k1_pubkey *adaptor) { +int secp256k1_musig_session_combine_nonces(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signers, size_t n_signers, int *nonce_parity, const secp256k1_pubkey *adaptor) { secp256k1_gej combined_noncej; secp256k1_ge combined_noncep; secp256k1_ge noncep; @@ -358,10 +390,10 @@ int secp256k1_musig_session_combine_nonces(const secp256k1_context* ctx, secp256 VERIFY_CHECK(ctx != NULL); ARG_CHECK(session != NULL); ARG_CHECK(signers != NULL); + ARG_CHECK(session->magic == session_magic); + ARG_CHECK(session->round == 1); + ARG_CHECK(n_signers == session->n_signers); - if (n_signers != session->n_signers) { - return 0; - } secp256k1_sha256_initialize(&sha); secp256k1_gej_set_infinity(&combined_noncej); for (i = 0; i < n_signers; i++) { @@ -369,20 +401,17 @@ int secp256k1_musig_session_combine_nonces(const secp256k1_context* ctx, secp256 return 0; } secp256k1_sha256_write(&sha, signers[i].nonce_commitment, 32); - secp256k1_pubkey_load(ctx, &noncep, &signers[i].nonce); + secp256k1_xonly_pubkey_load(ctx, &noncep, &signers[i].nonce); secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL); } secp256k1_sha256_finalize(&sha, nonce_commitments_hash); - /* Either the session is a verifier session or or the nonce_commitments_hash has - * been set in `musig_session_get_public_nonce`. */ - VERIFY_CHECK(!session->has_secret_data || session->nonce_commitments_hash_is_set); + /* If the signers' commitments changed between get_public_nonce and now we + * have to abort because in that case they may have seen our nonce before + * creating their commitment. That can happen if the signer_data given to + * this function is different to the signer_data given to get_public_nonce. + * */ if (session->has_secret_data && memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) { - /* If the signers' commitments changed between get_public_nonce and now we - * have to abort because in that case they may have seen our nonce before - * creating their commitment. That can happen if the signer_data given to - * this function is different to the signer_data given to get_public_nonce. - * */ return 0; } @@ -391,19 +420,16 @@ int secp256k1_musig_session_combine_nonces(const secp256k1_context* ctx, secp256 secp256k1_pubkey_load(ctx, &noncep, adaptor); secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL); } + + /* Negate nonce if Y coordinate is not square */ secp256k1_ge_set_gej(&combined_noncep, &combined_noncej); - 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; - secp256k1_ge_neg(&combined_noncep, &combined_noncep); + secp256k1_fe_normalize_var(&combined_noncep.y); + session->combined_nonce_parity = secp256k1_extrakeys_ge_even_y(&combined_noncep); + if (nonce_parity != NULL) { + *nonce_parity = session->combined_nonce_parity; } - if (nonce_is_negated != NULL) { - *nonce_is_negated = session->nonce_is_negated; - } - secp256k1_pubkey_save(&session->combined_nonce, &combined_noncep); - session->nonce_is_set = 1; + secp256k1_xonly_pubkey_save(&session->combined_nonce, &combined_noncep); + session->round = 2; return 1; } @@ -424,27 +450,22 @@ 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) { +static void secp256k1_musig_compute_messagehash(const secp256k1_context *ctx, unsigned char *msghash, const secp256k1_musig_session *session) { unsigned char buf[32]; secp256k1_ge rp; secp256k1_sha256 sha; + VERIFY_CHECK(session->round >= 2); + secp256k1_schnorrsig_sha256_tagged(&sha); - if (!session->nonce_is_set) { - return 0; - } - secp256k1_pubkey_load(ctx, &rp, &session->combined_nonce); + secp256k1_xonly_pubkey_load(ctx, &rp, &session->combined_nonce); secp256k1_fe_get_b32(buf, &rp.x); secp256k1_sha256_write(&sha, buf, 32); secp256k1_xonly_pubkey_serialize(ctx, buf, &session->combined_pk); secp256k1_sha256_write(&sha, buf, 32); - if (!session->msg_is_set) { - return 0; - } secp256k1_sha256_write(&sha, session->msg, 32); secp256k1_sha256_finalize(&sha, msghash); - return 1; } int secp256k1_musig_partial_sign(const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_musig_partial_signature *partial_sig) { @@ -456,15 +477,12 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, const secp256k1_m VERIFY_CHECK(ctx != NULL); ARG_CHECK(partial_sig != NULL); ARG_CHECK(session != NULL); - - if (!session->nonce_is_set || !session->has_secret_data) { - return 0; - } + ARG_CHECK(session->magic == session_magic); + ARG_CHECK(session->round == 2); + ARG_CHECK(session->has_secret_data); /* build message hash */ - if (!secp256k1_musig_compute_messagehash(ctx, msghash, session)) { - return 0; - } + secp256k1_musig_compute_messagehash(ctx, msghash, session); secp256k1_scalar_set_b32(&e, msghash, NULL); secp256k1_scalar_set_b32(&sk, session->seckey, &overflow); @@ -479,7 +497,7 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, const secp256k1_m secp256k1_scalar_clear(&k); return 0; } - if (session->nonce_is_negated) { + if (session->partial_nonce_parity != session->combined_nonce_parity) { secp256k1_scalar_negate(&k, &k); } @@ -503,10 +521,9 @@ int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp ARG_CHECK(sig64 != NULL); ARG_CHECK(partial_sigs != NULL); ARG_CHECK(session != NULL); + ARG_CHECK(session->magic == session_magic); + ARG_CHECK(session->round == 2); - if (!session->nonce_is_set) { - return 0; - } if (n_sigs != session->n_signers) { return 0; } @@ -522,7 +539,27 @@ int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp secp256k1_scalar_add(&s, &s, &term); } - secp256k1_pubkey_load(ctx, &noncep, &session->combined_nonce); + /* If there is a tweak then add (or subtract) `msghash` times `tweak` to `s`.*/ + if (session->pre_session.is_tweaked) { + unsigned char msghash[32]; + secp256k1_scalar e, scalar_tweak; + int overflow = 0; + + secp256k1_musig_compute_messagehash(ctx, msghash, session); + secp256k1_scalar_set_b32(&e, msghash, NULL); + secp256k1_scalar_set_b32(&scalar_tweak, session->pre_session.tweak, &overflow); + if (overflow || !secp256k1_eckey_privkey_tweak_mul(&e, &scalar_tweak)) { + /* This mimics the behavior of secp256k1_ec_seckey_tweak_mul regarding + * overflow and tweak being 0. */ + return 0; + } + if (session->pre_session.pk_parity) { + secp256k1_scalar_negate(&e, &e); + } + secp256k1_scalar_add(&s, &s, &e); + } + + secp256k1_xonly_pubkey_load(ctx, &noncep, &session->combined_nonce); VERIFY_CHECK(!secp256k1_fe_is_odd(&noncep.y)); secp256k1_fe_normalize(&noncep.x); secp256k1_fe_get_b32(&sig64[0], &noncep.x); @@ -548,17 +585,15 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2 ARG_CHECK(signer != NULL); ARG_CHECK(partial_sig != NULL); ARG_CHECK(pubkey != NULL); + ARG_CHECK(session->magic == session_magic); + ARG_CHECK(session->round == 2); + ARG_CHECK(signer->present); - if (!session->nonce_is_set || !signer->present) { - return 0; - } secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow); if (overflow) { return 0; } - if (!secp256k1_musig_compute_messagehash(ctx, msghash, session)) { - return 0; - } + secp256k1_musig_compute_messagehash(ctx, msghash, session); secp256k1_scalar_set_b32(&e, msghash, NULL); /* Multiplying the messagehash by the musig coefficient is equivalent @@ -567,13 +602,18 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2 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)) { + if (!secp256k1_xonly_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) { + + /* If the MuSig-combined point has an odd Y coordinate, 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 the + * MuSig-combined point was tweaked then `e` is negated if the combined key + * has an odd Y coordinate XOR the internal key has an odd Y coordinate.*/ + if (session->pre_session.pk_parity + != (session->pre_session.is_tweaked + && session->pre_session.internal_key_parity)) { secp256k1_scalar_negate(&e, &e); } @@ -585,7 +625,7 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2 secp256k1_gej_set_ge(&pkj, &pkp); secp256k1_ecmult(&ctx->ecmult_ctx, &rj, &pkj, &e, &s); - if (!session->nonce_is_negated) { + if (!session->combined_nonce_parity) { secp256k1_ge_neg(&rp, &rp); } secp256k1_gej_add_ge_var(&rj, &rj, &rp, NULL); @@ -593,7 +633,7 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2 return secp256k1_gej_is_infinity(&rj); } -int secp256k1_musig_partial_sig_adapt(const secp256k1_context* ctx, secp256k1_musig_partial_signature *adaptor_sig, const secp256k1_musig_partial_signature *partial_sig, const unsigned char *sec_adaptor32, int nonce_is_negated) { +int secp256k1_musig_partial_sig_adapt(const secp256k1_context* ctx, secp256k1_musig_partial_signature *adaptor_sig, const secp256k1_musig_partial_signature *partial_sig, const unsigned char *sec_adaptor32, int nonce_parity) { secp256k1_scalar s; secp256k1_scalar t; int overflow; @@ -614,7 +654,7 @@ int secp256k1_musig_partial_sig_adapt(const secp256k1_context* ctx, secp256k1_mu return 0; } - if (nonce_is_negated) { + if (nonce_parity) { secp256k1_scalar_negate(&t, &t); } @@ -624,7 +664,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 unsigned char *sig64, 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_parity) { secp256k1_scalar t; secp256k1_scalar s; int overflow; @@ -651,7 +691,7 @@ int secp256k1_musig_extract_secret_adaptor(const secp256k1_context* ctx, unsigne secp256k1_scalar_add(&t, &t, &s); } - if (!nonce_is_negated) { + if (!nonce_parity) { secp256k1_scalar_negate(&t, &t); } secp256k1_scalar_get_b32(sec_adaptor32, &t); diff --git a/src/modules/musig/musig.md b/src/modules/musig/musig.md index ec1f1df5..240e85ca 100644 --- a/src/modules/musig/musig.md +++ b/src/modules/musig/musig.md @@ -74,7 +74,7 @@ signature process, which is also a supported mode) acts as follows. ### Signing Participant -1. The signer starts the session by calling `secp256k1_musig_session_initialize`. +1. The signer starts the session by calling `secp256k1_musig_session_init`. This function outputs - an initialized session state in the out-pointer `session` - an array of initialized signer data in the out-pointer `signers` @@ -91,7 +91,7 @@ signature process, which is also a supported mode) acts as follows. length-32 byte arrays which can be communicated however is communicated. 3. Once all signers nonce commitments have been received, the signer records these commitments with the function `secp256k1_musig_session_get_public_nonce`. - If the signer did not provide a message to `secp256k1_musig_session_initialize`, + If the signer did not provide a message to `secp256k1_musig_session_init`, a message must be provided now. This function updates in place - the session state `session` @@ -133,8 +133,8 @@ A participant who wants to verify the signing process, i.e. check that nonce com are consistent and partial signatures are correct without contributing a partial signature, may do so using the above instructions except for the following changes: -1. A signing session should be produced using `musig_session_initialize_verifier` - rather than `musig_session_initialize`; this function takes no secret data or +1. A signing session should be produced using `musig_session_init_verifier` + rather than `musig_session_init`; this function takes no secret data or signer index. 2. The participant receives nonce commitments, public nonces and partial signatures, but does not produce these values. Therefore `secp256k1_musig_session_get_public_nonce` diff --git a/src/modules/musig/tests_impl.h b/src/modules/musig/tests_impl.h index 49880a87..22a5d05b 100644 --- a/src/modules/musig/tests_impl.h +++ b/src/modules/musig/tests_impl.h @@ -31,7 +31,7 @@ void musig_simple_test(secp256k1_scratch_space *scratch) { unsigned char session_id[2][32]; secp256k1_xonly_pubkey pk[2]; const unsigned char *ncs[2]; - secp256k1_pubkey public_nonce[3]; + unsigned char public_nonce[3][32]; secp256k1_musig_partial_signature partial_sig[2]; unsigned char final_sig[64]; @@ -45,19 +45,19 @@ void musig_simple_test(secp256k1_scratch_space *scratch) { 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); + CHECK(secp256k1_musig_session_init(ctx, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1); + CHECK(secp256k1_musig_session_init(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_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_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); @@ -75,6 +75,7 @@ void musig_simple_test(secp256k1_scratch_space *scratch) { void musig_api_tests(secp256k1_scratch_space *scratch) { secp256k1_scratch_space *scratch_small; secp256k1_musig_session session[2]; + secp256k1_musig_session session_uninitialized; secp256k1_musig_session verifier_session; secp256k1_musig_session_signer_data signer0[2]; secp256k1_musig_session_signer_data signer1[2]; @@ -90,10 +91,9 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { unsigned char ones[32]; unsigned char session_id[2][32]; unsigned char nonce_commitment[2][32]; - int nonce_is_negated; + int combined_nonce_parity; const unsigned char *ncs[2]; unsigned char msg[32]; - unsigned char msghash[32]; secp256k1_xonly_pubkey combined_pk; secp256k1_musig_pre_session pre_session; secp256k1_musig_pre_session pre_session_uninitialized; @@ -118,10 +118,11 @@ 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 */ + /* Simulate structs being uninitialized by setting it to 0s. We don't want + * to produce undefined behavior by actually providing uninitialized + * structs. */ memset(&pre_session_uninitialized, 0, sizeof(pre_session_uninitialized)); + memset(&session_uninitialized, 0, sizeof(session_uninitialized)); secp256k1_testrand256(session_id[0]); secp256k1_testrand256(session_id[1]); @@ -169,139 +170,188 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { 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); + /** Tweaking */ + ecount = 0; + { + secp256k1_xonly_pubkey tmp_internal_pk = combined_pk; + secp256k1_pubkey tmp_output_pk; + secp256k1_musig_pre_session tmp_pre_session = pre_session; + CHECK(secp256k1_musig_pubkey_tweak_add(ctx, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 1); + /* Reset pre_session */ + tmp_pre_session = pre_session; + CHECK(secp256k1_musig_pubkey_tweak_add(none, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_musig_pubkey_tweak_add(sign, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 1); + CHECK(ecount == 2); + tmp_pre_session = pre_session; + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, NULL, &tmp_output_pk, &tmp_internal_pk, tweak) == 0); + CHECK(ecount == 3); + /* Uninitialized pre_session */ + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &pre_session_uninitialized, &tmp_output_pk, &tmp_internal_pk, tweak) == 0); + CHECK(ecount == 4); + /* Using the same pre_session twice does not work */ + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 1); + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 0); + CHECK(ecount == 5); + tmp_pre_session = pre_session; + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, NULL, &tmp_internal_pk, tweak) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, NULL, tweak) == 0); + CHECK(ecount == 7); + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, NULL) == 0); + CHECK(ecount == 8); + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, ones) == 0); + CHECK(ecount == 8); + } + /** Session creation **/ ecount = 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(secp256k1_musig_session_init(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, &pre_session, 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_init(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, &pre_session, 2, 0, sk[0]) == 1); + CHECK(secp256k1_musig_session_init(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, &pre_session, 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_init(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, &pre_session, 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_init(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, &pre_session, 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_init(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, &pre_session, 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_init(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, &pre_session, 2, 0, sk[0]) == 1); + CHECK(secp256k1_musig_session_init(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, &pre_session, 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_init(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(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, NULL, 2, 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(secp256k1_musig_session_init(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 + CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 0, 0, sk[0]) == 0); + CHECK(ecount == 10); + /* If more than UINT32_MAX fits in a size_t, test that session_init * 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, &pre_session, ((size_t) UINT32_MAX) + 2, 0, sk[0]) == 0); + CHECK(secp256k1_musig_session_init(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 == 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); + CHECK(ecount == 11); + CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, NULL) == 0); + CHECK(ecount == 12); /* secret key overflows */ - 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_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, ones) == 0); + CHECK(ecount == 12); - 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); + CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1); + CHECK(secp256k1_musig_session_init(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, &pre_session, ncs, 2) == 1); + CHECK(secp256k1_musig_session_init_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, &pre_session, ncs, 2) == 0); + CHECK(secp256k1_musig_session_init_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, &pre_session, ncs, 2) == 0); + CHECK(secp256k1_musig_session_init_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, &pre_session, ncs, 2) == 0); + CHECK(secp256k1_musig_session_init_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(secp256k1_musig_session_init_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, &pre_session, NULL, 2) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 0) == 0); + CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, NULL, 2) == 0); CHECK(ecount == 5); + CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 0) == 0); + CHECK(ecount == 6); if (SIZE_MAX > UINT32_MAX) { - 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(secp256k1_musig_session_init_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, &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); + CHECK(ecount == 7); + CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 1); /** Signing step 0 -- exchange nonce commitments */ ecount = 0; { - secp256k1_pubkey nonce; + unsigned char nonce[32]; + secp256k1_musig_session session_0_tmp; + + memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp)); /* Can obtain public nonce after commitments have been exchanged; still can't sign */ - CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &nonce, ncs, 2, NULL) == 1); - CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 0); - CHECK(ecount == 0); + CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, nonce, ncs, 2, NULL) == 1); + CHECK(secp256k1_musig_partial_sign(none, &session_0_tmp, &partial_sig[0]) == 0); + CHECK(ecount == 1); } /** Signing step 1 -- exchange nonces */ ecount = 0; { - secp256k1_pubkey public_nonce[3]; + unsigned char public_nonce[3][32]; + secp256k1_musig_session session_0_tmp; - CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 2, NULL) == 1); + memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp)); + CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, public_nonce[0], ncs, 2, NULL) == 1); CHECK(ecount == 0); - CHECK(secp256k1_musig_session_get_public_nonce(none, NULL, signer0, &public_nonce[0], ncs, 2, NULL) == 0); + /* Reset session */ + memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp)); + CHECK(secp256k1_musig_session_get_public_nonce(none, NULL, signer0, public_nonce[0], ncs, 2, NULL) == 0); CHECK(ecount == 1); - CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], NULL, &public_nonce[0], ncs, 2, NULL) == 0); + /* uninitialized session */ + CHECK(secp256k1_musig_session_get_public_nonce(none, &session_uninitialized, signer0, public_nonce[0], ncs, 2, NULL) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, NULL, ncs, 2, NULL) == 0); + CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, NULL, public_nonce[0], ncs, 2, NULL) == 0); CHECK(ecount == 3); - CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], NULL, 2, NULL) == 0); + CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, NULL, ncs, 2, NULL) == 0); CHECK(ecount == 4); - /* Number of commitments and number of signers are different */ - CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 1, NULL) == 0); - CHECK(ecount == 4); - - CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 2, NULL) == 1); - CHECK(secp256k1_musig_session_get_public_nonce(none, &session[1], signer1, &public_nonce[1], ncs, 2, NULL) == 1); - - CHECK(secp256k1_musig_set_nonce(none, &signer0[0], &public_nonce[0]) == 1); - CHECK(secp256k1_musig_set_nonce(none, &signer0[1], &public_nonce[0]) == 0); - CHECK(secp256k1_musig_set_nonce(none, &signer0[1], &public_nonce[1]) == 1); - CHECK(secp256k1_musig_set_nonce(none, &signer0[1], &public_nonce[1]) == 1); - CHECK(ecount == 4); - - CHECK(secp256k1_musig_set_nonce(none, NULL, &public_nonce[0]) == 0); + CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, public_nonce[0], NULL, 2, NULL) == 0); CHECK(ecount == 5); - CHECK(secp256k1_musig_set_nonce(none, &signer1[0], NULL) == 0); + /* Number of commitments and number of signers are different */ + CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, public_nonce[0], ncs, 1, NULL) == 0); CHECK(ecount == 6); - CHECK(secp256k1_musig_set_nonce(none, &signer1[0], &public_nonce[0]) == 1); - CHECK(secp256k1_musig_set_nonce(none, &signer1[1], &public_nonce[1]) == 1); - CHECK(secp256k1_musig_set_nonce(none, &verifier_signer_data[0], &public_nonce[0]) == 1); - CHECK(secp256k1_musig_set_nonce(none, &verifier_signer_data[1], &public_nonce[1]) == 1); + CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, public_nonce[0], ncs, 2, NULL) == 1); + CHECK(secp256k1_musig_session_get_public_nonce(none, &session[1], signer1, public_nonce[1], ncs, 2, NULL) == 1); + + CHECK(secp256k1_musig_set_nonce(none, &signer0[0], public_nonce[0]) == 1); + CHECK(secp256k1_musig_set_nonce(none, &signer0[1], public_nonce[0]) == 0); + CHECK(secp256k1_musig_set_nonce(none, &signer0[1], public_nonce[1]) == 1); + CHECK(secp256k1_musig_set_nonce(none, &signer0[1], public_nonce[1]) == 1); + CHECK(ecount == 6); + + CHECK(secp256k1_musig_set_nonce(none, NULL, public_nonce[0]) == 0); + CHECK(ecount == 7); + CHECK(secp256k1_musig_set_nonce(none, &signer1[0], NULL) == 0); + CHECK(ecount == 8); + + CHECK(secp256k1_musig_set_nonce(none, &signer1[0], public_nonce[0]) == 1); + CHECK(secp256k1_musig_set_nonce(none, &signer1[1], public_nonce[1]) == 1); + CHECK(secp256k1_musig_set_nonce(none, &verifier_signer_data[0], public_nonce[0]) == 1); + CHECK(secp256k1_musig_set_nonce(none, &verifier_signer_data[1], public_nonce[1]) == 1); ecount = 0; - CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, &nonce_is_negated, &adaptor) == 1); - CHECK(secp256k1_musig_session_combine_nonces(none, NULL, signer0, 2, &nonce_is_negated, &adaptor) == 0); + memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp)); + CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, signer0, 2, &combined_nonce_parity, &adaptor) == 1); + memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp)); + CHECK(secp256k1_musig_session_combine_nonces(none, NULL, signer0, 2, &combined_nonce_parity, &adaptor) == 0); CHECK(ecount == 1); - CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], NULL, 2, &nonce_is_negated, &adaptor) == 0); + /* Uninitialized session */ + CHECK(secp256k1_musig_session_combine_nonces(none, &session_uninitialized, signer0, 2, &combined_nonce_parity, &adaptor) == 0); CHECK(ecount == 2); + CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, NULL, 2, &combined_nonce_parity, &adaptor) == 0); + CHECK(ecount == 3); /* Number of signers differs from number during intialization */ - CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 1, &nonce_is_negated, &adaptor) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, NULL, &adaptor) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, &nonce_is_negated, NULL) == 1); + CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, signer0, 1, &combined_nonce_parity, &adaptor) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, signer0, 2, NULL, &adaptor) == 1); + CHECK(ecount == 4); + memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp)); + CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, signer0, 2, &combined_nonce_parity, NULL) == 1); - CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, &nonce_is_negated, &adaptor) == 1); - CHECK(secp256k1_musig_session_combine_nonces(none, &session[1], signer0, 2, &nonce_is_negated, &adaptor) == 1); - CHECK(secp256k1_musig_session_combine_nonces(none, &verifier_session, verifier_signer_data, 2, &nonce_is_negated, &adaptor) == 1); + CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, &combined_nonce_parity, &adaptor) == 1); + CHECK(secp256k1_musig_session_combine_nonces(none, &session[1], signer0, 2, &combined_nonce_parity, &adaptor) == 1); + CHECK(secp256k1_musig_session_combine_nonces(none, &verifier_session, verifier_signer_data, 2, &combined_nonce_parity, &adaptor) == 1); } /** Signing step 2 -- partial signatures */ @@ -310,14 +360,17 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { CHECK(ecount == 0); CHECK(secp256k1_musig_partial_sign(none, NULL, &partial_sig[0]) == 0); CHECK(ecount == 1); - CHECK(secp256k1_musig_partial_sign(none, &session[0], NULL) == 0); + /* Uninitialized session */ + CHECK(secp256k1_musig_partial_sign(none, &session_uninitialized, &partial_sig[0]) == 0); CHECK(ecount == 2); + CHECK(secp256k1_musig_partial_sign(none, &session[0], NULL) == 0); + CHECK(ecount == 3); CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 1); CHECK(secp256k1_musig_partial_sign(none, &session[1], &partial_sig[1]) == 1); /* observer can't sign */ CHECK(secp256k1_musig_partial_sign(none, &verifier_session, &partial_sig[2]) == 0); - CHECK(ecount == 2); + CHECK(ecount == 4); ecount = 0; CHECK(secp256k1_musig_partial_signature_serialize(none, buf, &partial_sig[0]) == 1); @@ -344,14 +397,17 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { CHECK(ecount == 2); CHECK(secp256k1_musig_partial_sig_verify(vrfy, NULL, &signer0[0], &partial_sig[0], &pk[0]) == 0); CHECK(ecount == 3); - CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], NULL, &partial_sig[0], &pk[0]) == 0); + /* Unitialized session */ + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session_uninitialized, &signer0[0], &partial_sig[0], &pk[0]) == 0); CHECK(ecount == 4); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], NULL, &partial_sig[0], &pk[0]) == 0); + CHECK(ecount == 5); CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], NULL, &pk[0]) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig_overflow, &pk[0]) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], NULL) == 0); CHECK(ecount == 6); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig_overflow, &pk[0]) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], NULL) == 0); + CHECK(ecount == 7); CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1); CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[1], &signer1[0], &partial_sig[0], &pk[0]) == 1); @@ -359,21 +415,21 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[1], &signer1[1], &partial_sig[1], &pk[1]) == 1); CHECK(secp256k1_musig_partial_sig_verify(vrfy, &verifier_session, &verifier_signer_data[0], &partial_sig[0], &pk[0]) == 1); CHECK(secp256k1_musig_partial_sig_verify(vrfy, &verifier_session, &verifier_signer_data[1], &partial_sig[1], &pk[1]) == 1); - CHECK(ecount == 6); + CHECK(ecount == 7); /** Adaptor signature verification */ memcpy(&partial_sig_adapted[1], &partial_sig[1], sizeof(partial_sig_adapted[1])); ecount = 0; - CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], sec_adaptor, nonce_is_negated) == 1); + CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], sec_adaptor, combined_nonce_parity) == 1); CHECK(secp256k1_musig_partial_sig_adapt(none, NULL, &partial_sig[0], sec_adaptor, 0) == 0); CHECK(ecount == 1); CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], NULL, sec_adaptor, 0) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig_overflow, sec_adaptor, nonce_is_negated) == 0); + CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig_overflow, sec_adaptor, combined_nonce_parity) == 0); CHECK(ecount == 2); CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], NULL, 0) == 0); CHECK(ecount == 3); - CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], ones, nonce_is_negated) == 0); + CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], ones, combined_nonce_parity) == 0); CHECK(ecount == 3); /** Signing combining and verification */ @@ -386,28 +442,31 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { 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) == 0); + /* Unitialized session */ + CHECK(secp256k1_musig_partial_sig_combine(none, &session_uninitialized, final_sig, partial_sig_adapted, 2) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, NULL, 2) == 0); + CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], NULL, partial_sig_adapted, 2) == 0); CHECK(ecount == 3); + CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, NULL, 2) == 0); + CHECK(ecount == 4); { 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) == 0); } - CHECK(ecount == 3); + CHECK(ecount == 4); /* Wrong number of partial sigs */ CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 1) == 0); - CHECK(ecount == 3); + CHECK(ecount == 4); CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 2) == 1); - CHECK(ecount == 3); + CHECK(ecount == 4); 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, combined_nonce_parity) == 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(ecount == 1); @@ -417,7 +476,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { 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(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig_tmp, partial_sig, 2, combined_nonce_parity) == 0); } CHECK(ecount == 2); CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, NULL, 2, 0) == 0); @@ -426,7 +485,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { 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, combined_nonce_parity) == 0); } CHECK(ecount == 3); CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 0, 0) == 1); @@ -446,7 +505,7 @@ 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_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) { +void 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, unsigned char *nonce_other, unsigned char *sk, unsigned char *session_id) { secp256k1_musig_session session; secp256k1_musig_session session_tmp; unsigned char nonce_commitment[32]; @@ -456,26 +515,26 @@ int musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp256 secp256k1_xonly_pubkey pks_tmp[2]; secp256k1_xonly_pubkey combined_pk_tmp; secp256k1_musig_pre_session pre_session_tmp; - secp256k1_pubkey nonce; + unsigned char nonce[32]; /* Set up signers with different public keys */ secp256k1_testrand256(sk_dummy); pks_tmp[0] = pks[0]; 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_init(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, pre_session, 2, 0, sk) == 1); + CHECK(secp256k1_musig_session_init(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. */ - CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session_tmp, signers, &nonce, nonce_commitments, 2, NULL) == 1); - CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers_tmp, &nonce, nonce_commitments, 2, NULL) == 1); + CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session_tmp, signers, nonce, nonce_commitments, 2, NULL) == 1); + CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers_tmp, nonce, nonce_commitments, 2, NULL) == 1); CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1); - CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1); + CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], nonce) == 1); CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1); - return secp256k1_musig_compute_messagehash(ctx, msghash, &session); + secp256k1_musig_compute_messagehash(ctx, msghash, &session); } /* Creates a new session (with a different session id) and tries to use that session @@ -483,24 +542,24 @@ 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_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) { +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, unsigned char *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; unsigned char nonce_commitment[32]; unsigned char session_id[32]; - secp256k1_pubkey nonce; + unsigned char nonce[32]; const unsigned char *ncs[2]; /* Initialize new signers */ secp256k1_testrand256(session_id); - CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 1, sk) == 1); + CHECK(secp256k1_musig_session_init(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); + CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, nonce, ncs, 2, NULL) == 1); CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1); - CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1); - CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1); + CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], nonce) == 1); + CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], nonce) == 1); secp256k1_musig_session_combine_nonces(ctx, &session, signers_other, 2, NULL, NULL); if (do_test) { signers_to_use = signers_other; @@ -514,7 +573,7 @@ int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_xonly_pubkey * * 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_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) { +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, unsigned char *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; @@ -522,71 +581,37 @@ void musig_state_machine_late_msg_test(secp256k1_xonly_pubkey *pks, secp256k1_xo secp256k1_musig_session_signer_data signers[2]; unsigned char nonce_commitment[32]; const unsigned char *ncs[2]; - secp256k1_pubkey nonce; + unsigned char nonce[32]; 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, pre_session, 2, 1, sk) == 1); + CHECK(secp256k1_musig_session_init(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; /* Trying to get the nonce without providing a message fails. */ CHECK(ecount == 0); - CHECK(secp256k1_musig_session_get_public_nonce(ctx_tmp, &session, signers, &nonce, ncs, 2, NULL) == 0); + CHECK(secp256k1_musig_session_get_public_nonce(ctx_tmp, &session, signers, nonce, ncs, 2, NULL) == 0); CHECK(ecount == 1); /* Providing a message should make get_public_nonce succeed. */ - CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2, msg) == 1); + CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, nonce, ncs, 2, msg) == 1); /* Trying to set the message again fails. */ CHECK(ecount == 1); - CHECK(secp256k1_musig_session_get_public_nonce(ctx_tmp, &session, signers, &nonce, ncs, 2, msg) == 0); + CHECK(secp256k1_musig_session_get_public_nonce(ctx_tmp, &session, signers, nonce, ncs, 2, msg) == 0); CHECK(ecount == 2); /* Check that it's working */ CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1); - CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1); + CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], nonce) == 1); CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1); CHECK(secp256k1_musig_partial_sign(ctx, &session, &partial_sig)); CHECK(secp256k1_musig_partial_sig_verify(ctx, &session, &signers[1], &partial_sig, &pks[1])); -} - -/* Recreates a session with the given session_id, signers, pk, msg etc. parameters - * 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_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]; - unsigned char sig[64]; - int partial_verify, sig_combine; - - 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); - CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1); - CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1); - - partial_sigs[0] = *partial_sig_other; - partial_sigs[1] = *partial_sig; - if (do_combine != 0) { - 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); - if (do_combine != 0) { - /* Return 1 if both succeeded */ - return partial_verify && sig_combine; - } - /* Return 0 if both failed */ - return partial_verify || sig_combine; + secp256k1_context_destroy(ctx_tmp); } void musig_state_machine_tests(secp256k1_scratch_space *scratch) { + secp256k1_context *ctx_tmp = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_VERIFY); size_t i; secp256k1_musig_session session[2]; secp256k1_musig_session_signer_data signers0[2]; @@ -598,11 +623,16 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) { secp256k1_xonly_pubkey pk[2]; secp256k1_xonly_pubkey combined_pk; secp256k1_musig_pre_session pre_session; - secp256k1_pubkey nonce[2]; + unsigned char nonce[2][32]; const unsigned char *ncs[2]; secp256k1_musig_partial_signature partial_sig[2]; + unsigned char sig[64]; unsigned char msghash1[32]; unsigned char msghash2[32]; + int ecount; + + secp256k1_context_set_illegal_callback(ctx_tmp, counting_illegal_callback_fn, &ecount); + ecount = 0; /* Run state machine with the same objects twice to test that it's allowed to * reinitialize session and session_signer_data. */ @@ -616,54 +646,63 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) { 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); + CHECK(secp256k1_musig_session_init(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1); + CHECK(secp256k1_musig_session_init(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1); + /* Can't combine nonces unless we're through round 1 already */ + ecount = 0; + CHECK(secp256k1_musig_session_combine_nonces(ctx_tmp, &session[0], signers0, 2, NULL, NULL) == 0); + CHECK(ecount == 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); - /* Changing a nonce commitment is not okay */ - ncs[1] = (unsigned char*) "this isn't a nonce commitment..."; - CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2, NULL) == 0); - /* Repeating with the same nonce commitments is okay */ - 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[0], signers0, nonce[0], ncs, 2, NULL) == 1); + /* Calling the function again is not okay */ + ecount = 0; + CHECK(secp256k1_musig_session_get_public_nonce(ctx_tmp, &session[0], signers0, nonce[0], ncs, 2, NULL) == 0); + CHECK(ecount == 1); /* Get nonce for signer 1 */ - CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signers1, &nonce[1], 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[0], nonce[0]) == 1); /* Can't set nonce that doesn't match nonce commitment */ - CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], &nonce[0]) == 0); + CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], nonce[0]) == 0); /* Set correct nonce */ - CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], &nonce[1]) == 1); + CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], nonce[1]) == 1); /* Combine nonces */ CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signers0, 2, NULL, NULL) == 1); /* Not everyone is present from signer 1's view */ CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 0); /* Make everyone present */ - 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_set_nonce(ctx, &signers1[0], nonce[0]) == 1); + 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, &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); + 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); - /* Can't verify or sign until nonce is combined */ - CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 0); - CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 0); + /* Can't verify, sign or combine signatures until nonce is combined */ + ecount = 0; + CHECK(secp256k1_musig_partial_sig_verify(ctx_tmp, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_musig_partial_sign(ctx_tmp, &session[1], &partial_sig[1]) == 0); + CHECK(ecount == 2); + memset(&partial_sig[1], 0, sizeof(partial_sig[1])); + CHECK(secp256k1_musig_partial_sig_combine(ctx_tmp, &session[1], sig, partial_sig, 2) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 1); CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 1); /* messagehash should be the same as a session whose get_public_nonce was called * 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, &pre_session, ncs, msg, &nonce[0], sk[1], session_id[1]) == 1); + secp256k1_musig_compute_messagehash(ctx, msghash1, &session[1]); + musig_state_machine_diff_signer_msghash_test(msghash2, pk, &combined_pk, &pre_session, ncs, msg, nonce[0], sk[1], session_id[1]); CHECK(memcmp(msghash1, msghash2, 32) == 0); CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1); @@ -671,12 +710,9 @@ 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, &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, &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); + musig_state_machine_late_msg_test(pk, &combined_pk, &pre_session, nonce_commitment[0], nonce[0], sk[1], session_id[1], msg); } + secp256k1_context_destroy(ctx_tmp); } void scriptless_atomic_swap(secp256k1_scratch_space *scratch) { @@ -707,10 +743,10 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) { unsigned char noncommit_b[2][32]; const unsigned char *noncommit_a_ptr[2]; const unsigned char *noncommit_b_ptr[2]; - secp256k1_pubkey pubnon_a[2]; - secp256k1_pubkey pubnon_b[2]; - int nonce_is_negated_a; - int nonce_is_negated_b; + unsigned char pubnon_a[2][32]; + unsigned char pubnon_b[2][32]; + int combined_nonce_parity_a; + int combined_nonce_parity_b; secp256k1_musig_session_signer_data data_a[2]; secp256k1_musig_session_signer_data data_b[2]; @@ -734,28 +770,28 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) { 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, &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])); + CHECK(secp256k1_musig_session_init(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_init(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, &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])); + CHECK(secp256k1_musig_session_init(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_init(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]; /* Step 2: Exchange nonces */ - CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[0], data_a, &pubnon_a[0], noncommit_a_ptr, 2, NULL)); - CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[1], data_a, &pubnon_a[1], noncommit_a_ptr, 2, NULL)); - CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[0], data_b, &pubnon_b[0], noncommit_b_ptr, 2, NULL)); - CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[1], data_b, &pubnon_b[1], noncommit_b_ptr, 2, NULL)); - CHECK(secp256k1_musig_set_nonce(ctx, &data_a[0], &pubnon_a[0])); - CHECK(secp256k1_musig_set_nonce(ctx, &data_a[1], &pubnon_a[1])); - CHECK(secp256k1_musig_set_nonce(ctx, &data_b[0], &pubnon_b[0])); - CHECK(secp256k1_musig_set_nonce(ctx, &data_b[1], &pubnon_b[1])); - CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_a[0], data_a, 2, &nonce_is_negated_a, &pub_adaptor)); + CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[0], data_a, pubnon_a[0], noncommit_a_ptr, 2, NULL)); + CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[1], data_a, pubnon_a[1], noncommit_a_ptr, 2, NULL)); + CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[0], data_b, pubnon_b[0], noncommit_b_ptr, 2, NULL)); + CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[1], data_b, pubnon_b[1], noncommit_b_ptr, 2, NULL)); + CHECK(secp256k1_musig_set_nonce(ctx, &data_a[0], pubnon_a[0])); + CHECK(secp256k1_musig_set_nonce(ctx, &data_a[1], pubnon_a[1])); + CHECK(secp256k1_musig_set_nonce(ctx, &data_b[0], pubnon_b[0])); + CHECK(secp256k1_musig_set_nonce(ctx, &data_b[1], pubnon_b[1])); + CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_a[0], data_a, 2, &combined_nonce_parity_a, &pub_adaptor)); CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_a[1], data_a, 2, NULL, &pub_adaptor)); - CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_b[0], data_b, 2, &nonce_is_negated_b, &pub_adaptor)); + CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_b[0], data_b, 2, &combined_nonce_parity_b, &pub_adaptor)); CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_b[1], data_b, 2, NULL, &pub_adaptor)); /* Step 3: Signer 0 produces partial signatures for both chains. */ @@ -771,16 +807,16 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) { /* Step 5: Signer 0 adapts its own partial signature and combines it with the * partial signature from signer 1. This results in a complete signature which * 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)); + CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_b_adapted[0], &partial_sig_b[0], sec_adaptor, combined_nonce_parity_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) == 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, combined_nonce_parity_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_sig_adapt(ctx, &partial_sig_a[0], &partial_sig_a[0], sec_adaptor_extracted, combined_nonce_parity_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) == 1); CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_a, msg32_a, &combined_pk_a) == 1); @@ -819,6 +855,97 @@ void sha256_tag_test(void) { CHECK(memcmp(buf, buf2, 32) == 0); } +/* Attempts to create a signature for the combined public key using given secret + * keys and pre_session. */ +void musig_tweak_test_helper(const secp256k1_xonly_pubkey* combined_pubkey, const unsigned char *sk0, const unsigned char *sk1, secp256k1_musig_pre_session *pre_session) { + secp256k1_musig_session session[2]; + secp256k1_musig_session_signer_data signers0[2]; + secp256k1_musig_session_signer_data signers1[2]; + secp256k1_xonly_pubkey pk[2]; + unsigned char session_id[2][32]; + unsigned char msg[32]; + unsigned char nonce_commitment[2][32]; + unsigned char nonce[2][32]; + const unsigned char *ncs[2]; + secp256k1_musig_partial_signature partial_sig[2]; + unsigned char final_sig[64]; + + secp256k1_testrand256(session_id[0]); + secp256k1_testrand256(session_id[1]); + secp256k1_testrand256(msg); + + CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk0) == 1); + CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk1) == 1); + + CHECK(secp256k1_musig_session_init(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, combined_pubkey, pre_session, 2, 0, sk0) == 1); + CHECK(secp256k1_musig_session_init(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, combined_pubkey, pre_session, 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)); + 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_xonly_pubkey pk[2]; + secp256k1_musig_pre_session pre_session_P; + secp256k1_musig_pre_session pre_session_Q; + secp256k1_xonly_pubkey P; + unsigned char P_serialized[32]; + secp256k1_pubkey Q; + int Q_parity; + secp256k1_xonly_pubkey Q_xonly; + unsigned char Q_serialized[32]; + + secp256k1_sha256 sha; + unsigned char contract[32]; + unsigned char ec_commit_tweak[32]; + + /* Setup */ + secp256k1_testrand256(sk[0]); + secp256k1_testrand256(sk[1]); + secp256k1_testrand256(contract); + + 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, &P, &pre_session_P, pk, 2) == 1); + + CHECK(secp256k1_xonly_pubkey_serialize(ctx, P_serialized, &P) == 1); + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, P_serialized, 32); + secp256k1_sha256_write(&sha, contract, 32); + secp256k1_sha256_finalize(&sha, ec_commit_tweak); + pre_session_Q = pre_session_P; + CHECK(secp256k1_musig_pubkey_tweak_add(ctx, &pre_session_Q, &Q, &P, ec_commit_tweak) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &Q_xonly, &Q_parity, &Q)); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, Q_serialized, &Q_xonly)); + /* Check that musig_pubkey_tweak_add produces same result as + * xonly_pubkey_tweak_add. */ + CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, Q_serialized, Q_parity, &P, ec_commit_tweak) == 1); + + /* Test signing for P */ + musig_tweak_test_helper(&P, sk[0], sk[1], &pre_session_P); + /* Test signing for Q */ + musig_tweak_test_helper(&Q_xonly, sk[0], sk[1], &pre_session_Q); +} + void run_musig_tests(void) { int i; secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024); @@ -829,8 +956,10 @@ void run_musig_tests(void) { musig_api_tests(scratch); musig_state_machine_tests(scratch); for (i = 0; i < count; i++) { - /* Run multiple times to ensure that the nonce is negated in some tests */ + /* Run multiple times to ensure that pk and nonce have different y + * parities */ scriptless_atomic_swap(scratch); + musig_tweak_test(scratch); } sha256_tag_test();