AISOURCEOFTRUTH.COM
SCITT · RFC 9943 TRANSPARENCY SERVICE · SCRAPI

Register a signed statement, get a receipt and a permanent page

AI Source of Truth runs as a SCITT Transparency Service. Send a COSE_Sign1 signed statement over SCRAPI and get back a COSE receipt that any SCITT verifier can check offline with our log key. Each registered statement also gets the same permanent page every record gets. The receipt proves the statement is in the log. The page says what it is.

6
ROUTES
4
ISSUER ALGORITHMS
2
PAYLOAD PROFILES
SCRAPI ENDPOINTS

Base https://aisourceoftruth.com

ROUTEMETHODWHAT IT DOES
/entriesPOSTRegister a signed statement (Content-Type application/cose) with a Tier-2 token. 201 with the receipt and Location, or 202 with Location and Retry-After.
/entries/{entry_id}GETThe COSE receipt (200), 204 with Retry-After 5 while no checkpoint covers it yet, or 404. The entry id is the sha256 of the statement bytes.
/.well-known/scitt-keysGETThe COSE Key Set receipts verify with (application/cbor).
/.well-known/scitt-keys/{kid}GETOne COSE key by its base64url kid, or 404 "No such key".
/.well-known/transparency-configurationGETDiscovery: registration path, receipt format, keys and payload rules. CBOR, or JSON on Accept: application/json.
/r/{entry_id}GETThe permanent record page every registered statement gets, with errata, lineage and sealing on top.

Configuration: https://aisourceoftruth.com/.well-known/transparency-configuration. Spec: RFC 9943 (architecture), draft-ietf-scitt-scrapi-11 (SCRAPI), RFC 9942 (COSE receipts), RFC 9995 (hash envelope).

SUBMIT A STATEMENT

The payload is the hash of your content, never the content

  1. Register a publisher and its key (POST /v1/publishers). The COSE kid is that key id, <publisher>#<version>.
  2. Build a tagged COSE_Sign1 with alg, kid and CWT claims (15) iss and sub in the protected header, and an empty unprotected header.
  3. Put the hash of your content in the payload, never the content: a hash envelope, or a hashes-only JSON agent receipt.
  4. POST it to /entries with a Tier-2 Bearer token from /oauth/token.
curl -X POST https://aisourceoftruth.com/entries -H 'content-type: application/cose' -H 'authorization: Bearer <tier-2 token>' --data-binary @statement.cose -o receipt.cose
  • 201 Created: the body is the COSE receipt; Location is /entries/{entry_id}.
  • 202 Accepted: no checkpoint covered it within the wait; poll Location after Retry-After (5 s).
  • 4xx: Concise Problem Details (application/concise-problem-details+cbor) with the SCRAPI title, for example Malformed request or Bad Signature Algorithm.
  • Anonymous submit is refused: there is no private or unsigned ingest path.
issuer algorithmsES256 (P-256) (-7), ESP256 (P-256) (-9), EdDSA (Ed25519) (-8), Ed25519 (-19)
largest statement65,536 bytes
ACCEPTED PAYLOAD PROFILES
PROFILEHEADERACCEPTSMAX BYTES
Hash envelope (RFC 9995)258 payload_hash_alg, optional 259 preimage content type and 260 locationpayload is the artifact digest: sha-256 (-16)65,536
JSON agent receipt3 content typeapplication/json, application/agent-receipt+json, application/vnd.aisot.agent-receipt+json; hashes, identifiers, signatures and URLs only16,384

Anything else in the payload is content and is refused.

THE RECEIPT

RFC 9942, RFC9162_SHA256

formatCOSE_Sign1 by the log key, verifiable data structure RFC9162_SHA256 (395: 1)
protected{ 1: -8 (EdDSA), 4: kid, 15: { 1: issuer, 2: statement sub }, 395: 1 }
unprotected{ 396: { -1: [ bstr .cbor [tree_size, leaf_index, [audit path]] ] } }
payloaddetached: the RFC 6962 root of the latest checkpoint, which a verifier recomputes from the proof
entrythe record digest, sha256 of the statement bytes; leaf hash = SHA-256(0x00 || digest)
kidthe RFC 9679 COSE Key Thumbprint of the log key

