diff --git a/contrib/musig2-vectors.py b/contrib/musig2-vectors.py new file mode 100755 index 00000000..60e8e7c9 --- /dev/null +++ b/contrib/musig2-vectors.py @@ -0,0 +1,654 @@ +#!/usr/bin/env python + +import sys +import json +import textwrap + +max_pubkeys = 0 + +if len(sys.argv) < 2: + print( + "This script converts BIP MuSig2 test vectors in a given directory to a C file that can be used in the test framework." + ) + print("Usage: %s " % sys.argv[0]) + sys.exit(1) + + +def hexstr_to_intarray(str): + return ", ".join([f"0x{b:02X}" for b in bytes.fromhex(str)]) + + +def create_init(name): + return """ +static const struct musig_%s_vector musig_%s_vector = { +""" % ( + name, + name, + ) + + +def init_array(key): + return textwrap.indent("{ %s },\n" % hexstr_to_intarray(data[key]), 4 * " ") + + +def init_arrays(key): + s = textwrap.indent("{\n", 4 * " ") + s += textwrap.indent( + ",\n".join(["{ %s }" % hexstr_to_intarray(x) for x in data[key]]), 8 * " " + ) + s += textwrap.indent("\n},\n", 4 * " ") + return s + + +def init_indices(array): + return " %d, { %s }" % ( + len(array), + ", ".join(map(str, array) if len(array) > 0 else "0"), + ) + + +def init_is_xonly(case): + if len(case["tweak_indices"]) > 0: + return ", ".join(map(lambda x: "1" if x else "0", case["is_xonly"])) + return "0" + + +def init_optional_expected(case): + return hexstr_to_intarray(case["expected"]) if "expected" in case else 0 + + +def init_cases(cases, f): + s = textwrap.indent("{\n", 4 * " ") + for (i, case) in enumerate(cases): + s += textwrap.indent("%s\n" % f(case), 8 * " ") + s += textwrap.indent("},\n", 4 * " ") + return s + + +def finish_init(): + return "};\n" + + +s = ( + """/** + * Automatically generated by %s. + * + * The test vectors for the KeySort function are included in this file. They can + * be found in src/modules/extrakeys/tests_impl.h. */ +""" + % sys.argv[0] +) + + +s += """ +enum MUSIG_ERROR { + MUSIG_PUBKEY, + MUSIG_TWEAK, + MUSIG_PUBNONCE, + MUSIG_AGGNONCE, + MUSIG_SECNONCE, + MUSIG_SIG, + MUSIG_SIG_VERIFY, + MUSIG_OTHER +}; +""" + +# key agg vectors +with open(sys.argv[1] + "/key_agg_vectors.json", "r") as f: + data = json.load(f) + + max_key_indices = max( + len(test_case["key_indices"]) for test_case in data["valid_test_cases"] + ) + max_tweak_indices = max( + len(test_case["tweak_indices"]) for test_case in data["error_test_cases"] + ) + num_pubkeys = len(data["pubkeys"]) + max_pubkeys = max(num_pubkeys, max_pubkeys) + num_tweaks = len(data["tweaks"]) + num_valid_cases = len(data["valid_test_cases"]) + num_error_cases = len(data["error_test_cases"]) + + # Add structures for valid and error cases + s += ( + """ +struct musig_key_agg_valid_test_case { + size_t key_indices_len; + size_t key_indices[%d]; + unsigned char expected[32]; +}; +""" + % max_key_indices + ) + s += """ +struct musig_key_agg_error_test_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t tweak_indices_len; + size_t tweak_indices[%d]; + int is_xonly[%d]; + enum MUSIG_ERROR error; +}; +""" % ( + max_key_indices, + max_tweak_indices, + max_tweak_indices, + ) + + # Add structure for entire vector + s += """ +struct musig_key_agg_vector { + unsigned char pubkeys[%d][33]; + unsigned char tweaks[%d][32]; + struct musig_key_agg_valid_test_case valid_case[%d]; + struct musig_key_agg_error_test_case error_case[%d]; +}; +""" % ( + num_pubkeys, + num_tweaks, + num_valid_cases, + num_error_cases, + ) + + s += create_init("key_agg") + # Add pubkeys and tweaks to the vector + s += init_arrays("pubkeys") + s += init_arrays("tweaks") + + # Add valid cases to the vector + s += init_cases( + data["valid_test_cases"], + lambda case: "{ %s, { %s }}," + % (init_indices(case["key_indices"]), hexstr_to_intarray(case["expected"])), + ) + + def comment_to_error(case): + comment = case["comment"] + if "public key" in comment.lower(): + return "MUSIG_PUBKEY" + elif "tweak" in comment.lower(): + return "MUSIG_TWEAK" + else: + sys.exit("Unknown error") + + # Add error cases to the vector + s += init_cases( + data["error_test_cases"], + lambda case: "{ %s, %s, { %s }, %s }," + % ( + init_indices(case["key_indices"]), + init_indices(case["tweak_indices"]), + init_is_xonly(case), + comment_to_error(case), + ), + ) + + s += finish_init() + +# nonce gen vectors +with open(sys.argv[1] + "/nonce_gen_vectors.json", "r") as f: + data = json.load(f) + + # The MuSig2 implementation only allows messages of length 32 + data["test_cases"] = list( + filter(lambda c: c["msg"] is None or len(c["msg"]) == 64, data["test_cases"]) + ) + + num_tests = len(data["test_cases"]) + + s += """ +struct musig_nonce_gen_test_case { + unsigned char rand_[32]; + int has_sk; + unsigned char sk[32]; + unsigned char pk[33]; + int has_aggpk; + unsigned char aggpk[32]; + int has_msg; + unsigned char msg[32]; + int has_extra_in; + unsigned char extra_in[32]; + unsigned char expected[97]; +}; +""" + + s += ( + """ +struct musig_nonce_gen_vector { + struct musig_nonce_gen_test_case test_case[%d]; +}; +""" + % num_tests + ) + + s += create_init("nonce_gen") + + def init_array_maybe(array): + return "%d , { %s }" % ( + 0 if array is None else 1, + hexstr_to_intarray(array) if array is not None else 0, + ) + + s += init_cases( + data["test_cases"], + lambda case: "{ { %s }, %s, { %s }, %s, %s, %s, { %s } }," + % ( + hexstr_to_intarray(case["rand_"]), + init_array_maybe(case["sk"]), + hexstr_to_intarray(case["pk"]), + init_array_maybe(case["aggpk"]), + init_array_maybe(case["msg"]), + init_array_maybe(case["extra_in"]), + hexstr_to_intarray(case["expected"]), + ), + ) + + s += finish_init() + +# nonce agg vectors +with open(sys.argv[1] + "/nonce_agg_vectors.json", "r") as f: + data = json.load(f) + + num_pnonces = len(data["pnonces"]) + num_valid_cases = len(data["valid_test_cases"]) + num_error_cases = len(data["error_test_cases"]) + + pnonce_indices_len = 2 + for case in data["valid_test_cases"] + data["error_test_cases"]: + assert len(case["pnonce_indices"]) == pnonce_indices_len + + # Add structures for valid and error cases + s += """ +struct musig_nonce_agg_test_case { + size_t pnonce_indices[2]; + /* if valid case */ + unsigned char expected[66]; + /* if error case */ + int invalid_nonce_idx; +}; +""" + # Add structure for entire vector + s += """ +struct musig_nonce_agg_vector { + unsigned char pnonces[%d][66]; + struct musig_nonce_agg_test_case valid_case[%d]; + struct musig_nonce_agg_test_case error_case[%d]; +}; +""" % ( + num_pnonces, + num_valid_cases, + num_error_cases, + ) + + s += create_init("nonce_agg") + s += init_arrays("pnonces") + + for cases in (data["valid_test_cases"], data["error_test_cases"]): + s += init_cases( + cases, + lambda case: "{ { %s }, { %s }, %d }," + % ( + ", ".join(map(str, case["pnonce_indices"])), + init_optional_expected(case), + case["error"]["signer"] if "error" in case else 0, + ), + ) + s += finish_init() + +# sign/verify vectors +with open(sys.argv[1] + "/sign_verify_vectors.json", "r") as f: + data = json.load(f) + + # The MuSig2 implementation only allows messages of length 32 + assert list(filter(lambda x: len(x) == 64, data["msgs"]))[0] == data["msgs"][0] + data["msgs"] = [data["msgs"][0]] + + def filter_msg32(k): + return list(filter(lambda x: x["msg_index"] == 0, data[k])) + + data["valid_test_cases"] = filter_msg32("valid_test_cases") + data["sign_error_test_cases"] = filter_msg32("sign_error_test_cases") + data["verify_error_test_cases"] = filter_msg32("verify_error_test_cases") + data["verify_fail_test_cases"] = filter_msg32("verify_fail_test_cases") + + num_pubkeys = len(data["pubkeys"]) + max_pubkeys = max(num_pubkeys, max_pubkeys) + num_secnonces = len(data["secnonces"]) + num_pubnonces = len(data["pnonces"]) + num_aggnonces = len(data["aggnonces"]) + num_msgs = len(data["msgs"]) + num_valid_cases = len(data["valid_test_cases"]) + num_sign_error_cases = len(data["sign_error_test_cases"]) + num_verify_fail_cases = len(data["verify_fail_test_cases"]) + num_verify_error_cases = len(data["verify_error_test_cases"]) + + all_cases = ( + data["valid_test_cases"] + + data["sign_error_test_cases"] + + data["verify_error_test_cases"] + + data["verify_fail_test_cases"] + ) + max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases) + max_nonce_indices = max( + len(test_case["nonce_indices"]) if "nonce_indices" in test_case else 0 + for test_case in all_cases + ) + # Add structures for valid and error cases + s += ( + """ +/* Omit pubnonces in the test vectors because our partial signature verification + * implementation is able to accept the aggnonce directly. */ +struct musig_valid_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t aggnonce_index; + size_t msg_index; + size_t signer_index; + unsigned char expected[32]; +}; +""" + % max_key_indices + ) + + s += ( + """ +struct musig_sign_error_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t aggnonce_index; + size_t msg_index; + size_t secnonce_index; + enum MUSIG_ERROR error; +}; +""" + % max_key_indices + ) + + s += """ +struct musig_verify_fail_error_case { + unsigned char sig[32]; + size_t key_indices_len; + size_t key_indices[%d]; + size_t nonce_indices_len; + size_t nonce_indices[%d]; + size_t msg_index; + size_t signer_index; + enum MUSIG_ERROR error; +}; +""" % ( + max_key_indices, + max_nonce_indices, + ) + + # Add structure for entire vector + s += """ +struct musig_sign_verify_vector { + unsigned char sk[32]; + unsigned char pubkeys[%d][33]; + unsigned char secnonces[%d][194]; + unsigned char pubnonces[%d][194]; + unsigned char aggnonces[%d][66]; + unsigned char msgs[%d][32]; + struct musig_valid_case valid_case[%d]; + struct musig_sign_error_case sign_error_case[%d]; + struct musig_verify_fail_error_case verify_fail_case[%d]; + struct musig_verify_fail_error_case verify_error_case[%d]; +}; +""" % ( + num_pubkeys, + num_secnonces, + num_pubnonces, + num_aggnonces, + num_msgs, + num_valid_cases, + num_sign_error_cases, + num_verify_fail_cases, + num_verify_error_cases, + ) + + s += create_init("sign_verify") + s += init_array("sk") + s += init_arrays("pubkeys") + s += init_arrays("secnonces") + s += init_arrays("pnonces") + s += init_arrays("aggnonces") + s += init_arrays("msgs") + + s += init_cases( + data["valid_test_cases"], + lambda case: "{ %s, %d, %d, %d, { %s }}," + % ( + init_indices(case["key_indices"]), + case["aggnonce_index"], + case["msg_index"], + case["signer_index"], + init_optional_expected(case), + ), + ) + + def sign_error(case): + comment = case["comment"] + if "pubkey" in comment or "public key" in comment: + return "MUSIG_PUBKEY" + elif "Aggregate nonce" in comment: + return "MUSIG_AGGNONCE" + elif "Secnonce" in comment: + return "MUSIG_SECNONCE" + else: + sys.exit("Unknown sign error") + + s += init_cases( + data["sign_error_test_cases"], + lambda case: "{ %s, %d, %d, %d, %s }," + % ( + init_indices(case["key_indices"]), + case["aggnonce_index"], + case["msg_index"], + case["secnonce_index"], + sign_error(case), + ), + ) + + def verify_error(case): + comment = case["comment"] + if "exceeds" in comment: + return "MUSIG_SIG" + elif "Wrong signer" in comment or "Wrong signature" in comment: + return "MUSIG_SIG_VERIFY" + elif "pubnonce" in comment: + return "MUSIG_PUBNONCE" + elif "pubkey" in comment: + return "MUSIG_PUBKEY" + else: + sys.exit("Unknown verify error") + + for cases in ("verify_fail_test_cases", "verify_error_test_cases"): + s += init_cases( + data[cases], + lambda case: "{ { %s }, %s, %s, %d, %d, %s }," + % ( + hexstr_to_intarray(case["sig"]), + init_indices(case["key_indices"]), + init_indices(case["nonce_indices"]), + case["msg_index"], + case["signer_index"], + verify_error(case), + ), + ) + + s += finish_init() + +# tweak vectors +with open(sys.argv[1] + "/tweak_vectors.json", "r") as f: + data = json.load(f) + + num_pubkeys = len(data["pubkeys"]) + max_pubkeys = max(num_pubkeys, max_pubkeys) + num_pubnonces = len(data["pnonces"]) + num_tweaks = len(data["tweaks"]) + num_valid_cases = len(data["valid_test_cases"]) + num_error_cases = len(data["error_test_cases"]) + + all_cases = data["valid_test_cases"] + data["error_test_cases"] + max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases) + max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases) + max_nonce_indices = max(len(test_case["nonce_indices"]) for test_case in all_cases) + # Add structures for valid and error cases + s += """ +struct musig_tweak_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t nonce_indices_len; + size_t nonce_indices[%d]; + size_t tweak_indices_len; + size_t tweak_indices[%d]; + int is_xonly[%d]; + size_t signer_index; + unsigned char expected[32]; +}; +""" % ( + max_key_indices, + max_nonce_indices, + max_tweak_indices, + max_tweak_indices, + ) + + # Add structure for entire vector + s += """ +struct musig_tweak_vector { + unsigned char sk[32]; + unsigned char secnonce[97]; + unsigned char aggnonce[66]; + unsigned char msg[32]; + unsigned char pubkeys[%d][33]; + unsigned char pubnonces[%d][194]; + unsigned char tweaks[%d][32]; + struct musig_tweak_case valid_case[%d]; + struct musig_tweak_case error_case[%d]; +}; +""" % ( + num_pubkeys, + num_pubnonces, + num_tweaks, + num_valid_cases, + num_error_cases, + ) + s += create_init("tweak") + s += init_array("sk") + s += init_array("secnonce") + s += init_array("aggnonce") + s += init_array("msg") + s += init_arrays("pubkeys") + s += init_arrays("pnonces") + s += init_arrays("tweaks") + + s += init_cases( + data["valid_test_cases"], + lambda case: "{ %s, %s, %s, { %s }, %d, { %s }}," + % ( + init_indices(case["key_indices"]), + init_indices(case["nonce_indices"]), + init_indices(case["tweak_indices"]), + init_is_xonly(case), + case["signer_index"], + init_optional_expected(case), + ), + ) + + s += init_cases( + data["error_test_cases"], + lambda case: "{ %s, %s, %s, { %s }, %d, { %s }}," + % ( + init_indices(case["key_indices"]), + init_indices(case["nonce_indices"]), + init_indices(case["tweak_indices"]), + init_is_xonly(case), + case["signer_index"], + init_optional_expected(case), + ), + ) + + s += finish_init() + +# sigagg vectors +with open(sys.argv[1] + "/sig_agg_vectors.json", "r") as f: + data = json.load(f) + + num_pubkeys = len(data["pubkeys"]) + max_pubkeys = max(num_pubkeys, max_pubkeys) + num_tweaks = len(data["tweaks"]) + num_psigs = len(data["psigs"]) + num_valid_cases = len(data["valid_test_cases"]) + num_error_cases = len(data["error_test_cases"]) + + all_cases = data["valid_test_cases"] + data["error_test_cases"] + max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases) + max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases) + max_psig_indices = max(len(test_case["psig_indices"]) for test_case in all_cases) + + # Add structures for valid and error cases + s += """ +/* Omit pubnonces in the test vectors because they're only needed for + * implementations that do not directly accept an aggnonce. */ +struct musig_sig_agg_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t tweak_indices_len; + size_t tweak_indices[%d]; + int is_xonly[%d]; + unsigned char aggnonce[66]; + size_t psig_indices_len; + size_t psig_indices[%d]; + /* if valid case */ + unsigned char expected[64]; + /* if error case */ + int invalid_sig_idx; +}; +""" % ( + max_key_indices, + max_tweak_indices, + max_tweak_indices, + max_psig_indices, + ) + + # Add structure for entire vector + s += """ +struct musig_sig_agg_vector { + unsigned char pubkeys[%d][33]; + unsigned char tweaks[%d][32]; + unsigned char psigs[%d][32]; + unsigned char msg[32]; + struct musig_sig_agg_case valid_case[%d]; + struct musig_sig_agg_case error_case[%d]; +}; +""" % ( + num_pubkeys, + num_tweaks, + num_psigs, + num_valid_cases, + num_error_cases, + ) + + s += create_init("sig_agg") + s += init_arrays("pubkeys") + s += init_arrays("tweaks") + s += init_arrays("psigs") + s += init_array("msg") + + for cases in (data["valid_test_cases"], data["error_test_cases"]): + s += init_cases( + cases, + lambda case: "{ %s, %s, { %s }, { %s }, %s, { %s }, %d }," + % ( + init_indices(case["key_indices"]), + init_indices(case["tweak_indices"]), + init_is_xonly(case), + hexstr_to_intarray(case["aggnonce"]), + init_indices(case["psig_indices"]), + init_optional_expected(case), + case["error"]["signer"] if "error" in case else 0, + ), + ) + s += finish_init() +s += "enum { MUSIG_VECTORS_MAX_PUBKEYS = %d };" % max_pubkeys +print(s) diff --git a/examples/musig.c b/examples/musig.c index 3a657410..a34e7e78 100644 --- a/examples/musig.c +++ b/examples/musig.c @@ -26,7 +26,7 @@ struct signer_secrets { }; struct signer { - secp256k1_xonly_pubkey pubkey; + secp256k1_pubkey pubkey; secp256k1_musig_pubnonce pubnonce; secp256k1_musig_partial_sig partial_sig; }; @@ -45,7 +45,7 @@ int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_s break; } } - if (!secp256k1_keypair_xonly_pub(ctx, &signer->pubkey, NULL, &signer_secrets->keypair)) { + if (!secp256k1_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) { return 0; } return 1; @@ -55,13 +55,13 @@ int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_s * and return the tweaked aggregate pk. */ int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache) { secp256k1_pubkey output_pk; - unsigned char ordinary_tweak[32] = "this could be a BIP32 tweak...."; + unsigned char plain_tweak[32] = "this could be a BIP32 tweak...."; unsigned char xonly_tweak[32] = "this could be a taproot tweak.."; - /* Ordinary tweaking which, for example, allows deriving multiple child + /* Plain tweaking which, for example, allows deriving multiple child * public keys from a single aggregate key using BIP32 */ - if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, cache, ordinary_tweak)) { + if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, cache, plain_tweak)) { return 0; } /* Note that we did not provided an output_pk argument, because the @@ -112,7 +112,7 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st } /* 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)) { + if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_id, seckey, &signer[i].pubkey, msg32, NULL, NULL)) { return 0; } pubnonces[i] = &signer[i].pubnonce; @@ -164,7 +164,7 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st int i; struct signer_secrets signer_secrets[N_SIGNERS]; struct signer signers[N_SIGNERS]; - const secp256k1_xonly_pubkey *pubkeys_ptr[N_SIGNERS]; + const secp256k1_pubkey *pubkeys_ptr[N_SIGNERS]; secp256k1_xonly_pubkey agg_pk; secp256k1_musig_keyagg_cache cache; unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!"; diff --git a/include/secp256k1_extrakeys.h b/include/secp256k1_extrakeys.h index 685d6316..deb8dc8b 100644 --- a/include/secp256k1_extrakeys.h +++ b/include/secp256k1_extrakeys.h @@ -155,20 +155,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_ const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); -/** Sorts xonly public keys according to secp256k1_xonly_pubkey_cmp - * - * Returns: 0 if the arguments are invalid. 1 otherwise. - * - * Args: ctx: pointer to a context object - * In: pubkeys: array of pointers to pubkeys to sort - * n_pubkeys: number of elements in the pubkeys array - */ -SECP256K1_API int secp256k1_xonly_sort( - const secp256k1_context* ctx, - const secp256k1_xonly_pubkey **pubkeys, - size_t n_pubkeys -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - /** Compute the keypair for a secret key. * * Returns: 1: secret was valid, keypair is ready to use @@ -256,6 +242,35 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +/** Compare two public keys using lexicographic order + * + * Returns: <0 if the first public key is less than the second + * >0 if the first public key is greater than the second + * 0 if the two public keys are equal + * Args: ctx: a secp256k1 context object. + * In: pubkey1: first public key to compare + * pubkey2: second public key to compare + */ +SECP256K1_API int secp256k1_pubkey_cmp( + const secp256k1_context* ctx, + const secp256k1_pubkey* pk1, + const secp256k1_pubkey* pk2 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Sorts public keys using lexicographic order + * + * Returns: 0 if the arguments are invalid. 1 otherwise. + * + * Args: ctx: pointer to a context object + * In: pubkeys: array of pointers to pubkeys to sort + * n_pubkeys: number of elements in the pubkeys array + */ +SECP256K1_API int secp256k1_pubkey_sort( + const secp256k1_context* ctx, + const secp256k1_pubkey **pubkeys, + size_t n_pubkeys +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + #ifdef __cplusplus } #endif diff --git a/include/secp256k1_musig.h b/include/secp256k1_musig.h index adcc060f..c71b92ce 100644 --- a/include/secp256k1_musig.h +++ b/include/secp256k1_musig.h @@ -9,11 +9,9 @@ extern "C" { #include -/** 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 - * (examples/musig.c) that demonstrates how it can be used. +/** This module implements BIP MuSig2 v1.0.0-rc.3, a multi-signature scheme + * compatible with BIP-340 ("Schnorr"). You can find an example demonstrating + * the musig module in examples/musig.c. * * The module also supports BIP-341 ("Taproot") public key tweaking and adaptor * signatures as described in @@ -22,12 +20,8 @@ extern "C" { * 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. + * Since the first version of MuSig is essentially replaced by MuSig2, we use + * MuSig, musig and MuSig2 synonymously unless noted otherwise. */ /** Opaque data structures @@ -40,11 +34,11 @@ extern "C" { /** Opaque data structure that caches information about public key aggregation. * - * Guaranteed to be 165 bytes in size. It can be safely copied/moved. No + * Guaranteed to be 197 bytes in size. It can be safely copied/moved. No * serialization and parsing functions (yet). */ typedef struct { - unsigned char data[165]; + unsigned char data[197]; } secp256k1_musig_keyagg_cache; /** Opaque data structure that holds a signer's _secret_ nonce. @@ -190,8 +184,8 @@ SECP256K1_API int secp256k1_musig_partial_sig_parse( * * 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. + * Before aggregating, the pubkeys can be sorted with `secp256k1_pubkey_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. * @@ -219,14 +213,14 @@ SECP256K1_API int secp256k1_musig_pubkey_agg( secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache, - const secp256k1_xonly_pubkey * const* pubkeys, + const secp256k1_pubkey * const* pubkeys, size_t n_pubkeys ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(5); /** Obtain the aggregate public key from a keyagg_cache. * * This is only useful if you need the non-xonly public key, in particular for - * ordinary (non-xonly) tweaking or batch-verifying multiple key aggregations + * plain (non-xonly) tweaking or batch-verifying multiple key aggregations * (not implemented). * * Returns: 0 if the arguments are invalid, 1 otherwise @@ -241,7 +235,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get( secp256k1_musig_keyagg_cache *keyagg_cache ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Apply ordinary "EC" tweaking to a public key in a given keyagg_cache by +/** Apply plain "EC" tweaking to a public key in a given keyagg_cache by * adding the generator multiplied with `tweak32` to it. This is useful for * deriving child keys from an aggregate public key via BIP32. * @@ -357,6 +351,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_twea * 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) + * pubkey: public key of the signer creating the nonce * 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 @@ -371,10 +366,11 @@ SECP256K1_API int secp256k1_musig_nonce_gen( secp256k1_musig_pubnonce *pubnonce, const unsigned char *session_id32, const unsigned char *seckey, + const secp256k1_pubkey *pubkey, 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); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6); /** Aggregates the nonces of all signers into a single nonce * @@ -494,7 +490,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verif const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, - const secp256k1_xonly_pubkey *pubkey, + const secp256k1_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); diff --git a/src/modules/extrakeys/main_impl.h b/src/modules/extrakeys/main_impl.h index 8ed76a98..cadabab0 100644 --- a/src/modules/extrakeys/main_impl.h +++ b/src/modules/extrakeys/main_impl.h @@ -153,28 +153,6 @@ int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const u && secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity; } -/* This struct wraps a const context pointer to satisfy the secp256k1_hsort api - * which expects a non-const cmp_data pointer. */ -typedef struct { - const secp256k1_context *ctx; -} secp256k1_xonly_sort_cmp_data; - -static int secp256k1_xonly_sort_cmp(const void* pk1, const void* pk2, void *cmp_data) { - return secp256k1_xonly_pubkey_cmp(((secp256k1_xonly_sort_cmp_data*)cmp_data)->ctx, - *(secp256k1_xonly_pubkey **)pk1, - *(secp256k1_xonly_pubkey **)pk2); -} - -int secp256k1_xonly_sort(const secp256k1_context* ctx, const secp256k1_xonly_pubkey **pubkeys, size_t n_pubkeys) { - secp256k1_xonly_sort_cmp_data cmp_data; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkeys != NULL); - - cmp_data.ctx = ctx; - secp256k1_hsort(pubkeys, n_pubkeys, sizeof(*pubkeys), secp256k1_xonly_sort_cmp, &cmp_data); - return 1; -} - static void secp256k1_keypair_save(secp256k1_keypair *keypair, const secp256k1_scalar *sk, secp256k1_ge *pk) { secp256k1_scalar_get_b32(&keypair->data[0], sk); secp256k1_pubkey_save((secp256k1_pubkey *)&keypair->data[32], pk); @@ -304,4 +282,53 @@ int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_ke return ret; } +int secp256k1_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_pubkey* pk0, const secp256k1_pubkey* pk1) { + unsigned char out[2][33]; + const secp256k1_pubkey* pk[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + pk[0] = pk0; pk[1] = pk1; + for (i = 0; i < 2; i++) { + size_t outputlen = sizeof(out[i]); + /* If the public key is NULL or invalid, pubkey_serialize will + * call the illegal_callback and return 0. In that case we will + * serialize the key as all zeros which is less than any valid public + * key. This results in consistent comparisons even if NULL or invalid + * pubkeys are involved and prevents edge cases such as sorting + * algorithms that use this function and do not terminate as a + * result. */ + if (!secp256k1_ec_pubkey_serialize(ctx, out[i], &outputlen, pk[i], SECP256K1_EC_COMPRESSED)) { + /* Note that pubkey_serialize should already set the output to + * zero in that case, but it's not guaranteed by the API, we can't + * test it and writing a VERIFY_CHECK is more complex than + * explicitly memsetting (again). */ + memset(out[i], 0, sizeof(out[i])); + } + } + return secp256k1_memcmp_var(out[0], out[1], sizeof(out[1])); +} + +/* This struct wraps a const context pointer to satisfy the secp256k1_hsort api + * which expects a non-const cmp_data pointer. */ +typedef struct { + const secp256k1_context *ctx; +} secp256k1_pubkey_sort_cmp_data; + +static int secp256k1_pubkey_sort_cmp(const void* pk1, const void* pk2, void *cmp_data) { + return secp256k1_pubkey_cmp(((secp256k1_pubkey_sort_cmp_data*)cmp_data)->ctx, + *(secp256k1_pubkey **)pk1, + *(secp256k1_pubkey **)pk2); +} + +int secp256k1_pubkey_sort(const secp256k1_context* ctx, const secp256k1_pubkey **pubkeys, size_t n_pubkeys) { + secp256k1_pubkey_sort_cmp_data cmp_data; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkeys != NULL); + + cmp_data.ctx = ctx; + secp256k1_hsort(pubkeys, n_pubkeys, sizeof(*pubkeys), secp256k1_pubkey_sort_cmp, &cmp_data); + return 1; +} + #endif diff --git a/src/modules/extrakeys/tests_impl.h b/src/modules/extrakeys/tests_impl.h index 4121df0c..c4e695b4 100644 --- a/src/modules/extrakeys/tests_impl.h +++ b/src/modules/extrakeys/tests_impl.h @@ -619,14 +619,53 @@ void test_hsort(void) { } #undef NUM -void test_xonly_sort_helper(secp256k1_xonly_pubkey *pk, size_t *pk_order, size_t n_pk) { +void test_pubkey_comparison(void) { + unsigned char pk1_ser[33] = { + 0x02, + 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, + 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23 + }; + const unsigned char pk2_ser[33] = { + 0x03, + 0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d, + 0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c + }; + secp256k1_pubkey pk1; + secp256k1_pubkey pk2; + int ecount = 0; + secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); + + CHECK(secp256k1_ec_pubkey_parse(none, &pk1, pk1_ser, sizeof(pk1_ser)) == 1); + CHECK(secp256k1_ec_pubkey_parse(none, &pk2, pk2_ser, sizeof(pk2_ser)) == 1); + + CHECK(secp256k1_pubkey_cmp(none, NULL, &pk2) < 0); + CHECK(ecount == 1); + CHECK(secp256k1_pubkey_cmp(none, &pk1, NULL) > 0); + CHECK(ecount == 2); + CHECK(secp256k1_pubkey_cmp(none, &pk1, &pk2) < 0); + CHECK(secp256k1_pubkey_cmp(none, &pk2, &pk1) > 0); + CHECK(secp256k1_pubkey_cmp(none, &pk1, &pk1) == 0); + CHECK(secp256k1_pubkey_cmp(none, &pk2, &pk2) == 0); + CHECK(ecount == 2); + memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */ + CHECK(secp256k1_pubkey_cmp(none, &pk1, &pk2) < 0); + CHECK(ecount == 3); + CHECK(secp256k1_pubkey_cmp(none, &pk1, &pk1) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_pubkey_cmp(none, &pk2, &pk1) > 0); + CHECK(ecount == 6); + + secp256k1_context_destroy(none); +} + +void test_sort_helper(secp256k1_pubkey *pk, size_t *pk_order, size_t n_pk) { size_t i; - const secp256k1_xonly_pubkey *pk_test[5]; + const secp256k1_pubkey *pk_test[5]; for (i = 0; i < n_pk; i++) { pk_test[i] = &pk[pk_order[i]]; } - secp256k1_xonly_sort(ctx, pk_test, n_pk); + secp256k1_pubkey_sort(ctx, pk_test, n_pk); for (i = 0; i < n_pk; i++) { CHECK(secp256k1_memcmp_var(pk_test[i], &pk[i], sizeof(*pk_test[i])) == 0); } @@ -643,88 +682,131 @@ void permute(size_t *arr, size_t n) { } } -void rand_xonly_pk(secp256k1_xonly_pubkey *pk) { +void rand_pk(secp256k1_pubkey *pk) { unsigned char seckey[32]; secp256k1_keypair keypair; secp256k1_testrand256(seckey); CHECK(secp256k1_keypair_create(ctx, &keypair, seckey) == 1); - CHECK(secp256k1_keypair_xonly_pub(ctx, pk, NULL, &keypair) == 1); + CHECK(secp256k1_keypair_pub(ctx, pk, &keypair) == 1); } -void test_xonly_sort_api(void) { +void test_sort_api(void) { int ecount = 0; - secp256k1_xonly_pubkey pks[2]; - const secp256k1_xonly_pubkey *pks_ptr[2]; + secp256k1_pubkey pks[2]; + const secp256k1_pubkey *pks_ptr[2]; secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); pks_ptr[0] = &pks[0]; pks_ptr[1] = &pks[1]; - rand_xonly_pk(&pks[0]); - rand_xonly_pk(&pks[1]); + rand_pk(&pks[0]); + rand_pk(&pks[1]); - CHECK(secp256k1_xonly_sort(none, pks_ptr, 2) == 1); - CHECK(secp256k1_xonly_sort(none, NULL, 2) == 0); + CHECK(secp256k1_pubkey_sort(none, pks_ptr, 2) == 1); + CHECK(secp256k1_pubkey_sort(none, NULL, 2) == 0); CHECK(ecount == 1); - CHECK(secp256k1_xonly_sort(none, pks_ptr, 0) == 1); + CHECK(secp256k1_pubkey_sort(none, pks_ptr, 0) == 1); /* Test illegal public keys */ memset(&pks[0], 0, sizeof(pks[0])); - CHECK(secp256k1_xonly_sort(none, pks_ptr, 2) == 1); + CHECK(secp256k1_pubkey_sort(none, pks_ptr, 2) == 1); CHECK(ecount == 2); memset(&pks[1], 0, sizeof(pks[1])); - CHECK(secp256k1_xonly_sort(none, pks_ptr, 2) == 1); + CHECK(secp256k1_pubkey_sort(none, pks_ptr, 2) == 1); CHECK(ecount > 2); secp256k1_context_destroy(none); } -void test_xonly_sort(void) { - secp256k1_xonly_pubkey pk[5]; - unsigned char pk_ser[5][32]; +void test_sort(void) { + secp256k1_pubkey pk[5]; + unsigned char pk_ser[5][33] = { + { 0x02, 0x08 }, + { 0x02, 0x0b }, + { 0x02, 0x0c }, + { 0x03, 0x05 }, + { 0x03, 0x0a }, + }; int i; size_t pk_order[5] = { 0, 1, 2, 3, 4 }; for (i = 0; i < 5; i++) { - memset(pk_ser[i], 0, sizeof(pk_ser[i])); - } - pk_ser[0][0] = 5; - pk_ser[1][0] = 8; - pk_ser[2][0] = 0x0a; - pk_ser[3][0] = 0x0b; - pk_ser[4][0] = 0x0c; - for (i = 0; i < 5; i++) { - CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk[i], pk_ser[i])); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pk[i], pk_ser[i], sizeof(pk_ser[i]))); } permute(pk_order, 1); - test_xonly_sort_helper(pk, pk_order, 1); + test_sort_helper(pk, pk_order, 1); permute(pk_order, 2); - test_xonly_sort_helper(pk, pk_order, 2); + test_sort_helper(pk, pk_order, 2); permute(pk_order, 3); - test_xonly_sort_helper(pk, pk_order, 3); + test_sort_helper(pk, pk_order, 3); for (i = 0; i < count; i++) { permute(pk_order, 4); - test_xonly_sort_helper(pk, pk_order, 4); + test_sort_helper(pk, pk_order, 4); } for (i = 0; i < count; i++) { permute(pk_order, 5); - test_xonly_sort_helper(pk, pk_order, 5); + test_sort_helper(pk, pk_order, 5); } /* Check that sorting also works for random pubkeys */ for (i = 0; i < count; i++) { int j; - const secp256k1_xonly_pubkey *pk_ptr[5]; + const secp256k1_pubkey *pk_ptr[5]; for (j = 0; j < 5; j++) { - rand_xonly_pk(&pk[j]); + rand_pk(&pk[j]); pk_ptr[j] = &pk[j]; } - secp256k1_xonly_sort(ctx, pk_ptr, 5); + secp256k1_pubkey_sort(ctx, pk_ptr, 5); for (j = 1; j < 5; j++) { - CHECK(secp256k1_xonly_sort_cmp(&pk_ptr[j - 1], &pk_ptr[j], ctx) <= 0); + CHECK(secp256k1_pubkey_sort_cmp(&pk_ptr[j - 1], &pk_ptr[j], ctx) <= 0); } } } +/* Test vectors from BIP-MuSig2 */ +void test_sort_vectors(void) { + enum { N_PUBKEYS = 6 }; + unsigned char pk_ser[N_PUBKEYS][33] = { + { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, + 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, + 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 }, + { 0x02, 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 }, + { 0x03, 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 }, + { 0x02, 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 }, + { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, + 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, + 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xFF }, + { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, + 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, + 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 } + }; + secp256k1_pubkey pubkeys[N_PUBKEYS]; + secp256k1_pubkey *sorted[N_PUBKEYS]; + const secp256k1_pubkey *pks_ptr[N_PUBKEYS]; + int i; + + sorted[0] = &pubkeys[3]; + sorted[1] = &pubkeys[0]; + sorted[2] = &pubkeys[0]; + sorted[3] = &pubkeys[4]; + sorted[4] = &pubkeys[1]; + sorted[5] = &pubkeys[2]; + + for (i = 0; i < N_PUBKEYS; i++) { + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkeys[i], pk_ser[i], sizeof(pk_ser[i]))); + pks_ptr[i] = &pubkeys[i]; + } + CHECK(secp256k1_pubkey_sort(ctx, pks_ptr, N_PUBKEYS) == 1); + for (i = 0; i < N_PUBKEYS; i++) { + CHECK(secp256k1_memcmp_var(pks_ptr[i], sorted[i], sizeof(secp256k1_pubkey)) == 0); + } +} + void run_extrakeys_tests(void) { /* xonly key test cases */ test_xonly_pubkey(); @@ -738,8 +820,10 @@ void run_extrakeys_tests(void) { test_keypair_add(); test_hsort(); - test_xonly_sort_api(); - test_xonly_sort(); + test_pubkey_comparison(); + test_sort_api(); + test_sort(); + test_sort_vectors(); } #endif diff --git a/src/modules/musig/keyagg.h b/src/modules/musig/keyagg.h index a56dc9ef..9ccea847 100644 --- a/src/modules/musig/keyagg.h +++ b/src/modules/musig/keyagg.h @@ -16,7 +16,9 @@ typedef struct { secp256k1_ge pk; - secp256k1_fe second_pk_x; + /* If there is no "second" public key, second_pk is set to the point at + * infinity */ + secp256k1_ge second_pk; unsigned char pk_hash[32]; /* tweak is identical to value tacc[v] in the specification. */ secp256k1_scalar tweak; @@ -25,13 +27,23 @@ typedef struct { int parity_acc; } secp256k1_keyagg_cache_internal; -/* Requires that the saved point is not infinity */ +/* Save and load points to and from byte arrays, similar to + * secp256k1_pubkey_{save,load}. */ static void secp256k1_point_save(unsigned char *data, secp256k1_ge *ge); +/* In contrast to pubkey_load, point_load does not attempt to check that data + * has been initialized, since it is assumed that this check already happened + * (e.g. by comparing magic bytes) */ static void secp256k1_point_load(secp256k1_ge *ge, const unsigned char *data); +/* point_save_ext and point_load_ext are identical to point_save and point_load + * except that they allow saving and loading the point at infinity */ +static void secp256k1_point_save_ext(unsigned char *data, secp256k1_ge *ge); + +static void secp256k1_point_load_ext(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); +static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk); #endif diff --git a/src/modules/musig/keyagg_impl.h b/src/modules/musig/keyagg_impl.h index 33cdec2a..85bbacfa 100644 --- a/src/modules/musig/keyagg_impl.h +++ b/src/modules/musig/keyagg_impl.h @@ -47,13 +47,30 @@ static void secp256k1_point_load(secp256k1_ge *ge, const unsigned char *data) { } } +static void secp256k1_point_save_ext(unsigned char *data, secp256k1_ge *ge) { + if (secp256k1_ge_is_infinity(ge)) { + memset(data, 0, 64); + } else { + secp256k1_point_save(data, ge); + } +} + +static void secp256k1_point_load_ext(secp256k1_ge *ge, const unsigned char *data) { + unsigned char zeros[64] = { 0 }; + if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) { + secp256k1_ge_set_infinity(ge); + } else { + secp256k1_point_load(ge, data); + } +} + 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) + * - 64 byte "second" public key (set to the point at infinity 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 @@ -65,8 +82,8 @@ static void secp256k1_keyagg_cache_save(secp256k1_musig_keyagg_cache *cache, sec ptr += 4; secp256k1_point_save(ptr, &cache_i->pk); ptr += 64; - secp256k1_fe_get_b32(ptr, &cache_i->second_pk_x); - ptr += 32; + secp256k1_point_save_ext(ptr, &cache_i->second_pk); + ptr += 64; memcpy(ptr, cache_i->pk_hash, 32); ptr += 32; *ptr = cache_i->parity_acc; @@ -80,8 +97,8 @@ static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_k ptr += 4; secp256k1_point_load(&cache_i->pk, ptr); ptr += 64; - secp256k1_fe_set_b32(&cache_i->second_pk_x, ptr); - ptr += 32; + secp256k1_point_load_ext(&cache_i->second_pk, ptr); + ptr += 64; memcpy(cache_i->pk_hash, ptr, 32); ptr += 32; cache_i->parity_acc = *ptr & 1; @@ -107,17 +124,19 @@ static void secp256k1_musig_keyagglist_sha256(secp256k1_sha256 *sha) { } /* 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) { +static int secp256k1_musig_compute_pk_hash(const secp256k1_context *ctx, unsigned char *pk_hash, const secp256k1_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])) { + unsigned char ser[33]; + size_t ser_len = sizeof(ser); + if (!secp256k1_ec_pubkey_serialize(ctx, ser, &ser_len, pk[i], SECP256K1_EC_COMPRESSED)) { return 0; } - secp256k1_sha256_write(&sha, ser, 32); + VERIFY_CHECK(ser_len == sizeof(ser)); + secp256k1_sha256_write(&sha, ser, sizeof(ser)); } secp256k1_sha256_finalize(&sha, pk_hash); return 1; @@ -140,52 +159,59 @@ static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) { } /* 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) { + * otherwise tagged_hash(pk_hash, x) where pk_hash is the hash of public keys. + * second_pk is the point at infinity in case there is no second_pk. Assumes + * that pk is not the point at infinity and that the coordinates of pk and + * second_pk are normalized. */ +static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pk_hash, secp256k1_ge *pk, const secp256k1_ge *second_pk) { secp256k1_sha256 sha; - unsigned char buf[32]; - if (secp256k1_fe_cmp_var(x, second_pk_x) == 0) { + if (!secp256k1_ge_is_infinity(second_pk) + && secp256k1_fe_equal(&pk->x, &second_pk->x) + && secp256k1_fe_is_odd(&pk->y) == secp256k1_fe_is_odd(&second_pk->y)) { secp256k1_scalar_set_int(r, 1); } else { + unsigned char buf[33]; + size_t buflen = sizeof(buf); + int ret; secp256k1_musig_keyaggcoef_sha256(&sha); secp256k1_sha256_write(&sha, pk_hash, 32); - secp256k1_fe_get_b32(buf, x); - secp256k1_sha256_write(&sha, buf, 32); + ret = secp256k1_eckey_pubkey_serialize(pk, buf, &buflen, 1); + /* Serialization does not fail since the pk is not the point at infinity + * (according to this function's precondition). */ + VERIFY_CHECK(ret && buflen == sizeof(buf)); + secp256k1_sha256_write(&sha, buf, sizeof(buf)); 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); +static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk) { + secp256k1_musig_keyaggcoef_internal(r, cache_i->pk_hash, pk, &cache_i->second_pk); } 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; + const secp256k1_pubkey * const* pks; + secp256k1_ge second_pk; } 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]); + ret = secp256k1_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); + secp256k1_musig_keyaggcoef_internal(sc, ctx->pk_hash, pt, &ctx->second_pk); 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) { +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_pubkey * const* pubkeys, size_t n_pubkeys) { secp256k1_musig_pubkey_agg_ecmult_data ecmult_data; secp256k1_gej pkj; secp256k1_ge pkp; @@ -201,15 +227,15 @@ int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_s 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); + + secp256k1_ge_set_infinity(&ecmult_data.second_pk); 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])) { + secp256k1_ge pk; + if (!secp256k1_pubkey_load(ctx, &pk, pubkeys[i])) { return 0; } - ecmult_data.second_pk_x = pt.x; + ecmult_data.second_pk = pk; break; } } @@ -232,7 +258,7 @@ int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_s 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; + cache_i.second_pk = ecmult_data.second_pk; memcpy(cache_i.pk_hash, ecmult_data.pk_hash, sizeof(cache_i.pk_hash)); secp256k1_keyagg_cache_save(keyagg_cache, &cache_i); } diff --git a/src/modules/musig/musig.md b/src/modules/musig/musig.md index 5c9b8d78..44b0de4f 100644 --- a/src/modules/musig/musig.md +++ b/src/modules/musig/musig.md @@ -23,16 +23,16 @@ Therefore, users of the musig module must take great care to make sure of the fo # 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` and an ordinary tweak can be added with `secp256k1_ec_pubkey_tweak_add`. +A (Taproot) tweak can be added to the resulting public key with `secp256k1_xonly_pubkey_tweak_add` and a plain tweak can be added with `secp256k1_ec_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_xonly_tweak_add` and an ordinary tweak with `secp256k1_musig_pubkey_ec_tweak_add`. +1. Generate a keypair with `secp256k1_keypair_create` and obtain the public key with `secp256k1_keypair_pub`. +2. Call `secp256k1_musig_pubkey_agg` with the pubkeys of all participants. +3. Optionally add a (Taproot) tweak with `secp256k1_musig_pubkey_xonly_tweak_add` and a plain tweak with `secp256k1_musig_pubkey_ec_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`. diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h index 88e27e17..91420731 100644 --- a/src/modules/musig/session_impl.h +++ b/src/modules/musig/session_impl.h @@ -52,8 +52,8 @@ static void secp256k1_musig_secnonce_invalidate(const secp256k1_context* ctx, se 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. */ +/* Saves two group elements into a pubnonce. Requires that none of the provided + * group elements is infinity. */ static void secp256k1_musig_pubnonce_save(secp256k1_musig_pubnonce* nonce, secp256k1_ge* ge) { int i; memcpy(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4); @@ -62,8 +62,8 @@ static void secp256k1_musig_pubnonce_save(secp256k1_musig_pubnonce* nonce, secp2 } } -/* Works for both musig_pubnonce and musig_aggnonce. Returns 1 unless the nonce - * wasn't properly initialized */ +/* Loads two group elements from a pubnonce. 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; @@ -74,12 +74,24 @@ static int secp256k1_musig_pubnonce_load(const secp256k1_context* ctx, secp256k1 return 1; } +static const unsigned char secp256k1_musig_aggnonce_magic[4] = { 0xa8, 0xb7, 0xe4, 0x67 }; + static void secp256k1_musig_aggnonce_save(secp256k1_musig_aggnonce* nonce, secp256k1_ge* ge) { - secp256k1_musig_pubnonce_save((secp256k1_musig_pubnonce *) nonce, ge); + int i; + memcpy(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4); + for (i = 0; i < 2; i++) { + secp256k1_point_save_ext(&nonce->data[4 + 64*i], &ge[i]); + } } 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); + int i; + + ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4) == 0); + for (i = 0; i < 2; i++) { + secp256k1_point_load_ext(&ge[i], &nonce->data[4 + 64*i]); + } + return 1; } static const unsigned char secp256k1_musig_session_cache_magic[4] = { 0x9d, 0xed, 0xe9, 0x17 }; @@ -180,17 +192,69 @@ int secp256k1_musig_pubnonce_parse(const secp256k1_context* ctx, secp256k1_musig return 0; } } - /* The group elements can not be infinity because they were just parsed */ secp256k1_musig_pubnonce_save(nonce, ge); return 1; } +/* Outputs 33 zero bytes if the given group element is the point at infinity and + * otherwise outputs the compressed serialization */ +static void secp256k1_ge_serialize_ext(unsigned char *out33, secp256k1_ge* ge) { + if (secp256k1_ge_is_infinity(ge)) { + memset(out33, 0, 33); + } else { + int ret; + size_t size = 33; + ret = secp256k1_eckey_pubkey_serialize(ge, out33, &size, 1); + /* Serialize must succeed because the point is not at infinity */ + VERIFY_CHECK(ret && size == 33); + } +} + +/* Outputs the point at infinity if the given byte array is all zero, otherwise + * attempts to parse compressed point serialization. */ +static int secp256k1_ge_parse_ext(secp256k1_ge* ge, const unsigned char *in33) { + unsigned char zeros[33] = { 0 }; + + if (memcmp(in33, zeros, sizeof(zeros)) == 0) { + secp256k1_ge_set_infinity(ge); + return 1; + } + return secp256k1_eckey_pubkey_parse(ge, in33, 33); +} + 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); + 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_aggnonce_load(ctx, ge, nonce)) { + return 0; + } + for (i = 0; i < 2; i++) { + secp256k1_ge_serialize_ext(&out66[33*i], &ge[i]); + } + return 1; } 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); + 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_ge_parse_ext(&ge[i], &in66[33*i])) { + return 0; + } + } + secp256k1_musig_aggnonce_save(nonce, ge); + return 1; } int secp256k1_musig_partial_sig_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_sig* sig) { @@ -226,53 +290,71 @@ static int secp256k1_xonly_ge_serialize(unsigned char *output32, secp256k1_ge *g 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]; +/* Write optional inputs into the hash */ +static void secp256k1_nonce_function_musig_helper(secp256k1_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) { + unsigned char zero[7] = { 0 }; + /* The spec requires length prefixes to be between 1 and 8 bytes + * (inclusive) */ + VERIFY_CHECK(prefix_size <= 8); + /* Since the length of all input data fits in a byte, we can always pad the + * length prefix with prefix_size - 1 zero bytes. */ + secp256k1_sha256_write(sha, zero, prefix_size - 1); + if (data != NULL) { + secp256k1_sha256_write(sha, &len, 1); + secp256k1_sha256_write(sha, data, len); + } else { + len = 0; + secp256k1_sha256_write(sha, &len, 1); + } +} - /* TODO: this doesn't have the same sidechannel resistance as the BIP340 - * nonce function because the seckey feeds directly into SHA. */ +static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_id, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) { + secp256k1_sha256 sha; + unsigned char rand[32]; + unsigned char i; + unsigned char msg_present; + + if (seckey32 != NULL) { + secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"MuSig/aux", sizeof("MuSig/aux") - 1); + secp256k1_sha256_write(&sha, session_id, 32); + secp256k1_sha256_finalize(&sha, rand); + for (i = 0; i < 32; i++) { + rand[i] ^= seckey32[i]; + } + } else { + memcpy(rand, session_id, sizeof(rand)); + } /* 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_write(&sha, rand, sizeof(rand)); + secp256k1_nonce_function_musig_helper(&sha, 1, pk33, 33); + secp256k1_nonce_function_musig_helper(&sha, 1, agg_pk32, 32); + msg_present = msg32 != NULL; + secp256k1_sha256_write(&sha, &msg_present, 1); + if (msg_present) { + secp256k1_nonce_function_musig_helper(&sha, 8, msg32, 32); } - secp256k1_sha256_finalize(&sha, seed); + secp256k1_nonce_function_musig_helper(&sha, 4, extra_input32, 32); 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_sha256 sha_tmp = sha; + secp256k1_sha256_write(&sha_tmp, &i, 1); + secp256k1_sha256_finalize(&sha_tmp, 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) { +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 secp256k1_pubkey *pubkey, 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; + unsigned char pk_ser[33]; + size_t pk_ser_len = sizeof(pk_ser); + unsigned char aggpk_ser[32]; + unsigned char *aggpk_ser_ptr = NULL; int ret = 1; VERIFY_CHECK(ctx != NULL); @@ -281,6 +363,7 @@ int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secn ARG_CHECK(pubnonce != NULL); memset(pubnonce, 0, sizeof(*pubnonce)); ARG_CHECK(session_id32 != NULL); + ARG_CHECK(pubkey != 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 @@ -305,12 +388,17 @@ int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secn if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { return 0; } - ret_tmp = secp256k1_xonly_ge_serialize(pk_ser, &cache_i.pk); + ret_tmp = secp256k1_xonly_ge_serialize(aggpk_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; + aggpk_ser_ptr = aggpk_ser; } - secp256k1_nonce_function_musig(k, session_id32, msg32, seckey, pk_ser_ptr, extra_input32); + if (!secp256k1_ec_pubkey_serialize(ctx, pk_ser, &pk_ser_len, pubkey, SECP256K1_EC_COMPRESSED)) { + return 0; + } + VERIFY_CHECK(pk_ser_len == sizeof(pk_ser)); + + secp256k1_nonce_function_musig(k, session_id32, msg32, seckey, pk_ser, aggpk_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])); @@ -361,12 +449,7 @@ int secp256k1_musig_nonce_agg(const secp256k1_context* ctx, secp256k1_musig_aggn return 0; } for (i = 0; i < 2; i++) { - if (secp256k1_gej_is_infinity(&aggnonce_ptj[i])) { - /* Set to G according to the specification */ - aggnonce_pt[i] = secp256k1_ge_const_g; - } else { - secp256k1_ge_set_gej(&aggnonce_pt[i], &aggnonce_ptj[i]); - } + secp256k1_ge_set_gej(&aggnonce_pt[i], &aggnonce_ptj[i]); } secp256k1_musig_aggnonce_save(aggnonce, aggnonce_pt); return 1; @@ -380,11 +463,7 @@ static int secp256k1_musig_compute_noncehash(unsigned char *noncehash, secp256k1 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_ge_serialize_ext(buf, &aggnonce[i]); secp256k1_sha256_write(&sha, buf, sizeof(buf)); } secp256k1_sha256_write(&sha, agg_pk32, 32); @@ -398,6 +477,7 @@ static int secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigne secp256k1_ge fin_nonce_pt; secp256k1_gej fin_nonce_ptj; secp256k1_ge aggnonce[2]; + int ret; secp256k1_ge_set_gej(&aggnonce[0], &aggnoncej[0]); secp256k1_ge_set_gej(&aggnonce[1], &aggnoncej[1]); @@ -406,13 +486,16 @@ static int secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigne } /* fin_nonce = aggnonce[0] + b*aggnonce[1] */ secp256k1_scalar_set_b32(b, noncehash, NULL); + secp256k1_gej_set_infinity(&fin_nonce_ptj); secp256k1_ecmult(&fin_nonce_ptj, &aggnoncej[1], b, NULL); - secp256k1_gej_add_ge(&fin_nonce_ptj, &fin_nonce_ptj, &aggnonce[0]); + secp256k1_gej_add_ge_var(&fin_nonce_ptj, &fin_nonce_ptj, &aggnonce[0], NULL); 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; + if (secp256k1_ge_is_infinity(&fin_nonce_pt)) { + fin_nonce_pt = secp256k1_ge_const_g; } + ret = secp256k1_xonly_ge_serialize(fin_nonce, &fin_nonce_pt); + /* Can't fail since fin_nonce_pt is not infinity */ + VERIFY_CHECK(ret); secp256k1_fe_normalize_var(&fin_nonce_pt.y); *fin_nonce_parity = secp256k1_fe_is_odd(&fin_nonce_pt.y); return 1; @@ -471,7 +554,7 @@ int secp256k1_musig_nonce_process(const secp256k1_context* ctx, secp256k1_musig_ return 1; } -void secp256k1_musig_partial_sign_clear(secp256k1_scalar *sk, secp256k1_scalar *k) { +static 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]); @@ -514,25 +597,18 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p } secp256k1_fe_normalize_var(&pk.y); - /* The specification requires that the secret key is multiplied by - * g[v]*g*gp. All factors are -1 or 1. The value g[v] is -1 iff - * secp256k1_fe_is_odd(&cache_i.pk.y)), g is is -1 iff parity_acc is 1 and - * gp is -1 if secp256k1_fe_is_odd(&pk.y). Therefore, multiplying by - * g[v]*g*gp is equivalent to negating if - * secp256k1_fe_is_odd(&cache_i.pk.y)) - * XOR cache_i.parity_acc - * XOR secp256k1_fe_is_odd(&pk.y). - */ + /* Negate sk if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. + * This corresponds to the line "Let d = gâ‹…gaccâ‹…d' mod n" in the + * specification. */ if ((secp256k1_fe_is_odd(&cache_i.pk.y) - != cache_i.parity_acc) - != secp256k1_fe_is_odd(&pk.y)) { + != cache_i.parity_acc)) { 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_musig_keyaggcoef(&mu, &cache_i, &pk); secp256k1_scalar_mul(&sk, &sk, &mu); if (!secp256k1_musig_session_load(ctx, &session_i, session)) { @@ -555,7 +631,7 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p 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) { +int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_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; @@ -585,7 +661,7 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2 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)) { + if (!secp256k1_pubkey_load(ctx, &pkp, pubkey)) { return 0; } if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { @@ -594,14 +670,12 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2 /* 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_musig_keyaggcoef(&mu, &cache_i, &pkp); secp256k1_scalar_mul(&e, &session_i.challenge, &mu); - /* The specification requires that the public key is multiplied by g[v]*g. - * All factors are -1 or 1. The value g[v] is -1 iff - * secp256k1_fe_is_odd(&cache_i.pk.y)) and g is is -1 iff parity_acc is 1. - * Therefore, multiplying by g[v]*g is equivalent to negating if - * fe_is_odd(&cache_i.pk.y) XOR parity_acc. */ + /* Negate e if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. + * This corresponds to the line "Let g' = gâ‹…gacc mod n" and the multiplication "g'â‹…e" + * in the specification. */ if (secp256k1_fe_is_odd(&cache_i.pk.y) != cache_i.parity_acc) { secp256k1_scalar_negate(&e, &e); diff --git a/src/modules/musig/tests_impl.h b/src/modules/musig/tests_impl.h index 9660227e..ff6637d0 100644 --- a/src/modules/musig/tests_impl.h +++ b/src/modules/musig/tests_impl.h @@ -23,11 +23,13 @@ #include "../../hash.h" #include "../../util.h" -static int create_keypair_and_pk(secp256k1_keypair *keypair, secp256k1_xonly_pubkey *pk, const unsigned char *sk) { +#include "vectors.h" + +static int create_keypair_and_pk(secp256k1_keypair *keypair, secp256k1_pubkey *pk, const unsigned char *sk) { int ret; secp256k1_keypair keypair_tmp; ret = secp256k1_keypair_create(ctx, &keypair_tmp, sk); - ret &= secp256k1_keypair_xonly_pub(ctx, pk, NULL, &keypair_tmp); + ret &= secp256k1_keypair_pub(ctx, pk, &keypair_tmp); if (keypair != NULL) { *keypair = keypair_tmp; } @@ -47,8 +49,8 @@ void musig_simple_test(secp256k1_scratch_space *scratch) { 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]; + secp256k1_pubkey pk[2]; + const secp256k1_pubkey *pk_ptr[2]; secp256k1_musig_partial_sig partial_sig[2]; const secp256k1_musig_partial_sig *partial_sig_ptr[2]; unsigned char final_sig[64]; @@ -64,7 +66,7 @@ void musig_simple_test(secp256k1_scratch_space *scratch) { partial_sig_ptr[i] = &partial_sig[i]; 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_nonce_gen(ctx, &secnonce[i], &pubnonce[i], session_id[i], sk[i], &pk[i], NULL, NULL, NULL) == 1); } CHECK(secp256k1_musig_pubkey_agg(ctx, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); @@ -145,11 +147,11 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { 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]; + secp256k1_pubkey pk[2]; + const secp256k1_pubkey *pk_ptr[2]; + secp256k1_pubkey invalid_pk; + const secp256k1_pubkey *invalid_pk_ptr2[2]; + const secp256k1_pubkey *invalid_pk_ptr3[3]; unsigned char tweak[32]; int nonce_parity; unsigned char sec_adaptor[32]; @@ -294,44 +296,48 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { /** Session creation **/ ecount = 0; - CHECK(secp256k1_musig_nonce_gen(none, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 1); - CHECK(secp256k1_musig_nonce_gen(vrfy, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 1); - CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 1); + CHECK(secp256k1_musig_nonce_gen(none, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); + CHECK(secp256k1_musig_nonce_gen(vrfy, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); CHECK(ecount == 0); - CHECK(secp256k1_musig_nonce_gen(sttc, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 0); + CHECK(secp256k1_musig_nonce_gen(sttc, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); CHECK(ecount == 1); - CHECK(secp256k1_musig_nonce_gen(sign, NULL, &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 0); + CHECK(secp256k1_musig_nonce_gen(sign, NULL, &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); CHECK(ecount == 2); - CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], NULL, session_id[0], sk[0], msg, &keyagg_cache, max64) == 0); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], NULL, session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); CHECK(ecount == 3); - CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], NULL, sk[0], msg, &keyagg_cache, max64) == 0); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], NULL, sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); CHECK(ecount == 4); 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(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], zeros68, NULL, &pk[0], msg, &keyagg_cache, max64) == 0); CHECK(ecount == 4); 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(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], zeros68, sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], NULL, &pk[0], msg, &keyagg_cache, max64) == 1); CHECK(ecount == 4); /* invalid seckey */ - CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], max64, msg, &keyagg_cache, max64) == 0); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], max64, &pk[0], msg, &keyagg_cache, max64) == 0); CHECK(memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0); CHECK(ecount == 4); - CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], NULL, &keyagg_cache, max64) == 1); - CHECK(ecount == 4); - CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, NULL, max64) == 1); - CHECK(ecount == 4); - CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &invalid_keyagg_cache, max64) == 0); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], NULL, msg, &keyagg_cache, max64) == 0); CHECK(ecount == 5); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &invalid_pk, msg, &keyagg_cache, max64) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], NULL, &keyagg_cache, max64) == 1); + CHECK(ecount == 6); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, NULL, max64) == 1); + CHECK(ecount == 6); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &invalid_keyagg_cache, max64) == 0); + CHECK(ecount == 7); 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 == 5); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, NULL) == 1); + CHECK(ecount == 7); - /* 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); + /* Every in-argument except session_id and pubkey can be NULL */ + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], NULL, &pk[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[1], &pubnonce[1], session_id[1], sk[1], &pk[1], NULL, NULL, NULL) == 1); /** Serialize and parse public nonces **/ ecount = 0; @@ -376,11 +382,11 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { CHECK(ecount == 4); CHECK(secp256k1_musig_nonce_agg(none, &aggnonce, inf_pubnonce_ptr, 2) == 1); { - /* Check that the aggnonce is set to G */ + /* Check that the aggnonce encodes two points at infinity */ secp256k1_ge aggnonce_pt[2]; - secp256k1_musig_pubnonce_load(ctx, aggnonce_pt, (secp256k1_musig_pubnonce*)&aggnonce); + secp256k1_musig_aggnonce_load(ctx, aggnonce_pt, &aggnonce); for (i = 0; i < 2; i++) { - ge_equals_ge(&aggnonce_pt[i], &secp256k1_ge_const_g); + secp256k1_ge_is_infinity(&aggnonce_pt[i]); } } CHECK(ecount == 4); @@ -405,8 +411,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { 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, zeros68) == 1); CHECK(secp256k1_musig_aggnonce_parse(none, &aggnonce, aggnonce_ser) == 1); { @@ -609,25 +614,27 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { void musig_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { secp256k1_scalar k1[2], k2[2]; - secp256k1_nonce_function_musig(k1, args[0], args[1], args[2], args[3], args[4]); + secp256k1_nonce_function_musig(k1, args[0], args[1], args[2], args[3], args[4], args[5]); secp256k1_testrand_flip(args[n_flip], n_bytes); - secp256k1_nonce_function_musig(k2, args[0], args[1], args[2], args[3], args[4]); + secp256k1_nonce_function_musig(k2, args[0], args[1], args[2], args[3], args[4], args[5]); CHECK(secp256k1_scalar_eq(&k1[0], &k2[0]) == 0); CHECK(secp256k1_scalar_eq(&k1[1], &k2[1]) == 0); } void musig_nonce_test(void) { - unsigned char *args[5]; + unsigned char *args[6]; unsigned char session_id[32]; unsigned char sk[32]; + unsigned char pk[33]; unsigned char msg[32]; unsigned char agg_pk[32]; unsigned char extra_input[32]; int i, j; - secp256k1_scalar k[5][2]; + secp256k1_scalar k[6][2]; secp256k1_testrand_bytes_test(session_id, sizeof(session_id)); secp256k1_testrand_bytes_test(sk, sizeof(sk)); + secp256k1_testrand_bytes_test(pk, sizeof(pk)); secp256k1_testrand_bytes_test(msg, sizeof(msg)); secp256k1_testrand_bytes_test(agg_pk, sizeof(agg_pk)); secp256k1_testrand_bytes_test(extra_input, sizeof(extra_input)); @@ -636,30 +643,35 @@ void musig_nonce_test(void) { args[0] = session_id; args[1] = msg; args[2] = sk; - args[3] = agg_pk; - args[4] = extra_input; + args[3] = pk; + args[4] = agg_pk; + args[5] = 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)); + musig_nonce_bitflip(args, 3, sizeof(pk)); + musig_nonce_bitflip(args, 4, sizeof(agg_pk)); + musig_nonce_bitflip(args, 5, 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(pk, session_id, sizeof(session_id)); 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_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(k[2], args[0], args[1], NULL, args[3], args[4], args[5]); + secp256k1_nonce_function_musig(k[3], args[0], args[1], args[2], NULL, args[4], args[5]); + secp256k1_nonce_function_musig(k[4], args[0], args[1], args[2], args[3], NULL, args[5]); + secp256k1_nonce_function_musig(k[5], args[0], args[1], args[2], args[3], args[4], NULL); + for (i = 0; i < 6; i++) { + CHECK(!secp256k1_scalar_eq(&k[i][0], &k[i][1])); + for (j = i+1; j < 6; j++) { + CHECK(!secp256k1_scalar_eq(&k[i][0], &k[j][0])); + CHECK(!secp256k1_scalar_eq(&k[i][1], &k[j][1])); } } } @@ -684,10 +696,10 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) { 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_pubkey pk_a[2]; + const secp256k1_pubkey *pk_a_ptr[2]; + secp256k1_pubkey pk_b[2]; + const secp256k1_pubkey *pk_b_ptr[2]; secp256k1_musig_keyagg_cache keyagg_cache_a; secp256k1_musig_keyagg_cache keyagg_cache_b; secp256k1_xonly_pubkey agg_pk_a; @@ -729,10 +741,10 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) { 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); - 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); + CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_a[0], &pubnonce_a[0], seed_a[0], sk_a[0], &pk_a[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_a[1], &pubnonce_a[1], seed_a[1], sk_a[1], &pk_b[1], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_b[0], &pubnonce_b[0], seed_b[0], sk_b[0], &pk_b[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_b[1], &pubnonce_b[1], seed_b[1], sk_b[1], &pk_b[1], NULL, NULL, NULL) == 1); /* Step 2: Exchange nonces */ CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce_a, pubnonce_ptr_a, 2) == 1); @@ -816,7 +828,7 @@ void sha256_tag_test(void) { /* 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]; + secp256k1_pubkey pk[2]; unsigned char session_id[2][32]; unsigned char msg[32]; secp256k1_musig_secnonce secnonce[2]; @@ -840,8 +852,8 @@ void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigne CHECK(create_keypair_and_pk(&keypair[1], &pk[1], sk1) == 1); secp256k1_testrand256(msg); - 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_gen(ctx, &secnonce[0], &pubnonce[0], session_id[0], sk0, &pk[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce[1], &pubnonce[1], session_id[1], sk1, &pk[1], 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); @@ -857,11 +869,11 @@ void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigne } /* Create aggregate public key P[0], tweak multiple times (using xonly and - * ordinary tweaking) and test signing. */ + * plain tweaking) 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_pubkey pk[2]; + const secp256k1_pubkey *pk_ptr[2]; secp256k1_musig_keyagg_cache keyagg_cache; enum { N_TWEAKS = 8 }; secp256k1_pubkey P[N_TWEAKS + 1]; @@ -911,532 +923,376 @@ void musig_tweak_test(secp256k1_scratch_space *scratch) { } } -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_keyagg_cache_internal cache_i; - secp256k1_xonly_pubkey agg_pk; - unsigned char agg_pk_ser[32]; - secp256k1_musig_keyagg_cache keyagg_cache; +int musig_vectors_keyagg_and_tweak(enum MUSIG_ERROR *error, + secp256k1_musig_keyagg_cache *keyagg_cache, + unsigned char *agg_pk_ser, + const unsigned char pubkeys33[][33], + const unsigned char tweaks32[][32], + size_t key_indices_len, + const size_t *key_indices, + size_t tweak_indices_len, + const size_t *tweak_indices, + const int *is_xonly) { + secp256k1_pubkey pubkeys[MUSIG_VECTORS_MAX_PUBKEYS]; + const secp256k1_pubkey *pk_ptr[MUSIG_VECTORS_MAX_PUBKEYS]; int i; + secp256k1_pubkey agg_pk; + secp256k1_xonly_pubkey agg_pk_xonly; - for (i = 0; i < n_pks; i++) { - CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk[i], pk_ser[i]) == 1); - pk_ptr[i] = &pk[i]; + for (i = 0; i < (int)key_indices_len; i++) { + if (!secp256k1_ec_pubkey_parse(ctx, &pubkeys[i], pubkeys33[key_indices[i]], 33)) { + *error = MUSIG_PUBKEY; + return 0; + } + pk_ptr[i] = &pubkeys[i]; + } + if (!secp256k1_musig_pubkey_agg(ctx, NULL, NULL, keyagg_cache, pk_ptr, key_indices_len)) { + *error = MUSIG_OTHER; + return 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); + for (i = 0; i < (int)tweak_indices_len; i++) { + if (is_xonly[i]) { + if (!secp256k1_musig_pubkey_xonly_tweak_add(ctx, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) { + *error = MUSIG_TWEAK; + return 0; + } + } else { + if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) { + *error = MUSIG_TWEAK; + return 0; + } + } } - 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 agg_pk_expected[32] = {\n"); */ - /* for (k = 0; k < 4; k++) { */ - /* printf(" "); */ - /* for (l = 0; l < 8; l++) { */ - /* printf("0x%02X, ", agg_pk_ser[k*8+l]); */ - /* } */ - /* printf("\n"); */ - /* } */ - /* printf("};\n"); */ - CHECK(secp256k1_memcmp_var(agg_pk_ser, agg_pk_expected, sizeof(agg_pk_ser)) == 0); - free(pk); - free(pk_ptr); + if (!secp256k1_musig_pubkey_get(ctx, &agg_pk, keyagg_cache)) { + *error = MUSIG_OTHER; + return 0; + } + + if (!secp256k1_xonly_pubkey_from_pubkey(ctx, &agg_pk_xonly, NULL, &agg_pk)) { + *error = MUSIG_OTHER; + return 0; + } + + if (agg_pk_ser != NULL) { + if (!secp256k1_xonly_pubkey_serialize(ctx, agg_pk_ser, &agg_pk_xonly)) { + *error = MUSIG_OTHER; + return 0; + } + } + + return 1; } -/* 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; - 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, - 0xFB, 0x73, 0x0E, 0xBE, 0xAB, 0x80, 0xEC, 0x51, - 0x4C, 0xF8, 0x8A, 0x87, 0x7C, 0xEE, 0xEE, 0x0B, - }, - { /* 1 */ - 0xD7, 0x0C, 0xD6, 0x9A, 0x26, 0x47, 0xF7, 0x39, - 0x09, 0x73, 0xDF, 0x48, 0xCB, 0xFA, 0x2C, 0xCC, - 0x40, 0x7B, 0x8B, 0x2D, 0x60, 0xB0, 0x8C, 0x5F, - 0x16, 0x41, 0x18, 0x5C, 0x79, 0x98, 0xA2, 0x90, - }, - { /* 2 */ - 0x81, 0xA8, 0xB0, 0x93, 0x91, 0x2C, 0x9E, 0x48, - 0x14, 0x08, 0xD0, 0x97, 0x76, 0xCE, 0xFB, 0x48, - 0xAE, 0xB8, 0xB6, 0x54, 0x81, 0xB6, 0xBA, 0xAF, - 0xB3, 0xC5, 0x81, 0x01, 0x06, 0x71, 0x7B, 0xEB, - }, - { /* 3 */ - 0x2E, 0xB1, 0x88, 0x51, 0x88, 0x7E, 0x7B, 0xDC, - 0x5E, 0x83, 0x0E, 0x89, 0xB1, 0x9D, 0xDB, 0xC2, - 0x80, 0x78, 0xF1, 0xFA, 0x88, 0xAA, 0xD0, 0xAD, - 0x01, 0xCA, 0x06, 0xFE, 0x4F, 0x80, 0x21, 0x0B, - }, - }; + const struct musig_key_agg_vector *vector = &musig_key_agg_vector; - 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; - switch (i) { - case 0: - /* [X1, X2, X3] */ - n_pks = 3; - 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; - 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; - 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; - 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_keyagg_helper(pk, n_pks, agg_pk_expected[i], has_second_pk, second_pk_idx); + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_key_agg_valid_test_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + unsigned char agg_pk[32]; + + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(secp256k1_memcmp_var(agg_pk, c->expected, sizeof(agg_pk)) == 0); + } + + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_key_agg_error_test_case *c = &vector->error_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + + CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + CHECK(c->error == error); } } 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; + size_t i; + const struct musig_nonce_gen_vector *vector = &musig_nonce_gen_vector; - for (i = 0; i < 5; i++) { - memset(args[i], i, sizeof(args[i])); + for (i = 0; i < sizeof(vector->test_case)/sizeof(vector->test_case[0]); i++) { + const struct musig_nonce_gen_test_case *c = &vector->test_case[i]; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_keyagg_cache *keyagg_cache_ptr = NULL; + secp256k1_musig_secnonce secnonce; + secp256k1_musig_pubnonce pubnonce; + const unsigned char *sk = NULL; + const unsigned char *msg = NULL; + const unsigned char *extra_in = NULL; + secp256k1_pubkey pk; + + if (c->has_sk) { + sk = c->sk; + } + if (c->has_aggpk) { + /* Create keyagg_cache from aggpk */ + secp256k1_keyagg_cache_internal cache_i; + secp256k1_xonly_pubkey aggpk; + memset(&cache_i, 0, sizeof(cache_i)); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &aggpk, c->aggpk)); + CHECK(secp256k1_xonly_pubkey_load(ctx, &cache_i.pk, &aggpk)); + secp256k1_keyagg_cache_save(&keyagg_cache, &cache_i); + keyagg_cache_ptr = &keyagg_cache; + } + if (c->has_msg) { + msg = c->msg; + } + if (c->has_extra_in) { + extra_in = c->extra_in; + } + + CHECK(secp256k1_ec_pubkey_parse(ctx, &pk, c->pk, sizeof(c->pk))); + CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, c->rand_, sk, &pk, msg, keyagg_cache_ptr, extra_in) == 1); + CHECK(secp256k1_memcmp_var(&secnonce.data[4], c->expected, sizeof(secnonce)-4) == 0); } +} + + +void musig_test_vectors_nonceagg(void) { + size_t i; + int j; + const struct musig_nonce_agg_vector *vector = &musig_nonce_agg_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_nonce_agg_test_case *c = &vector->valid_case[i]; + secp256k1_musig_pubnonce pubnonce[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + secp256k1_musig_aggnonce aggnonce; + unsigned char aggnonce66[66]; - 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(secp256k1_memcmp_var(k32, k32_expected[i][j], 32) == 0); + CHECK(secp256k1_musig_pubnonce_parse(ctx, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]]) == 1); + pubnonce_ptr[j] = &pubnonce[j]; + } + CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 2)); + CHECK(secp256k1_musig_aggnonce_serialize(ctx, aggnonce66, &aggnonce)); + CHECK(secp256k1_memcmp_var(aggnonce66, c->expected, 33) == 0); + } + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_nonce_agg_test_case *c = &vector->error_case[i]; + secp256k1_musig_pubnonce pubnonce[2]; + for (j = 0; j < 2; j++) { + int expected = c->invalid_nonce_idx != j; + CHECK(expected == secp256k1_musig_pubnonce_parse(ctx, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]])); } } } -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[][32], const int *is_xonly_t, int n_tweaks, const secp256k1_pubkey *adaptor, const unsigned char **pk_ser, int signer_pos) { - secp256k1_keypair signer_keypair; +void musig_test_vectors_signverify(void) { + size_t i; + const struct musig_sign_verify_vector *vector = &musig_sign_verify_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_valid_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_pubkey pubkey; + secp256k1_musig_pubnonce pubnonce; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + secp256k1_musig_secnonce secnonce; + secp256k1_keypair keypair; + unsigned char partial_sig32[32]; + + CHECK(secp256k1_keypair_create(ctx, &keypair, vector->sk)); + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + + CHECK(secp256k1_musig_aggnonce_parse(ctx, &aggnonce, vector->aggnonces[c->aggnonce_index])); + CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache, NULL)); + + memcpy(&secnonce.data[0], secp256k1_musig_secnonce_magic, 4); + memcpy(&secnonce.data[4], vector->secnonces[0], sizeof(secnonce.data) - 4); + CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + CHECK(secp256k1_musig_partial_sig_serialize(ctx, partial_sig32, &partial_sig)); + CHECK(secp256k1_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0); + + CHECK(secp256k1_musig_pubnonce_parse(ctx, &pubnonce, vector->pubnonces[0])); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); + CHECK(secp256k1_musig_partial_sig_verify(ctx, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session)); + } + for (i = 0; i < sizeof(vector->sign_error_case)/sizeof(vector->sign_error_case[0]); i++) { + const struct musig_sign_error_case *c = &vector->sign_error_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + secp256k1_musig_secnonce secnonce; + secp256k1_keypair keypair; + int expected; + + if (i == 0) { + /* Skip this vector since the implementation does not error out when + * the signing key does not belong to any pubkey. */ + continue; + } + expected = c->error != MUSIG_PUBKEY; + CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(expected || c->error == error); + if (!expected) { + continue; + } + + expected = c->error != MUSIG_AGGNONCE; + CHECK(expected == secp256k1_musig_aggnonce_parse(ctx, &aggnonce, vector->aggnonces[c->aggnonce_index])); + if (!expected) { + continue; + } + CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache, NULL)); + + memcpy(&secnonce.data[0], secp256k1_musig_secnonce_magic, 4); + memcpy(&secnonce.data[4], vector->secnonces[c->secnonce_index], sizeof(secnonce.data) - 4); + { + /* In the last test vector we sign with an invalid secnonce, which + * triggers an illegal_callback. Hence, we need to use a custom + * context that does not abort in this case. */ + secp256k1_context *ctx_tmp = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + int32_t ecount = 0; + secp256k1_context_set_error_callback(ctx_tmp, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(ctx_tmp, counting_illegal_callback_fn, &ecount); + expected = c->error != MUSIG_SECNONCE; + CHECK(expected == secp256k1_musig_partial_sign(ctx_tmp, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + CHECK((!expected) == ecount); + secp256k1_context_destroy(ctx_tmp); + } + } + for (i = 0; i < sizeof(vector->verify_fail_case)/sizeof(vector->verify_fail_case[0]); i++) { + const struct musig_verify_fail_error_case *c = &vector->verify_fail_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + enum { NUM_PUBNONCES = 3 }; + secp256k1_musig_pubnonce pubnonce[NUM_PUBNONCES]; + const secp256k1_musig_pubnonce *pubnonce_ptr[NUM_PUBNONCES]; + secp256k1_pubkey pubkey; + int expected; + size_t j; + + CHECK(NUM_PUBNONCES <= c->nonce_indices_len); + for (j = 0; j < c->nonce_indices_len; j++) { + CHECK(secp256k1_musig_pubnonce_parse(ctx, &pubnonce[j], vector->pubnonces[c->nonce_indices[j]])); + pubnonce_ptr[j] = &pubnonce[j]; + } + + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, c->nonce_indices_len) == 1); + CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache, NULL)); + + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, vector->pubkeys[c->signer_index], sizeof(vector->pubkeys[0]))); + + expected = c->error != MUSIG_SIG; + CHECK(expected == secp256k1_musig_partial_sig_parse(ctx, &partial_sig, c->sig)); + if (!expected) { + continue; + } + expected = c->error != MUSIG_SIG_VERIFY; + CHECK(expected == secp256k1_musig_partial_sig_verify(ctx, &partial_sig, pubnonce, &pubkey, &keyagg_cache, &session)); + } + for (i = 0; i < sizeof(vector->verify_error_case)/sizeof(vector->verify_error_case[0]); i++) { + const struct musig_verify_fail_error_case *c = &vector->verify_error_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_pubnonce pubnonce; + int expected; + + expected = c->error != MUSIG_PUBKEY; + CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(expected || c->error == error); + if (!expected) { + continue; + } + expected = c->error != MUSIG_PUBNONCE; + CHECK(expected == secp256k1_musig_pubnonce_parse(ctx, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]])); + } +} + +void musig_test_vectors_tweak(void) { + size_t i; + const struct musig_tweak_vector *vector = &musig_tweak_vector; + secp256k1_pubkey pubkey; + secp256k1_musig_aggnonce aggnonce; 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); + CHECK(secp256k1_musig_aggnonce_parse(ctx, &aggnonce, vector->aggnonce)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_tweak_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_pubnonce pubnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + secp256k1_keypair keypair; + unsigned char partial_sig32[32]; + + memcpy(&secnonce.data[0], secp256k1_musig_secnonce_magic, 4); + memcpy(&secnonce.data[4], vector->secnonce, sizeof(secnonce.data) - 4); + + CHECK(secp256k1_keypair_create(ctx, &keypair, vector->sk)); + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + + CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, vector->msg, &keyagg_cache, NULL)); + + CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + CHECK(secp256k1_musig_partial_sig_serialize(ctx, partial_sig32, &partial_sig)); + CHECK(secp256k1_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0); + + CHECK(secp256k1_musig_pubnonce_parse(ctx, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]])); + CHECK(secp256k1_musig_partial_sig_verify(ctx, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session)); + } + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_tweak_case *c = &vector->error_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + CHECK(error == MUSIG_TWEAK); + } +} + +void musig_test_vectors_sigagg(void) { + size_t i, j; + const struct musig_sig_agg_vector *vector = &musig_sig_agg_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_sig_agg_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + unsigned char final_sig[64]; + secp256k1_musig_keyagg_cache keyagg_cache; + unsigned char agg_pk32[32]; + secp256k1_xonly_pubkey agg_pk; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; + const secp256k1_musig_partial_sig *partial_sig_ptr[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; + + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk32, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + CHECK(secp256k1_musig_aggnonce_parse(ctx, &aggnonce, c->aggnonce)); + CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, vector->msg, &keyagg_cache, NULL)); + for (j = 0; j < c->psig_indices_len; j++) { + CHECK(secp256k1_musig_partial_sig_parse(ctx, &partial_sig[j], vector->psigs[c->psig_indices[j]])); + partial_sig_ptr[j] = &partial_sig[j]; } - pk_ptr[i] = &pk[i]; + + CHECK(secp256k1_musig_partial_sig_agg(ctx, final_sig, &session, partial_sig_ptr, c->psig_indices_len) == 1); + CHECK(secp256k1_memcmp_var(final_sig, c->expected, sizeof(final_sig)) == 0); + + CHECK(secp256k1_xonly_pubkey_parse(ctx, &agg_pk, agg_pk32)); + CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, vector->msg, sizeof(vector->msg), &agg_pk) == 1); } - CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, keyagg_cache, pk_ptr, 3) == 1); - for (i = 0; i < n_tweaks; i++) { - if (is_xonly_t[i]) { - CHECK(secp256k1_musig_pubkey_xonly_tweak_add(ctx, NULL, keyagg_cache, tweak[i]) == 1); - } else { - CHECK(secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, keyagg_cache, tweak[i]) == 1); + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_sig_agg_case *c = &vector->error_case[i]; + secp256k1_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; + for (j = 0; j < c->psig_indices_len; j++) { + int expected = c->invalid_sig_idx != (int)j; + CHECK(expected == secp256k1_musig_partial_sig_parse(ctx, &partial_sig[j], vector->psigs[c->psig_indices[j]])); } } - 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, 0, 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(secp256k1_memcmp_var(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, 0, 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(secp256k1_memcmp_var(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, 0, 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(secp256k1_memcmp_var(sig, sig_expected, 32) == 0); - } - { - /* This is a test that includes an xonly 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[1][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, - }}; - int is_xonly_t[1] = { 1 }; - musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, tweak, is_xonly_t, 1, 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(secp256k1_memcmp_var(sig, sig_expected, 32) == 0); - } - { - /* This is a test that includes an ordinary public key tweak. */ - const unsigned char sig_expected[32] = { - 0x78, 0x40, 0x8D, 0xDC, 0xAB, 0x48, 0x13, 0xD1, - 0x39, 0x4C, 0x97, 0xD4, 0x93, 0xEF, 0x10, 0x84, - 0x19, 0x5C, 0x1D, 0x4B, 0x52, 0xE6, 0x3E, 0xCD, - 0x7B, 0xC5, 0x99, 0x16, 0x44, 0xE4, 0x4D, 0xDD, - }; - const unsigned char tweak[1][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, - }}; - int is_xonly_t[1] = { 0 }; - musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, tweak, is_xonly_t, 1, NULL, pk, 2); - - CHECK(musig_test_pk_parity(&keyagg_cache) == 1); - CHECK(!musig_test_is_second_pk(&keyagg_cache, sk)); - CHECK(fin_nonce_parity == 0); - CHECK(secp256k1_memcmp_var(sig, sig_expected, 32) == 0); - } - { - /* This is a test that includes an ordinary and an x-only public key tweak. */ - const unsigned char sig_expected[32] = { - 0xC3, 0xA8, 0x29, 0xA8, 0x14, 0x80, 0xE3, 0x6E, - 0xC3, 0xAB, 0x05, 0x29, 0x64, 0x50, 0x9A, 0x94, - 0xEB, 0xF3, 0x42, 0x10, 0x40, 0x3D, 0x16, 0xB2, - 0x26, 0xA6, 0xF1, 0x6E, 0xC8, 0x5B, 0x73, 0x57, - }; - - const unsigned char tweak[2][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, - }, - { - 0xAE, 0x2E, 0xA7, 0x97, 0xCC, 0x0F, 0xE7, 0x2A, - 0xC5, 0xB9, 0x7B, 0x97, 0xF3, 0xC6, 0x95, 0x7D, - 0x7E, 0x41, 0x99, 0xA1, 0x67, 0xA5, 0x8E, 0xB0, - 0x8B, 0xCA, 0xFF, 0xDA, 0x70, 0xAC, 0x04, 0x55, - }, - }; - int is_xonly_t[2] = { 0, 1 }; - musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, tweak, is_xonly_t, 2, NULL, pk, 2); - CHECK(musig_test_pk_parity(&keyagg_cache) == 0); - CHECK(!musig_test_is_second_pk(&keyagg_cache, sk)); - CHECK(fin_nonce_parity == 0); - CHECK(secp256k1_memcmp_var(sig, sig_expected, 32) == 0); - } - { - /* This is a test with four tweaks: x-only, ordinary, x-only, ordinary. */ - const unsigned char sig_expected[32] = { - 0x8C, 0x44, 0x73, 0xC6, 0xA3, 0x82, 0xBD, 0x3C, - 0x4A, 0xD7, 0xBE, 0x59, 0x81, 0x8D, 0xA5, 0xED, - 0x7C, 0xF8, 0xCE, 0xC4, 0xBC, 0x21, 0x99, 0x6C, - 0xFD, 0xA0, 0x8B, 0xB4, 0x31, 0x6B, 0x8B, 0xC7, - }; - const unsigned char tweak[4][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, - }, - { - 0xAE, 0x2E, 0xA7, 0x97, 0xCC, 0x0F, 0xE7, 0x2A, - 0xC5, 0xB9, 0x7B, 0x97, 0xF3, 0xC6, 0x95, 0x7D, - 0x7E, 0x41, 0x99, 0xA1, 0x67, 0xA5, 0x8E, 0xB0, - 0x8B, 0xCA, 0xFF, 0xDA, 0x70, 0xAC, 0x04, 0x55, - }, - { - 0xF5, 0x2E, 0xCB, 0xC5, 0x65, 0xB3, 0xD8, 0xBE, - 0xA2, 0xDF, 0xD5, 0xB7, 0x5A, 0x4F, 0x45, 0x7E, - 0x54, 0x36, 0x98, 0x09, 0x32, 0x2E, 0x41, 0x20, - 0x83, 0x16, 0x26, 0xF2, 0x90, 0xFA, 0x87, 0xE0, - }, - { - 0x19, 0x69, 0xAD, 0x73, 0xCC, 0x17, 0x7F, 0xA0, - 0xB4, 0xFC, 0xED, 0x6D, 0xF1, 0xF7, 0xBF, 0x99, - 0x07, 0xE6, 0x65, 0xFD, 0xE9, 0xBA, 0x19, 0x6A, - 0x74, 0xFE, 0xD0, 0xA3, 0xCF, 0x5A, 0xEF, 0x9D, - }, - }; - int is_xonly_t[4] = { 1, 0, 1, 0 }; - musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, tweak, is_xonly_t, 4, NULL, pk, 2); - CHECK(musig_test_pk_parity(&keyagg_cache) == 0); - CHECK(!musig_test_is_second_pk(&keyagg_cache, sk)); - CHECK(fin_nonce_parity == 1); - CHECK(secp256k1_memcmp_var(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, NULL, 0, &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(secp256k1_memcmp_var(sig, sig_expected, 32) == 0); - } } void run_musig_tests(void) { @@ -1457,7 +1313,10 @@ void run_musig_tests(void) { sha256_tag_test(); musig_test_vectors_keyagg(); musig_test_vectors_noncegen(); - musig_test_vectors_sign(); + musig_test_vectors_nonceagg(); + musig_test_vectors_signverify(); + musig_test_vectors_tweak(); + musig_test_vectors_sigagg(); secp256k1_scratch_space_destroy(ctx, scratch); } diff --git a/src/modules/musig/vectors.h b/src/modules/musig/vectors.h new file mode 100644 index 00000000..744c4050 --- /dev/null +++ b/src/modules/musig/vectors.h @@ -0,0 +1,345 @@ +/** + * Automatically generated by contrib/musig2-vectors.py. + * + * The test vectors for the KeySort function are included in this file. They can + * be found in src/modules/extrakeys/tests_impl.h. */ + +enum MUSIG_ERROR { + MUSIG_PUBKEY, + MUSIG_TWEAK, + MUSIG_PUBNONCE, + MUSIG_AGGNONCE, + MUSIG_SECNONCE, + MUSIG_SIG, + MUSIG_SIG_VERIFY, + MUSIG_OTHER +}; + +struct musig_key_agg_valid_test_case { + size_t key_indices_len; + size_t key_indices[4]; + unsigned char expected[32]; +}; + +struct musig_key_agg_error_test_case { + size_t key_indices_len; + size_t key_indices[4]; + size_t tweak_indices_len; + size_t tweak_indices[1]; + int is_xonly[1]; + enum MUSIG_ERROR error; +}; + +struct musig_key_agg_vector { + unsigned char pubkeys[7][33]; + unsigned char tweaks[2][32]; + struct musig_key_agg_valid_test_case valid_case[4]; + struct musig_key_agg_error_test_case error_case[5]; +}; + +static const struct musig_key_agg_vector musig_key_agg_vector = { + { + { 0x02, 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 }, + { 0x03, 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 }, + { 0x02, 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 }, + { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 }, + { 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 }, + { 0x04, 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 }, + { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 } + }, + { + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }, + { 0x25, 0x2E, 0x4B, 0xD6, 0x74, 0x10, 0xA7, 0x6C, 0xDF, 0x93, 0x3D, 0x30, 0xEA, 0xA1, 0x60, 0x82, 0x14, 0x03, 0x7F, 0x1B, 0x10, 0x5A, 0x01, 0x3E, 0xCC, 0xD3, 0xC5, 0xC1, 0x84, 0xA6, 0x11, 0x0B } + }, + { + { 3, { 0, 1, 2 }, { 0x90, 0x53, 0x9E, 0xED, 0xE5, 0x65, 0xF5, 0xD0, 0x54, 0xF3, 0x2C, 0xC0, 0xC2, 0x20, 0x12, 0x68, 0x89, 0xED, 0x1E, 0x5D, 0x19, 0x3B, 0xAF, 0x15, 0xAE, 0xF3, 0x44, 0xFE, 0x59, 0xD4, 0x61, 0x0C }}, + { 3, { 2, 1, 0 }, { 0x62, 0x04, 0xDE, 0x8B, 0x08, 0x34, 0x26, 0xDC, 0x6E, 0xAF, 0x95, 0x02, 0xD2, 0x70, 0x24, 0xD5, 0x3F, 0xC8, 0x26, 0xBF, 0x7D, 0x20, 0x12, 0x14, 0x8A, 0x05, 0x75, 0x43, 0x5D, 0xF5, 0x4B, 0x2B }}, + { 3, { 0, 0, 0 }, { 0xB4, 0x36, 0xE3, 0xBA, 0xD6, 0x2B, 0x8C, 0xD4, 0x09, 0x96, 0x9A, 0x22, 0x47, 0x31, 0xC1, 0x93, 0xD0, 0x51, 0x16, 0x2D, 0x8C, 0x5A, 0xE8, 0xB1, 0x09, 0x30, 0x61, 0x27, 0xDA, 0x3A, 0xA9, 0x35 }}, + { 4, { 0, 0, 1, 1 }, { 0x69, 0xBC, 0x22, 0xBF, 0xA5, 0xD1, 0x06, 0x30, 0x6E, 0x48, 0xA2, 0x06, 0x79, 0xDE, 0x1D, 0x73, 0x89, 0x38, 0x61, 0x24, 0xD0, 0x75, 0x71, 0xD0, 0xD8, 0x72, 0x68, 0x60, 0x28, 0xC2, 0x6A, 0x3E }}, + }, + { + { 2, { 0, 3 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY }, + { 2, { 0, 4 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY }, + { 2, { 5, 0 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY }, + { 2, { 0, 1 }, 1, { 0 }, { 1 }, MUSIG_TWEAK }, + { 1, { 6 }, 1, { 1 }, { 0 }, MUSIG_TWEAK }, + }, +}; + +struct musig_nonce_gen_test_case { + unsigned char rand_[32]; + int has_sk; + unsigned char sk[32]; + unsigned char pk[33]; + int has_aggpk; + unsigned char aggpk[32]; + int has_msg; + unsigned char msg[32]; + int has_extra_in; + unsigned char extra_in[32]; + unsigned char expected[97]; +}; + +struct musig_nonce_gen_vector { + struct musig_nonce_gen_test_case test_case[2]; +}; + +static const struct musig_nonce_gen_vector musig_nonce_gen_vector = { + { + { { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 1 , { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }, { 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 }, 1 , { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 }, 1 , { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, 1 , { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, { 0xB1, 0x14, 0xE5, 0x02, 0xBE, 0xAA, 0x4E, 0x30, 0x1D, 0xD0, 0x8A, 0x50, 0x26, 0x41, 0x72, 0xC8, 0x4E, 0x41, 0x65, 0x0E, 0x6C, 0xB7, 0x26, 0xB4, 0x10, 0xC0, 0x69, 0x4D, 0x59, 0xEF, 0xFB, 0x64, 0x95, 0xB5, 0xCA, 0xF2, 0x8D, 0x04, 0x5B, 0x97, 0x3D, 0x63, 0xE3, 0xC9, 0x9A, 0x44, 0xB8, 0x07, 0xBD, 0xE3, 0x75, 0xFD, 0x6C, 0xB3, 0x9E, 0x46, 0xDC, 0x4A, 0x51, 0x17, 0x08, 0xD0, 0xE9, 0xD2, 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 } }, + { { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 0 , { 0 }, { 0x02, 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 }, 0 , { 0 }, 0 , { 0 }, 0 , { 0 }, { 0x89, 0xBD, 0xD7, 0x87, 0xD0, 0x28, 0x4E, 0x5E, 0x4D, 0x5F, 0xC5, 0x72, 0xE4, 0x9E, 0x31, 0x6B, 0xAB, 0x7E, 0x21, 0xE3, 0xB1, 0x83, 0x0D, 0xE3, 0x7D, 0xFE, 0x80, 0x15, 0x6F, 0xA4, 0x1A, 0x6D, 0x0B, 0x17, 0xAE, 0x8D, 0x02, 0x4C, 0x53, 0x67, 0x96, 0x99, 0xA6, 0xFD, 0x79, 0x44, 0xD9, 0xC4, 0xA3, 0x66, 0xB5, 0x14, 0xBA, 0xF4, 0x30, 0x88, 0xE0, 0x70, 0x8B, 0x10, 0x23, 0xDD, 0x28, 0x97, 0x02, 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 } }, + }, +}; + +struct musig_nonce_agg_test_case { + size_t pnonce_indices[2]; + /* if valid case */ + unsigned char expected[66]; + /* if error case */ + int invalid_nonce_idx; +}; + +struct musig_nonce_agg_vector { + unsigned char pnonces[7][66]; + struct musig_nonce_agg_test_case valid_case[2]; + struct musig_nonce_agg_test_case error_case[3]; +}; + +static const struct musig_nonce_agg_vector musig_nonce_agg_vector = { + { + { 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x03, 0xBA, 0x47, 0xFB, 0xC1, 0x83, 0x44, 0x37, 0xB3, 0x21, 0x2E, 0x89, 0xA8, 0x4D, 0x84, 0x25, 0xE7, 0xBF, 0x12, 0xE0, 0x24, 0x5D, 0x98, 0x26, 0x22, 0x68, 0xEB, 0xDC, 0xB3, 0x85, 0xD5, 0x06, 0x41 }, + { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 }, + { 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, + { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x03, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, + { 0x04, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 }, + { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x31 }, + { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 } + }, + { + { { 0, 1 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x02, 0x47, 0x25, 0x37, 0x73, 0x45, 0xBD, 0xE0, 0xE9, 0xC3, 0x3A, 0xF3, 0xC4, 0x3C, 0x0A, 0x29, 0xA9, 0x24, 0x9F, 0x2F, 0x29, 0x56, 0xFA, 0x8C, 0xFE, 0xB5, 0x5C, 0x85, 0x73, 0xD0, 0x26, 0x2D, 0xC8 }, 0 }, + { { 2, 3 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0 }, + }, + { + { { 0, 4 }, { 0 }, 1 }, + { { 5, 1 }, { 0 }, 0 }, + { { 6, 1 }, { 0 }, 0 }, + }, +}; + +/* Omit pubnonces in the test vectors because our partial signature verification + * implementation is able to accept the aggnonce directly. */ +struct musig_valid_case { + size_t key_indices_len; + size_t key_indices[3]; + size_t aggnonce_index; + size_t msg_index; + size_t signer_index; + unsigned char expected[32]; +}; + +struct musig_sign_error_case { + size_t key_indices_len; + size_t key_indices[3]; + size_t aggnonce_index; + size_t msg_index; + size_t secnonce_index; + enum MUSIG_ERROR error; +}; + +struct musig_verify_fail_error_case { + unsigned char sig[32]; + size_t key_indices_len; + size_t key_indices[3]; + size_t nonce_indices_len; + size_t nonce_indices[3]; + size_t msg_index; + size_t signer_index; + enum MUSIG_ERROR error; +}; + +struct musig_sign_verify_vector { + unsigned char sk[32]; + unsigned char pubkeys[4][33]; + unsigned char secnonces[2][194]; + unsigned char pubnonces[5][194]; + unsigned char aggnonces[5][66]; + unsigned char msgs[1][32]; + struct musig_valid_case valid_case[4]; + struct musig_sign_error_case sign_error_case[6]; + struct musig_verify_fail_error_case verify_fail_case[3]; + struct musig_verify_fail_error_case verify_error_case[2]; +}; + +static const struct musig_sign_verify_vector musig_sign_verify_vector = { + { 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 }, + { + { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x02, 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 }, + { 0x02, 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, 0x61 }, + { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07 } + }, + { + { 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, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 } + }, + { + { 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }, + { 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, + { 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 }, + { 0x02, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x03, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }, + { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 } + }, + { + { 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 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x04, 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 }, + { 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, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09 }, + { 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, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 } + }, + { + { 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 } + }, + { + { 3, { 0, 1, 2 }, 0, 0, 0, { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }}, + { 3, { 1, 0, 2 }, 0, 0, 1, { 0x9F, 0xF2, 0xF7, 0xAA, 0xA8, 0x56, 0x15, 0x0C, 0xC8, 0x81, 0x92, 0x54, 0x21, 0x8D, 0x3A, 0xDE, 0xEB, 0x05, 0x35, 0x26, 0x90, 0x51, 0x89, 0x77, 0x24, 0xF9, 0xDB, 0x37, 0x89, 0x51, 0x3A, 0x52 }}, + { 3, { 1, 2, 0 }, 0, 0, 2, { 0xFA, 0x23, 0xC3, 0x59, 0xF6, 0xFA, 0xC4, 0xE7, 0x79, 0x6B, 0xB9, 0x3B, 0xC9, 0xF0, 0x53, 0x2A, 0x95, 0x46, 0x8C, 0x53, 0x9B, 0xA2, 0x0F, 0xF8, 0x6D, 0x7C, 0x76, 0xED, 0x92, 0x22, 0x79, 0x00 }}, + { 2, { 0, 1 }, 1, 0, 0, { 0xAE, 0x38, 0x60, 0x64, 0xB2, 0x61, 0x05, 0x40, 0x47, 0x98, 0xF7, 0x5D, 0xE2, 0xEB, 0x9A, 0xF5, 0xED, 0xA5, 0x38, 0x7B, 0x06, 0x4B, 0x83, 0xD0, 0x49, 0xCB, 0x7C, 0x5E, 0x08, 0x87, 0x95, 0x31 }}, + }, + { + { 2, { 1, 2 }, 0, 0, 0, MUSIG_PUBKEY }, + { 3, { 1, 0, 3 }, 0, 0, 0, MUSIG_PUBKEY }, + { 3, { 1, 2, 0 }, 2, 0, 0, MUSIG_AGGNONCE }, + { 3, { 1, 2, 0 }, 3, 0, 0, MUSIG_AGGNONCE }, + { 3, { 1, 2, 0 }, 4, 0, 0, MUSIG_AGGNONCE }, + { 3, { 0, 1, 2 }, 0, 0, 1, MUSIG_SECNONCE }, + }, + { + { { 0x97, 0xAC, 0x83, 0x3A, 0xDC, 0xB1, 0xAF, 0xA4, 0x2E, 0xBF, 0x9E, 0x07, 0x25, 0x61, 0x6F, 0x3C, 0x9A, 0x0D, 0x5B, 0x61, 0x4F, 0x6F, 0xE2, 0x83, 0xCE, 0xAA, 0xA3, 0x7A, 0x8F, 0xFA, 0xF4, 0x06 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG_VERIFY }, + { { 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 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 1, MUSIG_SIG_VERIFY }, + { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG }, + }, + { + { { 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 }, 3, { 0, 1, 2 }, 3, { 4, 1, 2 }, 0, 0, MUSIG_PUBNONCE }, + { { 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 }, 3, { 3, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_PUBKEY }, + }, +}; + +struct musig_tweak_case { + size_t key_indices_len; + size_t key_indices[3]; + size_t nonce_indices_len; + size_t nonce_indices[3]; + size_t tweak_indices_len; + size_t tweak_indices[4]; + int is_xonly[4]; + size_t signer_index; + unsigned char expected[32]; +}; + +struct musig_tweak_vector { + unsigned char sk[32]; + unsigned char secnonce[97]; + unsigned char aggnonce[66]; + unsigned char msg[32]; + unsigned char pubkeys[3][33]; + unsigned char pubnonces[3][194]; + unsigned char tweaks[5][32]; + struct musig_tweak_case valid_case[5]; + struct musig_tweak_case error_case[1]; +}; + +static const struct musig_tweak_vector musig_tweak_vector = { + { 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 }, + { 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, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 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 }, + { 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 }, + { + { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x02, 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 }, + { 0x02, 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 } + }, + { + { 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }, + { 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, + { 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 } + }, + { + { 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 }, + { 0xAE, 0x2E, 0xA7, 0x97, 0xCC, 0x0F, 0xE7, 0x2A, 0xC5, 0xB9, 0x7B, 0x97, 0xF3, 0xC6, 0x95, 0x7D, 0x7E, 0x41, 0x99, 0xA1, 0x67, 0xA5, 0x8E, 0xB0, 0x8B, 0xCA, 0xFF, 0xDA, 0x70, 0xAC, 0x04, 0x55 }, + { 0xF5, 0x2E, 0xCB, 0xC5, 0x65, 0xB3, 0xD8, 0xBE, 0xA2, 0xDF, 0xD5, 0xB7, 0x5A, 0x4F, 0x45, 0x7E, 0x54, 0x36, 0x98, 0x09, 0x32, 0x2E, 0x41, 0x20, 0x83, 0x16, 0x26, 0xF2, 0x90, 0xFA, 0x87, 0xE0 }, + { 0x19, 0x69, 0xAD, 0x73, 0xCC, 0x17, 0x7F, 0xA0, 0xB4, 0xFC, 0xED, 0x6D, 0xF1, 0xF7, 0xBF, 0x99, 0x07, 0xE6, 0x65, 0xFD, 0xE9, 0xBA, 0x19, 0x6A, 0x74, 0xFE, 0xD0, 0xA3, 0xCF, 0x5A, 0xEF, 0x9D }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 } + }, + { + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 1 }, 2, { 0xE2, 0x8A, 0x5C, 0x66, 0xE6, 0x1E, 0x17, 0x8C, 0x2B, 0xA1, 0x9D, 0xB7, 0x7B, 0x6C, 0xF9, 0xF7, 0xE2, 0xF0, 0xF5, 0x6C, 0x17, 0x91, 0x8C, 0xD1, 0x31, 0x35, 0xE6, 0x0C, 0xC8, 0x48, 0xFE, 0x91 }}, + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 0 }, 2, { 0x38, 0xB0, 0x76, 0x77, 0x98, 0x25, 0x2F, 0x21, 0xBF, 0x57, 0x02, 0xC4, 0x80, 0x28, 0xB0, 0x95, 0x42, 0x83, 0x20, 0xF7, 0x3A, 0x4B, 0x14, 0xDB, 0x1E, 0x25, 0xDE, 0x58, 0x54, 0x3D, 0x2D, 0x2D }}, + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 2, { 0, 1 }, { 0, 1 }, 2, { 0x40, 0x8A, 0x0A, 0x21, 0xC4, 0xA0, 0xF5, 0xDA, 0xCA, 0xF9, 0x64, 0x6A, 0xD6, 0xEB, 0x6F, 0xEC, 0xD7, 0xF7, 0xA1, 0x1F, 0x03, 0xED, 0x1F, 0x48, 0xDF, 0xFF, 0x21, 0x85, 0xBC, 0x2C, 0x24, 0x08 }}, + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 0, 0, 1, 1 }, 2, { 0x45, 0xAB, 0xD2, 0x06, 0xE6, 0x1E, 0x3D, 0xF2, 0xEC, 0x9E, 0x26, 0x4A, 0x6F, 0xEC, 0x82, 0x92, 0x14, 0x1A, 0x63, 0x3C, 0x28, 0x58, 0x63, 0x88, 0x23, 0x55, 0x41, 0xF9, 0xAD, 0xE7, 0x54, 0x35 }}, + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 1, 0, 1, 0 }, 2, { 0xB2, 0x55, 0xFD, 0xCA, 0xC2, 0x7B, 0x40, 0xC7, 0xCE, 0x78, 0x48, 0xE2, 0xD3, 0xB7, 0xBF, 0x5E, 0xA0, 0xED, 0x75, 0x6D, 0xA8, 0x15, 0x65, 0xAC, 0x80, 0x4C, 0xCC, 0xA3, 0xE1, 0xD5, 0xD2, 0x39 }}, + }, + { + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 4 }, { 0 }, 2, { 0 }}, + }, +}; + +/* Omit pubnonces in the test vectors because they're only needed for + * implementations that do not directly accept an aggnonce. */ +struct musig_sig_agg_case { + size_t key_indices_len; + size_t key_indices[2]; + size_t tweak_indices_len; + size_t tweak_indices[3]; + int is_xonly[3]; + unsigned char aggnonce[66]; + size_t psig_indices_len; + size_t psig_indices[2]; + /* if valid case */ + unsigned char expected[64]; + /* if error case */ + int invalid_sig_idx; +}; + +struct musig_sig_agg_vector { + unsigned char pubkeys[4][33]; + unsigned char tweaks[3][32]; + unsigned char psigs[9][32]; + unsigned char msg[32]; + struct musig_sig_agg_case valid_case[4]; + struct musig_sig_agg_case error_case[1]; +}; + +static const struct musig_sig_agg_vector musig_sig_agg_vector = { + { + { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x02, 0xD2, 0xDC, 0x6F, 0x5D, 0xF7, 0xC5, 0x6A, 0xCF, 0x38, 0xC7, 0xFA, 0x0A, 0xE7, 0xA7, 0x59, 0xAE, 0x30, 0xE1, 0x9B, 0x37, 0x35, 0x9D, 0xFD, 0xE0, 0x15, 0x87, 0x23, 0x24, 0xC7, 0xEF, 0x6E, 0x05 }, + { 0x03, 0xC7, 0xFB, 0x10, 0x1D, 0x97, 0xFF, 0x93, 0x0A, 0xCD, 0x0C, 0x67, 0x60, 0x85, 0x2E, 0xF6, 0x4E, 0x69, 0x08, 0x3D, 0xE0, 0xB0, 0x6A, 0xC6, 0x33, 0x57, 0x24, 0x75, 0x4B, 0xB4, 0xB0, 0x52, 0x2C }, + { 0x02, 0x35, 0x24, 0x33, 0xB2, 0x1E, 0x7E, 0x05, 0xD3, 0xB4, 0x52, 0xB8, 0x1C, 0xAE, 0x56, 0x6E, 0x06, 0xD2, 0xE0, 0x03, 0xEC, 0xE1, 0x6D, 0x10, 0x74, 0xAA, 0xBA, 0x42, 0x89, 0xE0, 0xE3, 0xD5, 0x81 } + }, + { + { 0xB5, 0x11, 0xDA, 0x49, 0x21, 0x82, 0xA9, 0x1B, 0x0F, 0xFB, 0x9A, 0x98, 0x02, 0x0D, 0x55, 0xF2, 0x60, 0xAE, 0x86, 0xD7, 0xEC, 0xBD, 0x03, 0x99, 0xC7, 0x38, 0x3D, 0x59, 0xA5, 0xF2, 0xAF, 0x7C }, + { 0xA8, 0x15, 0xFE, 0x04, 0x9E, 0xE3, 0xC5, 0xAA, 0xB6, 0x63, 0x10, 0x47, 0x7F, 0xBC, 0x8B, 0xCC, 0xCA, 0xC2, 0xF3, 0x39, 0x5F, 0x59, 0xF9, 0x21, 0xC3, 0x64, 0xAC, 0xD7, 0x8A, 0x2F, 0x48, 0xDC }, + { 0x75, 0x44, 0x8A, 0x87, 0x27, 0x4B, 0x05, 0x64, 0x68, 0xB9, 0x77, 0xBE, 0x06, 0xEB, 0x1E, 0x9F, 0x65, 0x75, 0x77, 0xB7, 0x32, 0x0B, 0x0A, 0x33, 0x76, 0xEA, 0x51, 0xFD, 0x42, 0x0D, 0x18, 0xA8 } + }, + { + { 0xB1, 0x5D, 0x2C, 0xD3, 0xC3, 0xD2, 0x2B, 0x04, 0xDA, 0xE4, 0x38, 0xCE, 0x65, 0x3F, 0x6B, 0x4E, 0xCF, 0x04, 0x2F, 0x42, 0xCF, 0xDE, 0xD7, 0xC4, 0x1B, 0x64, 0xAA, 0xF9, 0xB4, 0xAF, 0x53, 0xFB }, + { 0x61, 0x93, 0xD6, 0xAC, 0x61, 0xB3, 0x54, 0xE9, 0x10, 0x5B, 0xBD, 0xC8, 0x93, 0x7A, 0x34, 0x54, 0xA6, 0xD7, 0x05, 0xB6, 0xD5, 0x73, 0x22, 0xA5, 0xA4, 0x72, 0xA0, 0x2C, 0xE9, 0x9F, 0xCB, 0x64 }, + { 0x9A, 0x87, 0xD3, 0xB7, 0x9E, 0xC6, 0x72, 0x28, 0xCB, 0x97, 0x87, 0x8B, 0x76, 0x04, 0x9B, 0x15, 0xDB, 0xD0, 0x5B, 0x81, 0x58, 0xD1, 0x7B, 0x5B, 0x91, 0x14, 0xD3, 0xC2, 0x26, 0x88, 0x75, 0x05 }, + { 0x66, 0xF8, 0x2E, 0xA9, 0x09, 0x23, 0x68, 0x9B, 0x85, 0x5D, 0x36, 0xC6, 0xB7, 0xE0, 0x32, 0xFB, 0x99, 0x70, 0x30, 0x14, 0x81, 0xB9, 0x9E, 0x01, 0xCD, 0xB4, 0xD6, 0xAC, 0x7C, 0x34, 0x7A, 0x15 }, + { 0x4F, 0x5A, 0xEE, 0x41, 0x51, 0x08, 0x48, 0xA6, 0x44, 0x7D, 0xCD, 0x1B, 0xBC, 0x78, 0x45, 0x7E, 0xF6, 0x90, 0x24, 0x94, 0x4C, 0x87, 0xF4, 0x02, 0x50, 0xD3, 0xEF, 0x2C, 0x25, 0xD3, 0x3E, 0xFE }, + { 0xDD, 0xEF, 0x42, 0x7B, 0xBB, 0x84, 0x7C, 0xC0, 0x27, 0xBE, 0xFF, 0x4E, 0xDB, 0x01, 0x03, 0x81, 0x48, 0x91, 0x78, 0x32, 0x25, 0x3E, 0xBC, 0x35, 0x5F, 0xC3, 0x3F, 0x4A, 0x8E, 0x2F, 0xCC, 0xE4 }, + { 0x97, 0xB8, 0x90, 0xA2, 0x6C, 0x98, 0x1D, 0xA8, 0x10, 0x2D, 0x3B, 0xC2, 0x94, 0x15, 0x9D, 0x17, 0x1D, 0x72, 0x81, 0x0F, 0xDF, 0x7C, 0x6A, 0x69, 0x1D, 0xEF, 0x02, 0xF0, 0xF7, 0xAF, 0x3F, 0xDC }, + { 0x53, 0xFA, 0x9E, 0x08, 0xBA, 0x52, 0x43, 0xCB, 0xCB, 0x0D, 0x79, 0x7C, 0x5E, 0xE8, 0x3B, 0xC6, 0x72, 0x8E, 0x53, 0x9E, 0xB7, 0x6C, 0x2D, 0x0B, 0xF0, 0xF9, 0x71, 0xEE, 0x4E, 0x90, 0x99, 0x71 }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 } + }, + { 0x59, 0x9C, 0x67, 0xEA, 0x41, 0x0D, 0x00, 0x5B, 0x9D, 0xA9, 0x08, 0x17, 0xCF, 0x03, 0xED, 0x3B, 0x1C, 0x86, 0x8E, 0x4D, 0xA4, 0xED, 0xF0, 0x0A, 0x58, 0x80, 0xB0, 0x08, 0x2C, 0x23, 0x78, 0x69 }, + { + { 2, { 0, 1 }, 0, { 0 }, { 0 }, { 0x03, 0x41, 0x43, 0x27, 0x22, 0xC5, 0xCD, 0x02, 0x68, 0xD8, 0x29, 0xC7, 0x02, 0xCF, 0x0D, 0x1C, 0xBC, 0xE5, 0x70, 0x33, 0xEE, 0xD2, 0x01, 0xFD, 0x33, 0x51, 0x91, 0x38, 0x52, 0x27, 0xC3, 0x21, 0x0C, 0x03, 0xD3, 0x77, 0xF2, 0xD2, 0x58, 0xB6, 0x4A, 0xAD, 0xC0, 0xE1, 0x6F, 0x26, 0x46, 0x23, 0x23, 0xD7, 0x01, 0xD2, 0x86, 0x04, 0x6A, 0x2E, 0xA9, 0x33, 0x65, 0x65, 0x6A, 0xFD, 0x98, 0x75, 0x98, 0x2B }, 2, { 0, 1 }, { 0x04, 0x1D, 0xA2, 0x22, 0x23, 0xCE, 0x65, 0xC9, 0x2C, 0x9A, 0x0D, 0x6C, 0x2C, 0xAC, 0x82, 0x8A, 0xAF, 0x1E, 0xEE, 0x56, 0x30, 0x4F, 0xEC, 0x37, 0x1D, 0xDF, 0x91, 0xEB, 0xB2, 0xB9, 0xEF, 0x09, 0x12, 0xF1, 0x03, 0x80, 0x25, 0x85, 0x7F, 0xED, 0xEB, 0x3F, 0xF6, 0x96, 0xF8, 0xB9, 0x9F, 0xA4, 0xBB, 0x2C, 0x58, 0x12, 0xF6, 0x09, 0x5A, 0x2E, 0x00, 0x04, 0xEC, 0x99, 0xCE, 0x18, 0xDE, 0x1E }, 0 }, + { 2, { 0, 2 }, 0, { 0 }, { 0 }, { 0x02, 0x24, 0xAF, 0xD3, 0x6C, 0x90, 0x20, 0x84, 0x05, 0x8B, 0x51, 0xB5, 0xD3, 0x66, 0x76, 0xBB, 0xA4, 0xDC, 0x97, 0xC7, 0x75, 0x87, 0x37, 0x68, 0xE5, 0x88, 0x22, 0xF8, 0x7F, 0xE4, 0x37, 0xD7, 0x92, 0x02, 0x8C, 0xB1, 0x59, 0x29, 0x09, 0x9E, 0xEE, 0x2F, 0x5D, 0xAE, 0x40, 0x4C, 0xD3, 0x93, 0x57, 0x59, 0x1B, 0xA3, 0x2E, 0x9A, 0xF4, 0xE1, 0x62, 0xB8, 0xD3, 0xE7, 0xCB, 0x5E, 0xFE, 0x31, 0xCB, 0x20 }, 2, { 2, 3 }, { 0x10, 0x69, 0xB6, 0x7E, 0xC3, 0xD2, 0xF3, 0xC7, 0xC0, 0x82, 0x91, 0xAC, 0xCB, 0x17, 0xA9, 0xC9, 0xB8, 0xF2, 0x81, 0x9A, 0x52, 0xEB, 0x5D, 0xF8, 0x72, 0x6E, 0x17, 0xE7, 0xD6, 0xB5, 0x2E, 0x9F, 0x01, 0x80, 0x02, 0x60, 0xA7, 0xE9, 0xDA, 0xC4, 0x50, 0xF4, 0xBE, 0x52, 0x2D, 0xE4, 0xCE, 0x12, 0xBA, 0x91, 0xAE, 0xAF, 0x2B, 0x42, 0x79, 0x21, 0x9E, 0xF7, 0x4B, 0xE1, 0xD2, 0x86, 0xAD, 0xD9 }, 0 }, + { 2, { 0, 2 }, 1, { 0 }, { 0 }, { 0x02, 0x08, 0xC5, 0xC4, 0x38, 0xC7, 0x10, 0xF4, 0xF9, 0x6A, 0x61, 0xE9, 0xFF, 0x3C, 0x37, 0x75, 0x88, 0x14, 0xB8, 0xC3, 0xAE, 0x12, 0xBF, 0xEA, 0x0E, 0xD2, 0xC8, 0x7F, 0xF6, 0x95, 0x4F, 0xF1, 0x86, 0x02, 0x0B, 0x18, 0x16, 0xEA, 0x10, 0x4B, 0x4F, 0xCA, 0x2D, 0x30, 0x4D, 0x73, 0x3E, 0x0E, 0x19, 0xCE, 0xAD, 0x51, 0x30, 0x3F, 0xF6, 0x42, 0x0B, 0xFD, 0x22, 0x23, 0x35, 0xCA, 0xA4, 0x02, 0x91, 0x6D }, 2, { 4, 5 }, { 0x5C, 0x55, 0x8E, 0x1D, 0xCA, 0xDE, 0x86, 0xDA, 0x0B, 0x2F, 0x02, 0x62, 0x6A, 0x51, 0x2E, 0x30, 0xA2, 0x2C, 0xF5, 0x25, 0x5C, 0xAE, 0xA7, 0xEE, 0x32, 0xC3, 0x8E, 0x9A, 0x71, 0xA0, 0xE9, 0x14, 0x8B, 0xA6, 0xC0, 0xE6, 0xEC, 0x76, 0x83, 0xB6, 0x42, 0x20, 0xF0, 0x29, 0x86, 0x96, 0xF1, 0xB8, 0x78, 0xCD, 0x47, 0xB1, 0x07, 0xB8, 0x1F, 0x71, 0x88, 0x81, 0x2D, 0x59, 0x39, 0x71, 0xE0, 0xCC }, 0 }, + { 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 6, 7 }, { 0x83, 0x9B, 0x08, 0x82, 0x0B, 0x68, 0x1D, 0xBA, 0x8D, 0xAF, 0x4C, 0xC7, 0xB1, 0x04, 0xE8, 0xF2, 0x63, 0x8F, 0x93, 0x88, 0xF8, 0xD7, 0xA5, 0x55, 0xDC, 0x17, 0xB6, 0xE6, 0x97, 0x1D, 0x74, 0x26, 0xCE, 0x07, 0xBF, 0x6A, 0xB0, 0x1F, 0x1D, 0xB5, 0x0E, 0x4E, 0x33, 0x71, 0x92, 0x95, 0xF4, 0x09, 0x45, 0x72, 0xB7, 0x98, 0x68, 0xE4, 0x40, 0xFB, 0x3D, 0xEF, 0xD3, 0xFA, 0xC1, 0xDB, 0x58, 0x9E }, 0 }, + }, + { + { 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 7, 8 }, { 0 }, 1 }, + }, +}; +enum { MUSIG_VECTORS_MAX_PUBKEYS = 7 }; diff --git a/src/valgrind_ctime_test.c b/src/valgrind_ctime_test.c index 4fe93ef8..92ebac22 100644 --- a/src/valgrind_ctime_test.c +++ b/src/valgrind_ctime_test.c @@ -249,8 +249,8 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) { #ifdef ENABLE_MODULE_MUSIG { - secp256k1_xonly_pubkey pk; - const secp256k1_xonly_pubkey *pk_ptr[1]; + secp256k1_pubkey pk; + const secp256k1_pubkey *pk_ptr[1]; secp256k1_xonly_pubkey agg_pk; unsigned char session_id[32]; secp256k1_musig_secnonce secnonce; @@ -279,14 +279,14 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) { partial_sig_ptr[0] = &partial_sig; CHECK(secp256k1_keypair_create(ctx, &keypair, key)); - CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair)); + CHECK(secp256k1_keypair_pub(ctx, &pk, &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); + ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_id, key, &pk, msg, &cache, extra_input); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); CHECK(ret == 1); CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1));