Merge pull request #105 from jonasnick/update-musig

MuSig state machine simplifictions, API improvements and taproot tweaking
This commit is contained in:
Andrew Poelstra 2020-11-30 16:11:34 +00:00 committed by GitHub
commit ff4714e641
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 633 additions and 412 deletions

View File

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

View File

@ -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
* magic: Set during initialization in `pubkey_combine` 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
* 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

View File

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

View File

@ -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_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 (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.
* */
if (session->has_secret_data
&& memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) {
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);

View File

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

View File

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