From 22c88815c76e6edb23baf9401f820e1a944c3ecf Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Wed, 5 May 2021 15:45:31 +0000 Subject: [PATCH 1/3] musig: replace MuSig(1) with MuSig2 --- .gitignore | 2 + Makefile.am | 9 + examples/musig.c | 178 +++ include/secp256k1_musig.h | 799 +++++------ src/modules/musig/Makefile.am.include | 18 +- src/modules/musig/adaptor_impl.h | 101 ++ src/modules/musig/example.c | 170 --- src/modules/musig/keyagg.h | 34 + src/modules/musig/keyagg_impl.h | 280 ++++ src/modules/musig/main_impl.h | 734 +---------- src/modules/musig/musig.md | 249 +--- src/modules/musig/session.h | 25 + src/modules/musig/session_impl.h | 755 +++++++++++ src/modules/musig/tests_impl.h | 1751 ++++++++++++++----------- src/valgrind_ctime_test.c | 71 + 15 files changed, 2903 insertions(+), 2273 deletions(-) create mode 100644 examples/musig.c create mode 100644 src/modules/musig/adaptor_impl.h delete mode 100644 src/modules/musig/example.c create mode 100644 src/modules/musig/keyagg.h create mode 100644 src/modules/musig/keyagg_impl.h create mode 100644 src/modules/musig/session.h create mode 100644 src/modules/musig/session_impl.h diff --git a/.gitignore b/.gitignore index c4e5d9ccd..277c9e0aa 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,5 @@ build-aux/test-driver src/stamp-h1 libsecp256k1.pc contrib/gh-pr-create.sh + +example_musig \ No newline at end of file diff --git a/Makefile.am b/Makefile.am index fa455f979..2c29baa6e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -129,6 +129,15 @@ exhaustive_tests_LDFLAGS = -static TESTS += exhaustive_tests endif +if ENABLE_MODULE_MUSIG +noinst_PROGRAMS += example_musig +example_musig_SOURCES = examples/musig.c +example_musig_CPPFLAGS = -I$(top_srcdir)/include +example_musig_LDADD = libsecp256k1.la +example_musig_LDFLAGS = -static +TESTS += example_musig +endif + EXTRA_PROGRAMS = gen_ecmult_static_pre_g gen_ecmult_static_pre_g_SOURCES = src/gen_ecmult_static_pre_g.c # See Automake manual, Section "Errors with distclean" diff --git a/examples/musig.c b/examples/musig.c new file mode 100644 index 000000000..7cd664af9 --- /dev/null +++ b/examples/musig.c @@ -0,0 +1,178 @@ +/*********************************************************************** + * Copyright (c) 2018 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/** + * This file demonstrates how to use the MuSig module to create a multisignature. + * Additionally, see the documentation in include/secp256k1_musig.h. + */ + +#include +#include +#include +#include +#include + +struct signer_secrets { + secp256k1_keypair keypair; + secp256k1_musig_secnonce secnonce; +}; + +struct signer { + secp256k1_xonly_pubkey pubkey; + secp256k1_musig_pubnonce pubnonce; + secp256k1_musig_partial_sig partial_sig; +}; + + /* Number of public keys involved in creating the aggregate signature */ +#define N_SIGNERS 3 +/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */ +int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) { + unsigned char seckey[32]; + FILE *frand = fopen("/dev/urandom", "r"); + if (frand == NULL) { + return 0; + } + do { + if(!fread(seckey, sizeof(seckey), 1, frand)) { + fclose(frand); + return 0; + } + /* The probability that this not a valid secret key is approximately 2^-128 */ + } while (!secp256k1_ec_seckey_verify(ctx, seckey)); + fclose(frand); + if (!secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) { + return 0; + } + if (!secp256k1_keypair_xonly_pub(ctx, &signer->pubkey, NULL, &signer_secrets->keypair)) { + return 0; + } + return 1; +} + +/* Sign a message hash with the given key pairs and store the result in sig */ +int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const unsigned char* msg32, unsigned char *sig64) { + int i; + const secp256k1_xonly_pubkey *pubkeys[N_SIGNERS]; + const secp256k1_musig_pubnonce *pubnonces[N_SIGNERS]; + const secp256k1_musig_partial_sig *partial_sigs[N_SIGNERS]; + /* The same for all signers */ + secp256k1_musig_keyagg_cache cache; + secp256k1_musig_session session; + + for (i = 0; i < N_SIGNERS; i++) { + FILE *frand; + unsigned char seckey[32]; + unsigned char session_id[32]; + /* Create random session ID. It is absolutely necessary that the session ID + * is unique for every call of secp256k1_musig_nonce_gen. Otherwise + * it's trivial for an attacker to extract the secret key! */ + frand = fopen("/dev/urandom", "r"); + if(frand == NULL) { + return 0; + } + if (!fread(session_id, 32, 1, frand)) { + fclose(frand); + return 0; + } + fclose(frand); + if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) { + return 0; + } + /* Initialize session and create secret nonce for signing and public + * nonce to send to the other signers. */ + if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_id, seckey, msg32, NULL, NULL)) { + return 0; + } + pubkeys[i] = &signer[i].pubkey; + pubnonces[i] = &signer[i].pubnonce; + } + /* Communication round 1: A production system would exchange public nonces + * here before moving on. */ + for (i = 0; i < N_SIGNERS; i++) { + secp256k1_musig_aggnonce agg_pubnonce; + + /* Create aggregate pubkey, aggregate nonce and initialize signer data */ + if (!secp256k1_musig_pubkey_agg(ctx, NULL, NULL, &cache, pubkeys, N_SIGNERS)) { + return 0; + } + if (!secp256k1_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) { + return 0; + } + if (!secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, &cache, NULL)) { + return 0; + } + /* partial_sign will clear the secnonce by setting it to 0. That's because + * you must _never_ reuse the secnonce (or use the same session_id to + * create a secnonce). If you do, you effectively reuse the nonce and + * leak the secret key. */ + if (!secp256k1_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, &cache, &session)) { + return 0; + } + partial_sigs[i] = &signer[i].partial_sig; + } + /* Communication round 2: A production system would exchange + * partial signatures here before moving on. */ + for (i = 0; i < N_SIGNERS; i++) { + /* To check whether signing was successful, it suffices to either verify + * the aggregate signature with the aggregate public key using + * secp256k1_schnorrsig_verify, or verify all partial signatures of all + * signers individually. Verifying the aggregate signature is cheaper but + * verifying the individual partial signatures has the advantage that it + * can be used to determine which of the partial signatures are invalid + * (if any), i.e., which of the partial signatures cause the aggregate + * signature to be invalid and thus the protocol run to fail. It's also + * fine to first verify the aggregate sig, and only verify the individual + * sigs if it does not work. + */ + if (!secp256k1_musig_partial_sig_verify(ctx, &signer[i].partial_sig, &signer[i].pubnonce, &signer[i].pubkey, &cache, &session)) { + return 0; + } + } + return secp256k1_musig_partial_sig_agg(ctx, sig64, &session, partial_sigs, N_SIGNERS); +} + + int main(void) { + secp256k1_context* ctx; + int i; + struct signer_secrets signer_secrets[N_SIGNERS]; + struct signer signers[N_SIGNERS]; + const secp256k1_xonly_pubkey *pubkeys_ptr[N_SIGNERS]; + secp256k1_xonly_pubkey agg_pk; + unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!"; + unsigned char sig[64]; + + /* Create a context for signing and verification */ + ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + printf("Creating key pairs......"); + for (i = 0; i < N_SIGNERS; i++) { + if (!create_keypair(ctx, &signer_secrets[i], &signers[i])) { + printf("FAILED\n"); + return 1; + } + pubkeys_ptr[i] = &signers[i].pubkey; + } + printf("ok\n"); + printf("Combining public keys..."); + if (!secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, NULL, pubkeys_ptr, N_SIGNERS)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + printf("Signing message........."); + if (!sign(ctx, signer_secrets, signers, msg, sig)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + printf("Verifying signature....."); + if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &agg_pk)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + secp256k1_context_destroy(ctx); + return 0; +} diff --git a/include/secp256k1_musig.h b/include/secp256k1_musig.h index 724322489..79c6dc48a 100644 --- a/include/secp256k1_musig.h +++ b/include/secp256k1_musig.h @@ -7,364 +7,169 @@ extern "C" { #endif -#include +#include -/** This module implements a Schnorr-based multi-signature scheme called MuSig - * (https://eprint.iacr.org/2018/068.pdf). It is compatible with bip-schnorr. +/** This module implements a Schnorr-based multi-signature scheme called MuSig2 + * (https://eprint.iacr.org/2020/1261, see Appendix B for the exact variant). + * Signatures are compatible with BIP-340 ("Schnorr"). * There's an example C source file in the module's directory - * (src/modules/musig/example.c) that demonstrates how it can be used. + * (examples/musig.c) that demonstrates how it can be used. * - * The documentation in this include file is for reference and may not be sufficient - * for users to begin using the library. A full description of API usage can be found - * in src/modules/musig/musig.md + * The module also supports BIP-341 ("Taproot") public key tweaking and adaptor + * signatures as described in + * https://github.com/ElementsProject/scriptless-scripts/pull/24. + * + * It is recommended to read the documentation in this include file carefully. + * Further notes on API usage can be found in src/modules/musig/musig.md + * + * You may know that the MuSig2 scheme uses two "nonces" instead of one. This + * is not wrong, but only a technical detail we don't want to bother the user + * with. Therefore, the API only uses the singular term "nonce". + * + * Since the first version of MuSig is essentially replaced by MuSig2, when + * writing MuSig or musig here we mean MuSig2. */ -/** Data structure containing auxiliary data generated in `pubkey_combine` and - * required for `session_*_init`. - * Fields: - * magic: Set during initialization in `pubkey_combine` to allow - * detecting an uninitialized object. - * pk_hash: The 32-byte hash of the original public keys - * second_pk: Serialized x-coordinate of the second public key in the list. - * Filled with zeros if there is none. - * 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 +/** Opaque data structures + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. If you + * need to convert to a format suitable for storage, transmission, or + * comparison, use the corresponding serialization and parsing functions. */ -typedef struct { - uint64_t magic; - unsigned char pk_hash[32]; - unsigned char second_pk[32]; - 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 - * signature. - * - * This structure is not opaque, but it MUST NOT be copied or read or written to it - * directly. A signer who is online throughout the whole process and can keep this - * structure in memory can use the provided API functions for a safe standard - * workflow. See https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/ - * for more details about the risks associated with serializing or deserializing this - * structure. - * - * Fields: - * 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 - * msg: The 32-byte message (hash) to be signed - * 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 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. +/** Opaque data structure that caches information about public key aggregation. + * + * Guaranteed to be 165 bytes in size. It can be safely copied/moved. No + * serialization and parsing functions (yet). */ typedef struct { - uint64_t magic; - int round; - secp256k1_musig_pre_session pre_session; - secp256k1_xonly_pubkey combined_pk; - uint32_t n_signers; - int is_msg_set; - unsigned char msg[32]; - int has_secret_data; - unsigned char seckey[32]; - unsigned char secnonce[32]; - secp256k1_xonly_pubkey nonce; - int partial_nonce_parity; - unsigned char nonce_commitments_hash[32]; - secp256k1_xonly_pubkey combined_nonce; - int combined_nonce_parity; -} secp256k1_musig_session; + unsigned char data[165]; +} secp256k1_musig_keyagg_cache; -/** 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_init` or - * `musig_session_init_verifier`, which initializes - * all other fields. The public session is initialized with the signers' - * nonce_commitments. - * - * 2. In a non-public session the nonce_commitments are set with the function - * `musig_get_public_nonce`, which also returns the signer's public nonce. This - * ensures that the public nonce is not exposed until all commitments have been - * received. - * - * 3. Each individual data struct should be updated with `musig_set_nonce` once a - * nonce is available. This function takes a single signer data struct rather than - * an array because it may fail in the case that the provided nonce does not match - * the commitment. In this case, it is desirable to identify the exact party whose - * nonce was inconsistent. - * - * Fields: - * present: indicates whether the signer's nonce is set - * nonce: public nonce, must be a valid curvepoint if the signer is `present` - * nonce_commitment: commitment to the nonce, or all-bits zero if a commitment - * has not yet been set +/** Opaque data structure that holds a signer's _secret_ nonce. + * + * Guaranteed to be 68 bytes in size. + * + * WARNING: This structure MUST NOT be copied or read or written to directly. A + * signer who is online throughout the whole process and can keep this + * structure in memory can use the provided API functions for a safe standard + * workflow. See + * https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/ for + * more details about the risks associated with serializing or deserializing + * this structure. + * + * We repeat, copying this data structure can result in nonce reuse which will + * leak the secret signing key. */ typedef struct { - int present; - secp256k1_xonly_pubkey nonce; - unsigned char nonce_commitment[32]; -} secp256k1_musig_session_signer_data; + unsigned char data[68]; +} secp256k1_musig_secnonce; -/** Opaque data structure that holds a MuSig partial signature. - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. It is however - * guaranteed to be 32 bytes in size, and can be safely copied/moved. If you need - * to convert to a format suitable for storage, transmission, or comparison, use the - * `musig_partial_signature_serialize` and `musig_partial_signature_parse` - * functions. - */ +/** Opaque data structure that holds a signer's public nonce. +* +* Guaranteed to be 132 bytes in size. It can be safely copied/moved. Serialized +* and parsed with `musig_pubnonce_serialize` and `musig_pubnonce_parse`. +*/ typedef struct { - unsigned char data[32]; -} secp256k1_musig_partial_signature; + unsigned char data[132]; +} secp256k1_musig_pubnonce; -/** Computes a combined public key and the hash of the given public keys. - * - * Different orders of `pubkeys` result in different `combined_pk`s. - * - * The pubkeys can be sorted before combining with `secp256k1_xonly_sort` which - * ensures the same resulting `combined_pk` for the same multiset of pubkeys. - * This is useful to do before pubkey_combine, such that the order of pubkeys - * does not affect the combined public key. +/** Opaque data structure that holds an aggregate public nonce. * - * Returns: 1 if the public keys were successfully combined, 0 otherwise - * Args: ctx: pointer to a context object initialized for verification - * (cannot be NULL) - * scratch: scratch space used to compute the combined pubkey by - * multiexponentiation. If NULL, an inefficient algorithm is used. - * Out: combined_pk: the MuSig-combined xonly public key (cannot be NULL) - * pre_session: if non-NULL, pointer to a musig_pre_session struct to be used in - * `musig_session_init` or `musig_pubkey_tweak_add`. - * In: pubkeys: input array of pointers to 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. Must be greater than 0. + * Guaranteed to be 132 bytes in size. It can be safely copied/moved. + * Serialized and parsed with `musig_aggnonce_serialize` and + * `musig_aggnonce_parse`. */ -SECP256K1_API int secp256k1_musig_pubkey_combine( - const secp256k1_context* ctx, - secp256k1_scratch_space *scratch, - secp256k1_xonly_pubkey *combined_pk, - secp256k1_musig_pre_session *pre_session, - const secp256k1_xonly_pubkey * const* pubkeys, - size_t n_pubkeys -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); +typedef struct { + unsigned char data[132]; +} secp256k1_musig_aggnonce; -/** 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`. +/** Opaque data structure that holds a MuSig session. * - * 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). + * This structure is not required to be kept secret for the signing protocol to + * be secure. Guaranteed to be 133 bytes in size. It can be safely + * copied/moved. No serialization and parsing functions (yet). */ -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); +typedef struct { + unsigned char data[133]; +} secp256k1_musig_session; -/** Initializes a signing session for a signer - * - * Returns: 1: session is successfully initialized - * 0: session could not be initialized: secret key or secret nonce overflow - * Args: ctx: pointer to a context object, initialized for signing (cannot - * be NULL) - * Out: session: the session structure to initialize (cannot be NULL) - * signers: an array of signers' data to be initialized. Array length must - * equal to `n_signers` (cannot be NULL) - * nonce_commitment32: filled with a 32-byte commitment to the generated nonce - * (cannot be NULL) - * In: session_id32: a *unique* 32-byte ID to assign to this session (cannot be - * NULL). If a non-unique session_id32 was given then a partial - * signature will LEAK THE SECRET KEY. - * msg32: the 32-byte message to be signed. Shouldn't be NULL unless you - * require sharing nonce commitments before the message is known - * because it reduces nonce misuse resistance. If NULL, must be - * set with `musig_session_get_public_nonce`. - * combined_pk: the combined xonly public key of all signers (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. - * seckey: the signer's 32-byte secret key (cannot be NULL) +/** Opaque data structure that holds a partial MuSig signature. + * + * Guaranteed to be 36 bytes in size. Serialized and parsed with + * `musig_partial_sig_serialize` and `musig_partial_sig_parse`. */ -SECP256K1_API 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, - 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(10); +typedef struct { + unsigned char data[36]; +} secp256k1_musig_partial_sig; -/** 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 - * for signing - * 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_init`. Array length must equal to - * `n_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_init` otherwise can not be NULL. +/** Parse a signer's public nonce. + * + * Returns: 1 when the nonce could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: nonce: pointer to a nonce object + * In: in66: pointer to the 66-byte nonce to be parsed */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_public_nonce( +SECP256K1_API int secp256k1_musig_pubnonce_parse( const secp256k1_context* ctx, - secp256k1_musig_session *session, - secp256k1_musig_session_signer_data *signers, - unsigned char *nonce32, - const unsigned char *const *commitments, - size_t n_commitments, - const unsigned char *msg32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + secp256k1_musig_pubnonce* nonce, + const unsigned char *in66 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Initializes a verifier session that can be used for verifying nonce commitments - * and partial signatures. It does not have secret key material and therefore can not - * be used to create signatures. - * - * Returns: 1 when session is successfully initialized, 0 otherwise - * Args: ctx: pointer to a context object (cannot be NULL) - * Out: session: the session structure to initialize (cannot be NULL) - * signers: an array of signers' data to be initialized. Array length must - * equal to `n_signers`(cannot be NULL) - * In: msg32: the 32-byte message to be signed (cannot be NULL) - * combined_pk: the combined xonly public key of all signers (cannot be NULL) - * pre_session: pointer to a musig_pre_session struct from - * `musig_pubkey_combine` (cannot be NULL) - * pk_hash32: the 32-byte hash of the signers' individual keys (cannot be NULL) - * commitments: array of 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. +/** Serialize a signer's public nonce + * + * Returns: 1 when the nonce could be serialized, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: out66: pointer to a 66-byte array to store the serialized nonce + * In: nonce: pointer to the nonce */ -SECP256K1_API int secp256k1_musig_session_init_verifier( +SECP256K1_API int secp256k1_musig_pubnonce_serialize( 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 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7); + unsigned char *out66, + const secp256k1_musig_pubnonce* nonce +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Checks a signer's public nonce against a commitment to said nonce, and update - * data structure if they match - * - * Returns: 1: commitment was valid, data structure updated - * 0: commitment was invalid, nothing happened - * 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_init_verifier`. - * In: nonce32: signer's alleged public nonce (cannot be NULL) +/** Parse an aggregate public nonce. + * + * Returns: 1 when the nonce could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: nonce: pointer to a nonce object + * In: in66: pointer to the 66-byte nonce to be parsed */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_set_nonce( +SECP256K1_API int secp256k1_musig_aggnonce_parse( const secp256k1_context* ctx, - secp256k1_musig_session_signer_data *signer, - const unsigned char *nonce32 + secp256k1_musig_aggnonce* nonce, + const unsigned char *in66 ) 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 - * public nonce is the sum of every signer's public nonce. - * - * Returns: 1: nonces are successfully combined - * 0: a signer's nonce is missing - * Args: ctx: pointer to a context object (cannot be NULL) - * session: session to update with the combined public nonce (cannot be - * NULL) - * signers: an array of signers' data, which must have had public nonces - * set with `musig_set_nonce`. Array length must equal to `n_signers` - * (cannot be NULL) - * n_signers: the length of the signers array. Must be the total number of - * signers participating in the MuSig. - * 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. +/** Serialize an aggregate public nonce + * + * Returns: 1 when the nonce could be serialized, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: out66: pointer to a 66-byte array to store the serialized nonce + * In: nonce: pointer to the nonce */ -SECP256K1_API int secp256k1_musig_session_combine_nonces( +SECP256K1_API int secp256k1_musig_aggnonce_serialize( 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 + unsigned char *out66, + const secp256k1_musig_aggnonce* nonce ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Serialize a MuSig partial signature or adaptor signature +/** Serialize a MuSig partial signature * * Returns: 1 when the signature could be serialized, 0 otherwise * Args: ctx: a secp256k1 context object * Out: out32: pointer to a 32-byte array to store the serialized signature * In: sig: pointer to the signature */ -SECP256K1_API int secp256k1_musig_partial_signature_serialize( +SECP256K1_API int secp256k1_musig_partial_sig_serialize( const secp256k1_context* ctx, unsigned char *out32, - const secp256k1_musig_partial_signature* sig + const secp256k1_musig_partial_sig* sig ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Parse and verify a MuSig partial signature. +/** Parse a MuSig partial signature. * * Returns: 1 when the signature could be parsed, 0 otherwise. * Args: ctx: a secp256k1 context object @@ -375,113 +180,337 @@ SECP256K1_API int secp256k1_musig_partial_signature_serialize( * encoded numbers are out of range, signature verification with it is * guaranteed to fail for every message and public key. */ -SECP256K1_API int secp256k1_musig_partial_signature_parse( +SECP256K1_API int secp256k1_musig_partial_sig_parse( const secp256k1_context* ctx, - secp256k1_musig_partial_signature* sig, + secp256k1_musig_partial_sig* sig, const unsigned char *in32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +/** Computes an aggregate public key and uses it to initialize a keyagg_cache + * + * Different orders of `pubkeys` result in different `agg_pk`s. + * + * The pubkeys can be sorted before combining with `secp256k1_xonly_sort` which + * ensures the same `agg_pk` result for the same multiset of pubkeys. + * This is useful to do before `pubkey_agg`, such that the order of pubkeys + * does not affect the aggregate public key. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object initialized for verification + * scratch: scratch space used to compute the aggregate pubkey by + * multiexponentiation. Generally, the larger the scratch + * space, the faster this function. However, the returns of + * providing a larger scratch space are diminishing. If NULL, + * an inefficient algorithm is used. + * Out: agg_pk: the MuSig-aggregated x-only public key. If you do not need it, + * this arg can be NULL. + * keyagg_cache: if non-NULL, pointer to a musig_keyagg_cache struct that + * is required for signing (or observing the signing session + * and verifying partial signatures). + * In: pubkeys: input array of pointers to public keys to aggregate. The order + * is important; a different order will result in a different + * aggregate public key. + * n_pubkeys: length of pubkeys array. Must be greater than 0. + */ +SECP256K1_API int secp256k1_musig_pubkey_agg( + const secp256k1_context* ctx, + secp256k1_scratch_space *scratch, + secp256k1_xonly_pubkey *agg_pk, + secp256k1_musig_keyagg_cache *keyagg_cache, + const secp256k1_xonly_pubkey * const* pubkeys, + size_t n_pubkeys +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(5); + +/** Tweak an x-only public key in a given keyagg_cache by adding + * the generator multiplied with `tweak32` to it. + * + * The tweaking method is the same as `secp256k1_xonly_pubkey_tweak_add`. So in + * the following pseudocode xonly_pubkey_tweak_add_check (absent earlier + * failures) returns 1. + * + * secp256k1_musig_pubkey_agg(..., agg_pk, keyagg_cache, pubkeys, ...) + * secp256k1_musig_pubkey_tweak_add(..., output_pubkey, tweak32, keyagg_cache) + * secp256k1_xonly_pubkey_serialize(..., buf, output_pubkey) + * secp256k1_xonly_pubkey_tweak_add_check(..., buf, ..., agg_pk, tweak32) + * + * This function is required if you want to _sign_ for a tweaked aggregate key. + * On the other hand, 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`. + * + * 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 + * Out: output_pubkey: pointer to a public key to store the result. Will be set + * to an invalid value if this function returns 0. If you + * do not need it, this arg can be NULL. + * In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by + * `musig_pubkey_agg` + * In: 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). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_tweak_add( + const secp256k1_context* ctx, + secp256k1_pubkey *output_pubkey, + secp256k1_musig_keyagg_cache *keyagg_cache, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Starts a signing session by generating a nonce + * + * This function outputs a secret nonce that will be required for signing and a + * corresponding public nonce that is intended to be sent to other signers. + * + * MuSig differs from regular Schnorr signing in that implementers _must_ take + * special care to not reuse a nonce. This can be ensured by following these rules: + * + * 1. Each call to this function must have a UNIQUE session_id32 that must NOT BE + * REUSED in subsequent calls to this function. + * If you do not provide a seckey, session_id32 _must_ be UNIFORMLY RANDOM + * AND KEPT SECRET (even from other signers). If you do provide a seckey, + * session_id32 can instead be a counter (that must never repeat!). However, + * it is recommended to always choose session_id32 uniformly at random. + * 2. If you already know the seckey, message or aggregate public key + * cache, they can be optionally provided to derive the nonce and increase + * misuse-resistance. The extra_input32 argument can be used to provide + * additional data that does not repeat in normal scenarios, such as the + * current time. + * 3. Avoid copying (or serializing) the secnonce. This reduces the possibility + * that it is used more than once for signing. + * + * Remember that nonce reuse will leak the secret key! + * Note that using the same seckey for multiple MuSig sessions is fine. + * + * Returns: 0 if the arguments are invalid and 1 otherwise + * Args: ctx: pointer to a context object, initialized for signing + * Out: secnonce: pointer to a structure to store the secret nonce + * pubnonce: pointer to a structure to store the public nonce + * In: session_id32: a 32-byte session_id32 as explained above. Must be unique to this + * call to secp256k1_musig_nonce_gen and must be uniformly random + * unless you really know what you are doing. + * seckey: the 32-byte secret key that will later be used for signing, if + * already known (can be NULL) + * msg32: the 32-byte message that will later be signed, if already known + * (can be NULL) + * keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate + * (and potentially tweaked) public key if already known + * (can be NULL) + * extra_input32: an optional 32-byte array that is input to the nonce + * derivation function (can be NULL) + */ +SECP256K1_API int secp256k1_musig_nonce_gen( + const secp256k1_context* ctx, + secp256k1_musig_secnonce *secnonce, + secp256k1_musig_pubnonce *pubnonce, + const unsigned char *session_id32, + const unsigned char *seckey, + const unsigned char *msg32, + const secp256k1_musig_keyagg_cache *keyagg_cache, + const unsigned char *extra_input32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Aggregates the nonces of all signers into a single nonce + * + * This can be done by an untrusted party to reduce the communication + * between signers. Instead of everyone sending nonces to everyone else, there + * can be one party receiving all nonces, aggregating the nonces with this + * function and then sending only the aggregate nonce back to the signers. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: aggnonce: pointer to an aggregate public nonce object for + * musig_nonce_process + * In: pubnonces: array of pointers to public nonces sent by the + * signers + * n_pubnonces: number of elements in the pubnonces array. Must be + * greater than 0. + */ +SECP256K1_API int secp256k1_musig_nonce_agg( + const secp256k1_context* ctx, + secp256k1_musig_aggnonce *aggnonce, + const secp256k1_musig_pubnonce * const* pubnonces, + size_t n_pubnonces +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Takes the public nonces of all signers and computes a session that is + * required for signing and verification of partial signatures. + * + * If the adaptor argument is non-NULL, then the output of + * musig_partial_sig_agg will be a pre-signature which is not a valid Schnorr + * signature. In order to create a valid signature, the pre-signature and the + * secret adaptor must be provided to `musig_adapt`. + * + * Returns: 0 if the arguments are invalid or if some signer sent invalid + * pubnonces, 1 otherwise + * Args: ctx: pointer to a context object, initialized for verification + * Out: session: pointer to a struct to store the session + * In: aggnonce: pointer to an aggregate public nonce object that is the + * output of musig_nonce_agg + * msg32: the 32-byte message to sign + * keyagg_cache: pointer to the keyagg_cache that was used to create the + * aggregate (and potentially tweaked) pubkey + * adaptor: optional pointer to an adaptor point encoded as a public + * key if this signing session is part of an adaptor + * signature protocol (can be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_process( + const secp256k1_context* ctx, + secp256k1_musig_session *session, + const secp256k1_musig_aggnonce *aggnonce, + const unsigned char *msg32, + const secp256k1_musig_keyagg_cache *keyagg_cache, + const secp256k1_pubkey *adaptor +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + /** Produces a partial signature * - * Returns: 1: partial signature constructed - * 0: session in incorrect or inconsistent state - * Args: ctx: pointer to a context object (cannot be NULL) - * session: active signing session for which the combined nonce has been - * computed (cannot be NULL) - * Out: partial_sig: partial signature (cannot be NULL) + * This function overwrites the given secnonce with zeros and will abort if given a + * secnonce that is all zeros. This is a best effort attempt to protect against nonce + * reuse. However, this is of course easily defeated if the secnonce has been + * copied (or serialized). Remember that nonce reuse will leak the secret key! + * + * Returns: 0 if the arguments are invalid or the provided secnonce has already + * been used for signing, 1 otherwise + * Args: ctx: pointer to a context object + * Out: partial_sig: pointer to struct to store the partial signature + * In/Out: secnonce: pointer to the secnonce struct created in + * musig_nonce_gen that has been never used in a + * partial_sign call before + * In: keypair: pointer to keypair to sign the message with + * keyagg_cache: pointer to the keyagg_cache that was output when the + * aggregate public key for this session + * session: pointer to the session that was created with + * musig_nonce_process */ SECP256K1_API int secp256k1_musig_partial_sign( const secp256k1_context* ctx, - const secp256k1_musig_session *session, - secp256k1_musig_partial_signature *partial_sig -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + secp256k1_musig_partial_sig *partial_sig, + secp256k1_musig_secnonce *secnonce, + const secp256k1_keypair *keypair, + const secp256k1_musig_keyagg_cache *keyagg_cache, + const secp256k1_musig_session *session +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); -/** Checks that an individual partial signature verifies +/** Verifies an individual signer's partial signature * * This function is essential when using protocols with adaptor signatures. - * However, it is not essential for regular MuSig's, in the sense that if any - * partial signatures does not verify, the full signature will also not verify, so the + * However, it is not essential for regular MuSig sessions, in the sense that if any + * partial signature does not verify, the full signature will not verify either, so the * problem will be caught. But this function allows determining the specific party - * who produced an invalid signature, so that signing can be restarted without them. - * - * Returns: 1: partial signature verifies - * 0: invalid signature or bad data - * Args: ctx: pointer to a context object (cannot be NULL) - * session: active session for which the combined nonce has been computed - * (cannot be NULL) - * signer: data for the signer who produced this signature (cannot be NULL) - * In: partial_sig: signature to verify (cannot be NULL) - * pubkey: public key of the signer who produced the signature (cannot be NULL) + * who produced an invalid signature. + * + * Returns: 0 if the arguments are invalid or the partial signature does not + * verify, 1 otherwise + * Args ctx: pointer to a context object, initialized for verification + * In: partial_sig: pointer to partial signature to verify + * pubnonce: public nonce sent by the signer who produced the signature + * pubkey: public key of the signer who produced the signature + * keyagg_cache: pointer to the keyagg_cache that was output when the + * aggregate public key for this session + * session: pointer to the session that was created with + * musig_nonce_process */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify( const secp256k1_context* ctx, - const secp256k1_musig_session *session, - const secp256k1_musig_session_signer_data *signer, - const secp256k1_musig_partial_signature *partial_sig, - const secp256k1_xonly_pubkey *pubkey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + const secp256k1_musig_partial_sig *partial_sig, + const secp256k1_musig_pubnonce *pubnonce, + const secp256k1_xonly_pubkey *pubkey, + const secp256k1_musig_keyagg_cache *keyagg_cache, + const secp256k1_musig_session *session +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); -/** Combines partial signatures - * - * Returns: 1: all partial signatures have values in range. Does NOT mean the - * resulting signature verifies. - * 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) - * Out: sig64: complete signature (cannot be NULL) - * In: partial_sigs: array of partial signatures to combine (cannot be NULL) - * n_sigs: number of signatures in the partial_sigs array +/** Aggregates partial signatures + * + * Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean + * the resulting signature verifies). + * Args: ctx: pointer to a context object + * Out: sig64: complete (but possibly invalid) Schnorr signature + * In: session: pointer to the session that was created with + * musig_nonce_process + * partial_sigs: array of pointers to partial signatures to aggregate + * n_sigs: number of elements in the partial_sigs array. Must be + * greater than 0. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_combine( +SECP256K1_API int secp256k1_musig_partial_sig_agg( const secp256k1_context* ctx, - const secp256k1_musig_session *session, unsigned char *sig64, - const secp256k1_musig_partial_signature *partial_sigs, + const secp256k1_musig_session *session, + const secp256k1_musig_partial_sig * const* partial_sigs, size_t n_sigs ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -/** Converts a partial signature to an adaptor signature by adding a given secret - * adaptor. - * - * Returns: 1: signature and secret adaptor contained valid values - * 0: otherwise - * Args: ctx: pointer to a context object (cannot be NULL) - * Out: adaptor_sig: adaptor signature to produce (cannot be NULL) - * 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_parity: the `nonce_parity` output of `musig_session_combine_nonces` +/** Extracts the nonce_parity bit from a session + * + * This is used for adaptor signatures. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: nonce_parity: pointer to an integer that indicates the parity + * of the aggregate public nonce. Used for adaptor + * signatures. + * In: session: pointer to the session that was created with + * musig_nonce_process + */ +SECP256K1_API int secp256k1_musig_nonce_parity( + const secp256k1_context* ctx, + int *nonce_parity, + const secp256k1_musig_session *session +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Creates a signature from a pre-signature and an adaptor. + * + * If the sec_adaptor32 argument is incorrect, the output signature will be + * invalid. This function does not verify the signature. + * + * Returns: 0 if the arguments are invalid, or pre_sig64 or sec_adaptor32 contain + * invalid (overflowing) values. 1 otherwise (which does NOT mean the + * signature or the adaptor are valid!) + * Args: ctx: pointer to a context object + * Out: sig64: 64-byte signature. This pointer may point to the same + * memory area as `pre_sig`. + * In: pre_sig64: 64-byte pre-signature + * sec_adaptor32: 32-byte secret adaptor to add to the pre-signature + * nonce_parity: the output of `musig_nonce_parity` called with the + * session used for producing the pre-signature */ -SECP256K1_API int secp256k1_musig_partial_sig_adapt( +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_adapt( const secp256k1_context* ctx, - secp256k1_musig_partial_signature *adaptor_sig, - const secp256k1_musig_partial_signature *partial_sig, + unsigned char *sig64, + const unsigned char *pre_sig64, const unsigned char *sec_adaptor32, 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 - * signatures. This function will not fail unless given grossly invalid data; if it - * is merely given signatures that do not verify, the returned value will be - * nonsense. It is therefore important that all data be verified at earlier steps of - * any protocol that uses this function. - * - * Returns: 1: signatures contained valid data such that an adaptor could be extracted - * 0: otherwise - * Args: ctx: pointer to a context object (cannot be NULL) - * Out:sec_adaptor32: 32-byte secret adaptor (cannot be NULL) - * In: sig64: complete 2-of-2 signature (cannot be NULL) - * partial_sigs: array of partial signatures (cannot be NULL) - * n_partial_sigs: number of elements in partial_sigs array - * nonce_parity: the `nonce_parity` output of `musig_session_combine_nonces` +/** Extracts a secret adaptor from a MuSig pre-signature and corresponding + * signature + * + * This function will not fail unless given grossly invalid data; if it is + * merely given signatures that do not verify, the returned value will be + * nonsense. It is therefore important that all data be verified at earlier + * steps of any protocol that uses this function. In particular, this includes + * verifying all partial signatures that were aggregated into pre_sig64. + * + * Returns: 0 if the arguments are NULL, or sig64 or pre_sig64 contain + * grossly invalid (overflowing) values. 1 otherwise (which does NOT + * mean the signatures or the adaptor are valid!) + * Args: ctx: pointer to a context object + * Out:sec_adaptor32: 32-byte secret adaptor + * In: sig64: complete, valid 64-byte signature + * pre_sig64: the pre-signature corresponding to sig64, i.e., the + * aggregate of partial signatures without the secret + * adaptor + * nonce_parity: the output of `musig_nonce_parity` called with the + * session used for producing sig64 */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_secret_adaptor( +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_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, + const unsigned char *pre_sig64, int nonce_parity ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); diff --git a/src/modules/musig/Makefile.am.include b/src/modules/musig/Makefile.am.include index 0cd254d8a..dc2f77f1a 100644 --- a/src/modules/musig/Makefile.am.include +++ b/src/modules/musig/Makefile.am.include @@ -1,16 +1,8 @@ include_HEADERS += include/secp256k1_musig.h noinst_HEADERS += src/modules/musig/main_impl.h +noinst_HEADERS += src/modules/musig/keyagg.h +noinst_HEADERS += src/modules/musig/keyagg_impl.h +noinst_HEADERS += src/modules/musig/session.h +noinst_HEADERS += src/modules/musig/session_impl.h +noinst_HEADERS += src/modules/musig/adaptor_impl.h noinst_HEADERS += src/modules/musig/tests_impl.h - -noinst_PROGRAMS += example_musig -example_musig_SOURCES = src/modules/musig/example.c -example_musig_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include $(SECP_INCLUDES) -if !ENABLE_COVERAGE -example_musig_CPPFLAGS += -DVERIFY -endif -example_musig_LDADD = libsecp256k1.la $(SECP_LIBS) -example_musig_LDFLAGS = -static - -if USE_TESTS -TESTS += example_musig -endif diff --git a/src/modules/musig/adaptor_impl.h b/src/modules/musig/adaptor_impl.h new file mode 100644 index 000000000..3830e8a26 --- /dev/null +++ b/src/modules/musig/adaptor_impl.h @@ -0,0 +1,101 @@ +/*********************************************************************** + * Copyright (c) 2021 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_ADAPTOR_IMPL_H +#define SECP256K1_MODULE_MUSIG_ADAPTOR_IMPL_H + +#include + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_musig.h" + +#include "session.h" +#include "../../scalar.h" + +int secp256k1_musig_nonce_parity(const secp256k1_context* ctx, int *nonce_parity, const secp256k1_musig_session *session) { + secp256k1_musig_session_internal session_i; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(nonce_parity != NULL); + ARG_CHECK(session != NULL); + + if (!secp256k1_musig_session_load(ctx, &session_i, session)) { + return 0; + } + *nonce_parity = session_i.fin_nonce_parity; + return 1; +} + +int secp256k1_musig_adapt(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *pre_sig64, const unsigned char *sec_adaptor32, int nonce_parity) { + secp256k1_scalar s; + secp256k1_scalar t; + int overflow; + int ret = 1; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(pre_sig64 != NULL); + ARG_CHECK(sec_adaptor32 != NULL); + ARG_CHECK(nonce_parity == 0 || nonce_parity == 1); + + secp256k1_scalar_set_b32(&s, &pre_sig64[32], &overflow); + if (overflow) { + return 0; + } + secp256k1_scalar_set_b32(&t, sec_adaptor32, &overflow); + ret &= !overflow; + + /* Determine if the secret adaptor should be negated. + * + * The musig_session stores the X-coordinate and the parity of the "final nonce" + * (r + t)*G, where r*G is the aggregate public nonce and t is the secret adaptor. + * + * Since a BIP340 signature requires an x-only public nonce, in the case where + * (r + t)*G has odd Y-coordinate (i.e. nonce_parity == 1), the x-only public nonce + * corresponding to the signature is actually (-r - t)*G. Thus adapting a + * pre-signature requires negating t in this case. + */ + if (nonce_parity) { + secp256k1_scalar_negate(&t, &t); + } + + secp256k1_scalar_add(&s, &s, &t); + secp256k1_scalar_get_b32(&sig64[32], &s); + memmove(sig64, pre_sig64, 32); + secp256k1_scalar_clear(&t); + return ret; +} + +int secp256k1_musig_extract_adaptor(const secp256k1_context* ctx, unsigned char *sec_adaptor32, const unsigned char *sig64, const unsigned char *pre_sig64, int nonce_parity) { + secp256k1_scalar t; + secp256k1_scalar s; + int overflow; + int ret = 1; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sec_adaptor32 != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(pre_sig64 != NULL); + ARG_CHECK(nonce_parity == 0 || nonce_parity == 1); + + secp256k1_scalar_set_b32(&t, &sig64[32], &overflow); + ret &= !overflow; + secp256k1_scalar_negate(&t, &t); + + secp256k1_scalar_set_b32(&s, &pre_sig64[32], &overflow); + if (overflow) { + return 0; + } + secp256k1_scalar_add(&t, &t, &s); + + if (!nonce_parity) { + secp256k1_scalar_negate(&t, &t); + } + secp256k1_scalar_get_b32(sec_adaptor32, &t); + secp256k1_scalar_clear(&t); + return ret; +} + +#endif diff --git a/src/modules/musig/example.c b/src/modules/musig/example.c deleted file mode 100644 index 66cad7499..000000000 --- a/src/modules/musig/example.c +++ /dev/null @@ -1,170 +0,0 @@ -/********************************************************************** - * Copyright (c) 2018 Jonas Nick * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -/** - * This file demonstrates how to use the MuSig module to create a multisignature. - * Additionally, see the documentation in include/secp256k1_musig.h. - */ - -#include -#include -#include -#include -#include - - /* Number of public keys involved in creating the aggregate signature */ -#define N_SIGNERS 3 - /* Create a key pair and store it in seckey and pubkey */ -int create_keypair(const secp256k1_context* ctx, unsigned char *seckey, secp256k1_xonly_pubkey *pubkey) { - int ret; - secp256k1_keypair keypair; - FILE *frand = fopen("/dev/urandom", "r"); - if (frand == NULL) { - return 0; - } - do { - if(!fread(seckey, 32, 1, frand)) { - fclose(frand); - return 0; - } - /* The probability that this not a valid secret key is approximately 2^-128 */ - } while (!secp256k1_ec_seckey_verify(ctx, seckey)); - fclose(frand); - ret = secp256k1_keypair_create(ctx, &keypair, seckey); - ret &= secp256k1_keypair_xonly_pub(ctx, pubkey, NULL, &keypair); - - return ret; -} - -/* Sign a message hash with the given key pairs and store the result in sig */ -int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp256k1_xonly_pubkey** pubkeys, const unsigned char* msg32, unsigned char *sig64) { - secp256k1_musig_session musig_session[N_SIGNERS]; - unsigned char nonce_commitment[N_SIGNERS][32]; - const unsigned char *nonce_commitment_ptr[N_SIGNERS]; - secp256k1_musig_session_signer_data signer_data[N_SIGNERS][N_SIGNERS]; - unsigned char nonce[N_SIGNERS][32]; - int i, j; - secp256k1_musig_partial_signature partial_sig[N_SIGNERS]; - - for (i = 0; i < N_SIGNERS; i++) { - FILE *frand; - unsigned char session_id32[32]; - secp256k1_xonly_pubkey combined_pk; - secp256k1_musig_pre_session pre_session; - - /* Create combined pubkey and initialize signer data */ - if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, &pre_session, pubkeys, N_SIGNERS)) { - return 0; - } - /* Create random session ID. It is absolutely necessary that the session ID - * 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) { - return 0; - } - if (!fread(session_id32, 32, 1, frand)) { - fclose(frand); - return 0; - } - fclose(frand); - /* Initialize session */ - if (!secp256k1_musig_session_init(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, &pre_session, N_SIGNERS, seckeys[i])) { - return 0; - } - nonce_commitment_ptr[i] = &nonce_commitment[i][0]; - } - /* 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)) { - 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])) { - /* 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!). */ - return 0; - } - } - if (!secp256k1_musig_session_combine_nonces(ctx, &musig_session[i], signer_data[i], N_SIGNERS, NULL, NULL)) { - return 0; - } - } - for (i = 0; i < N_SIGNERS; i++) { - if (!secp256k1_musig_partial_sign(ctx, &musig_session[i], &partial_sig[i])) { - return 0; - } - } - /* Communication round 3: Exchange partial signatures */ - for (i = 0; i < N_SIGNERS; i++) { - for (j = 0; j < N_SIGNERS; j++) { - /* To check whether signing was successful, it suffices to either verify - * the combined signature with the combined public key using - * secp256k1_schnorrsig_verify, or verify all partial signatures of all - * signers individually. Verifying the combined signature is cheaper but - * verifying the individual partial signatures has the advantage that it - * can be used to determine which of the partial signatures are invalid - * (if any), i.e., which of the partial signatures cause the combined - * signature to be invalid and thus the protocol run to fail. It's also - * fine to first verify the combined sig, and only verify the individual - * sigs if it does not work. - */ - if (!secp256k1_musig_partial_sig_verify(ctx, &musig_session[i], &signer_data[i][j], &partial_sig[j], pubkeys[j])) { - return 0; - } - } - } - return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig64, partial_sig, N_SIGNERS); -} - - int main(void) { - secp256k1_context* ctx; - int i; - unsigned char seckeys[N_SIGNERS][32]; - secp256k1_xonly_pubkey pubkeys[N_SIGNERS]; - const secp256k1_xonly_pubkey *pubkeys_ptr[N_SIGNERS]; - secp256k1_xonly_pubkey combined_pk; - unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!"; - unsigned char sig[64]; - - /* Create a context for signing and verification */ - ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - printf("Creating key pairs......"); - for (i = 0; i < N_SIGNERS; i++) { - if (!create_keypair(ctx, seckeys[i], &pubkeys[i])) { - printf("FAILED\n"); - return 1; - } - pubkeys_ptr[i] = &pubkeys[i]; - } - printf("ok\n"); - printf("Combining public keys..."); - if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, NULL, pubkeys_ptr, N_SIGNERS)) { - printf("FAILED\n"); - return 1; - } - printf("ok\n"); - printf("Signing message........."); - if (!sign(ctx, seckeys, pubkeys_ptr, msg, sig)) { - printf("FAILED\n"); - return 1; - } - printf("ok\n"); - printf("Verifying signature....."); - if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &combined_pk)) { - printf("FAILED\n"); - return 1; - } - printf("ok\n"); - secp256k1_context_destroy(ctx); - return 0; -} - diff --git a/src/modules/musig/keyagg.h b/src/modules/musig/keyagg.h new file mode 100644 index 000000000..69c1f34ad --- /dev/null +++ b/src/modules/musig/keyagg.h @@ -0,0 +1,34 @@ +/*********************************************************************** + * Copyright (c) 2021 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_H +#define SECP256K1_MODULE_MUSIG_KEYAGG_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_musig.h" + +#include "../../field.h" +#include "../../group.h" +#include "../../scalar.h" + +typedef struct { + secp256k1_ge pk; + secp256k1_fe second_pk_x; + unsigned char pk_hash[32]; + secp256k1_scalar tweak; + int internal_key_parity; +} secp256k1_keyagg_cache_internal; + +/* Requires that the saved point is not infinity */ +static void secp256k1_point_save(unsigned char *data, secp256k1_ge *ge); + +static void secp256k1_point_load(secp256k1_ge *ge, const unsigned char *data); + +static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache); + +static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_fe *x); + +#endif diff --git a/src/modules/musig/keyagg_impl.h b/src/modules/musig/keyagg_impl.h new file mode 100644 index 000000000..9a747f4dc --- /dev/null +++ b/src/modules/musig/keyagg_impl.h @@ -0,0 +1,280 @@ +/*********************************************************************** + * Copyright (c) 2021 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H +#define SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H + +#include + +#include "keyagg.h" +#include "../../eckey.h" +#include "../../ecmult.h" +#include "../../field.h" +#include "../../group.h" +#include "../../hash.h" +#include "../../util.h" + +static void secp256k1_point_save(unsigned char *data, secp256k1_ge *ge) { + if (sizeof(secp256k1_ge_storage) == 64) { + secp256k1_ge_storage s; + secp256k1_ge_to_storage(&s, ge); + memcpy(data, &s, sizeof(s)); + } else { + VERIFY_CHECK(!secp256k1_ge_is_infinity(ge)); + secp256k1_fe_normalize_var(&ge->x); + secp256k1_fe_normalize_var(&ge->y); + secp256k1_fe_get_b32(data, &ge->x); + secp256k1_fe_get_b32(data + 32, &ge->y); + } +} + +static void secp256k1_point_load(secp256k1_ge *ge, const unsigned char *data) { + if (sizeof(secp256k1_ge_storage) == 64) { + /* When the secp256k1_ge_storage type is exactly 64 byte, use its + * representation as conversion is very fast. */ + secp256k1_ge_storage s; + memcpy(&s, data, sizeof(s)); + secp256k1_ge_from_storage(ge, &s); + } else { + /* Otherwise, fall back to 32-byte big endian for X and Y. */ + secp256k1_fe x, y; + secp256k1_fe_set_b32(&x, data); + secp256k1_fe_set_b32(&y, data + 32); + secp256k1_ge_set_xy(ge, &x, &y); + } +} + +static const unsigned char secp256k1_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf }; + +/* A keyagg cache consists of + * - 4 byte magic set during initialization to allow detecting an uninitialized + * object. + * - 64 byte aggregate (and potentially tweaked) public key + * - 32 byte X-coordinate of "second" public key (0 if not present) + * - 32 byte hash of all public keys + * - 1 byte the parity of the internal key (if tweaked, otherwise 0) + * - 32 byte tweak + */ +/* Requires that cache_i->pk is not infinity and cache_i->second_pk_x to be normalized. */ +static void secp256k1_keyagg_cache_save(secp256k1_musig_keyagg_cache *cache, secp256k1_keyagg_cache_internal *cache_i) { + unsigned char *ptr = cache->data; + memcpy(ptr, secp256k1_musig_keyagg_cache_magic, 4); + ptr += 4; + secp256k1_point_save(ptr, &cache_i->pk); + ptr += 64; + secp256k1_fe_get_b32(ptr, &cache_i->second_pk_x); + ptr += 32; + memcpy(ptr, cache_i->pk_hash, 32); + ptr += 32; + *ptr = cache_i->internal_key_parity; + ptr += 1; + secp256k1_scalar_get_b32(ptr, &cache_i->tweak); +} + +static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache) { + const unsigned char *ptr = cache->data; + ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_keyagg_cache_magic, 4) == 0); + ptr += 4; + secp256k1_point_load(&cache_i->pk, ptr); + ptr += 64; + secp256k1_fe_set_b32(&cache_i->second_pk_x, ptr); + ptr += 32; + memcpy(cache_i->pk_hash, ptr, 32); + ptr += 32; + cache_i->internal_key_parity = *ptr & 1; + ptr += 1; + secp256k1_scalar_set_b32(&cache_i->tweak, ptr, NULL); + return 1; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("KeyAgg list")||SHA256("KeyAgg list"). */ +static void secp256k1_musig_keyagglist_sha256(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + + sha->s[0] = 0xb399d5e0ul; + sha->s[1] = 0xc8fff302ul; + sha->s[2] = 0x6badac71ul; + sha->s[3] = 0x07c5b7f1ul; + sha->s[4] = 0x9701e2eful; + sha->s[5] = 0x2a72ecf8ul; + sha->s[6] = 0x201a4c7bul; + sha->s[7] = 0xab148a38ul; + sha->bytes = 64; +} + +/* Computes pk_hash = tagged_hash(pk[0], ..., pk[np-1]) */ +static int secp256k1_musig_compute_pk_hash(const secp256k1_context *ctx, unsigned char *pk_hash, const secp256k1_xonly_pubkey * const* pk, size_t np) { + secp256k1_sha256 sha; + size_t i; + + secp256k1_musig_keyagglist_sha256(&sha); + for (i = 0; i < np; i++) { + unsigned char ser[32]; + if (!secp256k1_xonly_pubkey_serialize(ctx, ser, pk[i])) { + return 0; + } + secp256k1_sha256_write(&sha, ser, 32); + } + secp256k1_sha256_finalize(&sha, pk_hash); + return 1; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("KeyAgg coefficient")||SHA256("KeyAgg coefficient"). */ +static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + + sha->s[0] = 0x6ef02c5aul; + sha->s[1] = 0x06a480deul; + sha->s[2] = 0x1f298665ul; + sha->s[3] = 0x1d1134f2ul; + sha->s[4] = 0x56a0b063ul; + sha->s[5] = 0x52da4147ul; + sha->s[6] = 0xf280d9d4ul; + sha->s[7] = 0x4484be15ul; + sha->bytes = 64; +} + +/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and + * tagged_hash(pk_hash, x) where pk_hash is the hash of public keys otherwise. + * second_pk_x can be 0 in case there is no second_pk. Assumes both field + * elements x and second_pk_x are normalized. */ +static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pk_hash, const secp256k1_fe *x, const secp256k1_fe *second_pk_x) { + secp256k1_sha256 sha; + unsigned char buf[32]; + + if (secp256k1_fe_cmp_var(x, second_pk_x) == 0) { + secp256k1_scalar_set_int(r, 1); + } else { + secp256k1_musig_keyaggcoef_sha256(&sha); + secp256k1_sha256_write(&sha, pk_hash, 32); + secp256k1_fe_get_b32(buf, x); + secp256k1_sha256_write(&sha, buf, 32); + secp256k1_sha256_finalize(&sha, buf); + secp256k1_scalar_set_b32(r, buf, NULL); + } + +} + +/* Assumes both field elements x and second_pk_x are normalized. */ +static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_fe *x) { + secp256k1_musig_keyaggcoef_internal(r, cache_i->pk_hash, x, &cache_i->second_pk_x); +} + +typedef struct { + const secp256k1_context *ctx; + /* pk_hash is the hash of the public keys */ + unsigned char pk_hash[32]; + const secp256k1_xonly_pubkey * const* pks; + secp256k1_fe second_pk_x; +} secp256k1_musig_pubkey_agg_ecmult_data; + +/* Callback for batch EC multiplication to compute keyaggcoef_0*P0 + keyaggcoef_1*P1 + ... */ +static int secp256k1_musig_pubkey_agg_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) { + secp256k1_musig_pubkey_agg_ecmult_data *ctx = (secp256k1_musig_pubkey_agg_ecmult_data *) data; + int ret; + ret = secp256k1_xonly_pubkey_load(ctx->ctx, pt, ctx->pks[idx]); + /* pubkey_load can't fail because the same pks have already been loaded in + * `musig_compute_pk_hash` (and we test this). */ + VERIFY_CHECK(ret); + secp256k1_musig_keyaggcoef_internal(sc, ctx->pk_hash, &pt->x, &ctx->second_pk_x); + return 1; +} + +int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_xonly_pubkey * const* pubkeys, size_t n_pubkeys) { + secp256k1_musig_pubkey_agg_ecmult_data ecmult_data; + secp256k1_gej pkj; + secp256k1_ge pkp; + size_t i; + + VERIFY_CHECK(ctx != NULL); + if (agg_pk != NULL) { + memset(agg_pk, 0, sizeof(*agg_pk)); + } + ARG_CHECK(pubkeys != NULL); + ARG_CHECK(n_pubkeys > 0); + + ecmult_data.ctx = ctx; + ecmult_data.pks = pubkeys; + /* No point on the curve has an X coordinate equal to 0 */ + secp256k1_fe_set_int(&ecmult_data.second_pk_x, 0); + for (i = 1; i < n_pubkeys; i++) { + if (secp256k1_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) { + secp256k1_ge pt; + if (!secp256k1_xonly_pubkey_load(ctx, &pt, pubkeys[i])) { + return 0; + } + ecmult_data.second_pk_x = pt.x; + break; + } + } + + if (!secp256k1_musig_compute_pk_hash(ctx, ecmult_data.pk_hash, pubkeys, n_pubkeys)) { + return 0; + } + if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &pkj, NULL, secp256k1_musig_pubkey_agg_callback, (void *) &ecmult_data, n_pubkeys)) { + /* In order to reach this line with the current implementation of + * ecmult_multi_var one would need to provide a callback that can + * fail. */ + return 0; + } + secp256k1_ge_set_gej(&pkp, &pkj); + secp256k1_fe_normalize_var(&pkp.y); + /* The resulting public key is infinity with negligible probability */ + VERIFY_CHECK(!secp256k1_ge_is_infinity(&pkp)); + if (keyagg_cache != NULL) { + secp256k1_keyagg_cache_internal cache_i = { 0 }; + cache_i.pk = pkp; + cache_i.second_pk_x = ecmult_data.second_pk_x; + memcpy(cache_i.pk_hash, ecmult_data.pk_hash, sizeof(cache_i.pk_hash)); + secp256k1_keyagg_cache_save(keyagg_cache, &cache_i); + } + + secp256k1_extrakeys_ge_even_y(&pkp); + if (agg_pk != NULL) { + secp256k1_xonly_pubkey_save(agg_pk, &pkp); + } + return 1; +} + +int secp256k1_musig_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) { + secp256k1_keyagg_cache_internal cache_i; + int overflow = 0; + secp256k1_scalar tweak; + + VERIFY_CHECK(ctx != NULL); + if (output_pubkey != NULL) { + memset(output_pubkey, 0, sizeof(*output_pubkey)); + } + ARG_CHECK(keyagg_cache != NULL); + ARG_CHECK(tweak32 != NULL); + + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + secp256k1_scalar_set_b32(&tweak, tweak32, &overflow); + if (overflow) { + return 0; + } + if (secp256k1_extrakeys_ge_even_y(&cache_i.pk)) { + cache_i.internal_key_parity ^= 1; + secp256k1_scalar_negate(&cache_i.tweak, &cache_i.tweak); + } + secp256k1_scalar_add(&cache_i.tweak, &cache_i.tweak, &tweak); + if (!secp256k1_eckey_pubkey_tweak_add(&cache_i.pk, &tweak)) { + return 0; + } + /* eckey_pubkey_tweak_add fails if cache_i.pk is infinity */ + VERIFY_CHECK(!secp256k1_ge_is_infinity(&cache_i.pk)); + secp256k1_keyagg_cache_save(keyagg_cache, &cache_i); + if (output_pubkey != NULL) { + secp256k1_pubkey_save(output_pubkey, &cache_i.pk); + } + return 1; +} + +#endif diff --git a/src/modules/musig/main_impl.h b/src/modules/musig/main_impl.h index 0ceacece9..53a629794 100644 --- a/src/modules/musig/main_impl.h +++ b/src/modules/musig/main_impl.h @@ -4,735 +4,11 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_MODULE_MUSIG_MAIN_ -#define _SECP256K1_MODULE_MUSIG_MAIN_ +#ifndef SECP256K1_MODULE_MUSIG_MAIN +#define SECP256K1_MODULE_MUSIG_MAIN -#include -#include "include/secp256k1.h" -#include "include/secp256k1_musig.h" -#include "hash.h" - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("KeyAgg list")||SHA256("KeyAgg list"). */ -static void secp256k1_musig_keyagglist_sha256(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); - - sha->s[0] = 0xb399d5e0ul; - sha->s[1] = 0xc8fff302ul; - sha->s[2] = 0x6badac71ul; - sha->s[3] = 0x07c5b7f1ul; - sha->s[4] = 0x9701e2eful; - sha->s[5] = 0x2a72ecf8ul; - sha->s[6] = 0x201a4c7bul; - sha->s[7] = 0xab148a38ul; - sha->bytes = 64; -} - -/* Computes ell = SHA256(pk[0], ..., pk[np-1]) */ -static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned char *ell, const secp256k1_xonly_pubkey * const* pk, size_t np) { - secp256k1_sha256 sha; - size_t i; - - secp256k1_musig_keyagglist_sha256(&sha); - for (i = 0; i < np; i++) { - unsigned char ser[32]; - if (!secp256k1_xonly_pubkey_serialize(ctx, ser, pk[i])) { - return 0; - } - secp256k1_sha256_write(&sha, ser, 32); - } - secp256k1_sha256_finalize(&sha, ell); - return 1; -} - -/* Initializes SHA256 with fixed midstate. This midstate was computed by applying - * SHA256 to SHA256("KeyAgg coefficient")||SHA256("KeyAgg coefficient"). */ -static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); - - sha->s[0] = 0x6ef02c5aul; - sha->s[1] = 0x06a480deul; - sha->s[2] = 0x1f298665ul; - sha->s[3] = 0x1d1134f2ul; - sha->s[4] = 0x56a0b063ul; - sha->s[5] = 0x52da4147ul; - sha->s[6] = 0xf280d9d4ul; - sha->s[7] = 0x4484be15ul; - sha->bytes = 64; -} - -/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and - * SHA256(ell, x) otherwise. second_pk_x can be NULL in case there is no - * second_pk. Assumes both field elements x and second_pk_x are normalized. */ -static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *ell, secp256k1_fe *x, const secp256k1_fe *second_pk_x) { - secp256k1_sha256 sha; - unsigned char buf[32]; - - if (secp256k1_fe_cmp_var(x, second_pk_x) == 0) { - secp256k1_scalar_set_int(r, 1); - } else { - secp256k1_musig_keyaggcoef_sha256(&sha); - secp256k1_sha256_write(&sha, ell, 32); - secp256k1_fe_get_b32(buf, x); - secp256k1_sha256_write(&sha, buf, 32); - secp256k1_sha256_finalize(&sha, buf); - secp256k1_scalar_set_b32(r, buf, NULL); - } -} - -/* Assumes both field elements x and second_pk_x are normalized. */ -static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_musig_pre_session *pre_session, secp256k1_fe *x) { - secp256k1_fe second_pk_x; - secp256k1_fe_set_b32(&second_pk_x, pre_session->second_pk); - secp256k1_musig_keyaggcoef_internal(r, pre_session->pk_hash, x, &second_pk_x); -} - -typedef struct { - const secp256k1_context *ctx; - unsigned char ell[32]; - const secp256k1_xonly_pubkey * const* pks; - secp256k1_fe second_pk_x; -} secp256k1_musig_pubkey_combine_ecmult_data; - -/* Callback for batch EC multiplication to compute ell_0*P0 + ell_1*P1 + ... */ -static int secp256k1_musig_pubkey_combine_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) { - secp256k1_musig_pubkey_combine_ecmult_data *ctx = (secp256k1_musig_pubkey_combine_ecmult_data *) data; - int ret; - ret = secp256k1_xonly_pubkey_load(ctx->ctx, pt, ctx->pks[idx]); - /* pubkey_load can't fail because the same pks have already been loaded (and - * we test this) */ - VERIFY_CHECK(ret); - secp256k1_musig_keyaggcoef_internal(sc, ctx->ell, &pt->x, &ctx->second_pk_x); - return 1; -} - -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++) { - memset(&signers[i], 0, sizeof(signers[i])); - signers[i].present = 0; - } -} - -static const uint64_t pre_session_magic = 0xf4adbbdf7c7dd304UL; - -int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, const secp256k1_xonly_pubkey * const* pubkeys, size_t n_pubkeys) { - secp256k1_musig_pubkey_combine_ecmult_data ecmult_data; - secp256k1_gej pkj; - secp256k1_ge pkp; - int pk_parity; - size_t i; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(combined_pk != NULL); - ARG_CHECK(pubkeys != NULL); - ARG_CHECK(n_pubkeys > 0); - - ecmult_data.ctx = ctx; - ecmult_data.pks = pubkeys; - /* No point on the curve has an X coordinate equal to 0 */ - secp256k1_fe_set_int(&ecmult_data.second_pk_x, 0); - for (i = 1; i < n_pubkeys; i++) { - secp256k1_ge pt; - if (!secp256k1_xonly_pubkey_load(ctx, &pt, pubkeys[i])) { - return 0; - } - if (secp256k1_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) { - ecmult_data.second_pk_x = pt.x; - break; - } - } - - if (!secp256k1_musig_compute_ell(ctx, ecmult_data.ell, pubkeys, n_pubkeys)) { - return 0; - } - if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &pkj, NULL, secp256k1_musig_pubkey_combine_callback, (void *) &ecmult_data, n_pubkeys)) { - /* The current implementation of ecmult_multi_var makes this code unreachable with tests. */ - return 0; - } - secp256k1_ge_set_gej(&pkp, &pkj); - secp256k1_fe_normalize_var(&pkp.y); - pk_parity = secp256k1_extrakeys_ge_even_y(&pkp); - secp256k1_xonly_pubkey_save(combined_pk, &pkp); - - if (pre_session != NULL) { - pre_session->magic = pre_session_magic; - memcpy(pre_session->pk_hash, ecmult_data.ell, 32); - pre_session->pk_parity = pk_parity; - pre_session->is_tweaked = 0; - secp256k1_fe_get_b32(pre_session->second_pk, &ecmult_data.second_pk_x); - } - return 1; -} - -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; - int ret; - - 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; - - ret = secp256k1_pubkey_load(ctx, &pk, output_pubkey); - /* Successful xonly_pubkey_tweak_add always returns valid output_pubkey */ - VERIFY_CHECK(ret); - - 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, const unsigned char *seckey) { - unsigned char combined_ser[32]; - int overflow; - secp256k1_scalar secret; - secp256k1_scalar mu; - 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)); - ARG_CHECK(session != NULL); - ARG_CHECK(signers != NULL); - ARG_CHECK(nonce_commitment32 != NULL); - ARG_CHECK(session_id32 != NULL); - ARG_CHECK(combined_pk != NULL); - ARG_CHECK(pre_session != NULL); - ARG_CHECK(pre_session->magic == pre_session_magic); - ARG_CHECK(seckey != NULL); - - ARG_CHECK(n_signers > 0); - ARG_CHECK(n_signers <= UINT32_MAX); - - memset(session, 0, sizeof(*session)); - - session->magic = session_magic; - if (msg32 != NULL) { - memcpy(session->msg, msg32, 32); - session->is_msg_set = 1; - } else { - session->is_msg_set = 0; - } - memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk)); - session->pre_session = *pre_session; - session->has_secret_data = 1; - session->n_signers = (uint32_t) n_signers; - secp256k1_musig_signers_init(signers, session->n_signers); - - /* Compute secret key */ - secp256k1_scalar_set_b32(&secret, seckey, &overflow); - if (overflow) { - secp256k1_scalar_clear(&secret); - return 0; - } - - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret); - secp256k1_ge_set_gej(&p, &pj); - secp256k1_fe_normalize_var(&p.x); - secp256k1_musig_keyaggcoef(&mu, &session->pre_session, &p.x); - /* 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 KeyAgg 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'| + 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_fe_normalize_var(&p.y); - 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); - secp256k1_scalar_get_b32(session->seckey, &secret); - - /* Compute secret nonce */ - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, session_id32, 32); - if (session->is_msg_set) { - secp256k1_sha256_write(&sha, msg32, 32); - } - secp256k1_xonly_pubkey_serialize(ctx, combined_ser, combined_pk); - secp256k1_sha256_write(&sha, combined_ser, 32); - secp256k1_sha256_write(&sha, seckey, 32); - secp256k1_sha256_finalize(&sha, session->secnonce); - secp256k1_scalar_set_b32(&secret, session->secnonce, &overflow); - if (overflow) { - secp256k1_scalar_clear(&secret); - return 0; - } - - /* Compute public nonce and commitment */ - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret); - secp256k1_ge_set_gej(&p, &pj); - secp256k1_fe_normalize_var(&p.y); - session->partial_nonce_parity = secp256k1_extrakeys_ge_even_y(&p); - secp256k1_xonly_pubkey_save(&session->nonce, &p); - - secp256k1_sha256_initialize(&sha); - secp256k1_xonly_pubkey_serialize(ctx, nonce_ser, &session->nonce); - secp256k1_sha256_write(&sha, nonce_ser, nonce_ser_size); - secp256k1_sha256_finalize(&sha, nonce_commitment32); - - session->round = 0; - secp256k1_scalar_clear(&secret); - return 1; -} - -int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, 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); - - 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->is_msg_set = 1; - } - secp256k1_sha256_initialize(&sha); - for (i = 0; i < n_commitments; i++) { - memcpy(signers[i].nonce_commitment, commitments[i], 32); - secp256k1_sha256_write(&sha, commitments[i], 32); - } - secp256k1_sha256_finalize(&sha, nonce_commitments_hash); - memcpy(session->nonce_commitments_hash, nonce_commitments_hash, 32); - - 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_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); - ARG_CHECK(session != NULL); - ARG_CHECK(signers != NULL); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(combined_pk != NULL); - ARG_CHECK(pre_session != NULL); - ARG_CHECK(pre_session->magic == pre_session_magic); - ARG_CHECK(commitments != NULL); - /* Check n_signers before checking commitments to allow testing the case where - * n_signers is big without allocating the space. */ - ARG_CHECK(n_signers > 0); - ARG_CHECK(n_signers <= UINT32_MAX); - for (i = 0; i < n_signers; i++) { - ARG_CHECK(commitments[i] != NULL); - } - (void) ctx; - - memset(session, 0, sizeof(*session)); - - session->magic = session_magic; - memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk)); - session->pre_session = *pre_session; - session->n_signers = (uint32_t) n_signers; - secp256k1_musig_signers_init(signers, session->n_signers); - - session->pre_session = *pre_session; - session->is_msg_set = 1; - memcpy(session->msg, msg32, 32); - session->has_secret_data = 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 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_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_parity, const secp256k1_pubkey *adaptor) { - secp256k1_gej combined_noncej; - secp256k1_ge combined_noncep; - secp256k1_ge noncep; - secp256k1_sha256 sha; - unsigned char nonce_commitments_hash[32]; - size_t i; - - 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); - - secp256k1_sha256_initialize(&sha); - secp256k1_gej_set_infinity(&combined_noncej); - for (i = 0; i < n_signers; i++) { - if (!signers[i].present) { - return 0; - } - secp256k1_sha256_write(&sha, signers[i].nonce_commitment, 32); - 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); - /* 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; - } - - /* Add public adaptor to nonce */ - if (adaptor != NULL) { - 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_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; - } - secp256k1_xonly_pubkey_save(&session->combined_nonce, &combined_noncep); - session->round = 2; - return 1; -} - -int secp256k1_musig_partial_signature_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_signature* sig) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(out32 != NULL); - ARG_CHECK(sig != NULL); - memcpy(out32, sig->data, 32); - return 1; -} - -int secp256k1_musig_partial_signature_parse(const secp256k1_context* ctx, secp256k1_musig_partial_signature* sig, const unsigned char *in32) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(in32 != NULL); - memcpy(sig->data, in32, 32); - return 1; -} - -/* Compute msghash = SHA256(combined_nonce, combined_pk, msg) */ -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); - 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); - secp256k1_sha256_write(&sha, session->msg, 32); - secp256k1_sha256_finalize(&sha, msghash); -} - -int secp256k1_musig_partial_sign(const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_musig_partial_signature *partial_sig) { - unsigned char msghash[32]; - int overflow; - secp256k1_scalar sk; - secp256k1_scalar e, k; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(partial_sig != NULL); - ARG_CHECK(session != NULL); - ARG_CHECK(session->magic == session_magic); - ARG_CHECK(session->round == 2); - ARG_CHECK(session->has_secret_data); - - /* build message hash */ - secp256k1_musig_compute_messagehash(ctx, msghash, session); - secp256k1_scalar_set_b32(&e, msghash, NULL); - - secp256k1_scalar_set_b32(&sk, session->seckey, &overflow); - if (overflow) { - secp256k1_scalar_clear(&sk); - return 0; - } - - secp256k1_scalar_set_b32(&k, session->secnonce, &overflow); - if (overflow || secp256k1_scalar_is_zero(&k)) { - secp256k1_scalar_clear(&sk); - secp256k1_scalar_clear(&k); - return 0; - } - if (session->partial_nonce_parity != session->combined_nonce_parity) { - secp256k1_scalar_negate(&k, &k); - } - - /* Sign */ - secp256k1_scalar_mul(&e, &e, &sk); - secp256k1_scalar_add(&e, &e, &k); - secp256k1_scalar_get_b32(&partial_sig->data[0], &e); - secp256k1_scalar_clear(&sk); - secp256k1_scalar_clear(&k); - - return 1; -} - -int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp256k1_musig_session *session, unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, size_t n_sigs) { - size_t i; - secp256k1_scalar s; - secp256k1_ge noncep; - (void) ctx; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(partial_sigs != NULL); - ARG_CHECK(session != NULL); - ARG_CHECK(session->magic == session_magic); - ARG_CHECK(session->round == 2); - - if (n_sigs != session->n_signers) { - return 0; - } - secp256k1_scalar_clear(&s); - for (i = 0; i < n_sigs; i++) { - int overflow; - secp256k1_scalar term; - - secp256k1_scalar_set_b32(&term, partial_sigs[i].data, &overflow); - if (overflow) { - return 0; - } - secp256k1_scalar_add(&s, &s, &term); - } - - /* 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); - secp256k1_scalar_get_b32(&sig64[32], &s); - - return 1; -} - -int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signer, const secp256k1_musig_partial_signature *partial_sig, const secp256k1_xonly_pubkey *pubkey) { - unsigned char msghash[32]; - secp256k1_scalar s; - secp256k1_scalar e; - secp256k1_scalar mu; - secp256k1_gej pkj; - secp256k1_gej rj; - secp256k1_ge pkp; - secp256k1_ge rp; - int overflow; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(session != NULL); - 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); - - secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow); - if (overflow) { - return 0; - } - secp256k1_musig_compute_messagehash(ctx, msghash, session); - secp256k1_scalar_set_b32(&e, msghash, NULL); - - if (!secp256k1_xonly_pubkey_load(ctx, &pkp, pubkey)) { - return 0; - } - /* Multiplying the messagehash by the KeyAgg coefficient is equivalent - * to multiplying the signer's public key by the coefficient, except - * much easier to do. */ - secp256k1_musig_keyaggcoef(&mu, &session->pre_session, &pkp.x); - secp256k1_scalar_mul(&e, &e, &mu); - - if (!secp256k1_xonly_pubkey_load(ctx, &rp, &signer->nonce)) { - return 0; - } - - /* 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); - } - - /* Compute rj = s*G + (-e)*pkj */ - secp256k1_scalar_negate(&e, &e); - - secp256k1_gej_set_ge(&pkj, &pkp); - secp256k1_ecmult(&rj, &pkj, &e, &s); - - if (!session->combined_nonce_parity) { - secp256k1_ge_neg(&rp, &rp); - } - secp256k1_gej_add_ge_var(&rj, &rj, &rp, NULL); - - 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_parity) { - secp256k1_scalar s; - secp256k1_scalar t; - int overflow; - - (void) ctx; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(adaptor_sig != NULL); - ARG_CHECK(partial_sig != NULL); - ARG_CHECK(sec_adaptor32 != NULL); - - secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow); - if (overflow) { - return 0; - } - secp256k1_scalar_set_b32(&t, sec_adaptor32, &overflow); - if (overflow) { - secp256k1_scalar_clear(&t); - return 0; - } - - if (nonce_parity) { - secp256k1_scalar_negate(&t, &t); - } - - secp256k1_scalar_add(&s, &s, &t); - secp256k1_scalar_get_b32(adaptor_sig->data, &s); - secp256k1_scalar_clear(&t); - 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_parity) { - secp256k1_scalar t; - secp256k1_scalar s; - int overflow; - size_t i; - - (void) ctx; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sec_adaptor32 != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(partial_sigs != NULL); - - secp256k1_scalar_set_b32(&t, &sig64[32], &overflow); - if (overflow) { - return 0; - } - secp256k1_scalar_negate(&t, &t); - - for (i = 0; i < n_partial_sigs; i++) { - secp256k1_scalar_set_b32(&s, partial_sigs[i].data, &overflow); - if (overflow) { - secp256k1_scalar_clear(&t); - return 0; - } - secp256k1_scalar_add(&t, &t, &s); - } - - if (!nonce_parity) { - secp256k1_scalar_negate(&t, &t); - } - secp256k1_scalar_get_b32(sec_adaptor32, &t); - secp256k1_scalar_clear(&t); - return 1; -} +#include "keyagg_impl.h" +#include "session_impl.h" +#include "adaptor_impl.h" #endif diff --git a/src/modules/musig/musig.md b/src/modules/musig/musig.md index 240e85ca2..814cdc746 100644 --- a/src/modules/musig/musig.md +++ b/src/modules/musig/musig.md @@ -1,198 +1,63 @@ -MuSig - Rogue-Key-Resistant Multisignatures Module +Notes on the musig module API =========================== -This module implements the MuSig [1] multisignature scheme. The majority of -the module is an API designed to be used by signing or auditing participants -in a multisignature scheme. This involves a somewhat complex state machine -and significant effort has been taken to prevent accidental misuse of the -API in ways that could lead to accidental signatures or loss of key material. - -The resulting signatures are valid Schnorr signatures as described in [2]. - -# Theory - -In MuSig all signers contribute key material to a single signing key, -using the equation - - P = sum_i µ_i * P_i - -where `P_i` is the public key of the `i`th signer and `µ_i` is a so-called -_MuSig coefficient_ computed according to the following equation - - L = H(P_1 || P_2 || ... || P_n) - µ_i = H(L || i) - -where H is a hash function modelled as a random oracle. - -To produce a multisignature `(s, R)` on a message `m` using verification key -`P`, signers act as follows: - -1. Each computes a nonce, or ephemeral keypair, `(k_i, R_i)`. Every signer - communicates `H(R_i)` to every participant (both signers and auditors). -2. Upon receipt of every `H(R_i)`, each signer communicates `R_i` to every - participant. The recipients check that each `R_i` is consistent with the - previously-communicated hash. -3. Each signer computes a combined nonce - `R = sum_i R_i` - and shared challenge - `e = H(R || P || m)` - and partial signature - `s_i = k_i + µ_i*x_i*e` - where `x_i` is the secret key corresponding to `P_i`. - -The complete signature is then the `(s, R)` where `s = sum_i s_i` and `R = sum_i R_i`. - -# API Usage - -The following sections describe use of our API, and are mirrored in code in `src/modules/musig/example.c`. - -It is essential to security that signers use a unique uniformly random nonce for all -signing sessions, and that they do not reuse these nonces even in the case that a -signing session fails to complete. To that end, all signing state is encapsulated -in the data structure `secp256k1_musig_session`. The API does not expose any -functionality to serialize or deserialize this structure; it is designed to exist -only in memory. - -Users who need to persist this structure must take additional security measures -which cannot be enforced by a C API. Some guidance is provided in the documentation -for this data structure in `include/secp256k1_musig.h`. - -## Key Generation - -To use MuSig, users must first compute their combined public key `P`, which is -suitable for use on a blockchain or other public key repository. They do this -by calling `secp256k1_musig_pubkey_combine`. - -This function takes as input a list of public keys `P_i` in the argument -`pubkeys`. It outputs the combined public key `P` in the out-pointer `combined_pk` -and hash `L` in the out-pointer `pk_hash32`, if this pointer is non-NULL. - -## Signing - -A participant who wishes to sign a message (as opposed to observing/auditing the -signature process, which is also a supported mode) acts as follows. - -### Signing Participant - -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` - - a commitment `H(R_i)` to a nonce in the out-pointer `nonce_commitment32` - It takes as input - - a unique session ID `session_id32` - - (optionally) a message to be signed `msg32` - - the combined public key output from `secp256k1_musig_pubkey_combine` - - the public key hash output from `secp256k1_musig_pubkey_combine` - - the signer's index `i` `my_index` - - the signer's secret key `seckey` -2. The signer then communicates `H(R_i)` to all other signers, and receives - commitments `H(R_j)` from all other signers `j`. These hashes are simply - 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_init`, - a message must be provided now. - This function updates in place - - the session state `session` - - the array of signer data `signers` - taking in as input the list of commitments `commitments` and outputting the - signer's public nonce `R_i` in the out-pointer `nonce`. -4. The signer then communicates `R_i` to all other signers, and receives `R_j` - from each signer `j`. On receipt of a nonce `R_j` he calls the function - `secp256k1_musig_set_nonce` to record this fact. This function checks that - the received nonce is consistent with the previously-received nonce and will - return 0 in this case. The signer must also call this function with his own - nonce and his own index `i`. - These nonces `R_i` are secp256k1 public keys; they should be serialized using - `secp256k1_ec_pubkey_serialize` and parsed with `secp256k1_ec_pubkey_parse`. -5. Once all nonces have been exchanged in this way, signers are able to compute - their partial signatures. They do so by calling `secp256k1_musig_session_combine_nonces` - which updates in place - - the session state `session` - - the array of signer data `signers` - It outputs an auxiliary integer `nonce_is_negated` and has an auxiliary input - `adaptor`. Both of these may be set to NULL for ordinary signing purposes. -6. The signer computes a partial signature `s_i` using the function - `secp256k1_musig_partial_sign` which takes the session state as input and - partial signature as output. -7. The signer then communicates the partial signature `s_i` to all other signers, or - to a central coordinator. These partial signatures should be serialized using - `musig_partial_signature_serialize` and parsed using `musig_partial_signature_parse`. -8. Each signer calls `secp256k1_musig_partial_sig_verify` on the other signers' partial - signatures to verify their correctness. If only the validity of the final signature - is important, not assigning blame, this step can be skipped. -9. Any signer, or central coordinator, may combine the partial signatures to obtain - a complete signature using `secp256k1_musig_partial_sig_combine`. This function takes - a signing session and array of MuSig partial signatures, and outputs a single - Schnorr signature. - -### Non-signing Participant - -A participant who wants to verify the signing process, i.e. check that nonce commitments -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_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` - and `secp256k1_musig_partial_sign` are not called. - -### Verifier - -The final signature is simply a valid Schnorr signature using the combined public key. It -can be verified using the `secp256k1_schnorrsig_verify` with the correct message and -public key output from `secp256k1_musig_pubkey_combine`. - -## Atomic Swaps +The following sections contain additional notes on the API of the musig module (`include/secp256k1_musig.h`). +A usage example can be found in `examples/musig.c`. + +# API misuse + +The musig API is designed to be as misuse resistant as possible. +However, the MuSig protocol has some additional failure modes (mainly due to interactivity) that do not appear in single-signing. +While the results can be catastrophic (e.g. leaking of the secret key), it is unfortunately not possible for the musig implementation to rule out all such failure modes. + +Therefore, users of the musig module must take great care to make sure of the following: + +1. A unique nonce per signing session is generated in `secp256k1_musig_nonce_gen`. + See the corresponding comment in `include/secp256k1_musig.h` for how to ensure that. +2. The `secp256k1_musig_secnonce` structure is never copied or serialized. + See also the comment on `secp256k1_musig_secnonce` in `include/secp256k1_musig.h`. +3. Opaque data structures are never written to or read from directly. + Instead, only the provided accessor functions are used. +4. If adaptor signatures are used, all partial signatures are verified. + +# Key Aggregation and (Taproot) Tweaking + +Given a set of public keys, the aggregate public key is computed with `secp256k1_musig_pubkey_agg`. +A (Taproot) tweak can be added to the resulting public key with `secp256k1_xonly_pubkey_tweak_add`. + +# Signing + +This is covered by `examples/musig.c`. +Essentially, the protocol proceeds in the following steps: + +1. Generate a keypair with `secp256k1_keypair_create` and obtain the xonly public key with `secp256k1_keypair_xonly_pub`. +2. Call `secp256k1_musig_pubkey_agg` with the xonly pubkeys of all participants. +3. Optionally add a (Taproot) tweak with `secp256k1_musig_pubkey_tweak_add`. +4. Generate a pair of secret and public nonce with `secp256k1_musig_nonce_gen` and send the public nonce to the other signers. +5. Someone (not necessarily the signer) aggregates the public nonce with `secp256k1_musig_nonce_agg` and sends it to the signers. +6. Process the aggregate nonce with `secp256k1_musig_nonce_process`. +7. Create a partial signature with `secp256k1_musig_partial_sign`. +8. Verify the partial signatures (optional in some scenarios) with `secp256k1_musig_partial_sig_verify`. +9. Someone (not necessarily the signer) obtains all partial signatures and aggregates them into the final Schnorr signature using `secp256k1_musig_partial_sig_agg`. + +The aggregate signature can be verified with `secp256k1_schnorrsig_verify`. + +Note that steps 1 to 6 can happen before the message to be signed is known to the signers. +Therefore, the communication round to exchange nonces can be viewed as a pre-processing step that is run whenever convenient to the signers. +This disables some of the defense-in-depth measures that may protect against API misuse in some cases. +Similarly, the API supports an alternative protocol flow where generating the aggregate key (steps 1 to 3) is allowed to happen after exchanging nonces (steps 4 to 6). + +# Verification + +A participant who wants to verify the partial signatures, but does not sign itself may do so using the above instructions except that the verifier skips steps 1, 4 and 7. + +# Atomic Swaps The signing API supports the production of "adaptor signatures", modified partial signatures which are offset by an auxiliary secret known to one party. That is, 1. One party generates a (secret) adaptor `t` with corresponding (public) adaptor `T = t*G`. -2. When combining nonces, each party adds `T` to the total nonce used in the signature. -3. The party who knows `t` must "adapt" their partial signature with `t` to complete the - signature. -4. Any party who sees both the final signature and the original partial signatures - can compute `t`. - -Using these adaptor signatures, two 2-of-2 MuSig signing protocols can be executed in -parallel such that one party's partial signatures are made atomic. That is, when the other -party learns one partial signature, she automatically learns the other. This has applications -in cross-chain atomic swaps. - -Such a protocol can be executed as follows. Consider two participants, Alice and Bob, who -are simultaneously producing 2-of-2 multisignatures for two blockchains A and B. They act -as follows. - -1. Before the protocol begins, Bob chooses a 32-byte auxiliary secret `t` at random and - computes a corresponding public point `T` by calling `secp256k1_ec_pubkey_create`. - He communicates `T` to Alice. -2. Together, the parties execute steps 1-4 of the signing protocol above. -3. At step 5, when combining the two parties' public nonces, both parties call - `secp256k1_musig_session_combine_nonces` with `adaptor` set to `T` and `nonce_is_negated` - set to a non-NULL pointer to int. -4. Steps 6 and 7 proceed as before. Step 8, verifying the partial signatures, is now - essential to the security of the protocol and must not be omitted! - -The above steps are executed identically for both signing sessions. However, step 9 will -not work as before, since the partial signatures will not add up to a valid total signature. -Additional steps must be taken, and it is at this point that the two signing sessions -diverge. From here on we consider "Session A" which benefits Alice (e.g. which sends her -coins) and "Session B" which benefits Bob (e.g. which sends him coins). - -5. In Session B, Bob calls `secp256k1_musig_partial_sig_adapt` with his partial signature - and `t`, to produce an adaptor signature. He can then call `secp256k1_musig_partial_sig_combine` - with this adaptor signature and Alice's partial signature, to produce a complete - signature for blockchain B. -6. Alice reads this signature from blockchain B. She calls `secp256k1_musig_extract_secret_adaptor`, - passing the complete signature along with her and Bob's partial signatures from Session B. - This function outputs `t`, which until this point was only known to Bob. -7. In Session A, Alice is now able to replicate Bob's action, calling - `secp256k1_musig_partial_sig_adapt` with her own partial signature and `t`, ultimately - producing a complete signature on blockchain A. - -[1] https://eprint.iacr.org/2018/068 -[2] https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki - +2. When calling `secp256k1_musig_nonce_process`, the public adaptor `T` is provided as the `adaptor` argument. +3. The party who is going to extract the secret adaptor `t` later must verify all partial signatures. +4. Due to step 2, the signature output of `secp256k1_musig_partial_sig_agg` is a pre-signature and not a valid Schnorr signature. All parties involved extract this session's `nonce_parity` with `secp256k1_musig_nonce_parity`. +5. The party who knows `t` must "adapt" the pre-signature with `t` (and the `nonce_parity` using `secp256k1_musig_adapt` to complete the signature. +6. Any party who sees both the final signature and the pre-signature (and has the `nonce_parity`) can extract `t` with `secp256k1_musig_extract_adaptor`. diff --git a/src/modules/musig/session.h b/src/modules/musig/session.h new file mode 100644 index 000000000..dfaa5e0d0 --- /dev/null +++ b/src/modules/musig/session.h @@ -0,0 +1,25 @@ +/*********************************************************************** + * Copyright (c) 2021 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_SESSION_H +#define SECP256K1_MODULE_MUSIG_SESSION_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_musig.h" + +#include "../../scalar.h" + +typedef struct { + int fin_nonce_parity; + unsigned char fin_nonce[32]; + secp256k1_scalar noncecoef; + secp256k1_scalar challenge; + secp256k1_scalar s_part; +} secp256k1_musig_session_internal; + +static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session); + +#endif diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h new file mode 100644 index 000000000..7cdcebe3e --- /dev/null +++ b/src/modules/musig/session_impl.h @@ -0,0 +1,755 @@ +/*********************************************************************** + * Copyright (c) 2021 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_SESSION_IMPL_H +#define SECP256K1_MODULE_MUSIG_SESSION_IMPL_H + +#include + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_extrakeys.h" +#include "../../../include/secp256k1_musig.h" + +#include "keyagg.h" +#include "session.h" +#include "../../eckey.h" +#include "../../hash.h" +#include "../../scalar.h" +#include "../../util.h" + +static const unsigned char secp256k1_musig_secnonce_magic[4] = { 0x22, 0x0e, 0xdc, 0xf1 }; + +static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, secp256k1_scalar *k) { + memcpy(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4); + secp256k1_scalar_get_b32(&secnonce->data[4], &k[0]); + secp256k1_scalar_get_b32(&secnonce->data[36], &k[1]); +} + +static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_musig_secnonce *secnonce) { + int is_zero; + ARG_CHECK(secp256k1_memcmp_var(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4) == 0); + secp256k1_scalar_set_b32(&k[0], &secnonce->data[4], NULL); + secp256k1_scalar_set_b32(&k[1], &secnonce->data[36], NULL); + /* We make very sure that the nonce isn't invalidated by checking the values + * in addition to the magic. */ + is_zero = secp256k1_scalar_is_zero(&k[0]) & secp256k1_scalar_is_zero(&k[1]); + secp256k1_declassify(ctx, &is_zero, sizeof(is_zero)); + ARG_CHECK(!is_zero); + return 1; +} + +/* If flag is true, invalidate the secnonce; otherwise leave it. Constant-time. */ +static void secp256k1_musig_secnonce_invalidate(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, int flag) { + secp256k1_memczero(secnonce->data, sizeof(secnonce->data), flag); + /* The flag argument is usually classified. So, above code makes the magic + * classified. However, we need the magic to be declassified to be able to + * compare it during secnonce_load. */ + secp256k1_declassify(ctx, secnonce->data, sizeof(secp256k1_musig_secnonce_magic)); +} + +static const unsigned char secp256k1_musig_pubnonce_magic[4] = { 0xf5, 0x7a, 0x3d, 0xa0 }; + +/* Requires that none of the provided group elements is infinity. Works for both + * musig_pubnonce and musig_aggnonce. */ +static void secp256k1_musig_pubnonce_save(secp256k1_musig_pubnonce* nonce, secp256k1_ge* ge) { + int i; + memcpy(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4); + for (i = 0; i < 2; i++) { + secp256k1_point_save(nonce->data + 4+64*i, &ge[i]); + } +} + +/* Works for both musig_pubnonce and musig_aggnonce. Returns 1 unless the nonce + * wasn't properly initialized */ +static int secp256k1_musig_pubnonce_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_musig_pubnonce* nonce) { + int i; + + ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4) == 0); + for (i = 0; i < 2; i++) { + secp256k1_point_load(&ge[i], nonce->data + 4 + 64*i); + } + return 1; +} + +static void secp256k1_musig_aggnonce_save(secp256k1_musig_aggnonce* nonce, secp256k1_ge* ge) { + secp256k1_musig_pubnonce_save((secp256k1_musig_pubnonce *) nonce, ge); +} + +static int secp256k1_musig_aggnonce_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_musig_aggnonce* nonce) { + return secp256k1_musig_pubnonce_load(ctx, ge, (secp256k1_musig_pubnonce *) nonce); +} + +static const unsigned char secp256k1_musig_session_cache_magic[4] = { 0x9d, 0xed, 0xe9, 0x17 }; + +/* A session consists of + * - 4 byte session cache magic + * - 1 byte the parity of the final nonce + * - 32 byte serialized x-only final nonce + * - 32 byte nonce coefficient b + * - 32 byte signature challenge hash e + * - 32 byte scalar s that is added to the partial signatures of the signers + */ +static void secp256k1_musig_session_save(secp256k1_musig_session *session, const secp256k1_musig_session_internal *session_i) { + unsigned char *ptr = session->data; + + memcpy(ptr, secp256k1_musig_session_cache_magic, 4); + ptr += 4; + *ptr = session_i->fin_nonce_parity; + ptr += 1; + memcpy(ptr, session_i->fin_nonce, 32); + ptr += 32; + secp256k1_scalar_get_b32(ptr, &session_i->noncecoef); + ptr += 32; + secp256k1_scalar_get_b32(ptr, &session_i->challenge); + ptr += 32; + secp256k1_scalar_get_b32(ptr, &session_i->s_part); +} + +static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session) { + const unsigned char *ptr = session->data; + + ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_session_cache_magic, 4) == 0); + ptr += 4; + session_i->fin_nonce_parity = *ptr; + ptr += 1; + memcpy(session_i->fin_nonce, ptr, 32); + ptr += 32; + secp256k1_scalar_set_b32(&session_i->noncecoef, ptr, NULL); + ptr += 32; + secp256k1_scalar_set_b32(&session_i->challenge, ptr, NULL); + ptr += 32; + secp256k1_scalar_set_b32(&session_i->s_part, ptr, NULL); + return 1; +} + +static const unsigned char secp256k1_musig_partial_sig_magic[4] = { 0xeb, 0xfb, 0x1a, 0x32 }; + +static void secp256k1_musig_partial_sig_save(secp256k1_musig_partial_sig* sig, secp256k1_scalar *s) { + memcpy(&sig->data[0], secp256k1_musig_partial_sig_magic, 4); + secp256k1_scalar_get_b32(&sig->data[4], s); +} + +static int secp256k1_musig_partial_sig_load(const secp256k1_context* ctx, secp256k1_scalar *s, const secp256k1_musig_partial_sig* sig) { + int overflow; + + ARG_CHECK(secp256k1_memcmp_var(&sig->data[0], secp256k1_musig_partial_sig_magic, 4) == 0); + secp256k1_scalar_set_b32(s, &sig->data[4], &overflow); + /* Parsed signatures can not overflow */ + VERIFY_CHECK(!overflow); + return 1; +} + +int secp256k1_musig_pubnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_pubnonce* nonce) { + secp256k1_ge ge[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out66 != NULL); + memset(out66, 0, 66); + ARG_CHECK(nonce != NULL); + + if (!secp256k1_musig_pubnonce_load(ctx, ge, nonce)) { + return 0; + } + for (i = 0; i < 2; i++) { + int ret; + size_t size = 33; + ret = secp256k1_eckey_pubkey_serialize(&ge[i], &out66[33*i], &size, 1); + /* serialize must succeed because the point was just loaded */ + VERIFY_CHECK(ret && size == 33); + } + return 1; +} + +int secp256k1_musig_pubnonce_parse(const secp256k1_context* ctx, secp256k1_musig_pubnonce* nonce, const unsigned char *in66) { + secp256k1_ge ge[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(nonce != NULL); + ARG_CHECK(in66 != NULL); + + for (i = 0; i < 2; i++) { + if (!secp256k1_eckey_pubkey_parse(&ge[i], &in66[33*i], 33)) { + return 0; + } + if (!secp256k1_ge_is_in_correct_subgroup(&ge[i])) { + return 0; + } + } + /* The group elements can not be infinity because they were just parsed */ + secp256k1_musig_pubnonce_save(nonce, ge); + return 1; +} + +int secp256k1_musig_aggnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_aggnonce* nonce) { + return secp256k1_musig_pubnonce_serialize(ctx, out66, (secp256k1_musig_pubnonce*) nonce); +} + +int secp256k1_musig_aggnonce_parse(const secp256k1_context* ctx, secp256k1_musig_aggnonce* nonce, const unsigned char *in66) { + return secp256k1_musig_pubnonce_parse(ctx, (secp256k1_musig_pubnonce*) nonce, in66); +} + +int secp256k1_musig_partial_sig_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_sig* sig) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out32 != NULL); + ARG_CHECK(sig != NULL); + memcpy(out32, &sig->data[4], 32); + return 1; +} + +int secp256k1_musig_partial_sig_parse(const secp256k1_context* ctx, secp256k1_musig_partial_sig* sig, const unsigned char *in32) { + secp256k1_scalar tmp; + int overflow; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(in32 != NULL); + + secp256k1_scalar_set_b32(&tmp, in32, &overflow); + if (overflow) { + return 0; + } + secp256k1_musig_partial_sig_save(sig, &tmp); + return 1; +} + +/* Normalizes the x-coordinate of the given group element. */ +static int secp256k1_xonly_ge_serialize(unsigned char *output32, secp256k1_ge *ge) { + if (secp256k1_ge_is_infinity(ge)) { + return 0; + } + secp256k1_fe_normalize_var(&ge->x); + secp256k1_fe_get_b32(output32, &ge->x); + return 1; +} + +static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_id, const unsigned char *msg32, const unsigned char *key32, const unsigned char *agg_pk32, const unsigned char *extra_input32) { + secp256k1_sha256 sha; + unsigned char seed[32]; + unsigned char i; + enum { n_extra_in = 4 }; + const unsigned char *extra_in[n_extra_in]; + + /* TODO: this doesn't have the same sidechannel resistance as the BIP340 + * nonce function because the seckey feeds directly into SHA. */ + + /* Subtract one from `sizeof` to avoid hashing the implicit null byte */ + secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"MuSig/nonce", sizeof("MuSig/nonce") - 1); + secp256k1_sha256_write(&sha, session_id, 32); + extra_in[0] = msg32; + extra_in[1] = key32; + extra_in[2] = agg_pk32; + extra_in[3] = extra_input32; + for (i = 0; i < n_extra_in; i++) { + unsigned char len; + if (extra_in[i] != NULL) { + len = 32; + secp256k1_sha256_write(&sha, &len, 1); + secp256k1_sha256_write(&sha, extra_in[i], 32); + } else { + len = 0; + secp256k1_sha256_write(&sha, &len, 1); + } + } + secp256k1_sha256_finalize(&sha, seed); + + for (i = 0; i < 2; i++) { + unsigned char buf[32]; + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, seed, 32); + secp256k1_sha256_write(&sha, &i, sizeof(i)); + secp256k1_sha256_finalize(&sha, buf); + secp256k1_scalar_set_b32(&k[i], buf, NULL); + } +} + +int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *session_id32, const unsigned char *seckey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { + secp256k1_keyagg_cache_internal cache_i; + secp256k1_scalar k[2]; + secp256k1_ge nonce_pt[2]; + int i; + unsigned char pk_ser[32]; + unsigned char *pk_ser_ptr = NULL; + int ret = 1; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secnonce != NULL); + memset(secnonce, 0, sizeof(*secnonce)); + ARG_CHECK(pubnonce != NULL); + memset(pubnonce, 0, sizeof(*pubnonce)); + ARG_CHECK(session_id32 != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + if (seckey == NULL) { + /* Check in constant time that the session_id is not 0 as a + * defense-in-depth measure that may protect against a faulty RNG. */ + unsigned char acc = 0; + for (i = 0; i < 32; i++) { + acc |= session_id32[i]; + } + ret &= !!acc; + memset(&acc, 0, sizeof(acc)); + } + + /* Check that the seckey is valid to be able to sign for it later. */ + if (seckey != NULL) { + secp256k1_scalar sk; + ret &= secp256k1_scalar_set_b32_seckey(&sk, seckey); + secp256k1_scalar_clear(&sk); + } + + if (keyagg_cache != NULL) { + int ret_tmp; + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + ret_tmp = secp256k1_xonly_ge_serialize(pk_ser, &cache_i.pk); + /* Serialization can not fail because the loaded point can not be infinity. */ + VERIFY_CHECK(ret_tmp); + pk_ser_ptr = pk_ser; + } + secp256k1_nonce_function_musig(k, session_id32, msg32, seckey, pk_ser_ptr, extra_input32); + VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0])); + VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1])); + VERIFY_CHECK(!secp256k1_scalar_eq(&k[0], &k[1])); + secp256k1_musig_secnonce_save(secnonce, k); + secp256k1_musig_secnonce_invalidate(ctx, secnonce, !ret); + + for (i = 0; i < 2; i++) { + secp256k1_gej nonce_ptj; + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj, &k[i]); + secp256k1_ge_set_gej(&nonce_pt[i], &nonce_ptj); + secp256k1_declassify(ctx, &nonce_pt[i], sizeof(nonce_pt)); + secp256k1_scalar_clear(&k[i]); + } + /* nonce_pt won't be infinity because k != 0 with overwhelming probability */ + secp256k1_musig_pubnonce_save(pubnonce, nonce_pt); + return ret; +} + +static int secp256k1_musig_sum_nonces(const secp256k1_context* ctx, secp256k1_gej *summed_nonces, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { + size_t i; + int j; + + secp256k1_gej_set_infinity(&summed_nonces[0]); + secp256k1_gej_set_infinity(&summed_nonces[1]); + + for (i = 0; i < n_pubnonces; i++) { + secp256k1_ge nonce_pt[2]; + if (!secp256k1_musig_pubnonce_load(ctx, nonce_pt, pubnonces[i])) { + return 0; + } + for (j = 0; j < 2; j++) { + secp256k1_gej_add_ge_var(&summed_nonces[j], &summed_nonces[j], &nonce_pt[j], NULL); + } + } + return 1; +} + +int secp256k1_musig_nonce_agg(const secp256k1_context* ctx, secp256k1_musig_aggnonce *aggnonce, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { + secp256k1_gej aggnonce_ptj[2]; + secp256k1_ge aggnonce_pt[2]; + int i; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(aggnonce != NULL); + ARG_CHECK(pubnonces != NULL); + ARG_CHECK(n_pubnonces > 0); + + if (!secp256k1_musig_sum_nonces(ctx, aggnonce_ptj, pubnonces, n_pubnonces)) { + return 0; + } + for (i = 0; i < 2; i++) { + if (secp256k1_gej_is_infinity(&aggnonce_ptj[i])) { + /* There must be at least one dishonest signer. If we would return 0 + here, we will never be able to determine who it is. Therefore, we + should continue such that the culprit is revealed when collecting + and verifying partial signatures. + + However, dealing with the point at infinity (loading, + de-/serializing) would require a lot of extra code complexity. + Instead, we set the aggregate nonce to some arbitrary point (the + generator). This is secure, because it only restricts the + abilities of the attacker: an attacker that forces the sum of + nonces to be infinity by sending some maliciously generated nonce + pairs can be turned into an attacker that forces the sum to be + the generator (by simply adding the generator to one of the + malicious nonces), and this does not change the winning condition + of the EUF-CMA game. */ + aggnonce_pt[i] = secp256k1_ge_const_g; + } else { + secp256k1_ge_set_gej(&aggnonce_pt[i], &aggnonce_ptj[i]); + } + } + secp256k1_musig_aggnonce_save(aggnonce, aggnonce_pt); + return 1; +} + +/* tagged_hash(aggnonce[0], aggnonce[1], agg_pk, msg) */ +static int secp256k1_musig_compute_noncehash(unsigned char *noncehash, secp256k1_ge *aggnonce, const unsigned char *agg_pk32, const unsigned char *msg) { + unsigned char buf[33]; + secp256k1_sha256 sha; + int i; + + secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"MuSig/noncecoef", sizeof("MuSig/noncecoef") - 1); + for (i = 0; i < 2; i++) { + size_t size; + if (!secp256k1_eckey_pubkey_serialize(&aggnonce[i], buf, &size, 1)) { + return 0; + } + VERIFY_CHECK(size == sizeof(buf)); + secp256k1_sha256_write(&sha, buf, sizeof(buf)); + } + secp256k1_sha256_write(&sha, agg_pk32, 32); + secp256k1_sha256_write(&sha, msg, 32); + secp256k1_sha256_finalize(&sha, noncehash); + return 1; +} + +static int secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_gej *aggnoncej, const unsigned char *agg_pk32, const unsigned char *msg) { + unsigned char noncehash[32]; + secp256k1_ge fin_nonce_pt; + secp256k1_gej fin_nonce_ptj; + secp256k1_ge aggnonce[2]; + + secp256k1_ge_set_gej(&aggnonce[0], &aggnoncej[0]); + secp256k1_ge_set_gej(&aggnonce[1], &aggnoncej[1]); + if (!secp256k1_musig_compute_noncehash(noncehash, aggnonce, agg_pk32, msg)) { + return 0; + } + /* fin_nonce = aggnonce[0] + b*aggnonce[1] */ + secp256k1_scalar_set_b32(b, noncehash, NULL); + secp256k1_ecmult(&fin_nonce_ptj, &aggnoncej[1], b, NULL); + secp256k1_gej_add_ge(&fin_nonce_ptj, &fin_nonce_ptj, &aggnonce[0]); + secp256k1_ge_set_gej(&fin_nonce_pt, &fin_nonce_ptj); + if (!secp256k1_xonly_ge_serialize(fin_nonce, &fin_nonce_pt)) { + /* unreachable with overwhelming probability */ + return 0; + } + secp256k1_fe_normalize_var(&fin_nonce_pt.y); + *fin_nonce_parity = secp256k1_fe_is_odd(&fin_nonce_pt.y); + return 1; +} + +int secp256k1_musig_nonce_process(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_aggnonce *aggnonce, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_pubkey *adaptor) { + secp256k1_keyagg_cache_internal cache_i; + secp256k1_ge aggnonce_pt[2]; + secp256k1_gej aggnonce_ptj[2]; + unsigned char fin_nonce[32]; + secp256k1_musig_session_internal session_i; + unsigned char agg_pk32[32]; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(session != NULL); + ARG_CHECK(aggnonce != NULL); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(keyagg_cache != NULL); + + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + secp256k1_fe_get_b32(agg_pk32, &cache_i.pk.x); + + if (!secp256k1_musig_aggnonce_load(ctx, aggnonce_pt, aggnonce)) { + return 0; + } + secp256k1_gej_set_ge(&aggnonce_ptj[0], &aggnonce_pt[0]); + secp256k1_gej_set_ge(&aggnonce_ptj[1], &aggnonce_pt[1]); + /* Add public adaptor to nonce */ + if (adaptor != NULL) { + secp256k1_ge adaptorp; + if (!secp256k1_pubkey_load(ctx, &adaptorp, adaptor)) { + return 0; + } + secp256k1_gej_add_ge_var(&aggnonce_ptj[0], &aggnonce_ptj[0], &adaptorp, NULL); + } + if (!secp256k1_musig_nonce_process_internal(&session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_ptj, agg_pk32, msg32)) { + return 0; + } + + secp256k1_schnorrsig_challenge(&session_i.challenge, fin_nonce, msg32, 32, agg_pk32); + + /* If there is a tweak then set `challenge` times `tweak` to the `s`-part.*/ + secp256k1_scalar_set_int(&session_i.s_part, 0); + if (!secp256k1_scalar_is_zero(&cache_i.tweak)) { + secp256k1_scalar e_tmp; + secp256k1_scalar_mul(&e_tmp, &session_i.challenge, &cache_i.tweak); + if (secp256k1_fe_is_odd(&cache_i.pk.y)) { + secp256k1_scalar_negate(&e_tmp, &e_tmp); + } + secp256k1_scalar_add(&session_i.s_part, &session_i.s_part, &e_tmp); + } + memcpy(session_i.fin_nonce, fin_nonce, sizeof(session_i.fin_nonce)); + secp256k1_musig_session_save(session, &session_i); + return 1; +} + +void secp256k1_musig_partial_sign_clear(secp256k1_scalar *sk, secp256k1_scalar *k) { + secp256k1_scalar_clear(sk); + secp256k1_scalar_clear(&k[0]); + secp256k1_scalar_clear(&k[1]); +} + +int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_partial_sig *partial_sig, secp256k1_musig_secnonce *secnonce, const secp256k1_keypair *keypair, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) { + secp256k1_scalar sk; + secp256k1_ge pk; + secp256k1_scalar k[2]; + secp256k1_scalar mu, s; + secp256k1_keyagg_cache_internal cache_i; + secp256k1_musig_session_internal session_i; + int ret; + + VERIFY_CHECK(ctx != NULL); + + ARG_CHECK(secnonce != NULL); + /* Fails if the magic doesn't match */ + ret = secp256k1_musig_secnonce_load(ctx, k, secnonce); + /* Set nonce to zero to avoid nonce reuse. This will cause subsequent calls + * of this function to fail */ + memset(secnonce, 0, sizeof(*secnonce)); + if (!ret) { + secp256k1_musig_partial_sign_clear(&sk, k); + return 0; + } + + ARG_CHECK(partial_sig != NULL); + ARG_CHECK(keypair != NULL); + ARG_CHECK(keyagg_cache != NULL); + ARG_CHECK(session != NULL); + + if (!secp256k1_keypair_load(ctx, &sk, &pk, keypair)) { + secp256k1_musig_partial_sign_clear(&sk, k); + return 0; + } + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + secp256k1_musig_partial_sign_clear(&sk, k); + return 0; + } + secp256k1_fe_normalize_var(&pk.y); + /* Determine if the secret key sk should be negated before signing. + * + * We use the following notation: + * - |.| is a function that normalizes a point to an even Y by negating + * if necessary, similar to secp256k1_extrakeys_ge_even_y + * - mu[i] is the i-th KeyAgg coefficient + * - t[i] is the i-th tweak + * + * The following public keys arise as intermediate steps: + * - P[i] is the i-th public key with corresponding secret key x[i] + * P[i] := x[i]*G + * - P_agg is the aggregate public key + * P_agg := mu[0]*|P[0]| + ... + mu[n-1]*|P[n-1]| + * - P_tweak[i] is the tweaked public key after the i-th tweaking operation + * P_tweak[0] := P_agg + * P_tweak[i] := |P_tweak[i-1]| + t[i]*G for i = 1, ..., m + * + * Note that our goal is to produce a partial signature corresponding to + * the final public key after m tweaking operations P_final = |P_tweak[m]|. + * + * Define d[i], d_agg, and d_tweak[i] so that: + * - |P[i]| = d[i]*P[i] + * - |P_agg| = d_agg*P_agg + * - |P_tweak[i]| = d_tweak[i]*P_tweak[i] + * + * In other words, d[i] = 1 if P[i] has even y coordinate, -1 otherwise; + * similarly for d_agg and d_tweak[i]. + * + * The (xonly) final public key is P_final = |P_tweak[m]| + * = d_tweak[m]*P_tweak[m] + * = d_tweak[m]*(|P_tweak[m-1]| + t[m]*G) + * = d_tweak[m]*(d_tweak[m-1]*(|P_tweak[m-2]| + t[m-1]*G) + t[m]*G) + * = d_tweak[m]*...*d_tweak[1]*|P_agg| + (d_tweak[m]*t[m]+...+*d_tweak[1]*t[1])*G. + * To simplify the equation let us define + * t := d_tweak[m]*t[m]+...+*d_tweak[1]*t[1] + * d_tweak := d_tweak[m]*...*d_tweak[1]. + * Then we have + * P_final - t*G + * = d_tweak*|P_agg| + * = d_tweak*d_agg*P_agg + * = d_tweak*d_agg*(mu[0]*|P[0]| + ... + mu[n-1]*|P[n-1]|) + * = d_tweak*d_agg*(d[0]*mu[0]*P[0] + ... + d[n-1]*mu[n-1]*P[n-1]) + * = sum((d_tweak*d_agg*d[i])*mu[i]*x[i])*G. + * + * Thus whether signer i should use the negated x[i] depends on the product + * d_tweak[m]*...*d_tweak[1]*d_agg*d[i]. In other words, negate if and only + * if the following holds: + * (P[i] has odd y) XOR (P_agg has odd y) + * XOR (P_tweak[1] has odd y) XOR ... XOR (P_tweak[m] has odd y) + * + * Let us now look at how the terms in the equation correspond to the if + * condition below for some values of m: + * m = 0: P_i has odd y = secp256k1_fe_is_odd(&pk.y) + * P_agg has odd y = secp256k1_fe_is_odd(&cache_i.pk.y) + * cache_i.internal_key_parity = 0 + * m = 1: P_i has odd y = secp256k1_fe_is_odd(&pk.y) + * P_agg has odd y = cache_i.internal_key_parity + * P_tweak[1] has odd y = secp256k1_fe_is_odd(&cache_i.pk.y) + * m = 2: P_i has odd y = secp256k1_fe_is_odd(&pk.y) + * P_agg has odd y XOR P_tweak[1] has odd y = cache_i.internal_key_parity + * P_tweak[2] has odd y = secp256k1_fe_is_odd(&cache_i.pk.y) + * etc. + */ + if ((secp256k1_fe_is_odd(&pk.y) + != secp256k1_fe_is_odd(&cache_i.pk.y)) + != cache_i.internal_key_parity) { + secp256k1_scalar_negate(&sk, &sk); + } + + /* Multiply KeyAgg coefficient */ + secp256k1_fe_normalize_var(&pk.x); + /* TODO Cache mu */ + secp256k1_musig_keyaggcoef(&mu, &cache_i, &pk.x); + secp256k1_scalar_mul(&sk, &sk, &mu); + + if (!secp256k1_musig_session_load(ctx, &session_i, session)) { + secp256k1_musig_partial_sign_clear(&sk, k); + return 0; + } + + if (session_i.fin_nonce_parity) { + secp256k1_scalar_negate(&k[0], &k[0]); + secp256k1_scalar_negate(&k[1], &k[1]); + } + + /* Sign */ + secp256k1_scalar_mul(&s, &session_i.challenge, &sk); + secp256k1_scalar_mul(&k[1], &session_i.noncecoef, &k[1]); + secp256k1_scalar_add(&k[0], &k[0], &k[1]); + secp256k1_scalar_add(&s, &s, &k[0]); + secp256k1_musig_partial_sig_save(partial_sig, &s); + secp256k1_musig_partial_sign_clear(&sk, k); + return 1; +} + +int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_xonly_pubkey *pubkey, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) { + secp256k1_keyagg_cache_internal cache_i; + secp256k1_musig_session_internal session_i; + secp256k1_scalar mu, e, s; + secp256k1_gej pkj; + secp256k1_ge nonce_pt[2]; + secp256k1_gej rj; + secp256k1_gej tmp; + secp256k1_ge pkp; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(partial_sig != NULL); + ARG_CHECK(pubnonce != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(keyagg_cache != NULL); + ARG_CHECK(session != NULL); + + if (!secp256k1_musig_session_load(ctx, &session_i, session)) { + return 0; + } + + /* Compute "effective" nonce rj = aggnonce[0] + b*aggnonce[1] */ + /* TODO: use multiexp to compute -s*G + e*mu*pubkey + aggnonce[0] + b*aggnonce[1] */ + if (!secp256k1_musig_pubnonce_load(ctx, nonce_pt, pubnonce)) { + return 0; + } + secp256k1_gej_set_ge(&rj, &nonce_pt[1]); + secp256k1_ecmult(&rj, &rj, &session_i.noncecoef, NULL); + secp256k1_gej_add_ge_var(&rj, &rj, &nonce_pt[0], NULL); + + if (!secp256k1_xonly_pubkey_load(ctx, &pkp, pubkey)) { + return 0; + } + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + /* Multiplying the challenge by the KeyAgg coefficient is equivalent + * to multiplying the signer's public key by the coefficient, except + * much easier to do. */ + secp256k1_musig_keyaggcoef(&mu, &cache_i, &pkp.x); + secp256k1_scalar_mul(&e, &session_i.challenge, &mu); + + /* If the MuSig-aggregate point has an odd Y coordinate, the signers will + * sign for the negation of their individual xonly public key. If the + * aggregate key is untweaked, then internal_key_parity is 0, so `e` is + * negated exactly when the aggregate key parity is odd. If the aggregate + * key is tweaked, then negation happens when the aggregate key has an odd Y + * coordinate XOR the internal key has an odd Y coordinate.*/ + + /* When producing a partial signature, signer i uses a possibly + * negated secret key: + * + * sk[i] = (d_tweak*d_agg*d[i])*x[i] + * + * to ensure that the aggregate signature will correspond to + * an aggregate public key with even Y coordinate (see the + * notation and explanation in musig_partial_sign). + * + * We use the following additional notation: + * - e is the (Schnorr signature) challenge + * - r[i] is the i-th signer's secret nonce + * - R[i] = r[i]*G is the i-th signer's public nonce + * - R is the aggregated public nonce + * - d_nonce is chosen so that |R| = d_nonce*R + * + * The i-th partial signature is: + * + * s[i] = d_nonce*r[i] + mu[i]*e*sk[i] + * + * In order to verify this partial signature, we need to check: + * + * s[i]*G = d_nonce*R[i] + mu[i]*e*sk[i]*G + * + * The verifier doesn't have access to sk[i]*G, but can construct + * it using the xonly public key |P[i]| as follows: + * + * sk[i]*G = d_tweak*d_agg*d[i]*x[i]*G + * = d_tweak*d_agg*d[i]*P[i] + * = d_tweak*d_agg*|P[i]| + * + * The if condition below is true whenever d_tweak*d_agg is + * negative (again, see the explanation in musig_partial_sign). In + * this case, the verifier negates e which will have the same end + * result as negating |P[i]|, since they are multiplied later anyway. + */ + if (secp256k1_fe_is_odd(&cache_i.pk.y) + != cache_i.internal_key_parity) { + secp256k1_scalar_negate(&e, &e); + } + + if (!secp256k1_musig_partial_sig_load(ctx, &s, partial_sig)) { + return 0; + } + /* Compute -s*G + e*pkj + rj (e already includes the keyagg coefficient mu) */ + secp256k1_scalar_negate(&s, &s); + secp256k1_gej_set_ge(&pkj, &pkp); + secp256k1_ecmult(&tmp, &pkj, &e, &s); + if (session_i.fin_nonce_parity) { + secp256k1_gej_neg(&rj, &rj); + } + secp256k1_gej_add_var(&tmp, &tmp, &rj, NULL); + + return secp256k1_gej_is_infinity(&tmp); +} + +int secp256k1_musig_partial_sig_agg(const secp256k1_context* ctx, unsigned char *sig64, const secp256k1_musig_session *session, const secp256k1_musig_partial_sig * const* partial_sigs, size_t n_sigs) { + size_t i; + secp256k1_musig_session_internal session_i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(session != NULL); + ARG_CHECK(partial_sigs != NULL); + ARG_CHECK(n_sigs > 0); + + if (!secp256k1_musig_session_load(ctx, &session_i, session)) { + return 0; + } + for (i = 0; i < n_sigs; i++) { + secp256k1_scalar term; + if (!secp256k1_musig_partial_sig_load(ctx, &term, partial_sigs[i])) { + return 0; + } + secp256k1_scalar_add(&session_i.s_part, &session_i.s_part, &term); + } + secp256k1_scalar_get_b32(&sig64[32], &session_i.s_part); + memcpy(&sig64[0], session_i.fin_nonce, 32); + return 1; +} + +#endif diff --git a/src/modules/musig/tests_impl.h b/src/modules/musig/tests_impl.h index a500f3bc0..383b4161e 100644 --- a/src/modules/musig/tests_impl.h +++ b/src/modules/musig/tests_impl.h @@ -1,112 +1,156 @@ -/********************************************************************** - * Copyright (c) 2018 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_MODULE_MUSIG_TESTS_ -#define _SECP256K1_MODULE_MUSIG_TESTS_ - -#include "secp256k1_musig.h" - -int secp256k1_xonly_pubkey_create(secp256k1_xonly_pubkey *pk, const unsigned char *seckey) { +/*********************************************************************** + * Copyright (c) 2018 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_TESTS_IMPL_H +#define SECP256K1_MODULE_MUSIG_TESTS_IMPL_H + +#include +#include + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_extrakeys.h" +#include "../../../include/secp256k1_musig.h" + +#include "session.h" +#include "keyagg.h" +#include "../../scalar.h" +#include "../../scratch.h" +#include "../../field.h" +#include "../../group.h" +#include "../../hash.h" +#include "../../util.h" + +static int create_keypair_and_pk(secp256k1_keypair *keypair, secp256k1_xonly_pubkey *pk, const unsigned char *sk) { int ret; - secp256k1_keypair keypair; - ret = secp256k1_keypair_create(ctx, &keypair, seckey); - ret &= secp256k1_keypair_xonly_pub(ctx, pk, NULL, &keypair); + secp256k1_keypair keypair_tmp; + ret = secp256k1_keypair_create(ctx, &keypair_tmp, sk); + ret &= secp256k1_keypair_xonly_pub(ctx, pk, NULL, &keypair_tmp); + if (keypair != NULL) { + *keypair = keypair_tmp; + } return ret; } -/* Just a simple (non-adaptor, non-tweaked) 2-of-2 MuSig combine, sign, verify +/* Just a simple (non-adaptor, non-tweaked) 2-of-2 MuSig aggregate, sign, verify * test. */ void musig_simple_test(secp256k1_scratch_space *scratch) { unsigned char sk[2][32]; - secp256k1_musig_session session[2]; - secp256k1_musig_session_signer_data signer0[2]; - secp256k1_musig_session_signer_data signer1[2]; - unsigned char nonce_commitment[2][32]; + secp256k1_keypair keypair[2]; + secp256k1_musig_pubnonce pubnonce[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + secp256k1_musig_aggnonce aggnonce; unsigned char msg[32]; - secp256k1_xonly_pubkey combined_pk; - secp256k1_musig_pre_session pre_session; + secp256k1_xonly_pubkey agg_pk; + secp256k1_musig_keyagg_cache keyagg_cache; unsigned char session_id[2][32]; + secp256k1_musig_secnonce secnonce[2]; secp256k1_xonly_pubkey pk[2]; const secp256k1_xonly_pubkey *pk_ptr[2]; - const unsigned char *ncs[2]; - unsigned char public_nonce[3][32]; - secp256k1_musig_partial_signature partial_sig[2]; + secp256k1_musig_partial_sig partial_sig[2]; + const secp256k1_musig_partial_sig *partial_sig_ptr[2]; unsigned char final_sig[64]; + secp256k1_musig_session session; + int i; - secp256k1_testrand256(session_id[0]); - secp256k1_testrand256(session_id[1]); - secp256k1_testrand256(sk[0]); - secp256k1_testrand256(sk[1]); secp256k1_testrand256(msg); + for (i = 0; i < 2; i++) { + secp256k1_testrand256(session_id[i]); + secp256k1_testrand256(sk[i]); + pk_ptr[i] = &pk[i]; + pubnonce_ptr[i] = &pubnonce[i]; + partial_sig_ptr[i] = &partial_sig[i]; - pk_ptr[0] = &pk[0]; - pk_ptr[1] = &pk[1]; - CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1); - CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1); + CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); + CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce[i], &pubnonce[i], session_id[i], sk[i], NULL, NULL, NULL) == 1); + } - CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1); - CHECK(secp256k1_musig_session_init(ctx, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, sk[1]) == 1); - CHECK(secp256k1_musig_session_init(ctx, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 1); + CHECK(secp256k1_musig_pubkey_agg(ctx, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 2) == 1); + CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, &keyagg_cache, NULL) == 1); - ncs[0] = nonce_commitment[0]; - ncs[1] = nonce_commitment[1]; + for (i = 0; i < 2; i++) { + CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig[i], &secnonce[i], &keypair[i], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(ctx, &partial_sig[i], &pubnonce[i], &pk[i], &keyagg_cache, &session) == 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_partial_sig_agg(ctx, final_sig, &session, partial_sig_ptr, 2) == 1); + CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, sizeof(msg), &agg_pk) == 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); +void pubnonce_summing_to_inf(secp256k1_musig_pubnonce *pubnonce) { + secp256k1_ge ge[2]; + int i; + secp256k1_gej summed_nonces[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; - 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); + ge[0] = secp256k1_ge_const_g; + ge[1] = secp256k1_ge_const_g; - CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1); - CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1); - CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1); - CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signer0[1], &partial_sig[1], &pk[1]) == 1); - CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signer1[1], &partial_sig[1], &pk[1]) == 1); + for (i = 0; i < 2; i++) { + secp256k1_musig_pubnonce_save(&pubnonce[i], ge); + pubnonce_ptr[i] = &pubnonce[i]; + secp256k1_ge_neg(&ge[0], &ge[0]); + secp256k1_ge_neg(&ge[1], &ge[1]); + } - CHECK(secp256k1_musig_partial_sig_combine(ctx, &session[0], final_sig, partial_sig, 2) == 1); - CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, sizeof(msg), &combined_pk) == 1); + secp256k1_musig_sum_nonces(ctx, summed_nonces, pubnonce_ptr, 2); + CHECK(secp256k1_gej_is_infinity(&summed_nonces[0])); + CHECK(secp256k1_gej_is_infinity(&summed_nonces[1])); +} + +int memcmp_and_randomize(unsigned char *value, const unsigned char *expected, size_t len) { + int ret; + size_t i; + ret = secp256k1_memcmp_var(value, expected, len); + for (i = 0; i < len; i++) { + value[i] = secp256k1_testrand_bits(8); + } + return ret; } 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]; - secp256k1_musig_session_signer_data verifier_signer_data[2]; - secp256k1_musig_partial_signature partial_sig[2]; - secp256k1_musig_partial_signature partial_sig_adapted[2]; - secp256k1_musig_partial_signature partial_sig_overflow; + secp256k1_musig_partial_sig partial_sig[2]; + const secp256k1_musig_partial_sig *partial_sig_ptr[2]; + secp256k1_musig_partial_sig invalid_partial_sig; + const secp256k1_musig_partial_sig *invalid_partial_sig_ptr[2]; unsigned char final_sig[64]; - unsigned char final_sig_cmp[64]; - + unsigned char pre_sig[64]; unsigned char buf[32]; unsigned char sk[2][32]; - unsigned char ones[32]; + secp256k1_keypair keypair[2]; + secp256k1_keypair invalid_keypair; + unsigned char max64[64]; + unsigned char zeros68[68] = { 0 }; unsigned char session_id[2][32]; - unsigned char nonce_commitment[2][32]; - int combined_nonce_parity; - const unsigned char *ncs[2]; + secp256k1_musig_secnonce secnonce[2]; + secp256k1_musig_secnonce secnonce_tmp; + secp256k1_musig_secnonce invalid_secnonce; + secp256k1_musig_pubnonce pubnonce[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + unsigned char pubnonce_ser[66]; + secp256k1_musig_pubnonce inf_pubnonce[2]; + const secp256k1_musig_pubnonce *inf_pubnonce_ptr[2]; + secp256k1_musig_pubnonce invalid_pubnonce; + const secp256k1_musig_pubnonce *invalid_pubnonce_ptr[1]; + secp256k1_musig_aggnonce aggnonce; + unsigned char aggnonce_ser[66]; unsigned char msg[32]; - secp256k1_xonly_pubkey combined_pk; - secp256k1_musig_pre_session pre_session; - secp256k1_musig_pre_session pre_session_uninitialized; + secp256k1_xonly_pubkey agg_pk; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_keyagg_cache invalid_keyagg_cache; + secp256k1_musig_session session; + secp256k1_musig_session invalid_session; secp256k1_xonly_pubkey pk[2]; const secp256k1_xonly_pubkey *pk_ptr[2]; secp256k1_xonly_pubkey invalid_pk; const secp256k1_xonly_pubkey *invalid_pk_ptr2[2]; const secp256k1_xonly_pubkey *invalid_pk_ptr3[3]; unsigned char tweak[32]; - + int nonce_parity; unsigned char sec_adaptor[32]; unsigned char sec_adaptor1[32]; secp256k1_pubkey adaptor; @@ -125,616 +169,480 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - memset(ones, 0xff, 32); + memset(max64, 0xff, sizeof(max64)); + memset(&invalid_keypair, 0, sizeof(invalid_keypair)); + memset(&invalid_pk, 0, sizeof(invalid_pk)); + memset(&invalid_secnonce, 0, sizeof(invalid_secnonce)); + memset(&invalid_partial_sig, 0, sizeof(invalid_partial_sig)); + pubnonce_summing_to_inf(inf_pubnonce); /* 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)); + memset(&invalid_keyagg_cache, 0, sizeof(invalid_keyagg_cache)); memset(&invalid_pk, 0, sizeof(invalid_pk)); + memset(&invalid_pubnonce, 0, sizeof(invalid_pubnonce)); + memset(&invalid_session, 0, sizeof(invalid_session)); - secp256k1_testrand256(session_id[0]); - secp256k1_testrand256(session_id[1]); - secp256k1_testrand256(sk[0]); - secp256k1_testrand256(sk[1]); - secp256k1_testrand256(msg); secp256k1_testrand256(sec_adaptor); + secp256k1_testrand256(msg); secp256k1_testrand256(tweak); - - pk_ptr[0] = &pk[0]; - pk_ptr[1] = &pk[1]; - CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1); - CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1); CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor) == 1); - for (i = 0; i < 2; i++) { + pk_ptr[i] = &pk[i]; invalid_pk_ptr2[i] = &invalid_pk; invalid_pk_ptr3[i] = &pk[i]; + pubnonce_ptr[i] = &pubnonce[i]; + inf_pubnonce_ptr[i] = &inf_pubnonce[i]; + partial_sig_ptr[i] = &partial_sig[i]; + invalid_partial_sig_ptr[i] = &partial_sig[i]; + secp256k1_testrand256(session_id[i]); + secp256k1_testrand256(sk[i]); + CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); } + invalid_pubnonce_ptr[0] = &invalid_pubnonce; + invalid_partial_sig_ptr[0] = &invalid_partial_sig; /* invalid_pk_ptr3 has two valid, one invalid pk, which is important to test - * musig_pubkeys_combine */ + * musig_pubkey_agg */ invalid_pk_ptr3[2] = &invalid_pk; /** main test body **/ - /* Key combination */ + /** Key aggregation **/ ecount = 0; - CHECK(secp256k1_musig_pubkey_combine(none, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1); - CHECK(secp256k1_musig_pubkey_combine(sign, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1); - /* pubkey_combine does not require a scratch space */ - CHECK(secp256k1_musig_pubkey_combine(vrfy, NULL, &combined_pk, &pre_session, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(none, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(sign, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + /* pubkey_agg does not require a scratch space */ + CHECK(secp256k1_musig_pubkey_agg(vrfy, NULL, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); /* A small scratch space works too, but will result in using an ineffecient algorithm */ scratch_small = secp256k1_scratch_space_create(ctx, 1); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, &pre_session, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch_small, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); secp256k1_scratch_space_destroy(ctx, scratch_small); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, NULL, &pre_session, pk_ptr, 2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, NULL, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, NULL, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, NULL, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, NULL, 2) == 0); CHECK(ecount == 1); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, NULL, 2) == 0); + CHECK(memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); + CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, invalid_pk_ptr2, 2) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, invalid_pk_ptr2, 2) == 0); + CHECK(memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); + CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, invalid_pk_ptr3, 3) == 0); CHECK(ecount == 3); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, invalid_pk_ptr3, 3) == 0); + CHECK(memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); + CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, pk_ptr, 0) == 0); CHECK(ecount == 4); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk_ptr, 0) == 0); + CHECK(memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); + CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, NULL, 0) == 0); CHECK(ecount == 5); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, NULL, 0) == 0); - CHECK(ecount == 6); + CHECK(memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1); - CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(none, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(sign, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); - /** Tweaking */ + /** 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) == 1); - tmp_pre_session = pre_session; - CHECK(secp256k1_musig_pubkey_tweak_add(sign, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 1); - tmp_pre_session = pre_session; - CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 1); - tmp_pre_session = pre_session; - CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, NULL, &tmp_output_pk, &tmp_internal_pk, tweak) == 0); + secp256k1_musig_keyagg_cache tmp_keyagg_cache = keyagg_cache; + CHECK(secp256k1_musig_pubkey_tweak_add(ctx, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); + /* Reset keyagg_cache */ + tmp_keyagg_cache = keyagg_cache; + CHECK(secp256k1_musig_pubkey_tweak_add(none, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); + tmp_keyagg_cache = keyagg_cache; + CHECK(secp256k1_musig_pubkey_tweak_add(sign, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); + tmp_keyagg_cache = keyagg_cache; + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); + tmp_keyagg_cache = keyagg_cache; + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, NULL, &tmp_keyagg_cache, tweak) == 1); + tmp_keyagg_cache = keyagg_cache; + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_output_pk, NULL, tweak) == 0); CHECK(ecount == 1); - /* Uninitialized pre_session */ - CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &pre_session_uninitialized, &tmp_output_pk, &tmp_internal_pk, tweak) == 0); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0); + tmp_keyagg_cache = keyagg_cache; + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_output_pk, &tmp_keyagg_cache, NULL) == 0); + CHECK(ecount == 2); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0); + tmp_keyagg_cache = keyagg_cache; + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_output_pk, &tmp_keyagg_cache, max64) == 0); CHECK(ecount == 2); - /* 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(memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0); + tmp_keyagg_cache = keyagg_cache; + /* Uninitialized keyagg_cache */ + CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_output_pk, &invalid_keyagg_cache, tweak) == 0); CHECK(ecount == 3); - tmp_pre_session = pre_session; - CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, NULL, &tmp_internal_pk, tweak) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, NULL, tweak) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, NULL) == 0); - CHECK(ecount == 6); - CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, ones) == 0); - CHECK(ecount == 6); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0); } /** Session creation **/ ecount = 0; - CHECK(secp256k1_musig_session_init(none, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 0); + CHECK(secp256k1_musig_nonce_gen(none, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 0); CHECK(ecount == 1); - CHECK(secp256k1_musig_session_init(vrfy, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 0); + CHECK(secp256k1_musig_nonce_gen(vrfy, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 1); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 1); CHECK(ecount == 2); - CHECK(secp256k1_musig_session_init(sign, NULL, signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 0); + CHECK(secp256k1_musig_nonce_gen(sign, NULL, &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 0); CHECK(ecount == 3); - CHECK(secp256k1_musig_session_init(sign, &session[0], NULL, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 0); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], NULL, session_id[0], sk[0], msg, &keyagg_cache, max64) == 0); CHECK(ecount == 4); - CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, NULL, session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 0); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], NULL, sk[0], msg, &keyagg_cache, max64) == 0); + CHECK(ecount == 5); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0); + /* no seckey and session_id is 0 */ + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], zeros68, NULL, msg, &keyagg_cache, max64) == 0); + CHECK(ecount == 5); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0); + /* session_id 0 is fine when a seckey is provided */ + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], zeros68, sk[0], msg, &keyagg_cache, max64) == 1); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], NULL, msg, &keyagg_cache, max64) == 1); CHECK(ecount == 5); - CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], NULL, msg, &combined_pk, &pre_session, 2, sk[0]) == 0); + /* invalid seckey */ + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], max64, msg, &keyagg_cache, max64) == 0); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], NULL, &keyagg_cache, max64) == 1); + CHECK(ecount == 5); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, NULL, max64) == 1); + CHECK(ecount == 5); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &invalid_keyagg_cache, max64) == 0); CHECK(ecount == 6); - CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, &pre_session, 2, sk[0]) == 1); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, NULL) == 1); CHECK(ecount == 6); - CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, NULL, &pre_session, 2, sk[0]) == 0); - CHECK(ecount == 7); - CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, NULL, 2, sk[0]) == 0); - CHECK(ecount == 8); - /* Uninitialized pre_session */ - CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session_uninitialized, 2, sk[0]) == 0); - CHECK(ecount == 9); - CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 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_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, ((size_t) UINT32_MAX) + 2, sk[0]) == 0); - CHECK(ecount == 11); - } else { - ecount = 11; - } - CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, NULL) == 0); - CHECK(ecount == 12); - /* secret key overflows */ - CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, ones) == 0); - CHECK(ecount == 12); - CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 1); - CHECK(secp256k1_musig_session_init(sign, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, sk[1]) == 1); - ncs[0] = nonce_commitment[0]; - ncs[1] = nonce_commitment[1]; + /* Every in-argument except session_id can be NULL */ + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], NULL, NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[1], &pubnonce[1], session_id[1], sk[1], NULL, NULL, NULL) == 1); + /** Serialize and parse public nonces **/ ecount = 0; - 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_init_verifier(none, NULL, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 0); + CHECK(secp256k1_musig_pubnonce_serialize(none, NULL, &pubnonce[0]) == 0); CHECK(ecount == 1); - CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, NULL, &combined_pk, &pre_session, ncs, 2) == 0); + CHECK(secp256k1_musig_pubnonce_serialize(none, pubnonce_ser, NULL) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, NULL, &pre_session, ncs, 2) == 0); + CHECK(memcmp_and_randomize(pubnonce_ser, zeros68, sizeof(pubnonce_ser)) == 0); + CHECK(secp256k1_musig_pubnonce_serialize(none, pubnonce_ser, &invalid_pubnonce) == 0); CHECK(ecount == 3); - 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_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_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, ((size_t) UINT32_MAX) + 2) == 0); - CHECK(ecount == 7); - } else { - ecount = 7; - } - CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 1); + CHECK(memcmp_and_randomize(pubnonce_ser, zeros68, sizeof(pubnonce_ser)) == 0); + CHECK(secp256k1_musig_pubnonce_serialize(none, pubnonce_ser, &pubnonce[0]) == 1); - /** Signing step 0 -- exchange nonce commitments */ ecount = 0; - { - unsigned char nonce[32]; - secp256k1_musig_session session_0_tmp; + CHECK(secp256k1_musig_pubnonce_parse(none, &pubnonce[0], pubnonce_ser) == 1); + CHECK(secp256k1_musig_pubnonce_parse(none, NULL, pubnonce_ser) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_musig_pubnonce_parse(none, &pubnonce[0], NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_musig_pubnonce_parse(none, &pubnonce[0], zeros68) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_musig_pubnonce_parse(none, &pubnonce[0], pubnonce_ser) == 1); - memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp)); + { + /* Check that serialize and parse results in the same value */ + secp256k1_musig_pubnonce tmp; + CHECK(secp256k1_musig_pubnonce_serialize(none, pubnonce_ser, &pubnonce[0]) == 1); + CHECK(secp256k1_musig_pubnonce_parse(none, &tmp, pubnonce_ser) == 1); + CHECK(memcmp(&tmp, &pubnonce[0], sizeof(tmp)) == 0); + } - /* Can obtain public nonce after commitments have been exchanged; still can't sign */ - 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); + /** Receive nonces and aggregate **/ + ecount = 0; + CHECK(secp256k1_musig_nonce_agg(none, &aggnonce, pubnonce_ptr, 2) == 1); + CHECK(secp256k1_musig_nonce_agg(none, NULL, pubnonce_ptr, 2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_musig_nonce_agg(none, &aggnonce, NULL, 2) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_musig_nonce_agg(none, &aggnonce, pubnonce_ptr, 0) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_musig_nonce_agg(none, &aggnonce, invalid_pubnonce_ptr, 1) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_musig_nonce_agg(none, &aggnonce, inf_pubnonce_ptr, 2) == 1); + { + /* Check that the aggnonce is set to G */ + secp256k1_ge aggnonce_pt[2]; + secp256k1_musig_pubnonce_load(ctx, aggnonce_pt, (secp256k1_musig_pubnonce*)&aggnonce); + for (i = 0; i < 2; i++) { + ge_equals_ge(&aggnonce_pt[i], &secp256k1_ge_const_g); + } } + CHECK(ecount == 4); + CHECK(secp256k1_musig_nonce_agg(none, &aggnonce, pubnonce_ptr, 2) == 1); + + /** Serialize and parse aggregate nonces **/ + ecount = 0; + CHECK(secp256k1_musig_aggnonce_serialize(none, aggnonce_ser, &aggnonce) == 1); + CHECK(secp256k1_musig_aggnonce_serialize(none, NULL, &aggnonce) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_musig_aggnonce_serialize(none, aggnonce_ser, NULL) == 0); + CHECK(ecount == 2); + CHECK(memcmp_and_randomize(aggnonce_ser, zeros68, sizeof(aggnonce_ser)) == 0); + CHECK(secp256k1_musig_aggnonce_serialize(none, aggnonce_ser, (secp256k1_musig_aggnonce*) &invalid_pubnonce) == 0); + CHECK(ecount == 3); + CHECK(memcmp_and_randomize(aggnonce_ser, zeros68, sizeof(aggnonce_ser)) == 0); + CHECK(secp256k1_musig_aggnonce_serialize(none, aggnonce_ser, &aggnonce) == 1); - /** Signing step 1 -- exchange nonces */ ecount = 0; + CHECK(secp256k1_musig_aggnonce_parse(none, &aggnonce, aggnonce_ser) == 1); + CHECK(secp256k1_musig_aggnonce_parse(none, NULL, aggnonce_ser) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_musig_aggnonce_parse(none, &aggnonce, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_musig_aggnonce_parse(none, &aggnonce, zeros68) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_musig_aggnonce_parse(none, &aggnonce, aggnonce_ser) == 1); + { - unsigned char public_nonce[3][32]; - secp256k1_musig_session session_0_tmp; - - 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); - /* 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); - /* 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_tmp, NULL, public_nonce[0], ncs, 2, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, NULL, ncs, 2, NULL) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, public_nonce[0], NULL, 2, NULL) == 0); - CHECK(ecount == 5); - /* 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_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; - 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); - /* 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_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, &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); + /* Check that serialize and parse results in the same value */ + secp256k1_musig_aggnonce tmp; + CHECK(secp256k1_musig_aggnonce_serialize(none, aggnonce_ser, &aggnonce) == 1); + CHECK(secp256k1_musig_aggnonce_parse(none, &tmp, aggnonce_ser) == 1); + CHECK(memcmp(&tmp, &aggnonce, sizeof(tmp)) == 0); } - /** Signing step 2 -- partial signatures */ + /** Process nonces **/ ecount = 0; - CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_musig_partial_sign(none, NULL, &partial_sig[0]) == 0); + CHECK(secp256k1_musig_nonce_process(none, &session, &aggnonce, msg, &keyagg_cache, &adaptor) == 1); + CHECK(secp256k1_musig_nonce_process(sign, &session, &aggnonce, msg, &keyagg_cache, &adaptor) == 1); + CHECK(secp256k1_musig_nonce_process(vrfy, NULL, &aggnonce, msg, &keyagg_cache, &adaptor) == 0); CHECK(ecount == 1); - /* Uninitialized session */ - CHECK(secp256k1_musig_partial_sign(none, &session_uninitialized, &partial_sig[0]) == 0); + CHECK(secp256k1_musig_nonce_process(vrfy, &session, NULL, msg, &keyagg_cache, &adaptor) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_partial_sign(none, &session[0], NULL) == 0); + CHECK(secp256k1_musig_nonce_process(vrfy, &session, (secp256k1_musig_aggnonce*) &invalid_pubnonce, msg, &keyagg_cache, &adaptor) == 0); CHECK(ecount == 3); + CHECK(secp256k1_musig_nonce_process(vrfy, &session, &aggnonce, NULL, &keyagg_cache, &adaptor) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_musig_nonce_process(vrfy, &session, &aggnonce, msg, NULL, &adaptor) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_musig_nonce_process(vrfy, &session, &aggnonce, msg, &invalid_keyagg_cache, &adaptor) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_musig_nonce_process(vrfy, &session, &aggnonce, msg, &keyagg_cache, NULL) == 1); + CHECK(ecount == 6); + CHECK(secp256k1_musig_nonce_process(vrfy, &session, &aggnonce, msg, &keyagg_cache, (secp256k1_pubkey *)&invalid_pk) == 0); + CHECK(ecount == 7); - 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(secp256k1_musig_nonce_process(vrfy, &session, &aggnonce, msg, &keyagg_cache, &adaptor) == 1); + + ecount = 0; + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 1); + /* The secnonce is set to 0 and subsequent signing attempts fail */ + CHECK(memcmp(&secnonce_tmp, zeros68, sizeof(secnonce_tmp)) == 0); + CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 0); + CHECK(ecount == 1); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK(secp256k1_musig_partial_sign(none, NULL, &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 0); + CHECK(ecount == 2); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], NULL, &keypair[0], &keyagg_cache, &session) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &invalid_secnonce, &keypair[0], &keyagg_cache, &session) == 0); CHECK(ecount == 4); + CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, NULL, &keyagg_cache, &session) == 0); + CHECK(ecount == 5); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &invalid_keypair, &keyagg_cache, &session) == 0); + CHECK(ecount == 6); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], NULL, &session) == 0); + CHECK(ecount == 7); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &invalid_keyagg_cache, &session) == 0); + CHECK(ecount == 8); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, NULL) == 0); + CHECK(ecount == 9); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &invalid_session) == 0); + CHECK(ecount == 10); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + + CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce[0], &keypair[0], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sign(none, &partial_sig[1], &secnonce[1], &keypair[1], &keyagg_cache, &session) == 1); ecount = 0; - CHECK(secp256k1_musig_partial_signature_serialize(none, buf, &partial_sig[0]) == 1); - CHECK(secp256k1_musig_partial_signature_serialize(none, NULL, &partial_sig[0]) == 0); + CHECK(secp256k1_musig_partial_sig_serialize(none, buf, &partial_sig[0]) == 1); + CHECK(secp256k1_musig_partial_sig_serialize(none, NULL, &partial_sig[0]) == 0); CHECK(ecount == 1); - CHECK(secp256k1_musig_partial_signature_serialize(none, buf, NULL) == 0); + CHECK(secp256k1_musig_partial_sig_serialize(none, buf, NULL) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig[0], buf) == 1); - CHECK(secp256k1_musig_partial_signature_parse(none, NULL, buf) == 0); + CHECK(secp256k1_musig_partial_sig_parse(none, &partial_sig[0], buf) == 1); + CHECK(secp256k1_musig_partial_sig_parse(none, NULL, buf) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_musig_partial_sig_parse(none, &partial_sig[0], max64) == 0); CHECK(ecount == 3); - CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig[0], NULL) == 0); + CHECK(secp256k1_musig_partial_sig_parse(none, &partial_sig[0], NULL) == 0); CHECK(ecount == 4); - CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig_overflow, ones) == 1); + + { + /* Check that serialize and parse results in the same value */ + secp256k1_musig_partial_sig tmp; + CHECK(secp256k1_musig_partial_sig_serialize(none, buf, &partial_sig[0]) == 1); + CHECK(secp256k1_musig_partial_sig_parse(none, &tmp, buf) == 1); + CHECK(memcmp(&tmp, &partial_sig[0], sizeof(tmp)) == 0); + } /** Partial signature verification */ ecount = 0; - CHECK(secp256k1_musig_partial_sig_verify(none, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1); - CHECK(secp256k1_musig_partial_sig_verify(sign, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1); - 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[0], &signer0[0], &partial_sig[1], &pk[0]) == 0); - CHECK(secp256k1_musig_partial_sig_verify(vrfy, NULL, &signer0[0], &partial_sig[0], &pk[0]) == 0); + CHECK(secp256k1_musig_partial_sig_verify(none, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(sign, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &partial_sig[1], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 0); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, NULL, &pubnonce[0], &pk[0], &keyagg_cache, &session) == 0); CHECK(ecount == 1); - /* Unitialized session */ - CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session_uninitialized, &signer0[0], &partial_sig[0], &pk[0]) == 0); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &invalid_partial_sig, &pubnonce[0], &pk[0], &keyagg_cache, &session) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], NULL, &partial_sig[0], &pk[0]) == 0); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &partial_sig[0], NULL, &pk[0], &keyagg_cache, &session) == 0); CHECK(ecount == 3); - CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], NULL, &pk[0]) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig_overflow, &pk[0]) == 0); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &partial_sig[0], &invalid_pubnonce, &pk[0], &keyagg_cache, &session) == 0); CHECK(ecount == 4); - CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], NULL) == 0); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], NULL, &keyagg_cache, &session) == 0); CHECK(ecount == 5); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &invalid_pk, &keyagg_cache, &session) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &pk[0], NULL, &session) == 0); + CHECK(ecount == 7); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &pk[0], &invalid_keyagg_cache, &session) == 0); + CHECK(ecount == 8); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, NULL) == 0); + CHECK(ecount == 9); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &invalid_session) == 0); + CHECK(ecount == 10); + + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(vrfy, &partial_sig[1], &pubnonce[1], &pk[1], &keyagg_cache, &session) == 1); - 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); - CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[1], &partial_sig[1], &pk[1]) == 1); - 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); + /** Signature aggregation and verification */ + ecount = 0; + CHECK(secp256k1_musig_partial_sig_agg(none, pre_sig, &session, partial_sig_ptr, 2) == 1); + CHECK(secp256k1_musig_partial_sig_agg(none, NULL, &session, partial_sig_ptr, 2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_musig_partial_sig_agg(none, pre_sig, NULL, partial_sig_ptr, 2) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_musig_partial_sig_agg(none, pre_sig, &invalid_session, partial_sig_ptr, 2) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_musig_partial_sig_agg(none, pre_sig, &session, NULL, 2) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_musig_partial_sig_agg(none, pre_sig, &session, invalid_partial_sig_ptr, 2) == 0); CHECK(ecount == 5); + CHECK(secp256k1_musig_partial_sig_agg(none, pre_sig, &session, partial_sig_ptr, 0) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_musig_partial_sig_agg(none, pre_sig, &session, partial_sig_ptr, 1) == 1); + CHECK(secp256k1_musig_partial_sig_agg(none, pre_sig, &session, partial_sig_ptr, 2) == 1); /** 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, combined_nonce_parity) == 1); - CHECK(secp256k1_musig_partial_sig_adapt(none, NULL, &partial_sig[0], sec_adaptor, 0) == 0); + CHECK(secp256k1_musig_nonce_parity(none, &nonce_parity, &session) == 1); + CHECK(secp256k1_musig_nonce_parity(none, NULL, &session) == 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, combined_nonce_parity) == 0); + CHECK(secp256k1_musig_nonce_parity(none, &nonce_parity, NULL) == 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, combined_nonce_parity) == 0); + CHECK(secp256k1_musig_nonce_parity(none, &nonce_parity, &invalid_session) == 0); CHECK(ecount == 3); - /** Signing combining and verification */ ecount = 0; - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 2) == 1); - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig_cmp, partial_sig_adapted, 2) == 1); - CHECK(memcmp(final_sig, final_sig_cmp, sizeof(final_sig)) == 0); - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig_cmp, partial_sig_adapted, 2) == 1); - CHECK(memcmp(final_sig, final_sig_cmp, sizeof(final_sig)) == 0); - - CHECK(secp256k1_musig_partial_sig_combine(none, NULL, final_sig, partial_sig_adapted, 2) == 0); + CHECK(secp256k1_musig_adapt(none, final_sig, pre_sig, sec_adaptor, nonce_parity) == 1); + CHECK(secp256k1_musig_adapt(none, NULL, pre_sig, sec_adaptor, 0) == 0); CHECK(ecount == 1); - /* Unitialized session */ - CHECK(secp256k1_musig_partial_sig_combine(none, &session_uninitialized, final_sig, partial_sig_adapted, 2) == 0); + CHECK(secp256k1_musig_adapt(none, final_sig, NULL, sec_adaptor, 0) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], NULL, partial_sig_adapted, 2) == 0); + CHECK(secp256k1_musig_adapt(none, final_sig, max64, sec_adaptor, 0) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_musig_adapt(none, final_sig, pre_sig, NULL, 0) == 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 == 4); - /* Wrong number of partial sigs */ - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 1) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 2) == 1); + CHECK(secp256k1_musig_adapt(none, final_sig, pre_sig, max64, 0) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_musig_adapt(none, final_sig, pre_sig, sec_adaptor, 2) == 0); CHECK(ecount == 4); + /* sig and pre_sig argument point to the same location */ + memcpy(final_sig, pre_sig, sizeof(final_sig)); + CHECK(secp256k1_musig_adapt(none, final_sig, final_sig, sec_adaptor, nonce_parity) == 1); + CHECK(secp256k1_schnorrsig_verify(vrfy, final_sig, msg, sizeof(msg), &agg_pk) == 1); - CHECK(secp256k1_schnorrsig_verify(vrfy, final_sig, msg, sizeof(msg), &combined_pk) == 1); + CHECK(secp256k1_musig_adapt(none, final_sig, pre_sig, sec_adaptor, nonce_parity) == 1); + CHECK(secp256k1_schnorrsig_verify(vrfy, final_sig, msg, sizeof(msg), &agg_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, combined_nonce_parity) == 1); + CHECK(secp256k1_musig_extract_adaptor(none, sec_adaptor1, final_sig, pre_sig, 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); + /* wrong nonce parity */ + CHECK(secp256k1_musig_extract_adaptor(none, sec_adaptor1, final_sig, pre_sig, !nonce_parity) == 1); + CHECK(memcmp(sec_adaptor, sec_adaptor1, 32) != 0); + CHECK(secp256k1_musig_extract_adaptor(none, NULL, final_sig, pre_sig, 0) == 0); CHECK(ecount == 1); - CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, NULL, partial_sig, 2, 0) == 0); + CHECK(secp256k1_musig_extract_adaptor(none, sec_adaptor1, NULL, pre_sig, 0) == 0); CHECK(ecount == 2); - { - 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, combined_nonce_parity) == 0); - } + CHECK(secp256k1_musig_extract_adaptor(none, sec_adaptor1, max64, pre_sig, 0) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, NULL, 2, 0) == 0); + CHECK(secp256k1_musig_extract_adaptor(none, sec_adaptor1, final_sig, NULL, 0) == 0); CHECK(ecount == 3); - { - secp256k1_musig_partial_signature partial_sig_tmp[2]; - partial_sig_tmp[0] = partial_sig[0]; - partial_sig_tmp[1] = partial_sig_overflow; - CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig_tmp, 2, combined_nonce_parity) == 0); - } + CHECK(secp256k1_musig_extract_adaptor(none, sec_adaptor1, final_sig, max64, 0) == 0); CHECK(ecount == 3); - CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 0, 0) == 1); - CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 2, 1) == 1); + CHECK(secp256k1_musig_extract_adaptor(none, sec_adaptor1, final_sig, pre_sig, 2) == 0); + CHECK(ecount == 4); /** cleanup **/ - memset(&session, 0, sizeof(session)); secp256k1_context_destroy(none); secp256k1_context_destroy(sign); secp256k1_context_destroy(vrfy); } -/* Initializes two sessions, one use the given parameters (session_id, - * nonce_commitments, etc.) except that `session_tmp` uses new signers with different - * public keys. The point of this test is to call `musig_session_get_public_nonce` - * with signers from `session_tmp` who have different public keys than the correct - * 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. */ -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]; - secp256k1_musig_session_signer_data signers[2]; - secp256k1_musig_session_signer_data signers_tmp[2]; - unsigned char sk_dummy[32]; - secp256k1_xonly_pubkey pks_tmp[2]; - const secp256k1_xonly_pubkey *pks_tmp_ptr[2]; - secp256k1_xonly_pubkey combined_pk_tmp; - secp256k1_musig_pre_session pre_session_tmp; - 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); - pks_tmp_ptr[0] = &pks_tmp[0]; - pks_tmp_ptr[1] = &pks_tmp[1]; - CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk_tmp, &pre_session_tmp, pks_tmp_ptr, 2) == 1); - CHECK(secp256k1_musig_session_init(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, &pre_session_tmp, 2, sk_dummy) == 1); - - CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 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_set_nonce(ctx, &signers[0], nonce_other) == 1); - CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], nonce) == 1); - CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1); - - secp256k1_musig_compute_messagehash(ctx, msghash, &session); -} +void musig_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { + secp256k1_scalar k1[2], k2[2]; -/* Creates a new session (with a different session id) and tries to use that session - * to combine nonces with given signers_other. This should fail, because the nonce - * 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, 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]; - unsigned char nonce[32]; - const unsigned char *ncs[2]; - - /* Initialize new signers */ - secp256k1_testrand256(session_id); - CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 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); - 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; - } else { - signers_to_use = signers; - } - return secp256k1_musig_session_combine_nonces(ctx, &session, signers_to_use, 2, NULL, NULL); + secp256k1_nonce_function_musig(k1, args[0], args[1], args[2], args[3], args[4]); + secp256k1_testrand_flip(args[n_flip], n_bytes); + secp256k1_nonce_function_musig(k2, args[0], args[1], args[2], args[3], args[4]); + CHECK(secp256k1_scalar_eq(&k1[0], &k2[0]) == 0); + CHECK(secp256k1_scalar_eq(&k1[1], &k2[1]) == 0); } -/* Initializaes a session with the given session_id, signers, pk, msg etc. - * 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, 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; - secp256k1_musig_session session; - secp256k1_musig_session_signer_data signers[2]; - unsigned char nonce_commitment[32]; - const unsigned char *ncs[2]; - 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_init(ctx, &session, signers, nonce_commitment, session_id, NULL, combined_pk, pre_session, 2, 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(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); - /* 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(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_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])); - 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]; - secp256k1_musig_session_signer_data signers1[2]; - unsigned char nonce_commitment[2][32]; - unsigned char session_id[2][32]; +void musig_nonce_test(void) { + unsigned char *args[5]; + unsigned char session_id[32]; + unsigned char sk[32]; unsigned char msg[32]; - unsigned char sk[2][32]; - secp256k1_xonly_pubkey pk[2]; - const secp256k1_xonly_pubkey *pk_ptr[2]; - secp256k1_xonly_pubkey combined_pk; - secp256k1_musig_pre_session pre_session; - 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. */ - for (i = 0; i < 2; i++) { - /* Setup */ - secp256k1_testrand256(session_id[0]); - secp256k1_testrand256(session_id[1]); - secp256k1_testrand256(sk[0]); - secp256k1_testrand256(sk[1]); - secp256k1_testrand256(msg); - pk_ptr[0] = &pk[0]; - pk_ptr[1] = &pk[1]; - CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1); - CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1); - CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1); - CHECK(secp256k1_musig_session_init(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 1); - CHECK(secp256k1_musig_session_init(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 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); - /* 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); - - /* Set nonces */ - 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); - /* Set correct nonce */ - 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); - - /* 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); - - /* Partially sign */ - CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1); - /* 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. */ - 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); - - CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[1], &pk[1]) == 1); - /* 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); + unsigned char agg_pk[32]; + unsigned char extra_input[32]; + int i, j; + secp256k1_scalar k[5][2]; + + secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, session_id, sizeof(session_id)); + secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, sk, sizeof(sk)); + secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, msg, sizeof(msg)); + secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, agg_pk, sizeof(agg_pk)); + secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, extra_input, sizeof(extra_input)); + + /* Check that a bitflip in an argument results in different nonces. */ + args[0] = session_id; + args[1] = msg; + args[2] = sk; + args[3] = agg_pk; + args[4] = extra_input; + for (i = 0; i < count; i++) { + musig_nonce_bitflip(args, 0, sizeof(session_id)); + musig_nonce_bitflip(args, 1, sizeof(msg)); + musig_nonce_bitflip(args, 2, sizeof(sk)); + musig_nonce_bitflip(args, 3, sizeof(agg_pk)); + musig_nonce_bitflip(args, 4, sizeof(extra_input)); + } + /* Check that if any argument is NULL, a different nonce is produced than if + * any other argument is NULL. */ + memcpy(msg, session_id, sizeof(msg)); + memcpy(sk, session_id, sizeof(sk)); + memcpy(agg_pk, session_id, sizeof(agg_pk)); + memcpy(extra_input, session_id, sizeof(extra_input)); + secp256k1_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4]); + secp256k1_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4]); + secp256k1_nonce_function_musig(k[2], args[0], args[1], NULL, args[3], args[4]); + secp256k1_nonce_function_musig(k[3], args[0], args[1], args[2], NULL, args[4]); + secp256k1_nonce_function_musig(k[4], args[0], args[1], args[2], args[3], NULL); + for (i = 0; i < 4; i++) { + for (j = i+1; j < 5; j++) { + CHECK(secp256k1_scalar_eq(&k[i][0], &k[j][0]) == 0); + CHECK(secp256k1_scalar_eq(&k[i][1], &k[j][1]) == 0); + } } - secp256k1_context_destroy(ctx_tmp); } void scriptless_atomic_swap(secp256k1_scratch_space *scratch) { @@ -742,112 +650,104 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) { * while the indices 0 and 1 refer to the two signers. Here signer 0 is * sending a-coins to signer 1, while signer 1 is sending b-coins to signer * 0. Signer 0 produces the adaptor signatures. */ + unsigned char pre_sig_a[64]; unsigned char final_sig_a[64]; + unsigned char pre_sig_b[64]; unsigned char final_sig_b[64]; - secp256k1_musig_partial_signature partial_sig_a[2]; - secp256k1_musig_partial_signature partial_sig_b_adapted[2]; - secp256k1_musig_partial_signature partial_sig_b[2]; + secp256k1_musig_partial_sig partial_sig_a[2]; + const secp256k1_musig_partial_sig *partial_sig_a_ptr[2]; + secp256k1_musig_partial_sig partial_sig_b[2]; + const secp256k1_musig_partial_sig *partial_sig_b_ptr[2]; unsigned char sec_adaptor[32]; unsigned char sec_adaptor_extracted[32]; secp256k1_pubkey pub_adaptor; - - unsigned char seckey_a[2][32]; - unsigned char seckey_b[2][32]; + unsigned char sk_a[2][32]; + unsigned char sk_b[2][32]; + secp256k1_keypair keypair_a[2]; + secp256k1_keypair keypair_b[2]; secp256k1_xonly_pubkey pk_a[2]; const secp256k1_xonly_pubkey *pk_a_ptr[2]; secp256k1_xonly_pubkey pk_b[2]; const secp256k1_xonly_pubkey *pk_b_ptr[2]; - secp256k1_musig_pre_session pre_session_a; - secp256k1_musig_pre_session pre_session_b; - secp256k1_xonly_pubkey combined_pk_a; - secp256k1_xonly_pubkey combined_pk_b; - secp256k1_musig_session musig_session_a[2]; - secp256k1_musig_session musig_session_b[2]; - unsigned char noncommit_a[2][32]; - unsigned char noncommit_b[2][32]; - const unsigned char *noncommit_a_ptr[2]; - const unsigned char *noncommit_b_ptr[2]; - 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]; - - const unsigned char seed[32] = "still tired of choosing seeds..."; + secp256k1_musig_keyagg_cache keyagg_cache_a; + secp256k1_musig_keyagg_cache keyagg_cache_b; + secp256k1_xonly_pubkey agg_pk_a; + secp256k1_xonly_pubkey agg_pk_b; + secp256k1_musig_secnonce secnonce_a[2]; + secp256k1_musig_secnonce secnonce_b[2]; + secp256k1_musig_pubnonce pubnonce_a[2]; + secp256k1_musig_pubnonce pubnonce_b[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr_a[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr_b[2]; + secp256k1_musig_aggnonce aggnonce_a; + secp256k1_musig_aggnonce aggnonce_b; + secp256k1_musig_session session_a, session_b; + int nonce_parity_a; + int nonce_parity_b; + unsigned char seed_a[2][32] = { "a0", "a1" }; + unsigned char seed_b[2][32] = { "b0", "b1" }; const unsigned char msg32_a[32] = "this is the message blockchain a"; const unsigned char msg32_b[32] = "this is the message blockchain b"; + int i; /* Step 1: key setup */ - secp256k1_testrand256(seckey_a[0]); - secp256k1_testrand256(seckey_a[1]); - secp256k1_testrand256(seckey_b[0]); - secp256k1_testrand256(seckey_b[1]); + for (i = 0; i < 2; i++) { + pk_a_ptr[i] = &pk_a[i]; + pk_b_ptr[i] = &pk_b[i]; + pubnonce_ptr_a[i] = &pubnonce_a[i]; + pubnonce_ptr_b[i] = &pubnonce_b[i]; + partial_sig_a_ptr[i] = &partial_sig_a[i]; + partial_sig_b_ptr[i] = &partial_sig_b[i]; + + secp256k1_testrand256(sk_a[i]); + secp256k1_testrand256(sk_b[i]); + CHECK(create_keypair_and_pk(&keypair_a[i], &pk_a[i], sk_a[i]) == 1); + CHECK(create_keypair_and_pk(&keypair_b[i], &pk_b[i], sk_b[i]) == 1); + } secp256k1_testrand256(sec_adaptor); + CHECK(secp256k1_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor) == 1); + + CHECK(secp256k1_musig_pubkey_agg(ctx, scratch, &agg_pk_a, &keyagg_cache_a, pk_a_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(ctx, scratch, &agg_pk_b, &keyagg_cache_b, pk_b_ptr, 2) == 1); - pk_a_ptr[0] = &pk_a[0]; - pk_a_ptr[1] = &pk_a[1]; - pk_b_ptr[0] = &pk_b[0]; - pk_b_ptr[1] = &pk_b[1]; - CHECK(secp256k1_xonly_pubkey_create(&pk_a[0], seckey_a[0])); - CHECK(secp256k1_xonly_pubkey_create(&pk_a[1], seckey_a[1])); - CHECK(secp256k1_xonly_pubkey_create(&pk_b[0], seckey_b[0])); - CHECK(secp256k1_xonly_pubkey_create(&pk_b[1], seckey_b[1])); - CHECK(secp256k1_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor)); - - CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_a, &pre_session_a, pk_a_ptr, 2)); - CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_b, &pre_session_b, pk_b_ptr, 2)); - - 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, 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, seckey_a[1])); - noncommit_a_ptr[0] = noncommit_a[0]; - noncommit_a_ptr[1] = noncommit_a[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, 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, seckey_b[1])); - noncommit_b_ptr[0] = noncommit_b[0]; - noncommit_b_ptr[1] = noncommit_b[1]; + CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_a[0], &pubnonce_a[0], seed_a[0], sk_a[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_a[1], &pubnonce_a[1], seed_a[1], sk_a[1], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_b[0], &pubnonce_b[0], seed_b[0], sk_b[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_b[1], &pubnonce_b[1], seed_b[1], sk_b[1], NULL, NULL, NULL) == 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, &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, &combined_nonce_parity_b, &pub_adaptor)); - CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_b[1], data_b, 2, NULL, &pub_adaptor)); + CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce_a, pubnonce_ptr_a, 2) == 1); + CHECK(secp256k1_musig_nonce_process(ctx, &session_a, &aggnonce_a, msg32_a, &keyagg_cache_a, &pub_adaptor) == 1); + CHECK(secp256k1_musig_nonce_parity(ctx, &nonce_parity_a, &session_a) == 1); + CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce_b, pubnonce_ptr_b, 2) == 1); + CHECK(secp256k1_musig_nonce_process(ctx, &session_b, &aggnonce_b, msg32_b, &keyagg_cache_b, &pub_adaptor) == 1); + CHECK(secp256k1_musig_nonce_parity(ctx, &nonce_parity_b, &session_b) == 1); /* Step 3: Signer 0 produces partial signatures for both chains. */ - CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_a[0], &partial_sig_a[0])); - CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_b[0], &partial_sig_b[0])); + CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig_a[0], &secnonce_a[0], &keypair_a[0], &keyagg_cache_a, &session_a) == 1); + CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig_b[0], &secnonce_b[0], &keypair_b[0], &keyagg_cache_b, &session_b) == 1); /* Step 4: Signer 1 receives partial signatures, verifies them and creates a * partial signature to send B-coins to signer 0. */ - CHECK(secp256k1_musig_partial_sig_verify(ctx, &musig_session_a[1], data_a, &partial_sig_a[0], &pk_a[0]) == 1); - CHECK(secp256k1_musig_partial_sig_verify(ctx, &musig_session_b[1], data_b, &partial_sig_b[0], &pk_b[0]) == 1); - CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_b[1], &partial_sig_b[1])); - - /* 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, 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, sizeof(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, combined_nonce_parity_b) == 1); + CHECK(secp256k1_musig_partial_sig_verify(ctx, &partial_sig_a[0], &pubnonce_a[0], &pk_a[0], &keyagg_cache_a, &session_a) == 1); + CHECK(secp256k1_musig_partial_sig_verify(ctx, &partial_sig_b[0], &pubnonce_b[0], &pk_b[0], &keyagg_cache_b, &session_b) == 1); + CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig_b[1], &secnonce_b[1], &keypair_b[1], &keyagg_cache_b, &session_b) == 1); + + /* Step 5: Signer 0 aggregates its own partial signature with the partial + * signature from signer 1 and adapts it. This results in a complete + * signature which is broadcasted by signer 0 to take B-coins. */ + CHECK(secp256k1_musig_partial_sig_agg(ctx, pre_sig_b, &session_b, partial_sig_b_ptr, 2) == 1); + CHECK(secp256k1_musig_adapt(ctx, final_sig_b, pre_sig_b, sec_adaptor, nonce_parity_b) == 1); + CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_b, msg32_b, sizeof(msg32_b), &agg_pk_b) == 1); + + /* Step 6: Signer 1 signs, extracts adaptor from the published signature, + * and adapts the signature to take A-coins. */ + CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig_a[1], &secnonce_a[1], &keypair_a[1], &keyagg_cache_a, &session_a) == 1); + CHECK(secp256k1_musig_partial_sig_agg(ctx, pre_sig_a, &session_a, partial_sig_a_ptr, 2) == 1); + CHECK(secp256k1_musig_extract_adaptor(ctx, sec_adaptor_extracted, final_sig_b, pre_sig_b, 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, 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, sizeof(msg32_a), &combined_pk_a) == 1); + CHECK(secp256k1_musig_adapt(ctx, final_sig_a, pre_sig_a, sec_adaptor_extracted, nonce_parity_a) == 1); + CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_a, msg32_a, sizeof(msg32_a), &agg_pk_a) == 1); } void sha256_tag_test_internal(secp256k1_sha256 *sha_tagged, unsigned char *tag, size_t taglen) { @@ -859,7 +759,7 @@ void sha256_tag_test_internal(secp256k1_sha256 *sha_tagged, unsigned char *tag, secp256k1_sha256_initialize(&sha); secp256k1_sha256_write(&sha, tag, taglen); secp256k1_sha256_finalize(&sha, buf); - /* buf = SHA256("KeyAgg coefficient") */ + /* buf = SHA256(tag) */ secp256k1_sha256_initialize(&sha); secp256k1_sha256_write(&sha, buf, 32); @@ -894,164 +794,158 @@ void sha256_tag_test(void) { } } -/* 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]; +/* Attempts to create a signature for the aggregate public key using given secret + * keys and keyagg_cache. */ +void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigned char *sk0, const unsigned char *sk1, secp256k1_musig_keyagg_cache *keyagg_cache) { 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]; + secp256k1_musig_secnonce secnonce[2]; + secp256k1_musig_pubnonce pubnonce[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + secp256k1_musig_aggnonce aggnonce; + secp256k1_keypair keypair[2]; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig[2]; + const secp256k1_musig_partial_sig *partial_sig_ptr[2]; unsigned char final_sig[64]; + int i; + + for (i = 0; i < 2; i++) { + pubnonce_ptr[i] = &pubnonce[i]; + partial_sig_ptr[i] = &partial_sig[i]; - secp256k1_testrand256(session_id[0]); - secp256k1_testrand256(session_id[1]); + secp256k1_testrand256(session_id[i]); + } + CHECK(create_keypair_and_pk(&keypair[0], &pk[0], sk0) == 1); + CHECK(create_keypair_and_pk(&keypair[1], &pk[1], sk1) == 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, sk0) == 1); - CHECK(secp256k1_musig_session_init(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, combined_pubkey, pre_session, 2, 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, sizeof(msg), combined_pubkey) == 1); + CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce[0], &pubnonce[0], session_id[0], sk0, NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce[1], &pubnonce[1], session_id[1], sk1, NULL, NULL, NULL) == 1); + + CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 2) == 1); + CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, keyagg_cache, NULL) == 1); + + CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig[0], &secnonce[0], &keypair[0], keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig[1], &secnonce[1], &keypair[1], keyagg_cache, &session) == 1); + + CHECK(secp256k1_musig_partial_sig_verify(ctx, &partial_sig[0], &pubnonce[0], &pk[0], keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(ctx, &partial_sig[1], &pubnonce[1], &pk[1], keyagg_cache, &session) == 1); + + CHECK(secp256k1_musig_partial_sig_agg(ctx, final_sig, &session, partial_sig_ptr, 2) == 1); + CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, sizeof(msg), agg_pk) == 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. */ +/* Create aggregate public key P[0], tweak multiple times and test signing. */ void musig_tweak_test(secp256k1_scratch_space *scratch) { unsigned char sk[2][32]; secp256k1_xonly_pubkey pk[2]; const secp256k1_xonly_pubkey *pk_ptr[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); - - pk_ptr[0] = &pk[0]; - pk_ptr[1] = &pk[1]; - CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1); - CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1); - CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &P, &pre_session_P, pk_ptr, 2) == 1); + secp256k1_musig_keyagg_cache keyagg_cache; + enum { N_TWEAKS = 8 }; + secp256k1_pubkey P[N_TWEAKS + 1]; + secp256k1_xonly_pubkey P_xonly[N_TWEAKS + 1]; + int i; - 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); + /* Key Setup */ + for (i = 0; i < 2; i++) { + pk_ptr[i] = &pk[i]; + secp256k1_testrand256(sk[i]); + CHECK(create_keypair_and_pk(NULL, &pk[i], sk[i]) == 1); + } + /* Compute P0 = keyagg(pk0, pk1) and test signing for it */ + CHECK(secp256k1_musig_pubkey_agg(ctx, scratch, &P_xonly[0], &keyagg_cache, pk_ptr, 2) == 1); + musig_tweak_test_helper(&P_xonly[0], sk[0], sk[1], &keyagg_cache); + + /* Compute Pi = |Pj| + tweaki*G where where j = i-1 and try signing for + * that key. The function |.| normalizes the point to have an even + * X-coordinate. This results in ordinary "xonly-tweaking". */ + for (i = 1; i < N_TWEAKS; i++) { + unsigned char tweak[32]; + int P_parity; + unsigned char P_serialized[32]; + + secp256k1_testrand256(tweak); + CHECK(secp256k1_musig_pubkey_tweak_add(ctx, &P[i], &keyagg_cache, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &P_xonly[i], &P_parity, &P[i])); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, P_serialized, &P_xonly[i])); + /* Check that musig_pubkey_tweak_add produces same result as + * xonly_pubkey_tweak_add. */ + CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, P_serialized, P_parity, &P_xonly[i-1], tweak) == 1); + /* Test signing for P[i] */ + musig_tweak_test_helper(&P_xonly[i], sk[0], sk[1], &keyagg_cache); + } } -void musig_test_vectors_helper(unsigned char pk_ser[][32], int n_pks, const unsigned char *combined_pk_expected, int has_second_pk, int second_pk_idx) { +void musig_test_vectors_keyagg_helper(const unsigned char **pk_ser, int n_pks, const unsigned char *agg_pk_expected, int has_second_pk, int second_pk_idx) { secp256k1_xonly_pubkey *pk = malloc(n_pks * sizeof(*pk)); const secp256k1_xonly_pubkey **pk_ptr = malloc(n_pks * sizeof(*pk_ptr)); - secp256k1_xonly_pubkey combined_pk; - unsigned char combined_pk_ser[32]; - secp256k1_musig_pre_session pre_session; - secp256k1_fe second_pk_x; + secp256k1_keyagg_cache_internal cache_i; + secp256k1_xonly_pubkey agg_pk; + unsigned char agg_pk_ser[32]; + secp256k1_musig_keyagg_cache keyagg_cache; int i; for (i = 0; i < n_pks; i++) { - CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk[i], pk_ser[i])); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk[i], pk_ser[i]) == 1); pk_ptr[i] = &pk[i]; } - CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, &pre_session, pk_ptr, n_pks) == 1); - CHECK(secp256k1_fe_set_b32(&second_pk_x, pre_session.second_pk)); - CHECK(secp256k1_fe_is_zero(&second_pk_x) == !has_second_pk); - if (!secp256k1_fe_is_zero(&second_pk_x)) { - CHECK(secp256k1_memcmp_var(&pk_ser[second_pk_idx], &pre_session.second_pk, sizeof(pk_ser[second_pk_idx])) == 0); + CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, &keyagg_cache, pk_ptr, n_pks) == 1); + CHECK(secp256k1_keyagg_cache_load(ctx, &cache_i, &keyagg_cache) == 1); + CHECK(secp256k1_fe_is_zero(&cache_i.second_pk_x) == !has_second_pk); + if (!secp256k1_fe_is_zero(&cache_i.second_pk_x)) { + secp256k1_ge pk_pt; + CHECK(secp256k1_xonly_pubkey_load(ctx, &pk_pt, &pk[second_pk_idx]) == 1); + CHECK(secp256k1_fe_equal_var(&pk_pt.x, &cache_i.second_pk_x) == 1); } - CHECK(secp256k1_xonly_pubkey_serialize(ctx, combined_pk_ser, &combined_pk)); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, agg_pk_ser, &agg_pk) == 1); /* TODO: remove when test vectors are not expected to change anymore */ /* int k, l; */ - /* printf("const unsigned char combined_pk_expected[32] = {\n"); */ + /* printf("const unsigned char agg_pk_expected[32] = {\n"); */ /* for (k = 0; k < 4; k++) { */ /* printf(" "); */ /* for (l = 0; l < 8; l++) { */ - /* printf("0x%02X, ", combined_pk_ser[k*8+l]); */ + /* printf("0x%02X, ", agg_pk_ser[k*8+l]); */ /* } */ /* printf("\n"); */ /* } */ /* printf("};\n"); */ - CHECK(secp256k1_memcmp_var(combined_pk_ser, combined_pk_expected, sizeof(combined_pk_ser)) == 0); + CHECK(secp256k1_memcmp_var(agg_pk_ser, agg_pk_expected, sizeof(agg_pk_ser)) == 0); free(pk); free(pk_ptr); } -void musig_test_vectors(void) { +/* Test vector public keys */ +const unsigned char vec_pk[3][32] = { + /* X1 */ + { + 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, + 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, + 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, + 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 + }, + /* X2 */ + { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }, + /* X3 */ + { + 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, + 0x15, 0xC2, 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, + 0x14, 0x93, 0x16, 0xC3, 0x51, 0x8C, 0xE7, 0xB7, + 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 + } +}; + +void musig_test_vectors_keyagg(void) { size_t i; - unsigned char pk_ser_tmp[4][32]; - unsigned char pk_ser[3][32] = { - /* X1 */ - { - 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, - 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, - 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, - 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 - }, - /* X2 */ - { - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 - }, - /* X3 */ - { - 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, - 0x15, 0xC2, 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, - 0x14, 0x93, 0x16, 0xC3, 0x51, 0x8C, 0xE7, 0xB7, - 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 - } - }; - const unsigned char combined_pk_expected[4][32] = { + const unsigned char *pk[4]; + const unsigned char agg_pk_expected[4][32] = { { /* 0 */ 0xE5, 0x83, 0x01, 0x40, 0x51, 0x21, 0x95, 0xD7, 0x4C, 0x83, 0x07, 0xE3, 0x96, 0x37, 0xCB, 0xE5, @@ -1078,7 +972,7 @@ void musig_test_vectors(void) { }, }; - for (i = 0; i < sizeof(combined_pk_expected)/sizeof(combined_pk_expected[0]); i++) { + for (i = 0; i < sizeof(agg_pk_expected)/sizeof(agg_pk_expected[0]); i++) { size_t n_pks; int has_second_pk; int second_pk_idx; @@ -1086,44 +980,331 @@ void musig_test_vectors(void) { case 0: /* [X1, X2, X3] */ n_pks = 3; - memcpy(pk_ser_tmp[0], pk_ser[0], sizeof(pk_ser_tmp[0])); - memcpy(pk_ser_tmp[1], pk_ser[1], sizeof(pk_ser_tmp[1])); - memcpy(pk_ser_tmp[2], pk_ser[2], sizeof(pk_ser_tmp[2])); + pk[0] = vec_pk[0]; + pk[1] = vec_pk[1]; + pk[2] = vec_pk[2]; has_second_pk = 1; second_pk_idx = 1; break; case 1: /* [X3, X2, X1] */ n_pks = 3; - memcpy(pk_ser_tmp[2], pk_ser[0], sizeof(pk_ser_tmp[0])); - memcpy(pk_ser_tmp[1], pk_ser[1], sizeof(pk_ser_tmp[1])); - memcpy(pk_ser_tmp[0], pk_ser[2], sizeof(pk_ser_tmp[2])); + pk[2] = vec_pk[0]; + pk[1] = vec_pk[1]; + pk[0] = vec_pk[2]; has_second_pk = 1; second_pk_idx = 1; break; case 2: /* [X1, X1, X1] */ n_pks = 3; - memcpy(pk_ser_tmp[0], pk_ser[0], sizeof(pk_ser_tmp[0])); - memcpy(pk_ser_tmp[1], pk_ser[0], sizeof(pk_ser_tmp[1])); - memcpy(pk_ser_tmp[2], pk_ser[0], sizeof(pk_ser_tmp[2])); + pk[0] = vec_pk[0]; + pk[1] = vec_pk[0]; + pk[2] = vec_pk[0]; has_second_pk = 0; second_pk_idx = 0; /* unchecked */ break; case 3: /* [X1, X1, X2, X2] */ n_pks = 4; - memcpy(pk_ser_tmp[0], pk_ser[0], sizeof(pk_ser_tmp[0])); - memcpy(pk_ser_tmp[1], pk_ser[0], sizeof(pk_ser_tmp[1])); - memcpy(pk_ser_tmp[2], pk_ser[1], sizeof(pk_ser_tmp[2])); - memcpy(pk_ser_tmp[3], pk_ser[1], sizeof(pk_ser_tmp[3])); + pk[0] = vec_pk[0]; + pk[1] = vec_pk[0]; + pk[2] = vec_pk[1]; + pk[3] = vec_pk[1]; has_second_pk = 1; second_pk_idx = 2; /* second_pk_idx = 3 is equally valid */ break; default: CHECK(0); } - musig_test_vectors_helper(pk_ser_tmp, n_pks, combined_pk_expected[i], has_second_pk, second_pk_idx); + musig_test_vectors_keyagg_helper(pk, n_pks, agg_pk_expected[i], has_second_pk, second_pk_idx); + } +} + +void musig_test_vectors_noncegen(void) { + enum { N = 3 }; + secp256k1_scalar k[N][2]; + const unsigned char k32_expected[N][2][32] = { + { + { + 0x8D, 0xD0, 0x99, 0x51, 0x79, 0x50, 0x5E, 0xB1, + 0x27, 0x3A, 0x07, 0x11, 0x58, 0x23, 0xC8, 0x6E, + 0xF7, 0x14, 0x39, 0x0F, 0xDE, 0x2D, 0xEE, 0xB6, + 0xF9, 0x31, 0x6A, 0xEE, 0xBE, 0x5C, 0x71, 0xFC, + }, + { + 0x73, 0x29, 0x2E, 0x47, 0x11, 0x34, 0x7D, 0xD3, + 0x9E, 0x36, 0x05, 0xEE, 0xD6, 0x45, 0x65, 0x49, + 0xB3, 0x0F, 0x3B, 0xC7, 0x16, 0x22, 0x5A, 0x18, + 0x65, 0xBA, 0xE1, 0xD9, 0x84, 0xEF, 0xF8, 0x9D, + }, + }, + /* msg32 is NULL */ + { + { + 0x67, 0x02, 0x5A, 0xF2, 0xA3, 0x56, 0x0B, 0xFC, + 0x1D, 0x95, 0xBD, 0xA6, 0xB2, 0x0B, 0x21, 0x50, + 0x97, 0x63, 0xDB, 0x17, 0x3B, 0xD9, 0x37, 0x30, + 0x17, 0x24, 0x66, 0xEC, 0xAF, 0xA2, 0x60, 0x3B, + }, + { + 0x0B, 0x1D, 0x9E, 0x8F, 0x43, 0xBD, 0xAE, 0x69, + 0x99, 0x6E, 0x0E, 0x3A, 0xBC, 0x30, 0x06, 0x4C, + 0x52, 0x37, 0x3E, 0x05, 0x3E, 0x70, 0xC6, 0xD6, + 0x18, 0x4B, 0xFA, 0xDA, 0xE0, 0xF0, 0xE2, 0xD9, + }, + }, + /* All fields except session_id are NULL */ + { + { + 0xA6, 0xC3, 0x24, 0xC7, 0xE8, 0xD1, 0x8A, 0xAA, + 0x59, 0xD7, 0xB4, 0x74, 0xDD, 0x73, 0x82, 0x6D, + 0x7E, 0x74, 0x91, 0x3F, 0x9B, 0x36, 0x12, 0xE4, + 0x4F, 0x28, 0x6E, 0x07, 0x54, 0x14, 0x58, 0x21, + }, + { + 0x4E, 0x75, 0xD3, 0x81, 0xCD, 0xB7, 0x3C, 0x68, + 0xA0, 0x7E, 0x64, 0x15, 0xE0, 0x0E, 0x89, 0x32, + 0x44, 0x21, 0x87, 0x4F, 0x4E, 0x03, 0xE8, 0x67, + 0x73, 0x4E, 0x33, 0x20, 0xCE, 0x24, 0xBA, 0x8E, + }, + }, + }; + unsigned char args[5][32]; + int i, j; + + for (i = 0; i < 5; i++) { + memset(args[i], i, sizeof(args[i])); + } + + secp256k1_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4]); + secp256k1_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4]); + secp256k1_nonce_function_musig(k[2], args[0], NULL, NULL, NULL, NULL); + /* TODO: remove when test vectors are not expected to change anymore */ + /* int t, u; */ + /* printf("const unsigned char k32_expected[N][2][32] = {\n"); */ + /* for (i = 0; i < N; i++) { */ + /* printf(" {\n"); */ + /* for (j = 0; j < 2; j++) { */ + /* unsigned char k32[32]; */ + /* secp256k1_scalar_get_b32(k32, &k[i][j]); */ + /* printf(" {\n"); */ + /* for (t = 0; t < 4; t++) { */ + /* printf(" "); */ + /* for (u = 0; u < 8; u++) { */ + /* printf("0x%02X, ", k32[t*8+u]); */ + /* } */ + /* printf("\n"); */ + /* } */ + /* printf(" },\n"); */ + /* } */ + /* printf(" },\n"); */ + /* } */ + /* printf("};\n"); */ + for (i = 0; i < N; i++) { + for (j = 0; j < 2; j++) { + unsigned char k32[32]; + secp256k1_scalar_get_b32(k32, &k[i][j]); + CHECK(memcmp(k32, k32_expected[i][j], 32) == 0); + } + } +} + +void musig_test_vectors_sign_helper(secp256k1_musig_keyagg_cache *keyagg_cache, int *fin_nonce_parity, unsigned char *sig, const unsigned char *secnonce_bytes, const unsigned char *agg_pubnonce_ser, const unsigned char *sk, const unsigned char *msg, const unsigned char *tweak, const secp256k1_pubkey *adaptor, const unsigned char **pk_ser, int signer_pos) { + secp256k1_keypair signer_keypair; + secp256k1_musig_secnonce secnonce; + secp256k1_xonly_pubkey pk[3]; + const secp256k1_xonly_pubkey *pk_ptr[3]; + secp256k1_xonly_pubkey agg_pk; + secp256k1_musig_session session; + secp256k1_musig_aggnonce agg_pubnonce; + secp256k1_musig_partial_sig partial_sig; + int i; + + CHECK(create_keypair_and_pk(&signer_keypair, &pk[signer_pos], sk) == 1); + for (i = 0; i < 3; i++) { + if (i != signer_pos) { + int offset = i < signer_pos ? 0 : -1; + CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk[i], pk_ser[i + offset]) == 1); + } + pk_ptr[i] = &pk[i]; + } + CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, keyagg_cache, pk_ptr, 3) == 1); + if (tweak != NULL) { + CHECK(secp256k1_musig_pubkey_tweak_add(ctx, NULL, keyagg_cache, tweak) == 1); + } + memcpy(&secnonce.data[0], secp256k1_musig_secnonce_magic, 4); + memcpy(&secnonce.data[4], secnonce_bytes, sizeof(secnonce.data) - 4); + CHECK(secp256k1_musig_aggnonce_parse(ctx, &agg_pubnonce, agg_pubnonce_ser) == 1); + CHECK(secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg, keyagg_cache, adaptor) == 1); + CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &signer_keypair, keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_nonce_parity(ctx, fin_nonce_parity, &session) == 1); + memcpy(sig, &partial_sig.data[4], 32); +} + +int musig_test_pk_parity(const secp256k1_musig_keyagg_cache *keyagg_cache) { + secp256k1_keyagg_cache_internal cache_i; + CHECK(secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache) == 1); + return secp256k1_fe_is_odd(&cache_i.pk.y); +} + +int musig_test_is_second_pk(const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *sk) { + secp256k1_ge pkp; + secp256k1_xonly_pubkey pk; + secp256k1_keyagg_cache_internal cache_i; + CHECK(create_keypair_and_pk(NULL, &pk, sk)); + CHECK(secp256k1_xonly_pubkey_load(ctx, &pkp, &pk)); + CHECK(secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)); + return secp256k1_fe_equal_var(&cache_i.second_pk_x, &pkp.x); +} + +/* TODO: Add test vectors for failed signing */ +void musig_test_vectors_sign(void) { + unsigned char sig[32]; + secp256k1_musig_keyagg_cache keyagg_cache; + int fin_nonce_parity; + const unsigned char secnonce[64] = { + 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6, + 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98, + 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF, + 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61, + 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85, + 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5, + 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5, + 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7, + }; + /* The nonces are already aggregated */ + const unsigned char agg_pubnonce[66] = { + 0x02, + 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, + 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, + 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, + 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, + 0x03, + 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, + 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, + 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, + 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9, + }; + const unsigned char sk[32] = { + 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE, + 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB, + 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE, + 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71, + }; + const unsigned char msg[32] = { + 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68, + 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5, + 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5, + 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF, + }; + const unsigned char *pk[2] = { vec_pk[0], vec_pk[1] }; + + { + /* This is a test where the combined public key point has an _odd_ y + * coordinate, the signer _is not_ the second pubkey in the list and the + * nonce parity is 1. */ + const unsigned char sig_expected[32] = { + 0x68, 0x53, 0x7C, 0xC5, 0x23, 0x4E, 0x50, 0x5B, + 0xD1, 0x40, 0x61, 0xF8, 0xDA, 0x9E, 0x90, 0xC2, + 0x20, 0xA1, 0x81, 0x85, 0x5F, 0xD8, 0xBD, 0xB7, + 0xF1, 0x27, 0xBB, 0x12, 0x40, 0x3B, 0x4D, 0x3B, + }; + musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, NULL, pk, 0); + /* TODO: remove when test vectors are not expected to change anymore */ + /* int k, l; */ + /* printf("const unsigned char sig_expected[32] = {\n"); */ + /* for (k = 0; k < 4; k++) { */ + /* printf(" "); */ + /* for (l = 0; l < 8; l++) { */ + /* printf("0x%02X, ", sig[k*8+l]); */ + /* } */ + /* printf("\n"); */ + /* } */ + /* printf("};\n"); */ + + /* Check that the description of the test vector is correct */ + CHECK(musig_test_pk_parity(&keyagg_cache) == 1); + CHECK(!musig_test_is_second_pk(&keyagg_cache, sk)); + CHECK(fin_nonce_parity == 1); + CHECK(memcmp(sig, sig_expected, 32) == 0); + } + { + /* This is a test where the aggregate public key point has an _even_ y + * coordinate, the signer _is_ the second pubkey in the list and the + * nonce parity is 0. */ + const unsigned char sig_expected[32] = { + 0x2D, 0xF6, 0x7B, 0xFF, 0xF1, 0x8E, 0x3D, 0xE7, + 0x97, 0xE1, 0x3C, 0x64, 0x75, 0xC9, 0x63, 0x04, + 0x81, 0x38, 0xDA, 0xEC, 0x5C, 0xB2, 0x0A, 0x35, + 0x7C, 0xEC, 0xA7, 0xC8, 0x42, 0x42, 0x95, 0xEA, + }; + musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, NULL, pk, 1); + /* Check that the description of the test vector is correct */ + CHECK(musig_test_pk_parity(&keyagg_cache) == 0); + CHECK(musig_test_is_second_pk(&keyagg_cache, sk)); + CHECK(fin_nonce_parity == 0); + CHECK(memcmp(sig, sig_expected, 32) == 0); + } + { + /* This is a test where the parity of aggregate public key point (1) is unequal to the + * nonce parity (0). */ + const unsigned char sig_expected[32] = { + 0x0D, 0x5B, 0x65, 0x1E, 0x6D, 0xE3, 0x4A, 0x29, + 0xA1, 0x2D, 0xE7, 0xA8, 0xB4, 0x18, 0x3B, 0x4A, + 0xE6, 0xA7, 0xF7, 0xFB, 0xE1, 0x5C, 0xDC, 0xAF, + 0xA4, 0xA3, 0xD1, 0xBC, 0xAA, 0xBC, 0x75, 0x17, + }; + musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, NULL, pk, 2); + /* Check that the description of the test vector is correct */ + CHECK(musig_test_pk_parity(&keyagg_cache) == 1); + CHECK(fin_nonce_parity == 0); + CHECK(!musig_test_is_second_pk(&keyagg_cache, sk)); + CHECK(memcmp(sig, sig_expected, 32) == 0); + } + { + /* This is a test that includes a public key tweak. */ + const unsigned char sig_expected[32] = { + 0x5E, 0x24, 0xC7, 0x49, 0x6B, 0x56, 0x5D, 0xEB, + 0xC3, 0xB9, 0x63, 0x9E, 0x6F, 0x13, 0x04, 0xA2, + 0x15, 0x97, 0xF9, 0x60, 0x3D, 0x3A, 0xB0, 0x5B, + 0x49, 0x13, 0x64, 0x17, 0x75, 0xE1, 0x37, 0x5B, + }; + const unsigned char tweak[32] = { + 0xE8, 0xF7, 0x91, 0xFF, 0x92, 0x25, 0xA2, 0xAF, + 0x01, 0x02, 0xAF, 0xFF, 0x4A, 0x9A, 0x72, 0x3D, + 0x96, 0x12, 0xA6, 0x82, 0xA2, 0x5E, 0xBE, 0x79, + 0x80, 0x2B, 0x26, 0x3C, 0xDF, 0xCD, 0x83, 0xBB, + }; + musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, tweak, NULL, pk, 2); + + CHECK(musig_test_pk_parity(&keyagg_cache) == 1); + CHECK(!musig_test_is_second_pk(&keyagg_cache, sk)); + CHECK(fin_nonce_parity == 1); + CHECK(memcmp(sig, sig_expected, 32) == 0); + } + { + /* This is a test that includes an adaptor. */ + const unsigned char sig_expected[32] = { + 0xD7, 0x67, 0xD0, 0x7D, 0x9A, 0xB8, 0x19, 0x8C, + 0x9F, 0x64, 0xE3, 0xFD, 0x9F, 0x7B, 0x8B, 0xAA, + 0xC6, 0x05, 0xF1, 0x8D, 0xFF, 0x18, 0x95, 0x24, + 0x2D, 0x93, 0x95, 0xD9, 0xC8, 0xE6, 0xDD, 0x7C, + }; + const unsigned char sec_adaptor[32] = { + 0xD5, 0x6A, 0xD1, 0x85, 0x00, 0xF2, 0xD7, 0x8A, + 0xB9, 0x54, 0x80, 0x53, 0x76, 0xF3, 0x9D, 0x1B, + 0x6D, 0x62, 0x04, 0x95, 0x12, 0x39, 0x04, 0x6D, + 0x99, 0x3A, 0x9C, 0x31, 0xE0, 0xF4, 0x78, 0x71, + }; + secp256k1_pubkey pub_adaptor; + CHECK(secp256k1_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor) == 1); + musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, &pub_adaptor, pk, 2); + + CHECK(musig_test_pk_parity(&keyagg_cache) == 1); + CHECK(!musig_test_is_second_pk(&keyagg_cache, sk)); + CHECK(fin_nonce_parity == 1); + CHECK(memcmp(sig, sig_expected, 32) == 0); } } @@ -1135,7 +1316,7 @@ void run_musig_tests(void) { musig_simple_test(scratch); } musig_api_tests(scratch); - musig_state_machine_tests(scratch); + musig_nonce_test(); for (i = 0; i < count; i++) { /* Run multiple times to ensure that pk and nonce have different y * parities */ @@ -1143,7 +1324,9 @@ void run_musig_tests(void) { musig_tweak_test(scratch); } sha256_tag_test(); - musig_test_vectors(); + musig_test_vectors_keyagg(); + musig_test_vectors_noncegen(); + musig_test_vectors_sign(); secp256k1_scratch_space_destroy(ctx, scratch); } diff --git a/src/valgrind_ctime_test.c b/src/valgrind_ctime_test.c index 10c00c474..aaab0a8f0 100644 --- a/src/valgrind_ctime_test.c +++ b/src/valgrind_ctime_test.c @@ -6,6 +6,7 @@ #include #include +#include #include "../include/secp256k1.h" #include "assumptions.h" @@ -35,6 +36,10 @@ #include "include/secp256k1_ecdsa_adaptor.h" #endif +#ifdef ENABLE_MODULE_MUSIG +#include "include/secp256k1_musig.h" +#endif + void run_tests(secp256k1_context *ctx, unsigned char *key); int main(void) { @@ -241,4 +246,70 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) { CHECK(ret == 0); } #endif + +#ifdef ENABLE_MODULE_MUSIG + { + secp256k1_xonly_pubkey pk; + const secp256k1_xonly_pubkey *pk_ptr[1]; + secp256k1_xonly_pubkey agg_pk; + unsigned char session_id[32]; + secp256k1_musig_secnonce secnonce; + secp256k1_musig_pubnonce pubnonce; + const secp256k1_musig_pubnonce *pubnonce_ptr[1]; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_keyagg_cache cache; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + const secp256k1_musig_partial_sig *partial_sig_ptr[1]; + unsigned char extra_input[32]; + unsigned char sec_adaptor[32]; + secp256k1_pubkey adaptor; + unsigned char pre_sig[64]; + int nonce_parity; + + pk_ptr[0] = &pk; + pubnonce_ptr[0] = &pubnonce; + VALGRIND_MAKE_MEM_DEFINED(key, 32); + memcpy(session_id, key, sizeof(session_id)); + session_id[0] = session_id[0] + 1; + memcpy(extra_input, key, sizeof(extra_input)); + extra_input[0] = extra_input[0] + 2; + memcpy(sec_adaptor, key, sizeof(sec_adaptor)); + sec_adaptor[0] = extra_input[0] + 3; + partial_sig_ptr[0] = &partial_sig; + + CHECK(secp256k1_keypair_create(ctx, &keypair, key)); + CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair)); + CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, &cache, pk_ptr, 1)); + CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor)); + VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + VALGRIND_MAKE_MEM_UNDEFINED(session_id, sizeof(session_id)); + VALGRIND_MAKE_MEM_UNDEFINED(extra_input, sizeof(extra_input)); + VALGRIND_MAKE_MEM_UNDEFINED(sec_adaptor, sizeof(sec_adaptor)); + ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_id, key, msg, &cache, extra_input); + VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + CHECK(ret == 1); + CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1)); + CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache, &adaptor) == 1); + + ret = secp256k1_keypair_create(ctx, &keypair, key); + VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + CHECK(ret == 1); + ret = secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &cache, &session); + VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + CHECK(ret == 1); + + VALGRIND_MAKE_MEM_DEFINED(&partial_sig, sizeof(partial_sig)); + CHECK(secp256k1_musig_partial_sig_agg(ctx, pre_sig, &session, partial_sig_ptr, 1)); + VALGRIND_MAKE_MEM_DEFINED(pre_sig, sizeof(pre_sig)); + + CHECK(secp256k1_musig_nonce_parity(ctx, &nonce_parity, &session)); + ret = secp256k1_musig_adapt(ctx, sig, pre_sig, sec_adaptor, nonce_parity); + VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + CHECK(ret == 1); + ret = secp256k1_musig_extract_adaptor(ctx, sec_adaptor, sig, pre_sig, nonce_parity); + VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + CHECK(ret == 1); + } +#endif } From 3c79d97bd92ec22cc204ff5a08c9b0e5adda12e6 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 17 Dec 2021 11:04:46 +0000 Subject: [PATCH 2/3] ci: increase timeout for macOS tasks --- .cirrus.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 0a65bc90c..b1849af43 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -119,8 +119,8 @@ task: name: "x86_64: macOS Catalina" macos_instance: image: catalina-base - # As of d4ca81f48e tasks with valgrind enabled take about 60 minutes - timeout_in: 90m + # tasks with valgrind enabled take about 90 minutes + timeout_in: 120m env: HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_INSTALL_CLEANUP: 1 From ac1e36769dda3964f7294319ecb06fb5c414938d Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 17 Dec 2021 13:41:47 +0000 Subject: [PATCH 3/3] musig: turn off multiexponentiation for now Before turning it on we need to have a discussion about our confidence in the correctness of the multiexponentiation code. --- include/secp256k1_musig.h | 12 +++++++----- src/modules/musig/keyagg_impl.h | 5 ++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/secp256k1_musig.h b/include/secp256k1_musig.h index 79c6dc48a..17ddf7d20 100644 --- a/include/secp256k1_musig.h +++ b/include/secp256k1_musig.h @@ -197,11 +197,13 @@ SECP256K1_API int secp256k1_musig_partial_sig_parse( * * Returns: 0 if the arguments are invalid, 1 otherwise * Args: ctx: pointer to a context object initialized for verification - * scratch: scratch space used to compute the aggregate pubkey by - * multiexponentiation. Generally, the larger the scratch - * space, the faster this function. However, the returns of - * providing a larger scratch space are diminishing. If NULL, - * an inefficient algorithm is used. + * scratch: should be NULL because it is not yet implemented. If it + * was implemented then the scratch space would be used to + * compute the aggregate pubkey by multiexponentiation. + * Generally, the larger the scratch space, the faster this + * function. However, the returns of providing a larger + * scratch space are diminishing. If NULL, an inefficient + * algorithm is used. * Out: agg_pk: the MuSig-aggregated x-only public key. If you do not need it, * this arg can be NULL. * keyagg_cache: if non-NULL, pointer to a musig_keyagg_cache struct that diff --git a/src/modules/musig/keyagg_impl.h b/src/modules/musig/keyagg_impl.h index 9a747f4dc..5299edca8 100644 --- a/src/modules/musig/keyagg_impl.h +++ b/src/modules/musig/keyagg_impl.h @@ -190,6 +190,7 @@ int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_s secp256k1_gej pkj; secp256k1_ge pkp; size_t i; + (void) scratch; VERIFY_CHECK(ctx != NULL); if (agg_pk != NULL) { @@ -216,7 +217,9 @@ int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_s if (!secp256k1_musig_compute_pk_hash(ctx, ecmult_data.pk_hash, pubkeys, n_pubkeys)) { return 0; } - if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &pkj, NULL, secp256k1_musig_pubkey_agg_callback, (void *) &ecmult_data, n_pubkeys)) { + /* TODO: actually use optimized ecmult_multi algorithms by providing a + * scratch space */ + if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &pkj, NULL, secp256k1_musig_pubkey_agg_callback, (void *) &ecmult_data, n_pubkeys)) { /* In order to reach this line with the current implementation of * ecmult_multi_var one would need to provide a callback that can * fail. */