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