v2 · ship-ready·identity mode

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.

· no servers· < 3s decrypt· x25519 + aes-gcm· bip-322 identity
vault.lock · { "v": 2 }
{
  "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": "…" }
}
self-contained · share anywhere · no metadata leak
§ how it works

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.

[01]

register

Sign a BIP-322 message to bind a browser-generated X25519 key to your address. Publishes to Nostr once. Reusable forever.

[02]

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.

[03]

share

The envelope encodes into the URL fragment — never sent to any server. Any channel works: Signal, email, a paper QR code.

[04]

unseal

Open the link. The browser finds your local device key, derives the shared secret, decrypts. Under three seconds.

§ why v2 ships

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 →

diff v1 → v2
sealing
on-chain binding tx required
purely local
unsealing
on-chain tx, exact amount
local decrypt, < 3s
wallet needs
psbt export / import (desktop)
any wallet with signMessage
crypto
wasm adaptor sigs (never shipped)
x25519 + aes-gcm (webcrypto)
recipient setup
publish bip-322 sig somewhere first
one click on first visit
recovery
rebinding protocol with old key
re-run device setup, any browser
fees
every seal, every unseal
zero (identity mode)
§ layered with orangecheck

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.

§ gate example
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, ... });
[01]

identity, not access

Bitcoin proves who you are. Encryption proves what you can see. Separate concerns.

[02]

nothing on chain

Envelopes live in URLs, files, or Nostr — never on the Bitcoin chain. Zero fees.

[03]

optional relay

Payment-gated mode exists for commerce. Explicit trust in a named relay — opt-in only.

§ open your inbox

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.