encrypt to a bitcoin address.
open in one click.
Bitcoin-identity-bound end-to-end encryption. Seal to any address. The holder decrypts in their browser, with the wallet they already use. No accounts. No chain transactions. No PSBT.
{
"v": 2,
"kind": "identity",
"id": "7d2f…9c1",
"alg": {
"kem": "x25519",
"aead": "aes-256-gcm",
"kdf": "hkdf-sha256"
},
"from": { "address": "bc1qalice…" },
"recipients": [
{
"address": "bc1qbob…",
"device_id": "a8b4…",
"eph_pk": "02cd…",
"wrapped_key": "…",
"nonce_kek": "…"
}
],
"ciphertext": "AQID…",
"sig": { "alg": "bip322", "value": "…" }
}four steps. one wallet signature.
Every user does exactly one “hard” thing, exactly once: sign a BIP-322 message. After that, sending and receiving are one click.
register
Sign a BIP-322 message to bind a browser-generated X25519 key to your address. Publishes to Nostr once. Reusable forever.
seal
Enter a recipient address. We fetch their device key, wrap a fresh AES-256-GCM key via X25519 ECDH, emit a self-contained envelope.
share
The envelope encodes into the URL fragment — never sent to any server. Any channel works: Signal, email, a paper QR code.
unseal
Open the link. The browser finds your local device key, derives the shared secret, decrypts. Under three seconds.
v1 was elegant. v2 is usable.
The original LOCK Protocol tried to gate access with adaptor signatures (no browser-compatible WASM ever shipped) and later with Proof-of-Access Bitcoin transactions (10-minute confirmations killed every flow). v2 treats Bitcoin as an identity system, not an access oracle. full postmortem →
sybil-resistant recipients.
Senders can require recipients to hold an orangecheck attestation meeting thresholds — e.g. ≥ 100k sats bonded for ≥ 30 days. Because a device record already contains a BIP-322 signature addressed to a Bitcoin identity, the same proof that lets a sender encrypt to you also proves you have stake on chain.
import { check } from '@orangecheck/sdk';
import { unseal } from '@orangecheck/lock-core';
// gate unseal on sybil-resistance
const r = await check({
addr: envelope.from.address,
minSats: 100_000,
minDays: 30,
});
if (!r.ok) throw new Error('stake too low');
const out = await unseal({ envelope, device, ... });identity, not access
Bitcoin proves who you are. Encryption proves what you can see. Separate concerns.
nothing on chain
Envelopes live in URLs, files, or Nostr — never on the Bitcoin chain. Zero fees.
optional relay
Payment-gated mode exists for commerce. Explicit trust in a named relay — opt-in only.
keys in your browser. identity on chain.
No signup. Your device holds your keys; your wallet proves who you are. Start sealing in thirty seconds.
with thanks to bram kanstein — whose work on bitcoin as sovereignty layer shaped the premise.