#!/usr/bin/env python3
"""
verify.py - check a sebbi.pro compliance state proof with no sebbi.pro involved.
Standard library only.

    python3 verify.py proof.json

Get proof.json from the JSON link on any proof page. What it checks:
  - each control's leaf hashes up its Merkle path to the state root
  - each state root hashes to its sealed link (owner, seq, time, root, previous link)
  - in a period proof, every link chains to the one before with no gaps
Then look up the block numbers at https://sebbi.pro/forever (or your own
anchored copy) to confirm the links were sealed when the proof says.
"""
import hashlib, json, sys

def H(s): return hashlib.sha256(s.encode("utf-8")).hexdigest()
def canon(o): return json.dumps(o, sort_keys=True, separators=(",", ":"))

def root_from(leaf, path):
    h = H("L" + canon(leaf))
    for p in path:
        h = H("N" + p["hash"] + h) if p["side"] == "L" else H("N" + h + p["hash"])
    return h

def link_of(owner, p):
    return H(canon({"owner": owner, "seq": p["seq"], "ts": p["ts"], "root": p["root"], "prev": p["prev"]}))

def check_point(owner, p):
    if not p.get("leaf"): return True, "control not in the file at that point (nothing to prove)"
    if root_from(p["leaf"], p["path"]) != p["root"]: return False, "path does not lead to the root"
    if link_of(owner, p) != p["link"]: return False, "root is not the sealed link"
    return True, "ok"

def main(f):
    d = json.load(open(f))
    owner = d["owner"]
    pts = d.get("points") or ([d["point"]] if d.get("point") else d.get("items") or [])
    good, passing = True, True
    for i, p in enumerate(pts):
        ok, why = check_point(owner, p)
        if d["kind"] == "period" and i and p["prev"] != pts[i - 1]["link"]:
            ok, why = False, "gap: link does not follow the previous one"
        leaf = p.get("leaf") or {}
        st = leaf.get("v", "-") + "/" + leaf.get("s", "-")
        passing = passing and leaf.get("v") == "PASS" and leaf.get("s") == "OK"
        print("%s  seq %s  block %s  %s  %s" % ("VALID  " if ok else "INVALID", p["seq"], p.get("block"), st, why))
        good = good and ok
    print("\nPROOF: " + ("VALID - every part hashes to its sealed link" if good else "INVALID - do not rely on it"))
    if good and d["kind"] in ("point", "period"):
        print("STATUS: " + ("the control was passing at every point shown" if passing else "the control was NOT passing at every point shown"))
    sys.exit(0 if good else 1)

if __name__ == "__main__":
    main(sys.argv[1] if len(sys.argv) > 1 else "proof.json")
