The Principia Machina/TPC-PY/diff fingerprint.py
Appearance
"""diff_fingerprint 0.1.0: the cross-residence differential for
tpc_fingerprint 0.1.0. Random TEST keys, salts and fields from a seed
(never a real secret), valid and malformed, both residences on the same
inputs, every render compared byte for byte; 0 differences is the pass.
Usage: python3 diff_fingerprint.py [seed] [cases]."""
import json
import os
import random
import subprocess
import sys
import tempfile
here = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, here)
from tpc_fingerprint import run_case, FNS # noqa: E402
seed = int(sys.argv[1]) if len(sys.argv) > 1 else 1
count = int(sys.argv[2]) if len(sys.argv) > 2 else 20000
rnd = random.Random(seed)
def pick(xs):
return xs[rnd.randrange(len(xs))]
def bad():
return rnd.random() < 0.04
def hexs(nbytes):
if bad():
return pick(["", "zz" * nbytes, "%0*x" % (nbytes * 2 - 1, rnd.getrandbits(nbytes * 8 - 4)),
("%0*x" % (nbytes * 2, rnd.getrandbits(nbytes * 8))).upper(), 5, None])
return "%0*x" % (nbytes * 2, rnd.getrandbits(nbytes * 8))
def ts():
if bad():
return pick(["2026092406234", "2026092406234x", 1700000000, "", None])
return "%04d%02d%02d%02d%02d%02d" % (rnd.randint(2001, 2099), rnd.randint(1, 12), rnd.randint(1, 28),
rnd.randint(0, 23), rnd.randint(0, 59), rnd.randint(0, 59))
def uid():
if bad():
return pick([0, -1, True, "7", 1.5, None])
return rnd.randint(1, 10 ** rnd.randint(1, 9))
def gen(fn):
if fn == "hkdf":
a = {"prk": hexs(pick([32, 32, 32, 64, 22])), "info": pick(["TPX-FINGERPRINT-1", "x", "", "café", "a|b"]),
"length": pick([1, 16, 32, 33, 42, 64, 100, 8160]) if not bad() else pick([0, 8161, -1, "32", 1.5])}
if rnd.random() < 0.3:
a["info_hex"] = hexs(rnd.randint(1, 20)) if not bad() else pick(["abc", "ZZ", 5, ""])
return a
if fn == "key_fp" or fn == "key_id":
return {"k": hexs(pick([32, 32, 32, 31, 33]))}
if fn == "agent_key":
return {"k": hexs(32), "agent_user_id": uid(), "salt": hexs(pick([16, 16, 16, 15, 17]))}
if fn == "call_sign":
return {"fp": hexs(pick([32, 32, 32, 31, 33]))}
f = {"sponsor_user_id": uid(), "sponsor_registration": ts(), "agent_user_id": uid(),
"agent_registration": ts(), "salt": hexs(16), "cert_serial": uid(), "cert_time": ts()}
if bad():
del f[pick(list(f.keys()))]
if bad():
f["extra"] = 1
return {"k": hexs(32), "fields": f if not bad() else [1]}
cases = []
for _ in range(count):
fn = pick(FNS)
cases.append({"fn": fn, "args": gen(fn)})
CASES_PATH = os.environ.get("TPC_DIFF_CASES") # named: kept, for crosspy.py
if not CASES_PATH:
fd, CASES_PATH = tempfile.mkstemp(prefix="tpc_diff_", suffix=".json") # outside the tree
os.close(fd)
with open(CASES_PATH, "w", encoding="utf-8") as f:
json.dump(cases, f, ensure_ascii=False)
py = [run_case(c["fn"], c["args"]) for c in cases]
php = json.loads(subprocess.run(["php", os.path.join(here, "diff_fingerprint.php"), CASES_PATH], capture_output=True,
text=True, check=True).stdout)
if not os.environ.get("TPC_DIFF_CASES"):
os.remove(CASES_PATH)
diffs = sum(1 for a, b in zip(py, php) if a != b)
outcomes = {}
for c, a in zip(cases, py):
k = c["fn"] + ("/ERROR" if a.startswith("ERROR") else "")
outcomes[k] = outcomes.get(k, 0) + 1
print("seed", seed, "cases", len(cases), "differences", diffs, "php_len", len(php),
json.dumps(outcomes, sort_keys=True))
for c, a, b in zip(cases, py, php):
if a != b:
print(json.dumps(c, ensure_ascii=False)); print(a); print("---"); print(b); break