Merge ElementsProject/secp256k1-zkp#211: Update musig module to BIP MuSig2 v1.0.0-rc.3

b43dd83b43eac0ca8ad9ee1f557e9126c9e08d9e musig: add missing static keyword to function (Jonas Nick)
068e6a036a953e48bc90f9a96b318e350f474a3a musig: add test vectors from BIP MuSig (Jonas Nick)
36621d13bedf44eeedd2a1773e30e849972e5bff musig: update to BIP v1.0.0-rc.2 "Add ''pk'' arg to ''NonceGen''" (Jonas Nick)
d717a4980bc3e2e36bd32a02466226ef49a5d625 musig: update to BIP v0.8 "Switch from X-only to plain pk inputs." (Jonas Nick)
304f1bc96d6bdb5c1b5b1b9a321eac8f9a27fde4 extrakeys: add pubkey_sort test vectors from BIP MuSig2 (Jonas Nick)
ae89051547435cab5042a13d85562def9cabdd61 extrakeys: replace xonly_sort with pubkey_sort (Jonas Nick)
98242fcdd9519d0d5a349b0344aeea0ab4e796e9 extrakeys: add secp256k1_pubkey_cmp (Jonas Nick)
73d5b6654d472eb0cebbffd5a934caf174d29307 musig: update to BIP v0.7.0 (NonceGen) (Jonas Nick)
060887e9d749062242b4de3935b27fdcb0802c87 musig: update to BIP v0.5.1 "Rename ordinary tweaking to plain" (Jonas Nick)
cbe2815633411479e8305deb8b69bce94df723af musig: update to BIP v0.4 "Allow the output of NonceAgg to be inf" (Jonas Nick)
206017d67d9bb8b21d5cc924ba53e1618274774c musig: update to BIP v0.3 (NonceGen) (Jonas Nick)
d800dd55db28a710bb510a2a5fc33519d355a91c musig: remove test vectors (Jonas Nick)

Pull request description:

  Version 1.0.0-rc.3 of BIP MuSig2 can be found [here](https://github.com/jonasnick/bips/pull/75). This PR does _not_ implement the following optional features that have been added to BIP MuSig2:

  - variable length messages
  - deterministic signing
  - identifiable aborts

  The PR also does _not_ yet change the `secnonce` structure to also contain the signer's public key (which would also imply changing the seckey argument in `sign` to a keypair). Additionally, we may want to rename some things in the future to be more consistent with the BIP (e.g. keyagg_cache vs. keyagg_ctx, applytweak vs. tweak_add).

ACKs for top commit:
  ariard:
    Light Code Review ACK b43dd83b, mostly looks on how the user API will make sense for Lightning, thanks for the answers!
  real-or-random:
    ACK b43dd83b43eac0ca8ad9ee1f557e9126c9e08d9e

Tree-SHA512: 9b1410951b55a1b0e6590b8c302052996d1fb6d9771765498b4282ff68b44ab0d6add8144c9330217b682ec5a93508b5546099db9a1f2c865f99253010dd76f4
This commit is contained in:
Tim Ruffing 2023-03-02 15:19:44 +01:00
commit 4f57024d86
No known key found for this signature in database
GPG Key ID: 8C461CCD293F6011
13 changed files with 1880 additions and 788 deletions

654
contrib/musig2-vectors.py Executable file
View File

@ -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 <dir>" % 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)

View File

@ -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!";

View File

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

View File

@ -9,11 +9,9 @@ extern "C" {
#include <stddef.h>
/** 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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

345
src/modules/musig/vectors.h Normal file
View File

@ -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 };

View File

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