Jump to content

The Principia Machina/TPC-PY/tpc fingerprint.py

From The Invariance Itself
Revision as of 15:43, 27 September 2026 by BFP Rauch (talk | contribs) (TPC-PY source tpc_fingerprint.py (0.1.0), SHA-256 65833c75c5570b5a; conformed TPS 0.3.0; PROPOSED, not declared (CO-8))
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
"""tpc_fingerprint 0.1.0 (DRAFT, pending the pause of landing round 8):
the FINGERPRINT, the KEY ID and the CALL SIGN of D127.1 as PMP-TPM
0.12.0 VOCABULARY (FINGERPRINT, KEY ID, K_TPX) words them, with TEST-KEY
vectors only: "no agent holds K_FP, so TPC-PY fixes the encoding and
computes no real fingerprint" (D127.1).

Reference implementation, Python standard library only (hashlib, hmac);
imports tpc_beta's canon_float for nothing but the harness's number
form. DATA for landing round 8 of branch tpm_project_closeout; not a
declared TPC-PY version and not TPX code. Every refused argument raises
ValueError with a short fixed message, and a refusal never echoes a key.
Keys are passed as lowercase hex (K_TPX: 64 hex, 32 bytes; a per-agent
salt: 32 hex, 16 bytes); the corpus states one fixed TEST KEY and never
a real secret.

hkdf_expand(prk, info, length) -> hex                    (RFC 5869 2.3)
  HKDF-Expand with HMAC-SHA-256: T(1) = HMAC(PRK, info || 0x01), T(i) =
  HMAC(PRK, T(i-1) || info || i); the first length bytes, length <= 255
  x 32. K_TPX is the PRK: D127.1 "K_FP = HKDF-Expand(K_TPX,
  "TPX-FINGERPRINT-1")", no Extract step (PD-SC-24: K_TPX is 32 bytes
  from the CSPRNG, already a uniform key; alternative: HKDF-Extract with
  an empty salt first). prk: hex, at least 32 bytes; info: a string
  (UTF-8), or bytes (the corpus passes RFC 5869's own test vectors as
  info_hex); length in 1..8160.

key_fp(k) -> hex          K_FP = HKDF-Expand(K_TPX, "TPX-FINGERPRINT-1"),
  32 bytes (D127.1; the per-purpose key). agent_key(k, agent_user_id,
  salt) = HKDF-Expand(K_TPX, enc(["TPX-FINGERPRINT-1", agent_user_id,
  salt])) is the per-agent derivation the speculation's 12.1 names; the
  fingerprint of record is under K_FP (D127.1's formula; PD-SC-25).

fingerprint(k, fields) -> dict                                  (D127.1)
  "FP = HMAC-SHA-256(K_FP, enc(["TPX-FINGERPRINT", "1", sponsor_user_id,
  sponsor_registration, agent_user_id, agent_registration, salt,
  cert_serial, cert_time])), enc the D97.1 netstring encoding ...; 64
  lowercase hex, cited in full on the dossier and the declaration line
  and by its first 16 hex as the CALL SIGN". fields: {sponsor_user_id,
  agent_user_id: MediaWiki user_id (integers >= 1, base-10 in the
  netstring); sponsor_registration, agent_registration, cert_time:
  MediaWiki timestamps, 14 digits YYYYMMDDHHMMSS (user_registration's
  own form; PD-SC-26; alternative: integer seconds); salt: 32 hex, the
  16 salt bytes entering the netstring as raw bytes (PD-SC-27;
  alternative: the 32-hex text); cert_serial: the certificate's ordinal
  on the DECLARATIONS page, an integer >= 1}.
  FP1 The netstring is D97's: each field as its byte length in decimal,
      ":", its bytes; a string as UTF-8, an integer as base-10 ASCII, the
      salt as its 16 bytes.
  FP2 The result: fingerprint (64 hex), call_sign (its first 16 hex),
      key_id (of K_TPX), and the preimage as hex for audit.

key_id(k) -> hex          HMAC-SHA-256(K_TPX, "TPX-KEY-ID") truncated to
  16 hex (D127.1): "names the key a fingerprint was made under".
call_sign(fp) -> str      The first 16 hex of a 64-hex fingerprint.
"""

import hashlib
import hmac
import os
import re
import sys

_here = os.path.dirname(os.path.abspath(__file__))
for _p in (_here,):
    if _p not in sys.path:
        sys.path.insert(0, _p)

VERSION = "0.1.0"
PURPOSE_FP = "TPX-FINGERPRINT-1"
TAG_FP = "TPX-FINGERPRINT"
TAG_KEY_ID = "TPX-KEY-ID"
FORM = "1"
_HEX = re.compile(r"[0-9a-f]+")
_TS = re.compile(r"[0-9]{14}")
_FKEYS = ("sponsor_user_id", "sponsor_registration", "agent_user_id",
          "agent_registration", "salt", "cert_serial", "cert_time")


def _is_int(x, lo, hi):
    return type(x) is int and lo <= x <= hi


