Journal

Signing for the decade after the one we are in

cryptographypost-quantumsealtrust

When the platform publishes an artifact — a benchmark databank, an evidence bundle, a keyring — it seals it. The seal is a signature over the exact bytes, and it answers a single question the reader would otherwise have to take on faith: are these the bytes the platform actually published, unaltered?

Two signatures, not one

The seal is hybrid. It carries an Ed25519 signature and an ML-DSA-65 signature over the same content, and both must verify. Ed25519 is the classical curve signature in wide use today; ML-DSA-65 is the lattice-based scheme standardised in FIPS 204, chosen because it is believed to resist an adversary with a large quantum computer.

Neither alone is the answer. Ed25519 is battle-tested but falls to a sufficiently capable quantum attacker. ML-DSA-65 is young, and young cryptography earns trust slowly. Requiring both means the seal is at least as strong as the stronger of the two at any point in its life: a classical break does not forge it, and a lattice surprise does not either. An artifact sealed today should still be checkable, and still be sound, well into the decade after this one.

Canonical bytes, or no signature at all

A signature is over bytes, but JSON is not bytes — the same object can be serialised many ways. So the seal is taken over a canonical form: RFC 8785 JSON Canonicalisation Scheme (JCS), which fixes key order, whitespace, and number formatting so there is exactly one byte string to sign and to check.

JCS is strict on purpose, and that strictness has teeth. It has no faithful representation for a non-integer floating-point number, which is why some documents cannot yet be sealed as they stand — a registry carrying raw floats is shown at its true, unsealed boundary rather than dressed in a seal it cannot honestly wear. The platform workbench says exactly which state a document is in: sealed and verified, or an unsealed registry, never the former standing in for the latter.

The reader holds the root

A signature is only as good as the key you check it against, so the trust root is pinned. The verifier ships with the root key baked in, and the well-known keyring it fetches must itself be signed by that pinned root before any artifact key it publishes is trusted. There is no step where the server gets to assert “trust this key” — the chain terminates at a key the reader already had.

You can run the same checks yourself. The @anulum/verify package is the exact verifier the Hub uses; the Trust page has the root pin, the keyring, and the steps. Verification you cannot reproduce is a claim; verification you can is evidence.