Every .rain v2 packet carries two independent signatures — ML-DSA-65
(FIPS 204, a module-LWE lattice scheme) and Ed25519. Both must pass. The public keys
are published below, so verification needs nothing from us and works offline.
Public endpoint, no authentication. Post any packet and get a structured verdict.
curl -X POST https://catalyst-rain.strategic-innovations.workers.dev/rain/verify \ -H 'content-type: application/json' \ --data @packet.rain
Served at the well-known path. Key id catalyst-prov-2026-07.
curl https://catalyst-rain.strategic-innovations.workers.dev/.well-known/catalyst-rain.json
Packets are appended to a hash-linked chain: each carries the digest of the one before it, so records cannot be reordered or removed without breaking every link that follows.
curl https://catalyst-rain.strategic-innovations.workers.dev/rain/head # current head curl https://catalyst-rain.strategic-innovations.workers.dev/rain/list # recent records curl https://catalyst-rain.strategic-innovations.workers.dev/rain/rec/<id> # one signed packet
Both signatures cover canonical(body ‖ hmk ‖ chain) — deep key-sorted, compact JSON.
Never the whole envelope, since a signature cannot sign itself.
body — the payloadhmk — Catalyst state-in-payload structure. The FNV-1a value here is named
state_token and is a bucketing device for hypervector positions. It is not an integrity
mechanism and is not treated as one.chain — seq, prev_hash, this_hashsignature — ML-DSA-65+Ed25519, plus the key_id that identifies which published key to check againstSign a demo packet, then break one byte of the body and watch verification fail.
curl -X POST https://catalyst-rain.strategic-innovations.workers.dev/rain/demo | tee p.json curl -X POST https://catalyst-rain.strategic-innovations.workers.dev/rain/verify -H 'content-type: application/json' \ --data-binary @<(jq '.packet' p.json)