mirror of
https://github.com/bitcoin/bips.git
synced 2026-11-02 19:41:29 +00:00
162 lines
5.0 KiB
Python
162 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Run test vectors for Schnorr signature half-aggregation.
|
|
|
|
Usage:
|
|
python run_test_vectors.py
|
|
|
|
Expects CSV files generated by gen_test_vectors.py in vectors/ directory.
|
|
"""
|
|
|
|
import csv
|
|
import os
|
|
from pathlib import Path
|
|
import sys
|
|
from typing import List, Tuple
|
|
|
|
from halfagg import Aggregate, IncAggregate, VerifyAggregate
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parent
|
|
VECTORS_DIR = ROOT / "vectors"
|
|
AGGREGATE_VECTORS = VECTORS_DIR / 'test_vectors_aggregate.csv'
|
|
INCAGGREGATE_VECTORS = VECTORS_DIR / 'test_vectors_incaggregate.csv'
|
|
VERIFY_VECTORS = VECTORS_DIR / 'test_vectors_verify.csv'
|
|
|
|
|
|
def parse_hex_list(hex_str: str) -> List[bytes]:
|
|
if not hex_str:
|
|
return []
|
|
return [bytes.fromhex(h) for h in hex_str.split(';')]
|
|
|
|
|
|
def parse_pms(pks_str: str, msgs_str: str, sigs_str: str) -> List[Tuple[bytes, bytes, bytes]]:
|
|
pks = parse_hex_list(pks_str)
|
|
msgs = parse_hex_list(msgs_str)
|
|
sigs = parse_hex_list(sigs_str)
|
|
if not pks:
|
|
return []
|
|
return list(zip(pks, msgs, sigs))
|
|
|
|
|
|
def parse_pm(pks_str: str, msgs_str: str) -> List[Tuple[bytes, bytes]]:
|
|
pks = parse_hex_list(pks_str)
|
|
msgs = parse_hex_list(msgs_str)
|
|
if not pks:
|
|
return []
|
|
return list(zip(pks, msgs))
|
|
|
|
|
|
def run_aggregate_tests() -> List[str]:
|
|
"""Run Aggregate test vectors. Returns list of failed test descriptions."""
|
|
failures = []
|
|
|
|
with open(AGGREGATE_VECTORS, newline='', encoding='utf-8') as f:
|
|
reader = csv.reader(f)
|
|
next(reader)
|
|
|
|
for row in reader:
|
|
index, pks_str, msgs_str, sigs_str, expected_result, expected_aggsig, comment = row
|
|
pms = parse_pms(pks_str, msgs_str, sigs_str)
|
|
|
|
if expected_result == "FALSE":
|
|
try:
|
|
Aggregate(pms)
|
|
failures.append(f"Aggregate #{index}: {comment}")
|
|
except ValueError:
|
|
pass
|
|
else:
|
|
try:
|
|
actual = Aggregate(pms)
|
|
if actual != bytes.fromhex(expected_aggsig):
|
|
failures.append(f"Aggregate #{index}: {comment}")
|
|
except ValueError:
|
|
failures.append(f"Aggregate #{index}: {comment}")
|
|
|
|
return failures
|
|
|
|
|
|
def run_incaggregate_tests() -> List[str]:
|
|
"""Run IncAggregate test vectors. Returns list of failed test descriptions."""
|
|
failures = []
|
|
|
|
with open(INCAGGREGATE_VECTORS, newline='', encoding='utf-8') as f:
|
|
reader = csv.reader(f)
|
|
next(reader)
|
|
|
|
for row in reader:
|
|
(index, aggsig_str, pm_pks_str, pm_msgs_str,
|
|
pms_pks_str, pms_msgs_str, pms_sigs_str,
|
|
expected_result, expected_aggsig, comment) = row
|
|
|
|
aggsig = bytes.fromhex(aggsig_str) if aggsig_str else bytes()
|
|
pm_aggd = parse_pm(pm_pks_str, pm_msgs_str)
|
|
pms_to_agg = parse_pms(pms_pks_str, pms_msgs_str, pms_sigs_str)
|
|
|
|
if expected_result == "FALSE":
|
|
try:
|
|
IncAggregate(aggsig, pm_aggd, pms_to_agg)
|
|
failures.append(f"IncAggregate #{index}: {comment}")
|
|
except ValueError:
|
|
pass
|
|
else:
|
|
try:
|
|
actual = IncAggregate(aggsig, pm_aggd, pms_to_agg)
|
|
if actual != bytes.fromhex(expected_aggsig):
|
|
failures.append(f"IncAggregate #{index}: {comment}")
|
|
except ValueError:
|
|
failures.append(f"IncAggregate #{index}: {comment}")
|
|
|
|
return failures
|
|
|
|
|
|
def run_verify_tests() -> List[str]:
|
|
"""Run VerifyAggregate test vectors. Returns list of failed test descriptions."""
|
|
failures = []
|
|
|
|
with open(VERIFY_VECTORS, newline='', encoding='utf-8') as f:
|
|
reader = csv.reader(f)
|
|
next(reader)
|
|
|
|
for row in reader:
|
|
index, aggsig_str, pks_str, msgs_str, expected_result, comment = row
|
|
|
|
aggsig = bytes.fromhex(aggsig_str)
|
|
pm = parse_pm(pks_str, msgs_str)
|
|
|
|
try:
|
|
result = VerifyAggregate(aggsig, pm)
|
|
expected = (expected_result == "TRUE")
|
|
if result != expected:
|
|
failures.append(f"VerifyAggregate #{index}: {comment}")
|
|
except ValueError:
|
|
if expected_result == "TRUE":
|
|
failures.append(f"VerifyAggregate #{index}: {comment}")
|
|
|
|
return failures
|
|
|
|
|
|
def main():
|
|
for filename in [AGGREGATE_VECTORS, INCAGGREGATE_VECTORS, VERIFY_VECTORS]:
|
|
if not os.path.exists(filename):
|
|
print(f"ERROR: Missing {filename}. Run gen_test_vectors.py first.")
|
|
sys.exit(1)
|
|
|
|
failures = []
|
|
failures.extend(run_aggregate_tests())
|
|
failures.extend(run_incaggregate_tests())
|
|
failures.extend(run_verify_tests())
|
|
|
|
if failures:
|
|
print("FAILED:")
|
|
for f in failures:
|
|
print(f" {f}")
|
|
sys.exit(1)
|
|
else:
|
|
print("All tests have passed.")
|
|
sys.exit(0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|