def _hex_bytes(s, nbytes_min, nbytes_max):
    if type(s) is not str or len(s) % 2 != 0 or _HEX.fullmatch(s) is None:
        return None
    n = len(s) // 2
    if n < nbytes_min or n > nbytes_max:
        return None
    return bytes.fromhex(s)


def _netstring(items):
    out = bytearray()
    for b in items:
        out += str(len(b)).encode("ascii")
        out += b":"
        out += b
    return bytes(out)


def hkdf_expand(prk, info, length):
    key = _hex_bytes(prk, 32, 1024)
    if key is None:
        raise ValueError("key")
    if type(info) is bytes:
        inf = info
    elif type(info) is str:
        inf = info.encode("utf-8")
    else:
        raise ValueError("info")
    if not _is_int(length, 1, 255 * 32):
        raise ValueError("length")
    return _expand_bytes(key, inf, length).hex()


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


def key_fp(k):
    key = _hex_bytes(k, 32, 32)
    if key is None:
        raise ValueError("key")
    return _expand_bytes(key, PURPOSE_FP.encode("utf-8"), 32).hex()


def agent_key(k, agent_user_id, salt):
    key = _hex_bytes(k, 32, 32)
    if key is None:
        raise ValueError("key")
    if not _is_int(agent_user_id, 1, 2 ** 53):
        raise ValueError("fields")
    sb = _hex_bytes(salt, 16, 16)
    if sb is None:
        raise ValueError("fields")
    info = _netstring([PURPOSE_FP.encode("utf-8"), str(agent_user_id).encode("ascii"), sb])
    return _expand_bytes(key, info, 32).hex()


def key_id(k):
    key = _hex_bytes(k, 32, 32)
    if key is None:
        raise ValueError("key")
    return hmac.new(key, TAG_KEY_ID.encode("utf-8"), hashlib.sha256).hexdigest()[:16]


def call_sign(fp):
    if type(fp) is not str or len(fp) != 64 or _HEX.fullmatch(fp) is None:
        raise ValueError("fingerprint")
    return fp[:16]


def _fields(fields):
    if type(fields) is not dict:
        raise ValueError("fields")
    for k in _FKEYS:
        if k not in fields:
            raise ValueError("fields")
    for k in fields:
        if k not in _FKEYS:
            raise ValueError("fields")
    for k in ("sponsor_user_id", "agent_user_id", "cert_serial"):
        if not _is_int(fields[k], 1, 2 ** 53):
            raise ValueError("fields")
    for k in ("sponsor_registration", "agent_registration", "cert_time"):
        v = fields[k]
        if type(v) is not str or _TS.fullmatch(v) is None:
            raise ValueError("fields")
    sb = _hex_bytes(fields["salt"], 16, 16)
    if sb is None:
        raise ValueError("fields")
    return sb


def fingerprint(k, fields):
    key = _hex_bytes(k, 32, 32)
    if key is None:
        raise ValueError("key")
    sb = _fields(fields)
    items = [TAG_FP.encode("utf-8"), FORM.encode("utf-8"),
             str(fields["sponsor_user_id"]).encode("ascii"),
             fields["sponsor_registration"].encode("utf-8"),
             str(fields["agent_user_id"]).encode("ascii"),
             fields["agent_registration"].encode("utf-8"),
             sb,
             str(fields["cert_serial"]).encode("ascii"),
             fields["cert_time"].encode("utf-8")]
    pre = _netstring(items)
    kfp = _expand_bytes(key, PURPOSE_FP.encode("utf-8"), 32)
    fp = hmac.new(kfp, pre, hashlib.sha256).hexdigest()
    return {"fingerprint": fp, "call_sign": fp[:16], "key_id": key_id(k),
            "preimage": pre.hex()}


def render_fingerprint(d):
    return "%s|%s|%s|%s" % (d["fingerprint"], d["call_sign"], d["key_id"], d["preimage"])


# ---------------------------------------------------------------- corpus

FNS = ("hkdf", "key_fp", "agent_key", "key_id", "call_sign", "fingerprint")


def run_case(fn, args):
    """One corpus case: the render, or "ERROR:" and the message."""
    if fn not in FNS:
        raise ValueError("fn")
    try:
        if fn == "hkdf":
            info = args["info"]
            if "info_hex" in args:
                if type(args["info_hex"]) is not str or _HEX.fullmatch(args["info_hex"] or "0") is None \
                        or len(args["info_hex"]) % 2:
                    raise ValueError("info")
                info = bytes.fromhex(args["info_hex"])
            return hkdf_expand(args["prk"], info, args["length"])
        if fn == "key_fp":
            return key_fp(args["k"])
        if fn == "agent_key":
            return agent_key(args["k"], args["agent_user_id"], args["salt"])
        if fn == "key_id":
            return key_id(args["k"])
        if fn == "call_sign":
            return call_sign(args["fp"])
        return render_fingerprint(fingerprint(args["k"], args["fields"]))
    except ValueError as ex:
        return "ERROR:" + str(ex)