{
  "protocol_version": "1.0",
  "name": "Rensei audit-chain verification key catalog",
  "issued_at": "2026-05-21",
  "description": "Rensei's audit chain signs each entry with a workspace-scoped Ed25519 key. Verification of any segment of the chain requires the public key corresponding to the signing_key_id referenced in the entry. This document describes the verification protocol and points at the catalog locations where per-workspace public keys are served.",
  "algorithm": {
    "signature": "Ed25519",
    "key_size_bits": 256,
    "key_format": "raw",
    "key_encoding": "base64",
    "signed_payload": "sha256(canonical(entry))",
    "entry_canonicalization": "RFC 8785 (JCS) over the audit_events row excluding the signature field. The platform implementation covers the ASCII subset of JCS sufficient for the current audit_events schema. Payloads containing non-ASCII strings or floating-point numbers require the full RFC 8785 specification, which is on the roadmap.",
    "reference": "RFC 8032 (Ed25519), RFC 8785 (JCS)"
  },
  "key_lifecycle": {
    "scope": "workspace",
    "rotation": "signing_key_id values identify the key entry under which an audit record was signed; historical entries remain verifiable against the recorded signing_key_id. Workspace key material is derived deterministically today, so registering a new signing_key_id is a lifecycle event rather than a cryptographic re-key. Cryptographic re-keying (fresh public key material per workspace, with the prior key marked revoked) is on the roadmap.",
    "revocation": "A signing key marked with a non-null revoked_at timestamp must not be used for new signatures. Verification of historical entries signed before revocation remains valid."
  },
  "discovery": {
    "saas": {
      "platform_host": "https://app.rensei.ai",
      "endpoint_pattern": "https://app.rensei.ai/.well-known/audit-keys/{workspace_id}.json",
      "notes": "The Rensei Platform serves per-workspace public keys via an unauthenticated endpoint reachable at the same path on both SaaS and self-hosted deployments. Auditors should obtain workspace_id from the audit record under review."
    },
    "self_hosted": {
      "endpoint_pattern": "{platform_host}/.well-known/audit-keys/{workspace_id}.json",
      "notes": "Customer deployments expose the catalog locally at the platform host. The path is workspace-scoped because keys are workspace-scoped."
    }
  },
  "response_format": {
    "type": "JWKS",
    "reference": "RFC 7517 (JSON Web Key Set)",
    "example": {
      "keys": [
        {
          "kid": "ksk_<12-hex>",
          "kty": "OKP",
          "crv": "Ed25519",
          "alg": "EdDSA",
          "use": "sig",
          "x": "<base64url-encoded 32-byte public key>",
          "rensei:workspace_id": "ws_<id>",
          "rensei:created_at": "<ISO 8601>",
          "rensei:revoked_at": null
        }
      ]
    }
  },
  "verification_steps": [
    "Read signing_key_id from the audit-chain entry.",
    "Retrieve the corresponding public key via the discovery endpoint matching the deployment model (SaaS or self-hosted).",
    "Canonicalize the entry per RFC 8785 (JCS), excluding the signature field.",
    "Compute SHA-256 over the canonicalized form.",
    "Verify the Ed25519 signature against the 32-byte SHA-256 digest from step 4 (not the canonical JSON string). The platform signs the digest, so use an Ed25519 implementation that accepts the raw 32-byte input; libraries that hash the message internally before signing will produce mismatched verifications.",
    "Confirm signing_key_id has no revoked_at timestamp earlier than the entry's occurred_at."
  ],
  "verification_documentation": "https://rensei.ai/security#audit",
  "schema_version_url": "https://rensei.ai/.well-known/audit-keys.json",
  "keys": []
}
