# Publishing and consuming with standard tools only

No MPAI software required on either end — just `openssl`, `curl`, `jq`, `sha256sum`
(and `xxd`), which every developer already has. The signatures made with `openssl` verify
against the Store byte-for-byte.

> **Section D was executed against this deployment on 2026-08-05** and returned `ACCEPT` for a
> real published implementation. If you change these commands, re-run them — the previous
> version of this document claimed to have been verified and had not been run here at all.

> **Certificate:** since 2026-08-06 this Store runs at `https://mpai.store` with a publicly
> trusted Let's Encrypt certificate, so no `-k` is needed. Every `curl` still goes through
> `$CURL` so the whole procedure can be pointed elsewhere by overriding one variable. The bare
> IP `https://51.89.150.50` also still answers, but with a self-signed certificate — if you use
> it, set `CURL="curl -k"` or curl exits 60 and, because these commands use `-s`, fails
> **silently** with an empty file.

Requires **OpenSSL 3.0+** (for `pkeyutl -rawin`, needed by Ed25519). Two rules that will
bite you otherwise: sign a **file**, never a pipe (Ed25519 is one-shot); and canonical
JSON is exactly **`jq -cSa`** with **no trailing newline**.

> **The `a` in `jq -cSa` is load-bearing — do not drop it.** The Store canonicalizes with
> Python's `ensure_ascii=True`, so every non-ASCII character is `\uXXXX`-escaped. `jq -cS`
> emits raw UTF-8, which is *different bytes* and a different SHA-256. One accented letter or
> em-dash in your metadata and you sign the wrong bytes; the Store rejects you and the error
> will not tell you why. `jq -cSa` (`--ascii-output`) matches the Store byte-for-byte.

Set these once:
```bash
STORE=https://mpai.store            # this Store's base URL
CURL="curl"                         # a real, publicly trusted certificate — no -k needed
ME=MPAI0050                         # your Implementer ID (from signing up)
TOKEN=xxxxxxxx                      # your submission token (shown once at sign-up)
AIM=MMC-TIQ-V2.5                    # the AIM you implement
META=my_metadata.json              # your AIM Metadata — MPAI-AIF V3 (V2 is rejected)
ARCHIVE=pkg.zip                    # the binary you built
ARCHIVE_URL=https://you.example/pkg.zip   # where YOU host it (the Store won't)
```

---

## A. Implementer — set up your key (once)

```bash
# make a signing key; the private half never leaves this machine
openssl genpkey -algorithm ED25519 -out mpai_key.pem

# its public half as raw hex (the only thing the Store gets)
PUB=$(openssl pkey -in mpai_key.pem -pubout -outform DER | tail -c 32 | xxd -p -c 32 | tr -d '\n')

# register it
$CURL -sS -X POST "$STORE/MPAI/AIFS/Implementer/Key" -H 'Content-Type: application/json' \
  -d "$(jq -n --arg i "$ME" --arg t "$TOKEN" --arg p "$PUB" \
        '{implementer:$i,token:$t,public:$p}')" > reg.json
KID=$(jq -r .keyid reg.json); NONCE=$(jq -r .nonce reg.json)

# prove you hold the private key: sign the Store's nonce (to a FILE, then send the hex)
printf '%s' "$NONCE" > nonce.txt
openssl pkeyutl -sign -inkey mpai_key.pem -rawin -in nonce.txt -out nonce.sig
$CURL -sS -X POST "$STORE/MPAI/AIFS/Implementer/Key/Confirm" -H 'Content-Type: application/json' \
  -d "$(jq -n --arg i "$ME" --arg t "$TOKEN" --arg k "$KID" \
        --arg s "$(xxd -p -c 256 nonce.sig | tr -d '\n')" \
        '{implementer:$i,token:$t,keyid:$k,signature:$s}')"
```

## B. Implementer — publish (per implementation)

