Proof Format: occ/1
Normative specification for the occ/1 proof format. Derived from the reference implementation.
Proof JSON schema
{
"version": "occ/1", // REQUIRED - exact value
"artifact": {
"hashAlg": "sha256", // REQUIRED - "sha256" only in v1
"digestB64": "<base64>" // REQUIRED - SHA-256, 32 decoded bytes
},
"commit": {
"nonceB64": "<base64>", // REQUIRED - >=16 decoded bytes
"counter": "42", // OPTIONAL - decimal string, monotonic
"slotCounter": "41", // OPTIONAL - slot's counter (< commit counter)
"slotHashB64": "<base64>", // OPTIONAL - SHA-256 of canonical slot body
"time": 1700000000000, // OPTIONAL - Unix ms
"prevB64": "<base64>", // OPTIONAL - chain link, 32 bytes
"epochId": "<hex>" // OPTIONAL - SHA-256 hex
},
"signer": {
"publicKeyB64": "<base64>", // REQUIRED - Ed25519, 32 bytes
"signatureB64": "<base64>" // REQUIRED - Ed25519, 64 bytes
},
"environment": {
"enforcement": "measured-tee", // REQUIRED - "stub"|"hw-key"|"measured-tee"
"measurement": "<opaque>", // REQUIRED - non-empty string
"attestation": { // OPTIONAL
"format": "aws-nitro", // REQUIRED when parent present
"reportB64": "<base64>" // REQUIRED when parent present
}
},
"slotAllocation": { // OPTIONAL - causal slot record
"version": "occ/slot/1",
"nonceB64": "<base64>", // same as commit.nonceB64
"counter": "41", // same as commit.slotCounter
"time": 1700000000000,
"epochId": "<hex>",
"publicKeyB64": "<base64>", // enclave Ed25519 key
"signatureB64": "<base64>" // Ed25519 over canonical slot body
},
"agency": { // OPTIONAL - actor-bound proof
"actor": { keyId, publicKeyB64, algorithm, provider },
"authorization": { purpose, actorKeyId, artifactHash, challenge, timestamp, signatureB64 },
"batchContext": { // OPTIONAL - present on batch proofs
"batchSize": 8,
"batchIndex": 0,
"batchDigests": ["<base64>", ...]
}
},
"attribution": { // OPTIONAL - signed creator metadata
"name": "string",
"title": "string",
"message": "string"
},
"timestamps": { // OPTIONAL - external timestamps
"artifact": { TsaToken },
"proof": { TsaToken }
},
"metadata": { }, // OPTIONAL - NOT signed, advisory
"claims": { } // OPTIONAL - NOT signed, advisory
}Signed body
The Ed25519 signature covers the canonical serialization of a SignedBody object:
{
version: proof.version,
artifact: proof.artifact,
actor: proof.agency?.actor, // when present
attribution: proof.attribution, // when present
commit: proof.commit, // ALL fields verbatim
publicKeyB64: proof.signer.publicKeyB64,
enforcement: proof.environment.enforcement,
measurement: proof.environment.measurement,
attestationFormat: proof.environment.attestation?.format // when present
}What is NOT signed
| Field | Reason |
|---|---|
signatureB64 | The seal -- cannot sign itself |
attestation.reportB64 | Vendor-signed, self-authenticating separately |
slotAllocation | Self-authenticating (own Ed25519 signature); bound via commit.slotHashB64 |
agency | P-256 signature independently verifiable; actor identity IS in signed body |
timestamps | Added post-signature by external TSA |
metadata | Advisory, not trusted |
claims | Advisory, not trusted |
Causal slot allocation
Every proof is causally bound to a pre-allocated slot. The slot is created before the artifact hash is known, proving the enclave committed to a nonce and counter independently of the artifact content.
| Binding | How |
|---|---|
| Nonce binding | commit.nonceB64 === slotAllocation.nonceB64 |
| Counter ordering | commit.slotCounter < commit.counter |
| Hash binding | commit.slotHashB64 === SHA-256(canonicalize(slotBody)) |
| Same enclave | slotAllocation.publicKeyB64 === signer.publicKeyB64 |
The slot has its own Ed25519 signature proving the enclave created it. The commit signature includes slotHashB64, cryptographically binding the proof to that exact slot.
Canonical serialization
The signed body is serialized to bytes using a deterministic algorithm:
- 1. Recursively sort all object keys in Unicode code-point order
- 2. Serialize with
JSON.stringify()-- no whitespace - 3. Encode the resulting string as UTF-8 (no BOM)
Top-level key order after sort:
actor? → artifact → attestationFormat? → attribution? → commit → enforcement → measurement → publicKeyB64 → version
Field classification
Signed (security-critical)
These fields are in the SignedBody. Tampering invalidates the signature:
version, artifact.*, agency.actor (when present), attribution.* (when present), commit.*, signer.publicKeyB64, environment.enforcement, environment.measurement, attestation.formatSelf-authenticating
Not in the signed body, but independently verifiable:
signatureB64 (Ed25519), attestation.reportB64 (vendor-signed), slotAllocation (own Ed25519 signature), agency.authorization (P-256)Advisory (unsigned)
Not signed. Must not be used for security decisions: timestamps, metadata, claims.
Algorithms
| Purpose | Algorithm | Details |
|---|---|---|
| Proof signature | Ed25519 (RFC 8032) | 32-byte key, 64-byte signature |
| Agency signature | ECDSA P-256 / ES256 | WebAuthn or direct; device-bound key |
| Hash | SHA-256 (FIPS 180-4) | 32 bytes, Base64 encoded |
| Encoding | Base64 (RFC 4648 §4) | Standard, with = padding |
| Counter | Decimal string | BigInt-safe, no leading zeros |