syntheogenesis / dee /core /certificate.py
github-actions[bot]
Deploy abc546b
143cadd
Raw
History Blame Contribute Delete
10.1 kB
"""The Run Certificate — a design and its complete justification, addressable.
WHY THIS EXISTS
---------------
The compiler already emits a design record (compiler.design_record), and it is
good: deterministic, plain text, states what it does NOT establish. But it is
one tool's record, it has no identity, and nothing can check it. A reviewer
handed that text has to take it on trust that it describes the run it claims
to describe.
A certificate fixes three things the record cannot:
1. IDENTITY. It is content-addressed. The id IS the hash of the content, so
"certificate 8f2a…" names exactly one document and nothing else. Two runs
that produced the same answer produce the same id; a run that differed
anywhere produces a different one. You cannot rename a result into
agreeing with you.
2. TAMPER EVIDENCE. Anyone can recompute the hash from the content. There is
no signing key to trust and none to lose — the document verifies itself.
3. COMPLETENESS THAT IS PART OF THE RECORD. What was NOT established is a
first-class section, hashed with everything else. You cannot quietly drop
the caveats and keep the id.
DETERMINISM IS THE WHOLE MECHANISM
----------------------------------
If the same inputs produced two different certificates, the hash would be
noise and every property above would collapse. So the canonical form:
* sorts every key, at every depth;
* contains NO clock and NO random source. A timestamp would give the same
run two ids, which is precisely the failure to avoid. Time is metadata the
caller attaches OUTSIDE the hashed payload;
* normalises floats through repr-stable rounding, because 0.1+0.2 must not
fork a certificate;
* refuses values it cannot canonicalise, rather than coercing them to a
string and hashing something that looks fine and means nothing.
WHAT A CERTIFICATE IS NOT
-------------------------
It is not a claim that the design is correct, or safe, or novel. It says: this
input, through this code at this version, produced this output, and here is
what nobody checked. A reviewer still has to do the science. The certificate
only guarantees they are reviewing what they think they are reviewing.
Pure logic: no network, no database, no I/O. Same discipline as compiler.py.
"""
from __future__ import annotations
import hashlib
import json
from typing import Any, Dict, List, Optional, Tuple
__all__ = [
"CERT_VERSION", "CanonicalError", "canonical", "content_hash",
"build", "verify", "render_text",
]
# Bumped only when the canonical form changes in a way that would alter hashes
# for unchanged inputs. It is part of the hashed payload, so old certificates
# stay verifiable against the rules they were minted under.
CERT_VERSION = "1"
_FLOAT_PLACES = 10
class CanonicalError(ValueError):
"""A value that cannot be canonicalised. Raised rather than coerced."""
def canonical(value: Any) -> Any:
"""Reduce a value to its canonical form, or refuse.
Refusing is the point. Coercing an unknown object with str() would produce
a hash that looks authoritative and means nothing — worse than an error,
because it fails silently and only at the moment somebody relies on it.
"""
if value is None or isinstance(value, (str, bool)):
return value
if isinstance(value, int) and not isinstance(value, bool):
return value
if isinstance(value, float):
if value != value or value in (float("inf"), float("-inf")):
raise CanonicalError(
"NaN and infinity have no canonical form; a certificate "
"containing one could never be reproduced.")
# Round before hashing so 0.30000000000000004 and 0.3 agree. Integral
# floats normalise to int so 1.0 and 1 cannot fork a certificate.
r = round(value, _FLOAT_PLACES)
return int(r) if r == int(r) else r
if isinstance(value, (list, tuple)):
return [canonical(v) for v in value]
if isinstance(value, dict):
out = {}
for k in sorted(value):
if not isinstance(k, str):
raise CanonicalError(
f"certificate keys must be strings; got {type(k).__name__}")
out[k] = canonical(value[k])
return out
raise CanonicalError(
f"{type(value).__name__} has no canonical form. Convert it "
"explicitly rather than letting the hash cover a repr.")
def _serialise(payload: Dict[str, Any]) -> str:
return json.dumps(canonical(payload), sort_keys=True, separators=(",", ":"),
ensure_ascii=False)
def content_hash(payload: Dict[str, Any]) -> str:
"""sha256 of the canonical serialisation, truncated to 16 hex chars.
Truncated because this is an identifier a human reads aloud and types into
a search box, not a cryptographic commitment against an adversary with
unlimited attempts. 64 bits still makes an accidental collision
inconceivable at any volume this will ever see.
"""
return hashlib.sha256(_serialise(payload).encode("utf-8")).hexdigest()[:16]
def build(*, kind: str, inputs: Dict[str, Any], outputs: Dict[str, Any],
passes: Optional[List[Dict[str, Any]]] = None,
not_established: Optional[List[str]] = None,
versions: Optional[Dict[str, str]] = None,
scope: Optional[Dict[str, str]] = None) -> Dict[str, Any]:
"""Assemble a certificate. Deterministic: same arguments, same id.
`not_established` is required to be explicit even when empty. An empty
list is a CLAIM — "we checked everything relevant" — and it should have to
be made deliberately rather than arrived at by forgetting the argument.
"""
payload = {
"cert_version": CERT_VERSION,
"kind": str(kind),
"inputs": inputs or {},
"outputs": outputs or {},
"passes": passes or [],
# Sorted so two runs that established the same gaps in a different
# order are the same certificate.
"not_established": sorted(str(x) for x in (not_established or [])),
"versions": versions or {},
"scope": scope or {},
}
cert = dict(payload)
cert["id"] = content_hash(payload)
return cert
def verify(cert: Dict[str, Any]) -> Tuple[bool, str]:
"""Recompute the id from the content. Returns (ok, explanation).
No key, no authority, no service to be up: the document checks itself.
Anyone holding it can run this, including someone who does not trust us —
which is the only kind of verification worth putting in a methods section.
"""
if not isinstance(cert, dict):
return False, "not a certificate object"
claimed = cert.get("id")
if not claimed:
return False, "no id — nothing to check the content against"
payload = {k: v for k, v in cert.items() if k != "id"}
if payload.get("cert_version") != CERT_VERSION:
# Not a failure. An older certificate is valid under the rules it was
# minted with; saying "invalid" would be a lie about tampering.
return False, (f"minted under cert_version "
f"{payload.get('cert_version')!r}, this build canonicalises "
f"{CERT_VERSION!r} — verify with that version's rules")
try:
actual = content_hash(payload)
except CanonicalError as exc:
return False, f"content cannot be canonicalised: {exc}"
if actual != claimed:
return False, (f"content does not match its id (claimed {claimed}, "
f"content hashes to {actual}) — it has been altered "
"since it was issued")
return True, f"content matches its id ({claimed})"
def render_text(cert: Dict[str, Any]) -> str:
"""Plain text, because it diffs, pastes into an email, survives every tool
in the chain, and cannot silently re-render differently later."""
L: List[str] = []
add = L.append
add("TURINGDNA RUN CERTIFICATE")
add(f"id {cert.get('id', '(unissued)')}")
add(f"kind {cert.get('kind', '')}")
add(f"cert-version {cert.get('cert_version', '')}")
add("=" * 72)
add("")
ok, why = verify(cert)
add(f"SELF-CHECK {'PASS' if ok else 'FAIL'}{why}")
add(" Recompute it yourself: sha256 of the canonical JSON of every field")
add(" except `id`, first 16 hex characters. No key required.")
add("")
for title, key in (("INPUTS", "inputs"), ("OUTPUTS", "outputs"),
("VERSIONS", "versions"), ("SCOPE", "scope")):
section = cert.get(key) or {}
if not section:
continue
add(title)
for k in sorted(section):
add(f" {k:<22} {section[k]}")
add("")
passes = cert.get("passes") or []
if passes:
add("PASSES")
for p in passes:
add(f" [{str(p.get('status', '')):<11}] {p.get('title', p.get('name', ''))}")
if p.get("detail"):
for line in _wrap(str(p["detail"]), 66):
add(f" {line}")
add("")
gaps = cert.get("not_established") or []
add("NOT ESTABLISHED BY THIS CERTIFICATE")
if gaps:
for g in gaps:
add(f" - {g}")
else:
add(" Nothing was recorded as unestablished. That is a CLAIM, not an")
add(" absence of information — read it as one.")
add("")
add("-" * 72)
add("This certificate attests that these inputs, through this code at these")
add("versions, produced these outputs. It is not a claim that the design is")
add("correct, safe, or novel, and it does not replace the review.")
return "\n".join(L)
def _wrap(text: str, width: int) -> List[str]:
words, line, out = str(text).split(), "", []
for w in words:
if line and len(line) + 1 + len(w) > width:
out.append(line)
line = w
else:
line = f"{line} {w}".strip()
if line:
out.append(line)
return out