Jump to content

The Principia Machina/TPC-PY/gen fingerprint corpus.py: Difference between revisions

From The Invariance Itself
TPC-PY source gen_fingerprint_corpus.py (0.1.0), SHA-256 625f7bfc9c1fb79d; conformed TPS 0.3.0; PROPOSED, not declared (CO-8)
 
m 1 revision imported
(No difference)

Revision as of 04:32, 28 September 2026

"""gen_fingerprint_corpus 0.1.0: builds fingerprint_corpus.json for
tpc_fingerprint 0.1.0. Deterministic. TEST-KEY vectors only: the fixed
TEST KEY is the 32 bytes 00 01 ... 1f, the per-agent salts are fixed
patterns, no real secret exists here (D127.1: TPC-PY fixes the encoding
and computes no real fingerprint). Expectations are computed
INDEPENDENTLY here with hashlib and hmac over the D97 netstring written
out by hand (never through the module), then asserted equal to the
module's render before pinning; RFC 5869's own test cases 1-3 (Expand
step) pin the HKDF."""
import hashlib
import hmac
import json
import os
import sys

here = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, here)
from tpc_fingerprint import run_case  # noqa: E402

cases = []
K = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
K2 = "ff" * 32
K3 = "0b" * 32
SALT = "00112233445566778899aabbccddeeff"
SALT2 = "0f" * 16


def add(name, fn, args, hand=False, check=None):
    got = run_case(fn, args)
    if check is not None:
        assert got == check, (name, got, check)
    cases.append({"name": name, "fn": fn, "args": args, "hand_checked": hand,
                  "expected": got})


def ind_expand(prk_hex, info, length):
    key = bytes.fromhex(prk_hex)
    out = b""
    t = b""
    i = 1
    while len(out) < length:
        t = hmac.new(key, t + info + bytes([i]), hashlib.sha256).digest()
        out += t
        i += 1
    return out[:length]


def ind_ns(items):
    return b"".join(str(len(b)).encode() + b":" + b for b in items)


def ind_fp(k, f):
    kfp = ind_expand(k, b"TPX-FINGERPRINT-1", 32)
    pre = ind_ns([b"TPX-FINGERPRINT", b"1", str(f["sponsor_user_id"]).encode(),
                  f["sponsor_registration"].encode(), str(f["agent_user_id"]).encode(),
                  f["agent_registration"].encode(), bytes.fromhex(f["salt"]),
                  str(f["cert_serial"]).encode(), f["cert_time"].encode()])
    fp = hmac.new(kfp, pre, hashlib.sha256).hexdigest()
    kid = hmac.new(bytes.fromhex(k), b"TPX-KEY-ID", hashlib.sha256).hexdigest()[:16]
    return "%s|%s|%s|%s" % (fp, fp[:16], kid, pre.hex())


# ---- hkdf (RFC 5869 test cases 1-3, the Expand step) -----------------------
add("H01 RFC 5869 test case 1", "hkdf",
    {"prk": "077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5", "info": "",
     "info_hex": "f0f1f2f3f4f5f6f7f8f9", "length": 42}, True,
    "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865")
add("H02 RFC 5869 test case 2 (82 bytes, three blocks)", "hkdf",
    {"prk": "06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244", "info": "",
     "info_hex": "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
     "length": 82}, True,
    "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87")
add("H03 RFC 5869 test case 3 (empty info)", "hkdf",
    {"prk": "19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04", "info": "",
     "info_hex": "", "length": 42}, True,
    "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8")
add("H04 the purpose key under the test key", "hkdf", {"prk": K, "info": "TPX-FINGERPRINT-1",
                                                       "length": 32}, True,
    ind_expand(K, b"TPX-FINGERPRINT-1", 32).hex())
add("H05 length 1", "hkdf", {"prk": K, "info": "x", "length": 1}, True,
    ind_expand(K, b"x", 1).hex())
add("H06 length 32", "hkdf", {"prk": K, "info": "x", "length": 32}, True,
    ind_expand(K, b"x", 32).hex())
