1 · An answer
Verify before acting
Every Resolve answer and decision receipt carries signature.kid. Accept it only when that kid is in the signed directory, then check the signature over the document’s SHA-256.
The same Ed25519 key signs every request CrawlCheck sends under its own name and every document an agent relies on: Resolve answers, decision receipts, site staples, DNS records and the heads of the answer log. Verify against this key and nothing else; when it rotates, the history below says which key was valid when.
hcIAczGf
active key (JWK thumbprint)
7
days of overlap on rotation
3
key events, hash-chained
intact
chain, checked from the first entry
Each check runs on your own machine.
1 · An answer
Every Resolve answer and decision receipt carries signature.kid. Accept it only when that kid is in the signed directory, then check the signature over the document’s SHA-256.
2 · Our crawler
Requests made under CrawlCheck’s own name carry HTTP Message Signatures (Web Bot Auth). A site can verify the signature against this key instead of maintaining an address range.
3 · An old signature
A signature made before a rotation verifies against the key that made it. The log below says when each key started and stopped signing, and every entry hashes the one before it.
| Thumbprint (JWK, SHA-256) | hcIAczGf-8EFBnkunmZlvFWnD2nHHeHeC9cM4BTiBVo |
| Valid from | 2026-09-11 20:24 UTC |
| Signs | every request sent under our own name, the key directory, and every signed document: Resolve answers, decision receipts, site staples, DNS records and answer-log heads |
| Overlap on rotation | 7 days: a new key is published before the old one stops signing, and the old one stays listed after |
| Thumbprint | Valid from | Stopped signing | Private half erased | Why |
|---|---|---|---|---|
| 0zNVreNVKdaTFJjtRJtvcFiesmG2qgWvvIBL_zbgwko | 2026-08-21 03:07 | 2026-09-18 20:24 | 2026-09-19 01:17 | moved from KV storage to a Worker secret |
Times are UTC. A key stops signing when the overlap ends; its private half is erased at the next sweep after that, and its public half stays listed so old signatures still verify.
Chain intact (checked from the genesis entry); coverage complete: every key the directory publishes has an entry.
| # | When (UTC) | Event | Key | Reason | Entry hash |
|---|---|---|---|---|---|
| 2 | 2026-09-18 21:17:40 | retired | 0zNVreNVKdaTFJjt… | moved from KV storage to a Worker secret | 8b9e4f47245c3324… |
| 1 | 2026-09-16 12:26:27 | publishing | 0zNVreNVKdaTFJjt… | published during overlap rotation; created 2026-08-21T03:07:11.000Z | 08d7e8ec87b75230… |
| 0 | 2026-09-12 04:42:56 | active | hcIAczGf-8EFBnku… | e092e9199a0eee49… |
Head 8b9e4f47245c3324f88704d7880d7e203acec175a7873421f8680f643c9ac5d6. The log began on 2026-09-12; its first entry records the key that was already active.
Each entry hashes {at, event, prev, reason, seq, storage, thumbprint} as canonical JSON with sorted keys; its prev is the hash of the entry before it, and the first entry points at 64 zeroes. Recompute the chain and it must reach head. A key that signed something last month appears here even if it no longer appears in the directory.
Daily anchor: since 2026-10-04 the head hash is a leaf in each day’s sealed Merkle root, timestamped with OpenTimestamps: /api/seal/lookup?id=keys-head&day=YYYY-MM-DD.