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
- Alice writes a Markdown post. 12,843 bytes.
- Her browser computes
sha256(bytes)locally — content never leaves her tab. - Client builds the canonical message (six lines,
oc-stamp:v1domain-separated). - Her wallet signs it via BIP-322. One prompt.
- Client derives
id = sha256(canonical_message), submits to two OTS calendars. - Client assembles the envelope: v, kind, id, content (hash + length + mime + ref), signer, signed_at, stake (null), ots (pending), sig.
- 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. - Alice ships
blogpost.md.stampalongside 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.
Flow 4 — Legal self-notarization
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.hashcommits 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/gateon 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
- Specification — normative rules.
- Envelope format — wire schema.
- OpenTimestamps integration — the anchor flow in detail.
- Security model — threat model and trust assumptions.