655 lines
18 KiB
Python
655 lines
18 KiB
Python
|
#!/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)
|