add("H07 length 33 (two blocks)", "hkdf", {"prk": K, "info": "x", "length": 33}, True,
    ind_expand(K, b"x", 33).hex())
add("H08 length 8160 (the maximum)", "hkdf", {"prk": K, "info": "x", "length": 8160}, True,
    ind_expand(K, b"x", 8160).hex())
add("H09 a UTF-8 info", "hkdf", {"prk": K, "info": "café", "length": 32}, True,
    ind_expand(K, "café".encode(), 32).hex())
add("H10 a 64-byte PRK", "hkdf", {"prk": K + K2, "info": "x", "length": 32}, True,
    ind_expand(K + K2, b"x", 32).hex())
for i in range(6):
    add("H%02d sweep info %d" % (11 + i, i), "hkdf", {"prk": K3, "info": "info-%d" % i,
                                                     "length": 16 + 7 * i}, False)
add("H17 length 0 refused", "hkdf", {"prk": K, "info": "x", "length": 0}, True, "ERROR:length")
add("H18 length 8161 refused", "hkdf", {"prk": K, "info": "x", "length": 8161}, True,
    "ERROR:length")
add("H19 a 31-byte PRK refused", "hkdf", {"prk": K[:62], "info": "x", "length": 32}, True,
    "ERROR:key")
add("H20 uppercase hex refused", "hkdf", {"prk": K.upper(), "info": "x", "length": 32}, True,
    "ERROR:key")
add("H21 info not a string refused", "hkdf", {"prk": K, "info": 5, "length": 32}, True,
    "ERROR:info")
add("H22 odd info_hex refused", "hkdf", {"prk": K, "info": "", "info_hex": "abc", "length": 32},
    True, "ERROR:info")

# ---- key_fp / agent_key / key_id / call_sign --------------------------------
add("F01 K_FP under the test key", "key_fp", {"k": K}, True,
    ind_expand(K, b"TPX-FINGERPRINT-1", 32).hex())
add("F02 K_FP under ff..ff", "key_fp", {"k": K2}, True, ind_expand(K2, b"TPX-FINGERPRINT-1", 32).hex())
add("F03 K_FP under 0b..0b", "key_fp", {"k": K3}, True, ind_expand(K3, b"TPX-FINGERPRINT-1", 32).hex())
for i in range(9):
    k = ("%02x" % (i * 17)) * 32
    add("F%02d sweep key %02x" % (4 + i, i * 17), "key_fp", {"k": k}, True,
        ind_expand(k, b"TPX-FINGERPRINT-1", 32).hex())
add("F13 a 33-byte key refused", "key_fp", {"k": K + "00"}, True, "ERROR:key")
add("F14 a 31-byte key refused", "key_fp", {"k": K[:62]}, True, "ERROR:key")
add("F15 non-hex refused", "key_fp", {"k": "zz" * 32}, True, "ERROR:key")
add("F16 key not a string refused", "key_fp", {"k": 5}, True, "ERROR:key")
add("F17 key_fp differs from key_id's input use", "key_fp", {"k": "a1" * 32}, True,
    ind_expand("a1" * 32, b"TPX-FINGERPRINT-1", 32).hex())
add("F18 key with a trailing space refused", "key_fp", {"k": K[:63] + " "}, True, "ERROR:key")
add("F19 empty key refused", "key_fp", {"k": ""}, True, "ERROR:key")
add("F20 key 00..00", "key_fp", {"k": "00" * 32}, True,
    ind_expand("00" * 32, b"TPX-FINGERPRINT-1", 32).hex())


def ind_agent_key(k, uid, salt):
    info = ind_ns([b"TPX-FINGERPRINT-1", str(uid).encode(), bytes.fromhex(salt)])
    return ind_expand(k, info, 32).hex()


add("A01 per-agent key (speculation 12.1's form)", "agent_key",
    {"k": K, "agent_user_id": 7, "salt": SALT}, True, ind_agent_key(K, 7, SALT))
