#!/usr/bin/env python3
# MIT licence — Knipsoft, 2026. Verifies a Backgammon Duo fair-dice record.
#   python3 fairdice_verify.py record.txt
# or: python3 fairdice_verify.py --commit HEX --seed HEX --skipped N --rolls "3-1 5-2 6-6"
import hashlib, hmac, re, sys

def roll(seed: bytes, i: int):
    h = hmac.new(seed, f"roll:{i}".encode(), hashlib.sha256).digest()
    d = []
    for b in h:
        if b >= 252:
            continue            # skip so every face is exactly as likely
        d.append(1 + b % 6)
        if len(d) == 2:
            break
    return d

def verify(commit: str, seed_hex: str, skipped: int, rolls):
    seed = bytes.fromhex(seed_hex)
    ok = True
    h = hashlib.sha256(seed).hexdigest()
    print(f"SHA-256(seed) = {h}")
    print("ok: matches the commitment" if h == commit.lower() else "FAIL: does not match the commitment")
    ok &= h == commit.lower()
    for j in range(skipped):
        d = roll(seed, j)
        if d[0] != d[1]:
            print(f"FAIL: skipped opening roll {j} was {d[0]}-{d[1]}, not a tie"); ok = False
    for n, (a, b) in enumerate(rolls):
        d = roll(seed, skipped + n)
        same = d == [a, b]
        ok &= same
        print(f"{'ok  ' if same else 'FAIL'} roll {n + 1}: derived {d[0]}-{d[1]}, played {a}-{b}")
    print("\nRESULT:", "every roll was fixed by the seed committed to before the first move." if ok else "this record does not verify.")
    return ok

if __name__ == "__main__":
    a = sys.argv[1:]
    if len(a) == 1:
        text = open(a[0]).read()
        g = lambda rx: (re.search(rx, text) or [None, ""])[1].strip()
        commit, seed, skipped = g(r"commitment:\s*([0-9a-fA-F]+)"), g(r"seed:\s*([0-9a-fA-F]+)"), int(g(r"skipped[^:]*:\s*(\d+)") or 0)
        rolls = [tuple(map(int, t.split("-"))) for t in g(r"rolls:\s*([\d\- ]+)").split()]
    else:
        kv = dict(zip(a[0::2], a[1::2]))
        commit, seed, skipped = kv["--commit"], kv["--seed"], int(kv.get("--skipped", 0))
        rolls = [tuple(map(int, t.split("-"))) for t in kv.get("--rolls", "").split()]
    sys.exit(0 if verify(commit, seed, skipped, rolls) else 1)
