Signatures and trust
The three kinds of signature, what each proves, the public trust list and key rotation.
On this page
Tidenda signs what it sends and what it publishes, so that receivers and anyone downstream of them can check where content came from and that it has not changed. Integrators and security reviewers use this overview to decide which signatures to check and what each one proves.
| Signature | Algorithm | Covers | Proves |
|---|---|---|---|
| Webhook request | HMAC-SHA256 | A timestamp and the raw request body | This request came from the platform, unaltered and recent |
| Document snapshot | Ed25519 | The snapshot JSON of a published version | This document version is exactly what the platform published |
| Media and transcripts | Ed25519 | Original image or audio bytes, or one transcript segment | This file, or this transcribed passage, is what the platform holds |
Webhook request signatures
Every webhook delivery carries an HMAC-SHA256 signature in the
X-Tidenda-Signature header, keyed with a secret shared between the
platform and one receiver. It covers a timestamp and the exact body
bytes, so a valid signature means the request is genuine, unmodified
and fresh, and a receiver that rejects old timestamps cannot be fed a
captured request again.
The proof ends at the receiver. Nobody else holds the secret, so the signature means nothing once the content moves on. Every receiver checks it; the recipe is in Implementing a webhook receiver.
Content signatures
When a document reaches usable or withheld, the platform stores
an immutable snapshot of that version and signs its bytes with
Ed25519. Images and audio files are signed the same way when they
are uploaded, over their original bytes. An editor who checks a
transcript passage against the recording and marks it verified
creates a signature over that one segment: the recording's id, the
segment's id, its start and end times, its speaker and its text.
These signatures are public-key signatures. Anyone holding the public key can check them, so a signed snapshot can pass through a distribution hub, an archive or a CDN and still be verified by the last system in the chain, without trusting any system in between and without access to a shared secret.
What each signature does not prove:
- A snapshot signature covers one version. Later edits produce a new version with its own snapshot.
- An image or audio signature covers the original upload only, not resized or re-encoded copies.
- A segment signature covers the text as it was when verified. Each verified segment also stores a hash of that text, so a later edit shows as a mismatch.
- A signature can be absent when content was stored while signing was unavailable. Unsigned content cannot be verified and is unsuitable for redistribution that promises provenance.
Domain separation
All content signatures use the same key. To stop a signature made for one kind of content from verifying as another, each kind prefixes its bytes with its own label before signing:
| Kind | Prefix |
|---|---|
| Document snapshot | tidenda-snapshot-v1\0 |
| Image | tidenda-image-v1\0 |
| Audio file | tidenda-audio-v1\0 |
| Transcript segment | tidenda-audio-segment-v1\0 |
| Rendered video | tidenda-video-v1\0 |
\0 is a single zero byte. The version in each label would change
only if the signed format changed.
The public trust list
The platform publishes the public keys it signs with at
GET https://<public-api-host>/api/keys. The endpoint needs no
credentials:
{
"active": "void-2026-05",
"keys": [
{ "keyId": "void-2026-05", "algorithm": "ed25519",
"publicKey": "<base64 SPKI DER>", "validFrom": "2026-05-12T00:00:00.000Z" },
{ "keyId": "void-2025-11", "algorithm": "ed25519",
"publicKey": "<base64 SPKI DER>", "validFrom": "2025-11-01T00:00:00.000Z",
"validUntil": "2026-05-12T00:00:00.000Z" }
]
}
Every signature names the key that made it in its keyId. active
is the key used for new signatures, or null when the deployment is
not signing. Keys are Ed25519 public keys in base64-encoded SPKI DER,
which standard cryptography libraries load directly.
Key rotation
Rotation adds a key: new signatures carry the new keyId, and the
previous key stays in the list with a validUntil date, so
everything it signed keeps verifying. A key can eventually be removed
from the list, after which content it signed can no longer be
verified against the platform.
A validUntil in the past means the key no longer signs new content;
it does not invalidate what the key signed before. Verifiers cache
the list for about an hour and fetch it again as soon as they meet an
unknown keyId, which makes a rotation invisible to them.