Files

79 lines
2.6 KiB
Python

#!/usr/bin/env python3
"""demo_ids.py -- real-data demo: 128-bit human-transcribable IDs with check symbols.
Takes a real file's SHA-256, folds it to a 128-bit integer, and emits a hyphenated
Crockford Base32 ID with a check symbol (transcription-safe: O/0 and I/L/1 confusions
are folded, hyphens ignored, one bad symbol caught). Verifies and decodes it back,
then proves the check symbol catches every single-symbol typo in the printed ID.
Run: python3 demo_ids.py [FILE ...]
"""
from __future__ import annotations
import hashlib
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
if HERE not in sys.path:
sys.path.insert(0, HERE)
import base32c # noqa: E402
DEFAULT_TARGETS = ["/usr/share/common-licenses/GPL-3", os.path.join(HERE, "base32c.py")]
def make_id(path: str) -> dict:
digest = hashlib.sha256(open(path, "rb").read()).digest()
value = int.from_bytes(digest[:16], "big") # 128-bit id space
ident = base32c.encode_checked(value, min_length=26, hyphenate=4)
decoded = base32c.decode_checked(ident)
typos = tested = caught = 0
body = ident.replace("-", "")
for pos in range(len(body)):
alternatives = base32c.CHECK_ALPHABET if pos == len(body) - 1 else base32c.ALPHABET
for alt in alternatives:
if alt == body[pos]:
continue
mutated = body[:pos] + alt + body[pos + 1 :]
tested += 1
if not base32c.verify(mutated):
caught += 1
return {
"path": path,
"sha256": digest.hex(),
"value": value,
"id": ident,
"roundtrip_ok": decoded == value,
"typos_tested": tested,
"typos_caught": caught,
}
def main(argv: list[str]) -> int:
targets = argv or DEFAULT_TARGETS
all_ok = True
for path in targets:
if not os.path.isfile(path):
print(f"SKIP {path}: not a file")
continue
row = make_id(path)
print(f"file {row['path']}")
print(f"sha256 {row['sha256']}")
print(f"id value {row['value']}")
print(f"public id {row['id']}")
print(f"round-trip {'OK' if row['roundtrip_ok'] else 'BROKEN'} (decode_checked == value)")
print(
f"typo sweep {row['typos_caught']}/{row['typos_tested']} single-symbol typos rejected"
f" ({row['typos_caught'] / row['typos_tested']:.1%})"
)
print()
all_ok &= row["roundtrip_ok"] and row["typos_caught"] == row["typos_tested"]
print("DEMO OK" if all_ok else "DEMO FAILED")
return 0 if all_ok else 1
if __name__ == "__main__":
raise SystemExit(main(sys.argv[1:]))