mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-10 09:06:15 +01:00
0cdc758a563 Merge bitcoin-core/secp256k1#1631: release: prepare for 0.6.0 39d5dfd542a release: prepare for 0.6.0 df2eceb2790 build: add ellswift.md and musig.md to release tarball a306bb7e903 tools: fix check-abi.sh after cmake out locations were changed 145868a84d2 Do not export `secp256k1_musig_nonce_gen_internal` b161bffb8bf Merge bitcoin-core/secp256k1#1579: Clear sensitive memory without getting optimized out (revival of #636) a38d879a1a6 Merge bitcoin-core/secp256k1#1628: Name public API structs 7d48f5ed02e Merge bitcoin-core/secp256k1#1581: test, ci: Lower default iteration count to 16 694342fdb71 Name public API structs 0f73caf7c62 test, ci: Lower default iteration count to 16 9a8db52f4e9 Merge bitcoin-core/secp256k1#1582: cmake, test: Add `secp256k1_` prefix to test names 765ef53335a Clear _gej instances after point multiplication to avoid potential leaks 349e6ab916b Introduce separate _clear functions for hash module 99cc9fd6d01 Don't rely on memset to set signed integers to 0 97c57f42ba8 Implement various _clear() functions with secp256k1_memclear() 9bb368d1466 Use secp256k1_memclear() to clear stack memory instead of memset() e3497bbf001 Separate between clearing memory and setting to zero in tests d79a6ccd43a Separate secp256k1_fe_set_int( . , 0 ) from secp256k1_fe_clear() 1c081262227 Add secp256k1_memclear() for clearing secret data 1464f15c812 Merge bitcoin-core/secp256k1#1625: util: Remove unused (u)int64_t formatting macros 980c08df80a util: Remove unused (u)int64_t formatting macros 9b7c59cbb90 Merge bitcoin-core/secp256k1#1624: ci: Update macOS image 096e3e23f63 ci: Update macOS image e7d384488e8 Don't clear secrets in pippenger implementation 68b55209f1b Merge bitcoin-core/secp256k1#1619: musig: ctimetests: fix _declassify range for generated nonce points f0868a9b3d8 Merge bitcoin-core/secp256k1#1595: build: 45839th attempt to fix symbol visibility on Windows 1fae76f50c0 Merge bitcoin-core/secp256k1#1620: Remove unused scratch space from API 8be3839fb2e Remove unused scratch space from API 57eda3ba300 musig: ctimetests: fix _declassify range for generated nonce points 87384f5c0f2 cmake, test: Add `secp256k1_` prefix to test names e59158b6eb7 Merge bitcoin-core/secp256k1#1553: cmake: Set top-level target output locations 18f9b967c25 Merge bitcoin-core/secp256k1#1616: examples: do not retry generating seckey randomness in musig 5bab8f6d3c4 examples: make key generation doc consistent e8908221a45 examples: do not retry generating seckey randomness in musig 70b6be1834e extrakeys: improve doc of keypair_create (don't suggest retry) 01b5893389e Merge bitcoin-core/secp256k1#1599: #1570 improve examples: remove key generation loop cd4f84f3ba8 Improve examples/documentation: remove key generation loops a88aa935063 Merge bitcoin-core/secp256k1#1603: f can never equal -m 3660fe5e2a9 Merge bitcoin-core/secp256k1#1479: Add module "musig" that implements MuSig2 multi-signatures (BIP 327) 168c92011f5 build: allow enabling the musig module in cmake f411841a46b Add module "musig" that implements MuSig2 multi-signatures (BIP 327) 0be79660f38 util: add constant-time is_zero_array function c8fbdb1b972 group: add ge_to_bytes_ext and ge_from_bytes_ext ef7ff03407f f can never equal -m c232486d84e Revert "cmake: Set `ENVIRONMENT` property for examples on Windows" 26e4a7c2146 cmake: Set top-level target output locations 4c57c7a5a95 Merge bitcoin-core/secp256k1#1554: cmake: Clean up testing code 447334cb06d include: Avoid visibility("default") on Windows 472faaa8ee6 Merge bitcoin-core/secp256k1#1604: doc: fix typos in `secp256k1_ecdsa_{recoverable_,}signature` API description 292310fbb24 doc: fix typos in `secp256k1_ecdsa_{recoverable_,}signature` API description 85e224dd97f group: add ge_to_bytes and ge_from_bytes 7c987ec89e6 cmake: Call `enable_testing()` unconditionally 6aa576515ef cmake: Delete `CTest` module git-subtree-dir: src/secp256k1 git-subtree-split: 0cdc758a56360bf58a851fe91085a327ec97685a
656 lines
18 KiB
Python
Executable file
656 lines
18 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
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_secnonce[97];
|
|
unsigned char expected_pubnonce[66];
|
|
};
|
|
"""
|
|
|
|
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 }, { %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_secnonce"]),
|
|
hexstr_to_intarray(case["expected_pubnonce"]),
|
|
),
|
|
)
|
|
|
|
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)
|