```bash
# 1. fingerprint the archive
ASHA=$(sha256sum "$ARCHIVE" | cut -d' ' -f1); ASIZE=$(stat -c%s "$ARCHIVE")
AMD5=$(md5sum "$ARCHIVE" | cut -d' ' -f1)

# 2. the canonical hash of your metadata (jq -cSa: keys sorted, compact, ASCII-escaped, no
#    trailing newline — this is exactly what the Store hashes, so the bytes must match)
MSHA=$(printf '%s' "$(jq -cSa . "$META")" | sha256sum | cut -d' ' -f1)

# 3. sign the submission manifest (proves you authored this submission)
jq -cSa -n --arg i "$ME" --arg m "$MSHA" --arg a "$ASHA" \
  '{_type:"mpai-submission",spec_version:"1.0",implementer_id:$i,metadata_sha256:$m,artifact_sha256:$a}' \
  | tr -d '\n' > manifest.json
openssl pkeyutl -sign -inkey mpai_key.pem -rawin -in manifest.json -out sub.sig

# 4. submit
$CURL -sS -X POST "$STORE/MPAI/AIFS/AIM" -H 'Content-Type: application/json' \
  -d "$(jq -n --arg i "$ME" --arg t "$TOKEN" --arg a "$AIM" --slurpfile md "$META" \
        --arg url "$ARCHIVE_URL" --arg sha "$ASHA" --arg md5 "$AMD5" --argjson size "$ASIZE" \
        --arg sig "$(xxd -p -c 256 sub.sig | tr -d '\n')" \
        '{implementer:$i,token:$t,aim:$a,metadata:$md[0],
          artifact:{download_url:$url,sha256:$sha,md5:$md5,size:$size},signature:$sig}')" > submit.json
IID=$(jq -r .id submit.json)
jq -r '.store_changes[]? | "changed: " + .' submit.json    # what the Store did to your file

# 5. counter-sign the statement the Store just signed (binds you to the PUBLISHED bytes +
#    the archive hash — this is the step that makes the signature un-swappable)
printf '%s' "$(jq -cSa '.statement.signed' submit.json)" > body.txt
openssl pkeyutl -sign -inkey mpai_key.pem -rawin -in body.txt -out cnt.sig
$CURL -sS -X POST "$STORE/MPAI/AIFS/Implementation/$IID/Countersign" -H 'Content-Type: application/json' \
  -d "$(jq -n --arg s "$(xxd -p -c 256 cnt.sig | tr -d '\n')" '{signature:$s}')"

# 6. host THIS file (it now carries the Store's Implementation ID) next to your archive
jq '.metadata' submit.json > stamped.json
```

## C. MPAI Store (operator) — one manual step

Approve the new implementer in `$STORE/admin` (turns their sign-up from *pending* into
*accepted* so their token works). Everything else — validating the metadata against the
V3 AIM Metadata schema (`AIMMetadata.json`; V2 metadata is rejected), assigning the
Implementation ID, signing the statement — is automatic on submit.

Withdrawing an implementation later in `/admin` hides it from the listings and makes
`/Implementation/{id}/Verify` answer `REVOKED` — but it does **not** invalidate the signed
statement already in the wild, which keeps verifying offline until it expires. Revoking a
*key* for real needs the offline root key (`scripts/trust_admin.py revoke`), which re-signs
`revoked.json`.

## D. Controller (consumer) — find, verify, run

Save this as `verify.sh` and run it (`STORE=… AIM=… ROOT_KID=… bash verify.sh`). It is a script
rather than a paste-into-your-shell sequence for one reason: **every check has to be able to stop
it**. `set -e` in your interactive shell would close your terminal on a rejection, and without it
a failed `openssl` just scrolls past and the run still ends on ACCEPT. Treat this block as code —
it is the only thing standing between you and a forged Store.

