live · mainnetoc · lock
x25519 + aes-256-gcm
oc · lock·identity-bound encryption

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.

· from mind of@bramk· no servers· 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": "…" }
}
§ 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.

§ thesis

identity, not access.

Your Bitcoin wallet is already an identity. v2 turns it into an inbox. Seal a message to any address — the holder opens it in one click, in the browser they already use. No signup. No fees. Nothing on chain. Nothing for us to hold. Decryption under three seconds, end to end. from v1 to v2 →

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.