@mattpiz/tlock-js
v0.10.0
Published
A library to encrypt data that can only be decrypted in the future using drand
Readme
@mattpiz/tlock-js
A TypeScript library for encrypting data which can only be decrypted at a set time in the future using drand. tlock-js uses AGE to symmetrically encrypt a payload, and encrypts the symmetric key using pairing-based cryptography so it can only be decrypted once drand's threshold network has produced randomness at a future round.
This is a fork of drand/tlock-js. It vendors a minimal drand client (dropping the
drand-clientandisomorphic-fetchdependencies), is published as a dual ESM + CJS package that runs unchanged in browsers and Node ≥ 18, and adds a small state-freecreateTlockwrapper. Ciphertexts remain interoperable with every drand tlock implementation.
Prerequisites
- Node ≥ 18 (uses the global
fetchand Web CryptoglobalThis.crypto), or any modern browser. - No
fetchorcryptopolyfill is required.
Using it as a library
pnpm add @mattpiz/tlock-jsThe package ships both ESM and CommonJS builds with type declarations; your bundler/runtime picks the right one via the exports map. It targets es2020.
High-level API: createTlock
The recommended entry point. createTlock returns a small context bound to a chain (drand quicknet by default). It holds no global state and makes no hidden network calls: because the chain parameters are supplied up front, encryptToRound and decryptWithBeacon are pure crypto over the bytes you pass in, and fetchBeacon is the only networked call. You decide what (if anything) to cache by holding the context and the beacons it returns.
import { createTlock } from "@mattpiz/tlock-js"
const tlock = createTlock() // defaults to drand quicknet
// Encrypt some bytes so they unlock at a future round (offline).
const ciphertext = await tlock.encryptToRound(new Uint8Array([1, 2, 3]), round)
// Later, once the round has been emitted: fetch its beacon once...
const beacon = await tlock.fetchBeacon(round) // the only network call
// ...then decrypt any number of ciphertexts for that round (offline).
const plaintext = await tlock.decryptWithBeacon(ciphertext, beacon)Pass createTlock({ info, baseUrl }) to target a different drand chain; QUICKNET_CHAIN_INFO / QUICKNET_CHAIN_URL are exported as the defaults.
Low-level primitives
The original primitives are still exported if you want to manage a chain client yourself:
timelockEncrypt(roundNumber, payload, chainClient)— encrypt a payload that can only be decrypted onceroundNumberis reached. Output is compatible with any drand tlock implementation.timelockDecrypt(ciphertext, chainClient)— read the round from a ciphertext (armored or unarmored) and decrypt it, throwing if the round hasn't been reached.roundAt(time, chainInfo)— the latest round emitted attime.roundTime(chainInfo, round)— the approximate emission time ofround.- Chain helpers:
HttpChainClient,HttpCachingChain,mainnetClient(),testnetClient(), and theChainInfo/RandomnessBeacontypes.
Developing
This repository uses pnpm (pinned via packageManager / corepack):
pnpm install # install dependencies
pnpm build # generate src/version.ts, then bundle dist/ (ESM + CJS + .d.ts) with tsup
pnpm test # run the jest suite
pnpm lint:fix # lint and autofixpnpm test includes a few live-network integration tests that hit the real drand HTTP API; they require connectivity. All other suites run offline.
Publishing
pnpm publish runs prepublishOnly (build + lint + test) and publishes the built dist/ (the package's main/module/types/exports all point under dist/). The scoped package is published publicly via publishConfig.access.
Notes
- Vite users may need to set the build target to
es2020:export default { build: { target: "es2020" }, optimizeDeps: { esbuildOptions: { target: "es2020", supported: { bigint: true } }, }, }
Test the drand web demo
drand hosts a live web demo of timelock encryption/decryption that runs entirely in your browser, fetching only the drand beacons it needs to decrypt.
Get in touch
This fork tracks drand/tlock-js; for questions about the underlying protocol:
- Open an issue on drand/tlock-js for upstream feature requests or bugs.
- Join the drand Slack to discuss Timelock, randomness beacons and more.
- Follow the drand blog and the @drand_loe account.
License
Dual-licensed under Apache 2.0 and MIT terms, following the upstream Permissive License Stack:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
