OPEN SPECIFICATION

GoVTrace Receipt Format v1.

A portable, third-party-verifiable artifact attesting that an AI action was evaluated by a named policy and produced a named verdict at a named time. Signed with Ed25519. Verifiable by anyone holding the public key, without ever contacting the issuing system.

Status: StableVersion: 1.0.0License: CC BY 4.0Editor: GoVTraceAI / gobots

1. Design goals

  1. Portable. A receipt can be detached from the issuing system and verified anywhere by anyone with the public key.
  2. Third-party verifiable. Verification does not require the issuer to be online, in business, or cooperative.
  3. Tamper-evident. Any modification to any signed field invalidates the signature.
  4. Compact. Receipts fit in a single JSON object suitable for embedding in logs, contracts, eDiscovery exports, and audit reports.
  5. Stable. v1 is frozen. Forward-compatible additions arrive as v1.x. Breaking changes arrive as v2.

2. Receipt object

A v1 receipt is a JSON object with the following top-level fields. Additional issuer-defined keys are allowed and MUST NOT be a reason to reject the receipt.

FieldTypeReqDescription
receipt_idstringyesUnique identifier. Format is issuer-defined.
signed_atstring (RFC 3339 UTC)yesTime the receipt was signed.
signature_algostringyesMUST be "Ed25519" in v1.
signaturestring (base64url)yesUnpadded base64url Ed25519 signature.
public_key_idstringyesStable identifier for the issuing public key.
signed_fieldsarray of stringsyesOrdered list of keys present in signed_fields_data.
signed_fields_dataobjectyesThe actual key/value mapping that was canonicalized and signed.
canonical_digeststring (hex)yesLowercase SHA-256 hex of the canonical bytes.
pdf_urlstringnoIssuer-served URL to a human-readable PDF rendition.
verify_urlstringnoIssuer-served URL to walk the chain (if any).

2.1 Required fields in signed_fields_data

A v1-compliant receipt MUST include at least these six keys. Issuer-defined keys MAY be added and are covered by the same signature.

FieldTypeReqDescription
run_idstringyesIssuer-defined identifier for the AI action being attested.
verdictstringyesThe decision: STOP, NEEDS_REVIEW, SAFE, or issuer-defined.
record_hashstringyesSHA-256 hex of the canonical record (DoCR) the verdict was made on.
policy_digeststringyesSHA-256 hex of the policy bundle that produced the verdict.
input_hashstringyesSHA-256 hex of the AI action's input bytes.
timestampstringyesRFC 3339 UTC timestamp of the verdict.

3. Canonicalization

The canonical byte string of signed_fields_data is JSON with sorted keys at every level, compact separators ("," and ":"), no whitespace, UTF-8.

# Python reference
import json
canonical = json.dumps(
    signed_fields_data,
    sort_keys=True,
    separators=(",", ":"),
).encode("utf-8")
// Node.js reference (no deps)
function canonicalize(value) {
  if (value === null || typeof value !== 'object') return JSON.stringify(value)
  if (Array.isArray(value)) return '[' + value.map(canonicalize).join(',') + ']'
  const keys = Object.keys(value).sort()
  return '{' + keys.map(k =>
    JSON.stringify(k) + ':' + canonicalize(value[k])
  ).join(',') + '}'
}

The canonical_digest field MUST equal sha256(canonical_bytes) rendered as lowercase hex. A verifier MAY recompute it and reject the receipt on mismatch.

4. Signing

The signature covers the raw 32 bytes of the SHA-256 digest of the canonical bytes. Not the hex string of the digest. Not the canonical bytes themselves. This produces a fixed-length signing input independent of receipt size.

digest_bytes = sha256(canonical_bytes)             # 32 bytes
signature    = ed25519.sign(private_key, digest_bytes)
signature_b64url = base64url_unpadded(signature)

The signature is an Ed25519 signature as defined by RFC 8032.

5. Public key publication

Issuers MUST publish their public key at a stable HTTPS URL. The recommended location is:

https://<issuer-domain>/.well-known/govtrace-pubkey.json

The document MUST be a JSON object with this shape:

{
  "key_id": "govtrace-signing-v1",
  "algorithm": "Ed25519",
  "public_key_b64url": "OwOdZ-d9QHwtuRCreEn6SIZ9iTuWxTpJPfeN5pGL-ns",
  "public_key_pem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n",
  "signs": "GoVTrace Receipt v1",
  "signature_encoding": "base64url (unpadded)"
}

The key_id in the published document MUST equal the public_key_id field in any receipt the holder of the corresponding private key issues. The reference engine publishes its key at https://govtrace-api.vercel.app/.well-known/govtrace-pubkey.json.

6. Verification procedure

Given a receipt object R:

  1. Validate R.signature_algo == "Ed25519". Otherwise reject.
  2. Resolve the public key for R.public_key_id. Pin it, fetch from /.well-known/govtrace-pubkey.json, or accept it out of band.
  3. Recompute the canonical bytes of R.signed_fields_data per section 3.
  4. Compute digest_bytes = sha256(canonical_bytes).
  5. (Recommended.) Verify R.canonical_digest == hex(digest_bytes).
  6. Verify the Ed25519 signature against digest_bytes using the resolved key.

If step 6 succeeds, the receipt is VALID. The verifier SHOULD echo back signed_fields_data so the user sees exactly what was attested. If step 6 fails, the receipt is INVALID and the verifier SHOULD NOT present signed_fields_data as trustworthy.

7. JSON Schema

A machine-readable JSON Schema for the receipt object is published at:

https://gobotsai.com/spec/receipt.schema.json

The schema is normative for field names and types. This document is normative for canonicalization and signing.

8. Reference implementations

9. Versioning and stability

  • v1 is frozen as of the publication date of this document.
  • Additive, backward-compatible changes to issuer-defined keys in signed_fields_data are allowed at any time.
  • Changes that affect signing or canonicalization rules require a major version bump (v2). v1 verifiers SHOULD reject receipts carrying an unrecognized spec_version.

10. Security considerations

  • A verifier MUST resolve the public key from a source the verifier itself trusts. Never accept a public key embedded in the same receipt being verified.
  • A receipt does not attest that the AI action signed actually occurred in the real world. It attests only that the issuer evaluated a given input under a given policy and reached the recorded verdict at the recorded time. Combine receipts with execution-time evidence to reconstruct what happened.
  • Receipts are not anonymized. Avoid placing direct identifiers in signed_fields_data. Use hashes (record_hash, input_hash) instead.

FULL TEXT

This page is a rendering of the canonical specification. The authoritative source is the Markdown file in the GoVTraceAI repository, published under CC BY 4.0.

Request a Walkthrough →

Week 1: working system