```bash
#!/usr/bin/env bash
set -euo pipefail
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
# Self-default so this block runs standalone under `set -u`. Override with CURL="curl -k"
# if you point STORE at the bare IP, which still serves a self-signed certificate.
CURL=${CURL:-curl}

hex2pem  () { printf '302a300506032b6570032100%s' "$1" | xxd -r -p | openssl pkey -pubin -inform DER; }
die      () { echo "REJECT: $*" >&2; exit 1; }
# A keyid IS the SHA-256 of the raw public key. That is what makes pinning mean anything: nobody
# can produce a different key with the same id. Never take a key from a document merely because
# the document filed it under the id you wanted.
keyid_of () { printf '%s' "$1" | xxd -r -p | sha256sum | cut -d' ' -f1; }

# root_signed <doc> <expected _type> <doc holding the trusted root keys> [keyid that MUST have signed]
# Checks a document the offline root signs — root.json itself, or revoked.json. In order: the
# declared type (root.json and revoked.json are signed identically, so without this a replayed
# root.json passes as an EMPTY revocation list); expiry; that every root key genuinely owns the
# id it is filed under; and that enough distinct valid root signatures meet the root's threshold.
root_signed () {
  local doc=$1 want=$2 trust=$3 need_kid=${4:-} good=0 need exp kid pub sig
  [ "$(jq -r '.signed._type' "$doc")" = "$want" ] \
    || die "$doc declares _type $(jq -r '.signed._type' "$doc"), expected $want"
  exp=$(jq -r '.signed.expires // empty' "$doc")
  [ -z "$exp" ] || [ "$(date -u -d "$exp" +%s)" -gt "$(date -u +%s)" ] || die "$doc expired ($exp)"
  printf '%s' "$(jq -cSa '.signed' "$doc")" > "$TMP/body"
  for kid in $(jq -r '.signed.roles.root.keyids[]' "$trust"); do
    pub=$(jq -r --arg k "$kid" '.signed.keys[$k].public // empty' "$trust")
    [ -n "$pub" ] || continue
    [ "$(keyid_of "$pub")" = "$kid" ] || die "root key filed under $kid does not hash to that id"
    sig=$(jq -r --arg k "$kid" '.signatures[]?|select(.keyid==$k).sig' "$doc" | head -1)
    [ -n "$sig" ] || continue
    hex2pem "$pub" > "$TMP/pem"; printf '%s' "$sig" | xxd -r -p > "$TMP/sig"
    if openssl pkeyutl -verify -pubin -inkey "$TMP/pem" -rawin -in "$TMP/body" -sigfile "$TMP/sig" \
         >/dev/null 2>&1; then
      good=$((good+1))
      if [ "$kid" = "$need_kid" ]; then need_kid=SIGNED; fi
    fi
  done
  need=$(jq -r '.signed.roles.root.threshold // 1' "$trust")
  [ "$good" -ge "$need" ] || die "$doc carries $good valid root signature(s), threshold is $need"
  [ -z "${4:-}" ] || [ "$need_kid" = SIGNED ] || die "$doc is not signed by your pinned root key"
}

# 1+2. ask the Store which implementation fits this host
$CURL -fsS -X POST "$STORE/MPAI/AIFS/AIM/$AIM/Select" -H 'Content-Type: application/json' \
  -d '{"budget":{"memory":"8G","cpu":{"class":"High"}},"architecture":"x86-64","os":"Linux","policy":"CHEAPEST"}' > sel.json
IID=$(jq -r .selected sel.json)
jq -r '.candidates[] | "  "+.id+"  "+.fit+"  score="+(.score|tostring)' sel.json

# 3. fetch the signed statement, the root, and the revocation list
$CURL -fsS "$STORE/MPAI/AIFS/Trust/Implementation/$IID" > stmt.json
$CURL -fsS "$STORE/MPAI/AIFS/Trust/Root" > root.json
$CURL -fsS "$STORE/MPAI/AIFS/Trust/Revoked" > revoked.json
printf '%s' "$(jq -cSa '.signed' stmt.json)" > signed.bin

# 4. REQUIRED: root.json must be the root you pinned. ROOT_KID must reach you by some other
#    channel than this download. A root you simply accept from the server proves nothing — an
#    attacker who serves you their own root and their own statements passes every check below,
#    and revocation silently stops working.
: "${ROOT_KID:?set it to the root keyid you were given out-of-band: printed fingerprint, config, mail}"
root_signed root.json mpai-root root.json "$ROOT_KID"

# 5. the revocation list is signed by that SAME offline root — verify it the same way. Fail
#    closed: no list, or a list you cannot verify, is a REJECT, not an empty list.
[ -s revoked.json ] || die "no revocation list — refuse"
root_signed revoked.json mpai-revocations root.json

# 6. the Store's online signing key comes from the now-verified root — and must not be revoked
KID=$(jq -r '.signed.roles.signing.keyids[0]' root.json)
jq -e --arg k "$KID" '.signed.revoked[]?|select(.keyid==$k)' revoked.json >/dev/null \
  && die "the Store's signing key is REVOKED" || true
STORE_PUB=$(jq -r --arg k "$KID" '.signed.keys[$k].public' root.json)
[ "$(keyid_of "$STORE_PUB")" = "$KID" ] || die "the signing key does not hash to its own keyid"
hex2pem "$STORE_PUB" > store_pub.pem
jq -r '.signatures[]|select(.role=="store-endorsement").sig' stmt.json | xxd -r -p > store.sig
openssl pkeyutl -verify -pubin -inkey store_pub.pem -rawin -in signed.bin -sigfile store.sig \
  || die "the Store's endorsement signature does not verify"

# 6b. the statement itself must still be inside its validity window. Statements are issued for
#     a fixed term; an expired one is not evidence about the file today.
SEXP=$(jq -r '.signed.expires // empty' stmt.json)
[ -z "$SEXP" ] || [ "$(date -u -d "$SEXP" +%s)" -gt "$(date -u +%s)" ] \
  || die "the trust statement expired ($SEXP) — ask the implementer to have it re-issued"

# 7. verify the implementer's counter-signature IF THERE IS ONE. Counter-signing is OPTIONAL:
#    it is offered at submission and many implementations are published without it. Absence is
#    not a fault — but it does mean the statement carries the Store's endorsement only, with no
#    proof of authorship. Decide for yourself whether that is enough for your use.
IMPL_PUB=$(jq -r '.signed.implementer_key.public // empty' stmt.json)
if [ -n "$IMPL_PUB" ]; then
  IMPL_KID=$(jq -r '.signed.implementer_key.keyid // empty' stmt.json)
  [ "$(keyid_of "$IMPL_PUB")" = "$IMPL_KID" ] || die "the implementer key does not hash to its own keyid"
  jq -e --arg k "$IMPL_KID" '.signed.revoked[]?|select(.keyid==$k)' revoked.json >/dev/null \
    && die "the implementer's signing key is REVOKED" || true
  hex2pem "$IMPL_PUB" > impl_pub.pem
  jq -r '.signatures[]|select(.role=="implementer-authenticity").sig' stmt.json | xxd -r -p > impl.sig
  openssl pkeyutl -verify -pubin -inkey impl_pub.pem -rawin -in signed.bin -sigfile impl.sig \
    || die "the implementer's counter-signature does not verify"
  COSIGN="counter-signed by the implementer"
else
  # If YOUR policy requires proof of authorship, change this line to: die "not counter-signed"
  COSIGN="NOT counter-signed — Store endorsement only"
fi

# 8. metadata hash matches the signed hash
$CURL -fsS "$(jq -r '.signed.aim_metadata.url' stmt.json)" > meta.bin \
  || die "could not FETCH the published metadata (network/TLS), which is not a hash mismatch"
[ "$(sha256sum meta.bin | cut -d' ' -f1)" = "$(jq -r '.signed.aim_metadata.hashes.sha256' stmt.json)" ] \
  || die "metadata hash mismatch"

# 9. download the archive FROM THE IMPLEMENTER and check its hash against the signed one
$CURL -fsS "$(jq -r '.signed.artifact.download_url' stmt.json)" -o impl.zip \
  || die "could not DOWNLOAD the archive from the implementer (network/TLS), not a hash mismatch"
[ "$(sha256sum impl.zip | cut -d' ' -f1)" = "$(jq -r '.signed.artifact.hashes.sha256' stmt.json)" ] \
  || die "archive hash mismatch"

echo "ACCEPT — $IID ($COSIGN)"
```