add("A02 another salt", "agent_key", {"k": K, "agent_user_id": 7, "salt": SALT2}, True,
    ind_agent_key(K, 7, SALT2))
add("A03 another user", "agent_key", {"k": K, "agent_user_id": 8, "salt": SALT}, True,
    ind_agent_key(K, 8, SALT))
for i in range(12):
    add("A%02d sweep" % (4 + i), "agent_key", {"k": K3, "agent_user_id": 100 + i * 37,
                                                "salt": ("%02x" % (i * 23 % 256)) * 16}, True,
        ind_agent_key(K3, 100 + i * 37, ("%02x" % (i * 23 % 256)) * 16))
add("A16 user_id 0 refused", "agent_key", {"k": K, "agent_user_id": 0, "salt": SALT}, True,
    "ERROR:fields")
add("A17 salt 15 bytes refused", "agent_key", {"k": K, "agent_user_id": 7, "salt": SALT[:30]},
    True, "ERROR:fields")
add("A18 salt 17 bytes refused", "agent_key", {"k": K, "agent_user_id": 7, "salt": SALT + "00"},
    True, "ERROR:fields")
add("A19 key malformed refused", "agent_key", {"k": "x", "agent_user_id": 7, "salt": SALT}, True,
    "ERROR:key")
add("A20 user_id a string refused", "agent_key", {"k": K, "agent_user_id": "7", "salt": SALT},
    True, "ERROR:fields")

add("I01 key id under the test key", "key_id", {"k": K}, True,
    hmac.new(bytes.fromhex(K), b"TPX-KEY-ID", hashlib.sha256).hexdigest()[:16])
add("I02 key id under ff..ff", "key_id", {"k": K2}, True,
    hmac.new(bytes.fromhex(K2), b"TPX-KEY-ID", hashlib.sha256).hexdigest()[:16])
for i in range(15):
    k = ("%02x" % ((i * 41 + 3) % 256)) * 32
    add("I%02d sweep %02x" % (3 + i, (i * 41 + 3) % 256), "key_id", {"k": k}, True,
        hmac.new(bytes.fromhex(k), b"TPX-KEY-ID", hashlib.sha256).hexdigest()[:16])
add("I18 a 31-byte key refused", "key_id", {"k": K[:62]}, True, "ERROR:key")
add("I19 uppercase refused", "key_id", {"k": K.upper()}, True, "ERROR:key")
add("I20 key not a string refused", "key_id", {"k": None}, True, "ERROR:key")

FP = "22f59d4401109a8b3660d16b8e483248c2e21648875022a1b66395aecdaf86c3"
add("C01 the call sign is the first 16 hex", "call_sign", {"fp": FP}, True, FP[:16])
add("C02 all zeros", "call_sign", {"fp": "0" * 64}, True, "0" * 16)
for i in range(15):
    fp = hashlib.sha256(b"cs%d" % i).hexdigest()
    add("C%02d sweep" % (3 + i), "call_sign", {"fp": fp}, True, fp[:16])
add("C18 63 hex refused", "call_sign", {"fp": FP[:63]}, True, "ERROR:fingerprint")
add("C19 uppercase refused", "call_sign", {"fp": FP.upper()}, True, "ERROR:fingerprint")
add("C20 not a string refused", "call_sign", {"fp": 5}, True, "ERROR:fingerprint")

# ---- fingerprint -----------------------------------------------------------
def fields(**over):
    f = {"sponsor_user_id": 1, "sponsor_registration": "20250101000000", "agent_user_id": 7,
         "agent_registration": "20260924062344", "salt": SALT, "cert_serial": 1,
         "cert_time": "20261001120000"}
    f.update(over)
    return f


add("P01 the reference pairing under the test key", "fingerprint", {"k": K, "fields": fields()},
    True, ind_fp(K, fields()))
add("P02 another key: another fingerprint", "fingerprint", {"k": K2, "fields": fields()}, True,
    ind_fp(K2, fields()))
