Receipts require at least one signature.

Signature entry fields:

  • keyId - signer key identity.
  • algorithm - signature suite (Ed25519, ECDSA-*, etc.).
  • signature - base64 signature payload.
  • signedAt - signature timestamp.

Optional controls:

  • signedContent with canonicalization mode and content hash.
  • certificateChain for X.509-backed verification.
  • timestampSignature for TSA-backed timestamping.
  • keyMetadata for key origin/usage lifecycle.

Canonicalization must be deterministic. In v1, the only supported signedContent.canonicalization value is json-canonical. cbor and protobuf are reserved for future versions.

v1 Expectations

  • Producers MUST emit signedContent.canonicalization=json-canonical.
  • Verifiers MUST reject unsupported canonicalization modes.
  • Signatures MUST be computed over the exact deterministic message bytes described below.

Signed Content Semantics

signedContent.includes defines the exact content that is signed.

Before evaluating includes paths, implementations MUST sanitize the envelope:

  1. Set signatures to an empty array.
  2. Set hashChain to the spec default object (chainId=default, sequence=1, and zeroed hash/prevHash sha256 digest values).

Supported include paths in v1:

  • spec -> sanitized envelope.spec
  • id -> sanitized envelope.id
  • type -> sanitized envelope.type
  • timestamp -> sanitized envelope.timestamp
  • payload -> sanitized envelope.payload
  • extensions -> sanitized envelope.extensions (or {} when absent)

Unknown include paths MUST fail signing/verification.

Serialization and Concatenation

For each path in signedContent.includes, in array order:

  1. Resolve the path to a JSON value from the sanitized envelope.
  2. Canonicalize that value using RFC 8785 JCS.
  3. Emit one segment as <path>:<jcs-json>.

The signing message is the UTF-8 encoding of all segments joined with newline (\n) in the same order as signedContent.includes.

Example segment sequence for includes = ["type", "timestamp", "payload"]:

type:{...JCS...}
timestamp:{...JCS...}
payload:{...JCS...}

signedContent.contentHash is the digest of this exact message byte stream.

Interoperability Evidence

Reference vectors:

These vectors are used to verify byte-for-byte canonical message and signature compatibility across SDK implementations.