Skip to content

Protocol · provenance

Prove who signed a file, and by which block it existed.

Sign anything with a Bitcoin address. Anchor the moment to Bitcoin. OC Stamp is orangecheck’s provenance protocol: one small file that says who signed it and when it existed, and that anyone can check, years from now, without asking us.

A stamp’s six-line note · test vector v05
oc-stamp:v1
address: bc1qnotary00000000000000000000000000000000
content_hash: sha256:fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210
content_length: 65536
content_mime: application/x-git-tree
signed_at: 2026-04-20T12:00:00Z
  • Open spec, MIT
  • No account needed
  • The file never leaves your device
  • Anchoring costs you nothing

The problem

Did you write it? Did it exist before a certain date?

You publish a post, a release or a contract. Later someone asks those two questions, and today the answers live with someone else.

A platform’s timestamp lasts as long as the platform does. PGP proves authorship, but nothing ties it to a date you can check. A notary or a vendor certificate means trusting that party. OpenTimestamps proves when a hash existed, but not who made it.

OC Stamp puts both answers in one small file that anyone can check, years from now, without asking us.

How it works

Hash it. Sign it. Anchor it.

  1. 01

    Your browser fingerprints the file

    It computes a SHA-256 hash locally. The file itself never leaves your device.
  2. 02

    Your Bitcoin wallet signs

    A stamp is a six-line note: your address, the file’s hash, its length, its type and the time you say you signed it. Its id is the SHA-256 of that note, and your wallet signs the id, so the signature covers every line. Signing moves nothing.
  3. 03

    The signature is anchored to Bitcoin

    The stamp’s id goes to public OpenTimestamps calendars. They batch many ids together and commit them to a Bitcoin block, usually within about an hour. The result is a .stamp file: the note, the signature, and the proof that links it to that block.
What Bitcoin provides
A signature from a real Bitcoin address (BIP-322), and Bitcoin’s block headers as a clock that nobody can wind back.
Pending and anchored
A new stamp is pending: the calendars have promised to anchor it, but no block contains it yet. Within about an hour it can be upgraded: the calendar returns a path from your stamp’s id to a real block header. Upgrading does not change the signature or the id. Until a stamp is upgraded, it proves who signed it but not when.
The sample on the verify page
It was never sent to a calendar, so it shows “no timestamp”. That is the honest result for that sample, not a fault. A stamp you make can be upgraded, and the verifier will try the upgrade for you and offer the upgraded file to download.

Why it exists

Every other tool proves one of these.

The spec’s own audit of the field, in words. A stamp proves who and when together.

  • Who signed it
    OC StampYes, a Bitcoin address
    PGPYes
    OpenTimestamps aloneNo
    C2PAYes
    EAS (Ethereum)Yes
  • When it existedAnchored to a public chain.
    OC StampYes, a Bitcoin block
    PGPNo
    OpenTimestamps aloneYes, a Bitcoin block
    C2PANo
    EAS (Ethereum)Yes, on Ethereum
  • A stake behind the signer
    OC StampCan name one, as the signer declares it
    PGPNo
    OpenTimestamps aloneNo
    C2PANo
    EAS (Ethereum)Token-gated
  • Checks offline
    OC StampYes
    PGPPartly: keyservers
    OpenTimestamps aloneYes
    C2PANeeds an X.509 chain
    EAS (Ethereum)No: needs an RPC node
  • Needs no one’s permission
    OC StampYes
    PGPPartly
    OpenTimestamps aloneYes
    C2PANo
    EAS (Ethereum)Yes

The full argument is in the spec’s WHY.md.

Where it stands

Open, stable, and free to use.

The spec is v1.0 and marked stable. The tools at stamp.ochk.io work today, free, with no account. Anchoring goes through public OpenTimestamps calendars and costs you nothing. OC Stamp never holds your coins: signing a stamp moves no bitcoin and spends no fee. orangecheck as a whole has not launched publicly yet.

The spec

oc-stamp-protocol

Version
1.0
Licence
MIT
Nostr kind
30083
Test vectors
5

Try it

What you can do today.

  • Drop a file, sign with a browser wallet or paste a signature from Sparrow, Electrum or a hardware wallet, and download the .stamp or copy a share link. Publishing to Nostr is optional and off by default.

    stamp.ochk.io/create
  • Drop the .stamp file or paste its JSON, and add the original file if you have it.

    stamp.ochk.io/verify
  • In your browser, in the playground.

    stamp.ochk.io/playground