add("P03 another salt: another fingerprint for the same pair", "fingerprint",
    {"k": K, "fields": fields(salt=SALT2)}, True, ind_fp(K, fields(salt=SALT2)))
add("P04 the certificate's serial enters", "fingerprint", {"k": K, "fields": fields(cert_serial=2)},
    True, ind_fp(K, fields(cert_serial=2)))
add("P05 the certificate's time enters", "fingerprint",
    {"k": K, "fields": fields(cert_time="20261001120001")}, True,
    ind_fp(K, fields(cert_time="20261001120001")))
add("P06 the sponsor's registration enters", "fingerprint",
    {"k": K, "fields": fields(sponsor_registration="20250101000001")}, True,
    ind_fp(K, fields(sponsor_registration="20250101000001")))
add("P07 the agent's registration enters", "fingerprint",
    {"k": K, "fields": fields(agent_registration="20260924062345")}, True,
    ind_fp(K, fields(agent_registration="20260924062345")))
add("P08 a large user_id", "fingerprint", {"k": K, "fields": fields(agent_user_id=123456789)},
    True, ind_fp(K, fields(agent_user_id=123456789)))
add("P09 the sponsor as its own agent's pair (user_id 1, 1)", "fingerprint",
    {"k": K, "fields": fields(agent_user_id=1)}, True, ind_fp(K, fields(agent_user_id=1)))
for i in range(7):
    f = fields(sponsor_user_id=10 + i, agent_user_id=20 + 3 * i, cert_serial=i + 1,
               salt=("%02x" % (i * 31 % 256)) * 16)
    add("P%02d sweep" % (10 + i), "fingerprint", {"k": K3, "fields": f}, True, ind_fp(K3, f))
add("P17 registration 13 digits refused", "fingerprint",
    {"k": K, "fields": fields(agent_registration="2026092406234")}, True, "ERROR:fields")
add("P18 registration with a letter refused", "fingerprint",
    {"k": K, "fields": fields(agent_registration="2026092406234x")}, True, "ERROR:fields")
add("P19 cert_serial 0 refused", "fingerprint", {"k": K, "fields": fields(cert_serial=0)}, True,
    "ERROR:fields")
add("P20 salt malformed refused", "fingerprint", {"k": K, "fields": fields(salt="zz" * 16)},
    True, "ERROR:fields")
add("P21 a missing field refused", "fingerprint",
    {"k": K, "fields": {k: v for k, v in fields().items() if k != "salt"}}, True, "ERROR:fields")
add("P22 an extra field refused", "fingerprint", {"k": K, "fields": dict(fields(), model="x")},
    True, "ERROR:fields")
add("P23 the key refused before the fields", "fingerprint", {"k": "x", "fields": fields(cert_serial=0)},
    True, "ERROR:key")
add("P24 user_id a boolean refused", "fingerprint", {"k": K, "fields": fields(agent_user_id=True)},
    True, "ERROR:fields")
add("P25 cert_time an integer refused (TS_MW form only)", "fingerprint",
    {"k": K, "fields": fields(cert_time=1700000000)}, True, "ERROR:fields")

names = [c["name"] for c in cases]
assert len(names) == len(set(names)), "duplicate case names"
counts = {}
for c in cases:
    counts[c["fn"]] = counts.get(c["fn"], 0) + 1
for fn, m in sorted(counts.items()):
    assert m >= 20, (fn, m)
out = {"corpus": "fingerprint_corpus", "version": "0.1.0", "module": "tpc_fingerprint 0.1.0",
       "test_key": "K_TEST = 000102...1f (32 bytes), a TEST KEY, never a real secret (D127.1)",
       "counts": counts, "cases": cases}
with open(os.path.join(here, "fingerprint_corpus.json"), "w", encoding="utf-8") as f:
    json.dump(out, f, indent=1, ensure_ascii=False)
    f.write("\n")
print("fingerprint_corpus.json", len(cases), "cases", counts)