A RECEIPT PROVES

  • this exact signed statement is in the log at that index
  • the log key signed the tree head that contains it

A RECEIPT DOES NOT PROVE

  • that the statement is true, or that the agent behaved well
  • anything about content the registry never saw: it stores the hash
SDK

npm install @aisourceoftruth/sdk

HELPERWHAT IT DOES
buildHashEnvelopeStatement({ artifactDigest, keyId, privateJwk, iss, sub })a COSE_Sign1 over the artifact's SHA-256 (RFC 9995 hash envelope), signed locally
client.registerStatement(bytes)POST /entries; the receipt on 201, null on 202
client.receipt(entryId)GET /entries/{id}; the receipt, or null while pending
CHECK A RECEIPT OFFLINE
curl -s https://aisourceoftruth.com/entries/<entry_id> -o receipt.cose
curl -s https://aisourceoftruth.com/.well-known/scitt-keys -o scitt-keys.cbor
curl -s https://aisourceoftruth.com/v1/export/verify.mjs -o verify.mjs
node verify.mjs --receipt receipt.cose --statement statement.cose --keys scitt-keys.cbor

POST /v1/export bundles carry each statement's receipt and the key set; node verify.mjs bundle.json checks the issuer signature and the receipt.

SIGSTORE BUNDLES AND OPENSSF MODEL SIGNING

LIVE A provenance record can carry a Sigstore bundle or an OpenSSF Model Signing signature as evidence about the artifact, and every record downloads as a Sigstore bundle. The Sigstore signer is shown apart from the publisher who signed the record.

importPut sigstore: { bundle } (and public_key for a bare-key bundle) in a provenance record and publish it through POST /v1/records as usual. No separate route. Accepts a Sigstore bundle (message signature or DSSE in-toto statement); an OpenSSF Model Signing model.sig; each signed model file digest resolves through /a/{sha256}. Bundle versions 0.1, 0.2, 0.3, at most 262,144 bytes.
refusedA bundle that fails any check refuses the whole record with 422 sigstore_invalid, naming the check in sigstore_check.
sdkbuildSigstoreProvenance({ bundle, creator, model }) in @aisourceoftruth/sdk
exportGET https://aisourceoftruth.com/r/{digest}/sigstore-bundle · application/vnd.dev.sigstore.bundle.v0.3+json · log entry kind aisot-record 0.0.1. Any record that is not a SCITT statement, as a bundle: the publisher's key as the verification material, the publisher's signature as a message signature over the record body, and one log entry for the registry log with its inclusion proof and the signed checkpoint. Computed on read; free.
trusted roothttps://aisourceoftruth.com/.well-known/sigstore/trusted_root.json · The registry log key and the pinned timestamp authority roots, so a verifier can check exported bundles. Stock Sigstore clients check the message signature and reject the unknown log entry kind; verify.mjs checks the proof and the checkpoint.

VERIFIED AT INGEST

  • the DSSE or message signature over the artifact digest
  • each Rekor v1 or v2 log entry: its body, the signed entry timestamp, the inclusion proof and the signed checkpoint, against the pinned Sigstore public-good trusted root
  • each RFC 3161 timestamp over the signature, against the trusted root's TSA chains
  • a Fulcio certificate: the code signing use, the chain and validity at the verified signing time
  • that the record's artifact digest is one the bundle signs

NOT VERIFIED

  • the certificate's embedded SCT
  • the TSA certificate's revocation status
  • a bare key bundle has no anchor: the key is the signer's own claim or the one the publisher supplied
  • a certificate from a private CA is refused, not checked
$ curl -H 'Accept: application/json' https://aisourceoftruth.com/.well-known/transparency-configuration # the service configuration as data
$ curl -H 'Accept: application/json' https://aisourceoftruth.com/scitt # this page is a rendering of the API. Reproduce it as data.