SPB Git

spb/wp34_uqo

Public
3.3 KB · 73 lines python
1"""Cross-check Rust-produced (seckey, msg, sig) triples against the pure-Python references2`wp34.ecdsa` and `wp34.schnorr` (exact arithmetic). Used by run_bench.py (pass counts go into the3results JSON) and by tests/test_sig_crosscheck.py (pytest gate).45Usage: PYTHONPATH=src python experiments/signature_benchmarks/python_crosscheck.py <triples.json>6"""7from __future__ import annotations8import json, sys, time9from pathlib import Path1011ROOT = Path(__file__).resolve().parents[2]12sys.path.insert(0, str(ROOT / "src"))13from wp34 import ecdsa as D, schnorr as B  # noqa: E402141516def crosscheck(path: str | Path, resign: bool = True) -> dict:17    doc = json.loads(Path(path).read_text())18    items = doc["items"]19    n = len(items)20    c = {21        "n": n, "source": str(path),22        "ecdsa_k256_sig_verified_by_python": 0, "ecdsa_libsecp_sig_verified_by_python": 0,23        "ecdsa_python_resign_identical": 0,24        "schnorr_k256_sig_verified_by_python": 0, "schnorr_libsecp_sig_verified_by_python": 0,25        "schnorr_python_resign_identical": 0,26        "tampered_sig_rejected_by_python": 0,27    }28    t0 = time.time()29    for it in items:30        d = int(it["seckey"], 16)31        msg = bytes.fromhex(it["msg"])32        aux = bytes.fromhex(it["aux_rand"])33        pub = bytes.fromhex(it["pubkey_uncompressed"])34        Q = (int.from_bytes(pub[1:33], "big"), int.from_bytes(pub[33:65], "big"))35        for key, cnt in (("ecdsa_sig_k256", "ecdsa_k256_sig_verified_by_python"),36                         ("ecdsa_sig_libsecp256k1", "ecdsa_libsecp_sig_verified_by_python")):37            sig = bytes.fromhex(it[key])38            r, s = int.from_bytes(sig[:32], "big"), int.from_bytes(sig[32:], "big")39            if D.verify(Q, msg, (r, s)):40                c[cnt] += 141        if resign:42            r, s = D.sign(d, msg)  # RFC 6979, low-S43            if r.to_bytes(32, "big") + s.to_bytes(32, "big") == bytes.fromhex(it["ecdsa_sig_k256"]):44                c["ecdsa_python_resign_identical"] += 145        pkx = bytes.fromhex(it["pubkey_xonly"])46        for key, cnt in (("schnorr_sig_k256", "schnorr_k256_sig_verified_by_python"),47                         ("schnorr_sig_libsecp256k1", "schnorr_libsecp_sig_verified_by_python")):48            sig = bytes.fromhex(it[key])49            if B.verify(msg, pkx, sig):50                c[cnt] += 151        if resign:52            sig = B.sign(msg, d.to_bytes(32, "big"), aux)53            if sig == bytes.fromhex(it["schnorr_sig_k256"]):54                c["schnorr_python_resign_identical"] += 155        # negative control: flip one bit of s -> Python must reject56        sig = bytearray(bytes.fromhex(it["schnorr_sig_libsecp256k1"]))57        sig[63] ^= 0x0158        if not B.verify(msg, pkx, bytes(sig)):59            c["tampered_sig_rejected_by_python"] += 160    c["elapsed_s"] = round(time.time() - t0, 2)61    c["resign_checked"] = resign62    keys = ["ecdsa_k256_sig_verified_by_python", "ecdsa_libsecp_sig_verified_by_python",63            "schnorr_k256_sig_verified_by_python", "schnorr_libsecp_sig_verified_by_python",64            "tampered_sig_rejected_by_python"]65    if resign:66        keys += ["ecdsa_python_resign_identical", "schnorr_python_resign_identical"]67    c["all_pass"] = all(c[k] == n for k in keys)68    return c697071if __name__ == "__main__":72    print(json.dumps(crosscheck(sys.argv[1]), indent=1))73
Files · c732f7e320257301eb619a8227b914374a41aac4
Menu

Theme