Trust & verification
The long-term goal is for downloading an MPAI implementation to feel like pulling a signed container image: before anything runs, a consumer proves it really came from the Store and was not tampered with. The Store implements a small, TUF-like (The Update Framework) handshake for exactly this.
Two keys: an offline root, and an online signer
The Store separates the trust anchor from the day-to-day signer, so a breach of the web server is recoverable:
root.json and
revoked.json, and consumers pin this rather than the signing key.
Its private half is held off this web server; nothing the web
process can reach is able to produce a root signature.
c9b886102d2925fccebc8ce3bf19d03a6fb0e6e28d02d498fe52dbd72226b779
62e0444a3b338a425f5284a8688d4745225724138860d51e1249da5f1791b2c6
/trust/root.json/.well-known/mpai-store-root
· revocations: /trust/revoked.jsonCo-signed statements (implementer + Store)
Implementers generate their own Ed25519 keypair and register only the public key (proving possession by signing a challenge). When they sign a submission, the published statement carries two signatures — implementer-authenticity (who made it) and store-endorsement (it passed validation). The Store never holds an implementer's private key, so a Store breach cannot forge an implementer's authorship.
What the Store signs
For each published implementation the Store signs a statement that binds the Implementation ID to the exact hash of the published metadata (and, when supplied, the artifact), plus a validity window:
{
"_type": "mpai-implementation-statement",
"spec_version": "1.0",
"version": 1,
"implementation_id": "<implementation-id>",
"aim_metadata": { "url": ".../metadata", "hashes": { "sha256": "<hash of published metadata>" } },
"artifact": { "download_url": "...", "size": 213, "hashes": { "sha256": "<hash of AIM bytes>" } },
"issued": "2026-06-30T12:00:00Z",
"expires": "2026-09-28T12:00:00Z"
}
That object is canonicalized (sorted keys, no whitespace) and signed; the published bundle is
{ "signed": {…}, "signatures": [ { "keyid", "sig" } ] }, served at
/trust/implementations/<id>.json.
How a consumer (SCI) verifies — in order
- Pin the offline root keyid (from
/.well-known/mpai-store-root, cross-checked out-of-band). Verify/trust/root.jsonis self-signed by it, and read the online signing key from itssigningrole. - Load
/trust/revoked.json(root-signed); refuse any key that appears on it. - Fetch the signed statement for the Implementation ID.
- Re-canonicalize
signedand check the Store's Ed25519 signature with the online key. (Verify over bytes you re-canonicalize — never a supplied blob.) - If the statement carries an
implementer_key+ implementer-authenticity signature, verify it too — the Store's signature vouches for that key, so it is root-anchored. - Check the
implementation_idmatches; check the validity window and that the version is not older than one seen (rollback protection). - Download the metadata; check its SHA-256 equals the signed hash. If an artifact is bound: download it; check size and SHA-256.
- All pass → ACCEPT (authentic — then review the code). Any failure → REJECT.
Try it
Every step above is doable with standard tools you already have — openssl, curl,
jq, sha256sum — with no MPAI software. The complete, copy-paste sequence is in
the publishing & verification guide, section D.
A quick integrity check against the running Store:
curl -s https://mpai.store/MPAI/AIFS/Trust/Implementation/$IMPL_ID > stmt.json
curl -s "$(jq -r '.signed.artifact.download_url' stmt.json)" | sha256sum | cut -d' ' -f1
jq -r '.signed.artifact.hashes.sha256' stmt.json # the two must matchThe two hashes must be identical. If they differ, the bytes you received are not the bytes the Store signed — stop, and do not run them. Changing a single byte of the archive changes the hash, which is precisely what this check is for.
Recovering trust after an attack
Because consumers pin the offline root — not the online key — a compromised online key is
recoverable. The offline root revokes the bad key (published, signed, at
/trust/revoked.json) and signs a new root version
naming a fresh online key. A consumer's verifier walks from the root it already pinned to the new version,
confirms the offline-root signature, and starts rejecting anything signed by the revoked key — no blind
"trust us again" required.
How this maps to TUF
The envelope is kept TUF-shaped. root.json plays TUF's root role (self-signed,
versioned, with a root and a signing role); each statement is a targets-style
assertion; revoked.json is a signed kill-list. There is currently no snapshot/timestamp
role or transparency log, so freeze and rollback are bounded by the short expiry window and the version check.