Integrity

Don't trust this page.
Check it.

Every machine-readable document this institution publishes is signed. The signature can be verified without asking us anything — and the box below does exactly that, in your browser, right now.

An institution that publishes regulatory dates is asking to be believed about facts that carry penalties. The usual answer to “why should I believe this file?” is the padlock in the address bar. That answer is weaker than it looks: HTTPS proves these bytes came from whatever server answered for this domain, at the moment you asked. It proves nothing about the copy — and copies are how a corpus like this actually travels. A mirror. A cached crawl. A vendor's snapshot. A model's training set. In every one of those, a modified obligations.json with one date moved is indistinguishable from ours.

So each document is published with a detached assertion: a short signed statement naming the document, its SHA-256, when it was issued and how long it should be trusted. The signature is Ed25519 over the canonical form of that statement. Checking it needs the public key and nothing else — no call to us, no account, no rate limit, no permission.

Live verification
Running in your browser against the files as they are being served to you.
Fetch the public key document
Fetch the obligation corpus and its assertion
Hash the corpus with SHA-256
Compare that hash to the one inside the signed statement
Verify the Ed25519 signature over the statement
Waiting.

Nothing above is a claim we are making about ourselves. Your browser fetched two files, computed a hash and checked a signature; the only thing we contributed was the maths being hard to forge. If a single byte of the corpus had been altered — by us, by a mirror, by anything between — step four would be red and the page would say so.

What a signature proves, and what it does not. It proves the bytes you hold are the bytes this institution published, and that nobody altered them in transit or in a copy. It proves nothing whatsoever about whether the regulatory claims inside them are correct. That is what the link to primary law on every row is for, and why every row has one. A signed wrong answer is still a wrong answer — every correction this institution has published is on the evidence page, including one issued the day this page went up.

What is signed

The index of all of them is at /.well-known/assertions.json, the public keys at /.well-known/keys.json, and the envelope schema at /.well-known/assertion.schema.json. The index is a convenience and deliberately not the trust anchor: an assertion is checked against the key document and the document it covers, so a tampered index can hide an assertion but never forge one.

Verify it from a terminal

The same check, without a browser. Any Ed25519 implementation will do; this uses Node, which is already required for the MCP server.

curl -s https://lunarasociety.com/corpus/obligations.json -o obligations.json
curl -s https://lunarasociety.com/corpus/obligations.assertion.json -o assertion.json
curl -s https://lunarasociety.com/.well-known/keys.json -o keys.json

node -e '
const c = require("crypto"), fs = require("fs");
const env = JSON.parse(fs.readFileSync("assertion.json"));
const key = JSON.parse(fs.readFileSync("keys.json")).keys.find(k => k.kid === env.assertion.key_id);
const doc = fs.readFileSync("obligations.json");

// RFC 8785: sorted keys, no whitespace
const canon = v => Array.isArray(v) ? "[" + v.map(canon) + "]"
  : v && typeof v === "object"
    ? "{" + Object.keys(v).sort().map(k => JSON.stringify(k) + ":" + canon(v[k])) + "}"
    : JSON.stringify(v);

const b64u = b => b.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"");
const sig  = c.verify(null, Buffer.from(canon(env.assertion)),
               c.createPublicKey({ key, format: "jwk" }),
               Buffer.from(env.signature.value, "base64url"));
const hash = b64u(c.createHash("sha256").update(doc).digest()) === env.assertion.claims.digest.value;

console.log("signature:", sig ? "valid" : "INVALID");
console.log("digest:   ", hash ? "matches" : "MISMATCH");
'

The key

One Ed25519 key is published today, and it is marked status: development in the key document rather than quietly presented as more than it is. It was generated in an ephemeral build container, not on dedicated hardware in someone's custody. That is enough to establish that the copy you hold is the copy we published — which is the entire job it is doing here. It is not enough to hang a legal conclusion on, and the key document says so in the key's own assurance field, where a machine reading it will see it too.

Keys are valid for two years. A superseded key stays published and is marked revoked with a date and a reason, because a key that simply disappears turns every assertion it ever signed into “unknown key” — indistinguishable from a forgery. Revocation with a reason tells a verifier which of those two it is looking at.

Why this exists now

There is no dramatic reason. Nobody has mirrored this corpus and altered it, as far as we know. It is here because the primitive is the same one that everything after it needs: an identity assertion, an authority credential, a permission scope, a statement that some agent is allowed to act for some organisation — all of them are a signed statement with a subject, a claim, an issuer and a window of validity. The envelope was designed for that and the only thing currently inside it is a hash of a JSON file. That is the right order to build it in. A signing scheme first proved on documents nobody is attacking is a signing scheme that works before it is needed.

If a signature here fails to verify, that is either an attack or our mistake, and we would rather be told about either: rosario@lunarasociety.com.