DEV Community

Zeke
Zeke

Posted on • Edited on

How to Prove a File Existed Before a Certain Date Using Bitcoin (21 Sats, No Account)

The timestamp problem

You ship a file. A week later, someone claims they had the same idea first. How do you prove your file existed before theirs?

Cryptographic hashes solve "this file is unchanged." They do not solve "this hash existed at this time." For that you need a timestamp that somebody else can verify without trusting you.

The two usual answers are a Certificate Authority timestamp (trusts the CA) or a blockchain transaction (costs fees, requires a wallet, requires you to wait for confirmation). Both have real costs.

OpenTimestamps solves this by aggregating many hashes into a Merkle tree and anchoring the root in a Bitcoin transaction. One on-chain transaction serves thousands of commitments. The trust model is Bitcoin's own hash rate. The downside: the OTS public calendars operate on their own schedule — you wait for aggregation, then wait for confirmation. This can take hours.

PowForge Witness (PFWIT) puts an HTTP endpoint in front of this pipeline, with a 10-minute aggregation cycle and a Lightning payment gate.

How it works

Submit a hash, pay a 21-sat Lightning invoice, and your hash lands in the next 10-minute Merkle batch. The batch root gets submitted to four OTS calendar servers. Once a Bitcoin block confirms the calendar's aggregation transaction, every root in that batch has a provable timestamp tied to that block height.

For individual hashes, the proof chain is:

your_hash → Merkle inclusion path → batch_root → OTS proof → Bitcoin block header
Enter fullscreen mode Exit fullscreen mode

Every element in that chain is independently verifiable. The OTS proof file format is an open standard. You can verify with the reference ots CLI, not with PowForge.

Submit a hash

Pick a file. Hash it. Send the hash with a POST request:

# Hash your file
sha256sum myfile.txt
# 3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea  myfile.txt

# Submit for timestamping (returns a Lightning invoice)
HASH="3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea"
curl -s -X POST https://captcha.powforge.dev/api/timestamp \
  -H "Content-Type: application/json" \
  -d "{\"hash\": \"$HASH\"}"
Enter fullscreen mode Exit fullscreen mode

Response:

{
  "invoice": "lnbc210n1p4pk...",
  "payment_hash": "d85057...",
  "hash": "3f79bb7b...",
  "price_sats": 21
}
Enter fullscreen mode Exit fullscreen mode

Pay the invoice with any Lightning wallet. 21 sats. Once paid, your hash is queued for the next batch cycle.

Check payment status

After paying the invoice, poll the check endpoint using the payment_hash from the submit response:

PAYMENT_HASH="d85057..."
curl -s "https://captcha.powforge.dev/api/timestamp/check/$PAYMENT_HASH"
Enter fullscreen mode Exit fullscreen mode

When payment is confirmed and the hash has been witnessed, the status transitions:

  • pending_paymentpaidpending_witnesswitnessed

Get the certificate

After witnessing (within 10 minutes of payment confirmation), retrieve the certificate using your original file hash:

HASH="3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea"
curl -s "https://captcha.powforge.dev/api/pfwit/certificate/$HASH"
Enter fullscreen mode Exit fullscreen mode

Response once witnessed:

{
  "pfwit_version": 1,
  "found": true,
  "hash": "3f79bb7b...",
  "batch_id": 4,
  "merkle_root": "7e2a...",
  "leaf_index": 12,
  "merkle_proof": ["ab3c...", "11d4...", "..."],
  "anchored_at": "2026-05-23T14:03:11.000Z",
  "ots_status": "submitted",
  "ots_proof_hex": "004f...",
  "ots_download_url": "https://captcha.powforge.dev/api/witness/proof/4",
  "verify_command": "curl -s \"https://...\" -o proof.ots && ots verify proof.ots"
}
Enter fullscreen mode Exit fullscreen mode

When ots_status is confirmed, the proof has a Bitcoin block attestation. The verify_command is a copy-paste-ready command to independently verify the OTS proof.

Verify independently

The whole point is you should not have to trust PowForge to use this. Download the OTS proof file and verify it yourself:

# Install opentimestamps-client
pip install opentimestamps-client

# Download and verify (use the batch_id from the certificate response)
curl -s "https://captcha.powforge.dev/api/witness/proof/BATCH_ID" -o proof.ots
ots verify proof.ots
Enter fullscreen mode Exit fullscreen mode

When the Bitcoin block is confirmed (1-2 hours after submission), ots verify will tell you which Bitcoin block height attests to the existence of the Merkle root, which includes your hash.

You can then check that block independently on any Bitcoin block explorer. The OTS proof file is self-contained: it contains the Merkle path from the calendar's aggregated root down to the Bitcoin block header, serialized in the standard OTS binary format.

What this is good for

Code signing without a CA. Hash your release binary and get a Bitcoin-anchored timestamp. Nobody can backdate a timestamp that is already in a Bitcoin block.

Research priority. Hash a preprint, submit it, get the OTS proof. If someone claims you copied their work, the Bitcoin timestamp is objective.

Audit logs. Hash a database export or a log file at end-of-day and anchor it. The chain proves you had that exact data at that exact time.

Contract snapshots. Hash the text of an agreement at signing time. Neither party can retroactively claim the document said something different.

What this is not

A database timestamp that says you signed something. A notary service. A legal instrument. It is a cryptographic proof that a specific 256-bit hash was committed to a Merkle tree at a specific time, and that tree root is embedded in the Bitcoin ledger. The legal weight of that proof depends entirely on jurisdiction and context. On its own it is a mathematical fact. What that fact is worth to a court is a separate question.

The 21-sat number

21 sats is symbolic — matching the oracle price and the Bitcoin supply cap in spirit. At current rates it is less than a tenth of a cent. The payment serves two purposes: it covers OTS calendar submission cost and it creates a real commitment that prevents spam flooding the pipeline.

The falsifier

I am filing a hypothesis: at least one publisher pays for a timestamp via POST /api/timestamp by 2026-06-30. If nobody outside my home IP calls that endpoint in 30 days, the hypothesis is falsified and I will say so explicitly. Progress on this hypothesis is visible by checking the endpoint — if it responds with an invoice, the service is live.

If you try it and it works, or does not work, I want to know. Open an issue at the GitHub mirror or reply here.


All code is MIT. The OTS proof format is an open standard. The calendar servers are operated by the OpenTimestamps project and independent parties. The pipeline runs on PowForge infrastructure at captcha.powforge.dev.

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.