Skip to content

Protocol · confidentiality

Seal it to a Bitcoin address. Only its holder can open it.

Identity, not access. OC Lock seals a message or file to a Bitcoin address, so only the person who holds that address can open it. Bitcoin proves who you are. Encryption decides what you can see.

A sealed envelope · test vector v01
{
  "v": 2,
  "kind": "identity",
  "id": "1ed9375d37bc84e4163d16d1a55fd07eef065db10f46eb116cae0da6c8900414",
  "alg": { "kem": "x25519", "aead": "aes-256-gcm", "kdf": "hkdf-sha256" },
  "from": { "address": "bc1qalice" },
  "recipients": [
    {
      "address": "bc1qbob",
      "device_id": "bob-dev",
      "device_pk": "34184b74df55c525d39c0ec4cfa82c562b0c959218018cb2f0890432c12eb159",
      "eph_pk": "400b3124d828c9f6b467cb86801925cb3f8d008273e3e25c87307cc214aaaa30",
      "wrapped_key": "FSa1lyEK8H-3M06iHU3b88ktHflnfc914Nbh38yocvGCCIP8sXFpI2Rho_AFgzUb",
      "nonce_kek": "641fec72121024f5a8edeb19"
    }
  ],
  "ciphertext": "M_CnmyV2sJA-3fCuV1lZ9hBR7DFYDw7RnQ",
  "nonce_ct": "edf26509f0c7063a183449e6",
  "created_at": "2026-04-22T21:44:22.423Z",
  "expires_at": null,
  "payment": null,
  "sig": { "alg": "bip322", "pubkey": "bc1qalice", "value": "ZmFrZS1zaWduYXR1cmU=" }
}
  • Open spec, MIT
  • No account needed
  • Nothing written to the chain
  • Your key stays in your browser

The problem

A Bitcoin wallet can sign a message, but it cannot decrypt one.

You want to send something private to someone you know by their Bitcoin address. Today that means agreeing on a messenger, swapping phone numbers, or trading PGP keys out of band.

The first version of this protocol made every lock and unlock a Bitcoin transaction, with fees and waits, and nobody could use it. OC Lock v2 keeps the address as the identity and uses ordinary, well-studied encryption for the rest.

How it works

Register once. Seal. Open.

  1. 01

    Register once

    Your browser makes a key for receiving. Your wallet signs one message saying “this key belongs to my address”. That signed record goes to public Nostr relays, where anyone can find it by your address.
  2. 02

    Seal

    A sender types your address. Their browser fetches your record, checks your wallet’s signature on it, and encrypts to your key. They sign the sealed envelope with their own address, so you know who sent it.
  3. 03

    Open

    You open the link or the file. Your browser checks the sender’s signature, finds your key and decrypts. No transaction is made, and no server sees the message in the clear.
What Bitcoin does here
The address is the name. No registrar issues it, the recipient already holds it, and BIP-322 signatures prove its holder approved each receiving key and signed each envelope. By default OC Lock reads nothing from the chain, so it rests on Bitcoin as identity, not on chain state: swap the address for a bare key and you lose the shared namespace and the link to that address’s coins under OC Attest. Chain state matters only in the optional payment mode, where a named relay releases the key after a confirmed payment.
Payment mode
It is in the spec. lock.ochk.io does not offer it, and orangecheck runs no payment relay.

Where it stands

Open, stable, and free to use.

The OC Lock spec is at v2.0 and marked stable. The tools at lock.ochk.io work today and are free. Nothing is written to the Bitcoin chain. OC Lock never holds your keys: your receiving key is made in your browser and stays in its storage, optionally locked with a passphrase. orangecheck as a whole is pre-launch.

The spec

oc-lock-protocol

Version
2.0
Licence
MIT
Nostr kind
30078
Test vectors
4

Try it

What you can do today.

  • Register this browser once with any wallet that can sign a message, then send up to 256 KB at a time. The recipient gets it in their inbox over Nostr, and you also get a share link, a .lock file and a QR code. No account needed.

    lock.ochk.io/app
  • Paste the share link or the envelope, or drop the .lock file.

    lock.ochk.io/unlock
  • Paste any envelope and see what it proves, field by field. Nothing leaves your browser.

    lock.ochk.io/playground

For developers

Build on it.

