Sealing and timelock
How an order is encrypted so that nobody can read it before its epoch's decryption time, and why the scheme is drand timelock.
Envelope, public
protocolVersionschemeepochIdciphertextciphertextHashorderCommitment
Sealed payload, unreadable until the round
order: market, side, size, limit, walletsignaturecancelHash
Sealed payload#
plaintext = abi.encode(KasumiOrder order, bytes signature, bytes32 cancelHash)
cancelHash is keccak256(cancelSecret) for a secret only the submitter knows (§8).
Scheme#
A sealing scheme (SealingScheme in packages/sdk/src/sealing.ts) has an id, seal(plaintext, decryptTime), unseal(ciphertext) and unlockTime(ciphertext). The envelope carries the scheme id.
v1 ships one scheme, id 1: timelock encryption to the drand quicknet network (tlock, age format). The
decryption key for a round is the network's threshold BLS signature over that round. It does not exist
until a threshold of drand nodes produce it, and it is public afterwards. Every order of an epoch is sealed
to the first round at or after the epoch's decryption time:
round = ceil((decryptTime - genesis) / period) + 1 // genesis 1692803367, period 3 s
The quicknet public key and chain hash are pinned in the SDK. The client derives the round from the epoch schedule, never from a value the relay supplies for the order. The relay reads the round from the ciphertext header and refuses ciphertexts locked to any other round, without being able to read them.
Why drand and not Shutter#
Shutter was the first candidate. The evaluation, against Shutter's API and SDK as of 2026-10-02:
- Event-based triggers exist in the API, but the keypers watch the chain where the Shutter registry lives
(Gnosis or Chiado). The request has no chain parameter. An
EpochClosedevent on an Arbitrum Orbit chain cannot trigger a key release directly. Mirroring the event to Gnosis would add a relayer that has to be trusted. - Time-based triggers work, but each epoch needs an identity registration. Without an API key the limit is 5 registrations per IP per day. The premium tier is described as roughly one registration per minute, which rules out sub-minute epochs.
- The keyper set size and threshold are not officially documented, and the API README states that the network is not fully decentralised.
So with either system the practical trigger is time-based. drand needs no registration, has no rate limit, and has 3 second rounds. That is why it is the default. The cost of a time-based trigger is described in THREAT_MODEL.md: key release does not wait for the commitment to land.
A Shutter scheme would implement SealingScheme with a new id. No envelope, contract or matcher change is
needed. It is not implemented in v1.