live · mainnetoc · docs
specs · api · guides
docs / protocol walkthrough

Protocol walkthrough

Narrative companion to the spec. If you want the normative rules, read the spec. If you want to understand why and how, read this.

The mental model

flowchart LR
    W["Wallet"] -->|BIP-322 sign| M["canonical message"]
    M -->|H(bytes) = id| ID["envelope id"]
    ID -->|submit| OTS[("OTS calendar(s)")]
    OTS -->|pending proof| P["pending"]
    P -.~1h later.-> CONF["confirmed<br/>(Merkle path<br/>to block header)"]
    M --> ENV[(".stamp envelope<br/>JSON, self-contained")]
    CONF -->|upgrade ots.proof| ENV
    ENV --> BC["Bitcoin block<br/>anchor"]

    classDef base fill:#0a0a0a,stroke:#f97316,stroke-width:2px,color:#fafafa;
    classDef store fill:#18181b,stroke:#52525b,color:#fafafa;
    class W,M,ID,P,CONF,BC base;
    class OTS,ENV store;

Every stamp is one signing ceremony, one calendar submission, one later upgrade. The envelope is self-contained: canonical message, BIP-322 signature, OTS proof, optional stake context. Verification is a pure function of envelope + Bitcoin headers.

Flow 1 — Alice stamps a blog post

  1. Alice writes a Markdown post. 12,843 bytes.
  2. Her browser computes sha256(bytes) locally — content never leaves her tab.
  3. Client builds the canonical message (six lines, oc-stamp:v1 domain-separated).
  4. Her wallet signs it via BIP-322. One prompt.
  5. Client derives id = sha256(canonical_message), submits to two OTS calendars.
  6. Client assembles the envelope: v, kind, id, content (hash + length + mime + ref), signer, signed_at, stake (null), ots (pending), sig.
  7. About an hour later, an OTS calendar anchors the root to a Bitcoin block. The upgraded proof contains the Merkle path from id up to the block header. Any client can fetch and replace ots.proof.
  8. Alice ships blogpost.md.stamp alongside her post.

A year later, Bob reads the post offline on a plane. He loads the .stamp, his tool reconstructs the canonical message, re-derives the id, verifies the BIP-322 signature, walks the OTS proof to the Bitcoin header Merkle root, and confirms the bytes he has match content.hash. No network required.

Flow 2 — Commit-signing with git-stamp

Current state of tag signing: GPG keys nobody audits, keyservers nobody trusts. Developers already have Bitcoin wallets.

$ git-stamp tag v2.1.0
> Reading tree… SHA256:e7…
> Canonical message (sign with your wallet):
>   oc-stamp:v1
>   address: bc1qalice…
>   content_hash: sha256:e7…
>   content_length: 48128
>   content_mime: application/x-git-tree
>   signed_at: 2026-04-24T18:30:00Z
> [Sparrow] Signed. Submitting to OTS calendars…
> Stamp written: .git/stamps/v2.1.0.stamp

Anyone cloning runs git-stamp verify v2.1.0 — authorship, priority, and tree-hash equality all checked, no GPG keyserver involved.

Flow 3 — Sybil-gated publishing feed

A platform accepts submissions from anyone but wants a stake signal. With stamps, the stake is time-pinned: the platform can require that the signer held stake at the moment they wrote the content, not just right now.

import { ocGate } from '@orangecheck/gate';
import { verify } from '@orangecheck/stamp-core';

app.post('/submit', async (req, res) => {
    const { stamp, bytes } = req.body;
    const r = await verify({ envelope: stamp, content: bytes });
    if (!r.ok) return res.status(400).json({ error: r.code });
    if (!r.envelope.stake) return res.status(403).json({ error: 'no_stake' });

    const att = await ocGate.resolve(r.envelope.stake.attestation_id);
    if (att.sats_bonded < 100_000 || att.days_unspent < 30) {
        return res.status(403).json({ error: 'below_threshold' });
    }
    // accept
});

Time-pinned stake defeats farmed-stake-in-the-last-week gaming.

Wills, assignment agreements, IP disclosures, NDAs. A notary's job is "this document existed, signed by this person, on this date." OC Stamp produces that cryptographically:

  • Authorship: BIP-322 bound to a provable Bitcoin address.
  • Priority: confirmed OTS anchor in a specific Bitcoin block, adversarially public.
  • Tamper-evidence: content.hash commits to the bytes; any edit invalidates the id and the signature.

In jurisdictions that recognize digital signatures (Federal Rules of Evidence 901/902 in the US, eIDAS in the EU), a BIP-322-signed PDF with a confirmed OTS anchor is admissible.

Flow 5 — DAO proposal with durable provenance

A proposal is a Markdown doc. Today it lives in a forum thread whose authorship is whoever clicked "post." With OC Stamp, the proposal author includes a .stamp envelope carrying who proposed, when, at what stake — and the DAO's later vote (via OC Vote) can reference the stamp id.

What's NOT in the protocol

  • Our own timestamping layer. OTS works. Peter Todd built it correctly.
  • A proprietary Nostr kind. We use 30083 in the OrangeCheck family range (30078 for attestations and lock device records, 30080–30082 for vote). No overloading.
  • Keyservers we operate. Envelopes are self-contained; directory is optional.
  • Custody of signer keys. Never. The wallet the user already holds is the identity.
  • Making OTS non-optional for signing. A signed-but-unanchored envelope is a legitimate artifact; any later client can upgrade it.

What's layered from OrangeCheck

  • Optional stake reference in stake.attestation_id. Composes with @orangecheck/gate on the consumer side.
  • Identity continuity — the same Bitcoin address the user holds an OrangeCheck attestation under, an OC Lock device record under, is the stamp signer.

Where to go next