Share links look like stamp.ochk.io/v#… and verify as they open. The stamp rides in the part after #, which browsers never send to a server. None of these needs you to sign in.

For developers

Build on it.

Two packages implement the spec, plus a command-line tool.

npm install @orangecheck/stamp-core @orangecheck/stamp-ots

Core

@orangecheck/stamp-core

canonical message, envelope, stamp(), verify(); 1.1.0

OpenTimestamps

@orangecheck/stamp-ots

calendar submission, proof upgrade, anchor checks; 0.3.0

CLI

@orangecheck/stamp-cli

stamp for files and git-stamp for signing git tags; 0.2.1

TypeScript · stamp some bytes, then anchor them
import { stamp } from '@orangecheck/stamp-core';
import { submitToCalendars, toStampOts } from '@orangecheck/stamp-ots';

const env = await stamp({
  content: new TextEncoder().encode('hello stamp'),
  mime: 'text/plain',
  signer: { address: 'bc1q…', signMessage: (msg) => wallet.signBip322(msg) },
});
const proof = await submitToCalendars(env.id); // a pending proof
const dotStamp = { ...env, ots: toStampOts(proof) };
signMessage is yours to supply: any wallet that returns a base64 BIP-322 signature works.

Check one

Verify a stamp someone sent you.

If you got a link, open it: it checks itself in your browser. If you got a file, paste its JSON here, or drop the .stamp at stamp.ochk.io/verify. Add the original file there too if you have it; your browser hashes it locally and compares.

The verifier checks, in order:

  1. The stamp’s version and shape.
  2. That the six-line note rebuilds from the stamp’s fields and hashes to its id. Change any field and this fails.
  3. That the signature is valid for the signer’s Bitcoin address (BIP-322).
  4. If the stamp claims a block: that the proof leads from the id to that block, and that the real block header matches.
  5. If you added the file: that its hash matches.

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

The result says what passed, and lists plainly what it did not check.

You do not need us for any of this. From the command line: npx -p @orangecheck/stamp-cli stamp verify post.md.stamp post.md --require-anchor. Anyone with the stamp and Bitcoin block headers can run the same checks on their own machine, offline.

What you trust

Every party you rely on, by name.

The signer’s wallet and key
A stamp proves that whoever held the address’s key signed. If the key was stolen, so is the signature.
The OpenTimestamps calendars, until upgrade
stamp.ochk.io submits to alice.btc.calendar.opentimestamps.org, bob.btc.calendar.opentimestamps.org and finney.calendar.eternitywall.com, through a small relay on stamp.ochk.io because the calendars do not accept submissions straight from a browser. A calendar can fail to anchor your stamp. It cannot backdate it. Once upgraded, the proof stands on Bitcoin alone.
A source of block headers
The web verifier and the CLI read headers from mempool.space. Each header is checked against the block hash in the stamp, so the source can only fail to answer, not lie about a block. Point the CLI at your own node to remove even that.
Nostr relays, only if you publish
Relays help people find stamps. They cannot change one: the signature inside is what counts.

What it is not

The limits, plainly.

Not a judge of truth
A stamp proves who signed some bytes and that those bytes existed by a block. It says nothing about whether the content is true, or original.
Not a clock to the second
The time is a block, roughly ten minutes wide. The signed_at time inside the stamp is the signer’s own claim. Only the anchor proves anything about time.
Not revocable
A stamp is permanent by design. You can sign a later statement; you cannot unsign this one.
Not private
The signer’s address is in plain text. Use a fresh address if you need distance, and seal the content with OC Lock first if it is secret.

Where it is used

Apps that use it.

Public address pages on ochk.io
ochk.io/u/<address> lists the stamps an address has published to Nostr, and checks each one before showing it.
OC Pledge
A promise can name a stamp as its proof: “I will publish X by this date” is kept if a matching stamp exists. The pledge spec defines this test. The tools check that the rule is well formed, but pledge.ochk.io does not yet look the stamp up for you: whoever resolves the pledge does.
ochk.app (opens in a new tab)
It anchors each receipt to Bitcoin through the same OpenTimestamps calendars and the same @orangecheck/stamp-ots code. Its receipts are not stamps: orangecheck signs them with its receipt key, not with a Bitcoin address.

None of the showcase apps (vault, chat, cosign, the demo) makes stamps today.

Stamp your first file.

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.