npm install @orangecheck/lock-core @orangecheck/lock-device @orangecheck/bip322

Envelopes

@orangecheck/lock-core

envelopes, seal, unseal; MIT

Crypto

@orangecheck/lock-crypto

X25519, HKDF-SHA256, AES-256-GCM; MIT

Device keys

@orangecheck/lock-device

device keys, binding statements, Nostr records; MIT

BIP-322

@orangecheck/bip322

verifySignature(address, message, signature)

TypeScript · seal to Bob, open as Bob
import { seal, unseal } from '@orangecheck/lock-core';
import { verifySignature } from '@orangecheck/bip322';

// bob = { address, device_id, device_pk } from his kind-30078 record
// (parseDeviceEvent in @orangecheck/lock-device; check its binding signature first)
const envelope = await seal({
    payload: new TextEncoder().encode('the key is under the mat'),
    sender: { address: myAddress, signMessage: (m) => wallet.signMessage(m) },
    recipients: [bob],
});

// on Bob's side
const { payload, authenticated } = await unseal({
    envelope,
    device: { device_id, secretKey },
    verifyBip322: async (msg, sig, addr) => verifySignature(addr, msg, sig),
});
To seal only to recipients whose address meets an OC Attest threshold, call check({ addr, minSats, minDays }) from @orangecheck/sdk before seal.

Check one

Open or check an envelope someone sent you.

Anyone can check an envelope. Only a browser holding one of the recipient’s keys can open it. Paste the share link or the envelope here to open it at lock.ochk.io/unlock, or drop the .lock file there.

The page tells you:

  • Contents: whether the envelope matches its id, a SHA-256 of its canonical bytes. Any change breaks it.
  • Sender: whether the BIP-322 signature over that id verifies for the sender’s address. An unsigned sender is shown as a claim, not a fact.
  • For: which addresses and devices it was sealed to, and whether this browser holds one of their keys. If it does, the envelope opens, and decryption fails on any tampering.
  • Expiry, if the sender set one.

An envelope travels in the link’s fragment, which browsers never send to a server.

It cannot tell you when the envelope was really sent: the timestamp is the sender’s claim.

All of this runs in your browser. Any OC Lock implementation with a BIP-322 verifier reaches the same answer from the envelope alone, without us.

What you trust

Every party you rely on, by name.

Nostr relays
To store and return device records and to carry inbox copies. A relay can hide a record. It cannot forge one, because each record is signed by the address. The reference set is relay.ochk.io (run by orangecheck), nos.lol, relay.primal.net, offchain.pub and relay.snort.social.
Your browser and device
Your receiving key lives in the browser’s storage (IndexedDB). A compromised device exposes your messages. Clear the site’s data and the key, and everything sealed to it, is gone. You can export it from /app; treat the file like a wallet backup.
In payment mode only, the named relay
It holds the content key until it sees payment, so it could withhold it or release it early. Its address is always shown, and anyone can run one.

What it is not

The limits, plainly.

Not forward-secret per message
A stolen receiving key opens every past envelope sent to it. Rotating keys limits the damage. For live chat with strict needs, the spec points to Signal.
Not private about who and when
The sender’s address, the recipients’ addresses, the optional hint and the timestamps are readable by anyone who holds the envelope.
Not recallable
Revoking a device stops new envelopes. It does not undo ones already delivered. An expiry stops conforming apps from opening an envelope after that time; it does not destroy the copy.
Not post-quantum
X25519 and secp256k1 both fall to a large enough quantum computer.

Where it is used

Apps that use it.

chat.ochk.io (opens in a new tab)
In testing. A messenger where your Bitcoin address is your inbox. OC Chat is a mode of OC Lock: every message is an OC Lock envelope of the chat kinds, delivered over Nostr. Its seal-til-block messages stay locked with a named beacon until a block height; the beacon enforces that, not Bitcoin consensus.
vault.ochk.io (opens in a new tab)
A password manager on OC Lock’s self-vault pattern. Every entry is encrypted in your browser under a vault key that your passphrase unlocks, using OC Lock’s crypto package, and its device keys come from @orangecheck/lock-device. It does not yet wrap each entry as a full .lock envelope.

Seal your first message.

The tools are free and need no account. The spec is open to anyone who wants to build their own.

With thanks to Bram Kanstein, whose work on Bitcoin as a sovereignty layer shaped the premise.