#!/usr/bin/env python3
"""Verify a QBUNKER seal with nothing but Python's hashlib (no QBUNKER code, no elliptic curves).
usage: python3 qbunker_verify.py <wallet>   (fetches https://qbunker.click/api/bunker/<wallet>)
   or: python3 qbunker_verify.py proof.json
"""
import hashlib, json, struct, sys, urllib.request
H = lambda *a: hashlib.sha256(b''.join(a)).digest()
def adrs(t, key=0, chain=0, step=0, height=0, index=0): return struct.pack('>6I', t, key, chain, step, height, index) + b'\0' * 8
arg = sys.argv[1]
data = json.load(open(arg)) if arg.endswith('.json') else json.load(urllib.request.urlopen(f'https://qbunker.click/api/bunker/{arg}'))
seal = data['seals'][0] if 'seals' in data else data
text, p = seal['text'], seal['pq']
root, pub, sig = bytes.fromhex(p['root']), bytes.fromhex(p['pubSeed']), bytes.fromhex(p['sig'])
assert len(sig) == 2404, 'signature must be 2,404 bytes'
key = struct.unpack('>I', sig[:4])[0]
dg = H(text.encode())
d = [x for b in dg for x in (b >> 4, b & 15)]; c = sum(15 - x for x in d); d += [(c >> 8) & 15, (c >> 4) & 15, c & 15]
ends = []
for i in range(67):
    x = sig[4 + 32 * i: 36 + 32 * i]
    for j in range(d[i], 15): x = H(pub, adrs(1, key, i, j), x)
    ends.append(x)
node, j = H(pub, adrs(2, key), *ends), key
for h in range(8):
    sib = sig[4 + 67 * 32 + 32 * h: 4 + 67 * 32 + 32 * (h + 1)]
    node = H(pub, adrs(3, 0, 0, 0, h + 1, j >> 1), *((sib, node) if j & 1 else (node, sib))); j >>= 1
print('claim:\n' + text + '\n')
print('PQ signature:', 'VALID' if node == root else 'INVALID', f'(key #{key}, root {p["root"][:16]}...)')
sys.exit(0 if node == root else 1)
