1"""Gate: signatures produced by the Rust engines (libsecp256k1 via rust-secp256k1, RustCrypto k256)2must verify under the pure-Python exact-arithmetic references src/wp34/{ecdsa,schnorr}.py, and the3Python references must re-derive the same deterministic signatures byte for byte.45The triples are written by experiments/signature_benchmarks/sigbench (--crosscheck-out) through6run_bench.py into results/signature_benchmarks/crosscheck_triples_<host>.json. If no such file7exists the test builds the crate and generates a small set itself.8"""9import json, pathlib, subprocess, sys1011import pytest1213ROOT = pathlib.Path(__file__).resolve().parents[1]14sys.path.insert(0, str(ROOT / "src"))15sys.path.insert(0, str(ROOT / "experiments" / "signature_benchmarks"))16from python_crosscheck import crosscheck # noqa: E40217from wp34 import schnorr as B # noqa: E4021819RESULTS = ROOT / "results" / "signature_benchmarks"20CRATE = ROOT / "experiments" / "signature_benchmarks" / "sigbench"212223def _triples_file(tmp_path_factory) -> pathlib.Path:24 files = sorted(RESULTS.glob("crosscheck_triples_*.json")) if RESULTS.exists() else []25 if files:26 return files[0]27 binary = CRATE / "target" / "release" / "sigbench"28 if not binary.exists():29 subprocess.run(["cargo", "build", "--release"], cwd=CRATE, check=True)30 out = tmp_path_factory.mktemp("sig") / "triples.json"31 subprocess.run([str(binary), "--vectors", str(ROOT / "data/vectors/bip340_test_vectors.csv"),32 "--reps", "1", "--batch-ops", "50", "--batch-min-sigs", "50", "--batch-sizes", "1,4",33 "--crosscheck-n", "40", "--python-crosscheck-n", "40", "--bootstrap", "10",34 "--crosscheck-out", str(out)], check=True, capture_output=True)35 return out363738@pytest.fixture(scope="module")39def triples(tmp_path_factory):40 return _triples_file(tmp_path_factory)414243def test_rust_signatures_verify_under_python_reference(triples):44 c = crosscheck(triples, resign=True)45 n = c["n"]46 assert n >= 4047 assert c["ecdsa_k256_sig_verified_by_python"] == n48 assert c["ecdsa_libsecp_sig_verified_by_python"] == n49 assert c["schnorr_k256_sig_verified_by_python"] == n50 assert c["schnorr_libsecp_sig_verified_by_python"] == n51 # deterministic nonces: RFC 6979 (ECDSA) and BIP340 aux-rand nonce derivation -> identical bytes52 assert c["ecdsa_python_resign_identical"] == n53 assert c["schnorr_python_resign_identical"] == n54 # negative control: one flipped bit must be rejected by the reference55 assert c["tampered_sig_rejected_by_python"] == n56 assert c["all_pass"]575859def test_bip340_vectors_python_reference():60 """The Python reference itself must agree with the official BIP340 vectors (independent of Rust)."""61 rows = (ROOT / "data/vectors/bip340_test_vectors.csv").read_text().splitlines()[1:]62 n_checked = 063 for row in rows:64 f = row.split(",")65 pk, msg, sig, expected = bytes.fromhex(f[2]), bytes.fromhex(f[4]), bytes.fromhex(f[5]), f[6] == "TRUE"66 assert B.verify(msg, pk, sig) == expected, f"vector {f[0]}: {f[7]}"67 if f[1]:68 assert B.sign(msg, bytes.fromhex(f[1]), bytes.fromhex(f[3])) == sig, f"vector {f[0]} sign"69 n_checked += 170 assert n_checked == 1971