If it prints ACCEPT it is the file the named implementer published and the Store stands
behind it. That is authenticity, not safety — read the code before you run it. It is not
freshness either: there is no signed catalogue, and `revoked.json` revokes *keys*, not
implementations, so a **withdrawn** implementation's statement still verifies until it
expires. To catch that you must ask the Store online:

```bash
$CURL -sS -X POST "$STORE/MPAI/AIFS/Implementation/$IID/Verify" -H 'Content-Type: application/json' \
  -d "$(jq -n --arg f "$(sha256sum impl.zip | cut -d' ' -f1)" \
        '{fingerprint:$f,algorithm:"SHA256",subject:"ARCHIVE"}')"   # VALID | INVALID | REVOKED
```

---

**Why this is the whole story:** the bytes signed here (`jq -cSa` output) are byte-identical to
the Store's own canonicalization — checked on metadata full of accents and em-dashes, same
SHA-256 — and `openssl`'s Ed25519 is the same algorithm the Store verifies with. Nothing above
needs software from MPAI or from us, and that is the point, not a convenience: a consumer who
must first download and trust our verifier has only moved the question of what to trust.

There is deliberately **no MPAI-supplied verifier program** — a consumer who must first download
and trust our tool has only moved the question of what to trust. This section IS the definition of
verification. (The Store's own trust tests exercise the same checks through an internal reference
implementation at `tests/_sci_verify.py`; it is test infrastructure, never shipped or required, and
where it and this section could ever disagree, this section is right.)
