Time-sealed envelopes
An envelope that cannot be opened before a chosen @beat — not by you, not by us, not by anyone holding a single key.
format: beattime-seal-v1 · last updated August 2026
Proof of existence answers “this existed before then.” This layer answers the opposite question: “this cannot be read until then.” Both are free, both are public, and neither requires an account.
1The idea
You seal something now and name the moment it may be read: a letter to a child, a sealed bid, a disclosure with an embargo, an archive that should outlive the person who made it. Until that moment arrives the content is unreadable, and afterwards anyone holding the envelope can open it.
The hard part is not the encryption. It is answering the obvious follow-up question: what stops the people running the service from reading it early? Most “time capsule” products answer with a promise. This one answers with arithmetic.
2Why a threshold, not a promise
The envelope's key is split with Shamir's scheme into n shares, of which any t reconstruct it. Fewer than t reveal nothing at all — not “nothing practical”, literally nothing: every possible key remains equally likely.
The shares are then locked to independent holders, so opening early would require compromising several of them at once:
key ──split──┬─→ share 1 ──sealed to──→ drand (threshold network, League of Entropy)
├─→ share 2 ──sealed to──→ an operator's key server
└─→ share 3 ──handed to──→ you, as a recovery code
any 2 of 3 reconstruct the key · any 1 reveals nothing
A leak of our share tells an attacker nothing. A compromise of drand's threshold tells an attacker nothing. That is the whole point: no single key holder — including BeatTime — can open an envelope before its time.
3The three kinds of share
| Kind | Released by | When |
|---|---|---|
drand | the drand threshold network | at a chosen round |
beat | an operator's key server | at the chosen @beat |
escrow | nobody — it is handed to you | from the moment of sealing |
The first two use timelock encryption (tlock): a share is encrypted to an identity that only a future signature can unlock, so the key to open it does not exist yet — not anywhere, not to anyone.
The third is a recovery code, printed in Crockford Base32 so it survives being copied by hand from a piece of paper years later:
7F3A-K5MZ-8PQT-…-2WXR
It buys survivability: with it the envelope opens even if every beacon disappears. It costs a little confidentiality, because it is a static secret — so keep it on paper in a safe, not in a cloud folder. We call it a recovery share, never “extra security”.
4@beat as the address of a moment
The opening moment is stored as an absolute beat index — the number of 86.4-second beats since 1970-01-01T00:00:00Z. One integer, no timezone, no calendar, no ambiguity a decade from now.
beat_index = unix_microseconds / 86_400_000 (integer division)
Computed on whole microseconds, never by dividing by 86.4 — that value has no exact binary representation and the result drops by one at beat boundaries. Index 0 is midnight UTC on 1 January 1970, so noon UTC is always @500.
5Inside the envelope
The envelope is JSON. The payload can travel inside it or sit alongside it as a separate file, which is what you want for large attachments.
| Layer | Construction |
|---|---|
| Key split | Shamir over GF(256), reducing polynomial 0x11B |
| Key derivation | HKDF-SHA256, info beattime-seal-v1|aead |
| Payload | AES-256-GCM in 64 KiB segments (STREAM construction) |
| Share sealing | Boneh–Franklin IBE on BLS12-381, scheme bls-unchained-g1-rfc9380 |
| Recovery code | Crockford Base32, 14 groups of 4 |
The payload is segmented rather than encrypted in one piece for a specific reason: a single AES-GCM tag cannot be checked until the whole file has been read, which would mean either buffering gigabytes or handing out unauthenticated plaintext. Each segment carries its own tag, so a stream verifies as it goes; a counter in the nonce prevents reordering and a final-segment flag prevents truncation.
6API
Everything here is public and free, with no account and no key. Note what is not here: there is no endpoint that seals or opens an envelope. Sealing takes a secret share as input, so a server doing it could open every envelope it ever made — and the whole construction would be decoration. That work happens in your client.
| Endpoint | Purpose |
|---|---|
GET /api/seal/info | Format parameters, profiles and the pinned drand chain. |
GET /api/seal/beat | Instant ↔ beat index. No arguments returns the current beat. |
GET /api/seal/round | @beat → drand round: the bridge to existing tlock tooling. |
GET /api/seal/key | BeatTime's operator public key. |
GET /api/seal/share/<beat_index> | A released share. 404 before its beat — never a hint. |
POST /api/seal/validate | Check an envelope without opening it. Send the header only. |
GET /.well-known/beat-key-operators.json | Operator registry: op, public key, addresses. |
Released shares are immutable and served with a one-year cache header. Mirroring them is encouraged rather than tolerated: once a share is public it is ordinary public data, and every extra copy makes the envelopes depend less on any one server still being online.
Addresses in the registry are a hint. The source of truth is the public key recorded in the envelope itself, so a share fetched from anywhere — a mirror, an archive, a stranger's USB stick — is verified locally against it.
The holders in that registry right now — read live from it, so this list and the JSON cannot disagree:
| Operator | Public key (BLS12-381 on G2, base64) |
|---|---|
beattime |
jN8nAWDv7kfa7qXX8LvxBniOi3EksnRr6YA474t8VtYzrIHEttBwikf+0RWwutscBhukGwik6kjOumfo27iT7VXjPytmIOBAVFcO4538Vy3SIfewNy0LhuEGCERv3baD |
beatkey-konveriaPolska |
gx2ddUgSltcankuX20EsIFfRfkzAPkLMSRjdCxr67v6MVdNFPJ4U1imLdBNNdJe8FwyfIPEhKLPCMGQkD55TkaBh3TOsCYVoALwDogncHnOgdaaDHUaLiOF7LXs7Zktu |
2 independent holders of the beat share, alongside drand and the recovery code. They are separate organisations on separate hosting — two shares with one hosting provider would look independent and would not be, so that is checked before an operator is added.
7Try it in five minutes
No server seals an envelope for you — not this one, not anybody's. The input to sealing is a secret share, so a server able to seal would be able to open everything it ever sealed. What this service publishes is the public half: the parameters, the time mapping, the operator registry and the shares that are released once their moment has passed.
The sealing itself has to happen on the machine the contents are already on. If you would rather not write that code, the capsule tool is exactly it — the same format, implemented in the page and running in your browser. Nothing it produces is transmitted anywhere; open the network tab and watch it stay quiet.
Or watch the mechanism work from a terminal right now, without writing anything:
What moment is this, as a number?
curl -s "https://beattime.live/api/seal/beat?utc=2030-01-01T00:00:00Z"
Comes back with the absolute beat index — one integer that names that moment for everyone, with no timezone and no calendar to misread a decade from now.
Which drand round would a share be sealed to?
curl -s "https://beattime.live/api/seal/round?beat=<index from above>"
That round number is what existing tlock tooling takes. This endpoint is the entire bridge between @beat and the wider timelock ecosystem.
A share that has not been released yet
curl -i "https://beattime.live/api/seal/share/<a future index>"
404. Not “not yet”, not a countdown, not a partial answer — a future share is indistinguishable from one that never existed. Ask for a beat that has already passed and the same call returns the signature.
Check it yourself, without trusting the answer
A share is only worth what it verifies against, so verify it against the key in the registry rather than against the server that handed it to you:
git clone https://github.com/DeiFlagellum/beat-key && cd beat-key
go run ./cmd/verify-share -pub <public_key> -beat <index> -sig <signature>
The tool recomputes the identity from the beat index instead of believing the one in the response — a server returning a signature over some other identity would hand you a share that verifies but opens nothing.
8Run your own key server
Anyone can hold a share. The key server is a container that publishes one thing — a signature over a beat identity, and only once that beat has passed. It generates its own key on first start, inside the container, with no import path: nobody can hand you a key and you cannot accidentally deploy someone else's.
docker run -e BEAT_KEY_OP=your-org -v beat-key:/data \
ghcr.io/deiflagellum/beat-key@sha256:9913de07399a36a3a007f7ac95a5597a…
It holds no user data — no ciphertext ever passes through it, so there is nothing to retain and nothing to report in a breach. It needs no uptime guarantee either: the signatures are deterministic, so downtime means envelopes open later, never that anything is lost. The real request to an operator is “keep 32 bytes safe for years.”
The image is public and built from public source at github.com/DeiFlagellum/beat-key, and that is deliberate rather than incidental: an operator has to be able to rebuild it and compare. An image you cannot rebuild is an image whose author you have to trust — and then the operator's share would not be independent at all.
9What this does not protect against
The honest list, because a security claim without its limits is marketing.
- A stolen recovery code. It is a static secret, and whoever holds it needs only one beacon. Paper in a safe, not a copy in the cloud.
- Choosing the unrecoverable profile. With two shares and no recovery code, either party disappearing means the content is gone for good. That is a feature — but one to choose deliberately.
- Operators that are not really independent. Two shares held by the same organisation, or by an organisation and someone who can compel it, count as one. A key server running on infrastructure the envelope's author administers is not a second holder, whoever the invoice is addressed to.
- Beacon networks outliving your envelope. Chains rotate and get retired. The envelope records which chain it was sealed to; it cannot make that chain exist in twenty years.
- Traffic analysis of the header. Payload size and opening moment are visible from day one. Everything else belongs inside the ciphertext.