How OpenTimestamps works: what a Bitcoin timestamp proves
What an OpenTimestamps proof shows about your work and what it does not, how exact the Bitcoin date is, and how to verify an .ots file yourself.
A Bitcoin timestamp, such as an OpenTimestamps proof, shows that one exact file existed no later than the time of a particular Bitcoin block, give or take an hour or two. It does not show who wrote the file, whether it is right, or that nobody had the same idea earlier. And you can check one yourself with free software, without trusting whoever made it.
What does a Bitcoin timestamp prove?
OpenTimestamps, an open format for Bitcoin timestamps, sums it up in one line: "A timestamp proves that some data existed prior to some point in time" (opentimestamps.org, checked 9 October 2026). Everything else people read into a timestamp is extra.
The proof is about bytes, not ideas. If you timestamp a PDF, the proof covers that PDF exactly. Re-export it, fix a typo or strip its metadata, and the proof no longer matches the new file.
It is also one-sided. It gives a latest possible date, not a creation date: the file may be years older than the block. Peter Todd's 2016 announcement of OpenTimestamps puts the evidential limit plainly: "A timestamp only proves a message existed, not the message." Someone could timestamp two conflicting versions and later show only the one that suits them (Todd, 2016, checked 9 October 2026).
| A Bitcoin timestamp shows | It does not show |
|---|---|
| These exact bytes existed no later than a given block's time | When the file was created |
| The file is unchanged, if it still matches the proof | Who wrote it, or who stamped it |
| The proof holds without trusting the service that made it | That the content is correct, reviewed or original |
| That no one had it first, legal priority or ownership |
Who made something is a separate question. Signatures help answer it, together with knowing who controls the signing key. If your concern is an unpublished idea, see How to protect a research idea before you publish.
How does OpenTimestamps work?
It takes four steps: fingerprint, bundle, anchor and upgrade.
1. Your file becomes a fingerprint
The client computes a SHA-256 hash of the file: a 64-character fingerprint. The same bytes always give the same fingerprint, a one-byte change gives a completely different one, and the fingerprint cannot be turned back into the file. Add a single space to a stamped file and the official client rejects it with File does not match original! (tested 9 October 2026).
Only the fingerprint leaves your machine. The client also mixes in a random nonce before sending it, so, in the words of its README, "a remote calendar learns nothing about the contents of anything you timestamp".
One gap is worth knowing. The .ots file itself records the plain SHA-256 of what you stamped (ots info prints it on its first line). If the stamped text is short and guessable, such as a gene name or a one-line claim, anyone holding the proof could hash likely guesses and see which one matches. Mixing a random salt into what you stamp closes that gap. Papex does this, so even a short text cannot be recovered from its fingerprint.
2. Calendar servers bundle many fingerprints
Rather than one Bitcoin transaction per file, public calendar servers collect submissions and build a Merkle tree: hashes are paired and hashed together, level by level, until one root hash remains. Todd's example is to "create a merkle tree of those 10,000 files and timestamp the tip of that tree in one transaction". The public calendars "are free to use and they don't require any registration or api key" (opentimestamps.org).
Your proof records the path from your fingerprint to that root: at each level, which neighbouring hash to add, and on which side.
3. One Bitcoin transaction commits the root
The calendar writes the root into a Bitcoin transaction. Once a miner includes that transaction in a block, the block header commits to it. The header's merkle root "is derived from the hashes of all transactions included in this block, ensuring that none of those transactions can be modified without modifying the header" (Bitcoin developer documentation, checked 9 October 2026). The header also carries the block's time.
Change anything along the chain from file to block header and the hashes stop lining up. The client's last check is exactly this: the computed value must equal the header's merkle root, and the header's time is the time it reports (python-opentimestamps source).
4. Pending proofs and complete proofs
You get an .ots file at once, but it is incomplete: it ends with a note saying which calendar will finish the job. The client's README says confirmation "takes a few hours". Running ots upgrade later fetches the rest of the path and writes it into the file.
The difference matters for archiving. An incomplete proof needs that calendar to still be online; a complete one needs only Bitcoin block headers. The README says future clients will verify past timestamps "provided that the relevant calendar data is available", so upgrade your proofs and keep the upgraded file.
You rely on calendars to be available, not to be honest. As Todd's announcement puts it:
"Calendars aren't authoritative — at worst they can deny service, not produce false proofs."
How accurate is a Bitcoin timestamp?
To within hours, not minutes. Miners set the time in each block header themselves, and Bitcoin enforces only loose bounds. A block's time "must be strictly greater than the median time of the previous 11 blocks", and "full nodes will not accept blocks with headers more than two hours in the future according to their clock" (Bitcoin developer documentation).
The Bitcoin Wiki states the upper bound as "network-adjusted time + 2 hours". Since Bitcoin Core 27.0, that check uses the node's own system clock: "Network-adjusted time has been removed from consensus code" (both checked 9 October 2026). Either way, the Wiki's conclusion holds: "Block times are accurate only to within an hour or two." Todd's estimate is that a block time will "very likely be accurate to within two or three hours", and "almost certainly within a day".
So read a Bitcoin timestamp as: this version existed no later than about the block's time, with an hour or two of tolerance. That is plenty to show a dataset existed before a paper appeared, or a hypothesis before the results came in. It is not the tool for deciding which of two submissions arrived first on the same afternoon.
What does checking a real proof look like?
Papex Labs' educational record PXH-0BADXVXY7QM3, "Educational record: P is not equal to NP", is a public example of the mechanism. It is a teaching record, not a research result. Its check page (Check evidence on the record) offers the timestamp evidence as one download, papex-timestamp-evidence.zip, which holds the proof, witness.json.ots, and witness.json, the exact bytes the proof covers.
Three times are attached to it, and they come from different clocks:
| Time (UTC, 5 October 2026) | Event | Whose clock |
|---|---|---|
| 11:18:33 | Version signed | Papex's server |
| 11:18:35 | Fingerprint submitted to OpenTimestamps | Papex's server |
| 11:26:56 | Bitcoin block 970009 | The Bitcoin block header |
Only the last one can be checked without trusting Papex. This is what that check looked like on 9 October 2026:
shasum -a 256 witness.jsongave7ed0729a…f055a4, the same value as the "File sha256 hash" line fromots info witness.json.ots. The proof is about these exact bytes.ots infoshowed the whole path: the calendar's tree, then a Bitcoin transaction (111204d7…22a7df), then 13 pairing steps up the block's own transaction tree, ending at block 970009 with merkle root74e144e8…f95781.- Block 970009 on mempool.space and on blockstream.info shows the same merkle root, 5,787 transactions and a block time of 2026-10-05 11:26:56 UTC. The transaction is in that block, carrying the calendar's 32-byte root in an OP_RETURN output.
Conclusion: the signed evidence existed no later than about 11:27 UTC on 5 October 2026, within Bitcoin's tolerance. Here the block came about eight minutes after submission; it often takes longer.
How do I verify an .ots file?
You need three things: the .ots file, the original file exactly as it was stamped (or its SHA-256), and a way to read Bitcoin block headers. The commands below come from the official Python client's README and its built-in help, version 0.7.2 (checked 9 October 2026).
1. Install the client. It needs Python 3.
pip3 install opentimestamps-client
2. Put the proof next to the original. By default, ots verify paper.pdf.ots looks for paper.pdf in the same folder. Use -f to name the file explicitly, or -d with the hex SHA-256 if you only have the hash.
ots verify -f paper-final.pdf paper.pdf.ots
ots verify -d <sha256-in-hex> paper.pdf.ots
3. Verify against your own Bitcoin node. This is the strongest check. The README says verifying needs "a local Bitcoin Core node (a pruned node is fine)". The client reads your node's local configuration, or you can give it the address.
ots --bitcoin-node http://USER:PASS@127.0.0.1:8332/ verify paper.pdf.ots
A good result looks like the README's example: Success! Bitcoin block 358391 attests existence as of 2015-05-28 CEST. The client prints only the date, in your local time zone. For the hour, ask your node with bitcoin-cli getblockhash 358391, then bitcoin-cli getblockheader <hash>, which returns the block's time and merkleroot.
4. No node? Check the last step by hand. The --no-bitcoin option tells the client to do everything except contact Bitcoin.
ots --no-bitcoin verify witness.json.ots
It checks the file against the proof, then prints what is left, here: To verify manually, check that Bitcoin block 970009 has merkleroot 74e144e89dee…. Look the block up on two independent explorers and compare the merkle root and the time. This moves your trust from your own node to those explorers, so use two. The command still ends with an error status, because nothing was checked against Bitcoin.
5. If the proof is pending, run ots upgrade paper.pdf.ots, which keeps the old file as a .bak, then verify again. ots info paper.pdf.ots lists every step in the proof if you want to read it.
| Message | What it means |
|---|---|
Success! Bitcoin block N attests existence as of … | The path was checked against that block's header |
File does not match original! | Your file is not byte-for-byte the one that was stamped |
Pending confirmation in Bitcoin blockchain | Not yet in a block; upgrade later |
Could not connect to Bitcoin node | No node found; use --bitcoin-node or --no-bitcoin |
For a quick look, opentimestamps.org checks an .ots file and the stamped file in the browser. The project's JavaScript library falls back to public block explorers when no node is available, and its README is frank about it: "Verification using block explorers is convenient but not as secure as asking a local node."
RFC 3161 trusted timestamping or a Bitcoin timestamp: which should I use?
RFC 3161 (2001) is the standard for trusted timestamping by an authority. You send a hash to a Time Stamping Authority (TSA), which returns a signed token containing your hash and the time. The TSA must "use a trustworthy source of time", must time-stamp only a hash, and is required "not to examine the imprint being time-stamped in any way" (checked 9 October 2026). To verify, you check the token's signature and, the RFC adds, whether the TSA's certificate has been revoked.
Your trust sits with that authority. If its private key is compromised, "any token signed by the TSA using that private key cannot be trusted anymore". Because keys have a finite lifetime, the RFC also says tokens should be time-stamped again later to renew trust. In return you get an immediate, precise time: the format allows fractions of a second, with an optional stated accuracy.
Research groups use it too: timestamp.stanford.edu, made in a Stanford lab, hashes files in the browser and timestamps the digest "against several public timestamp authority servers in compliance with RFC 3161" (checked 9 October 2026).
| RFC 3161 | OpenTimestamps (Bitcoin) | |
|---|---|---|
| Who you trust | The TSA, its key and its certificate chain | Bitcoin's public history; calendars only for availability |
| Precision | Seconds or better | An hour or two |
| Time to a finished proof | Immediate | Usually a few hours |
| Checking it years later | TSA certificate status, or a renewed timestamp | Block headers, which any Bitcoin node holds |
| Cost | Depends on the provider | Free public calendars |
Law is the other difference. In the UK and the EU, the eIDAS Regulation gives a qualified electronic time stamp "the presumption of the accuracy of the date and the time it indicates and the integrity of the data to which the date and time are bound" (Article 41, UK version, checked 9 October 2026). Qualified time stamps are signed or sealed by a qualified trust service provider (Article 42). If you need that presumption, ask your legal adviser which provider to use; this post is not legal advice.
When each fits:
- RFC 3161: you need a precise time, a legal presumption, or your lab notebook or document system already supports it.
- OpenTimestamps: you want a proof that anyone can check decades from now without relying on one company's keys or certificates, and an hour or two of precision is enough. Preregistered hypotheses, datasets, code releases and manuscript versions are typical cases.
- Both: they fail in different ways, so together they cover more.
Keeping the record as you go
A timestamp is most useful when it is made as a version is settled, not months later. Papex builds this into signing. A signature links the people who signed to one exact version of a record; a later edit is a new version with its own signature and date, and earlier versions stay as they were.
When you sign, only a salted fingerprint of the version leaves Papex. It is timestamped with OpenTimestamps and anchored in Bitcoin, and the .ots proof checks with any OpenTimestamps tool, without Papex, exactly as in the example above. You need no wallet and no cryptocurrency.
Drafts stay private while you work. After signing, you choose whether to keep the version private, share it with people you invite, or publish it.
The limits are the ones this post describes. The timestamp shows that a version existed by a date; the signature shows who signed which exact version. Neither proves authorship, ownership, originality, correctness or priority in law, and the signing time comes from Papex's own clock, while the Bitcoin time is the independent one. If a patent may be involved, public disclosure can affect patent rights, so talk to a patent attorney or your tech-transfer office before you publish.
You can start a record at papex.org.
Sources
- OpenTimestamps: A timestamping proof standard, checked 9 October 2026
- OpenTimestamps Client README (opentimestamps-client on GitHub), checked 9 October 2026
- OpenTimestamps Client command-line options, otsclient/args.py, checked 9 October 2026
- OpenTimestamps Client verification code, otsclient/cmds.py, checked 9 October 2026
- python-opentimestamps, BitcoinBlockHeaderAttestation (notary.py), checked 9 October 2026
- javascript-opentimestamps README, checked 9 October 2026
- Peter Todd, OpenTimestamps: Scalable, Trust-Minimized, Distributed Timestamping with Bitcoin (2016), checked 9 October 2026
- Bitcoin developer documentation: Block chain, block headers, checked 9 October 2026
- Bitcoin developer documentation: getblockhash, checked 9 October 2026
- Bitcoin developer documentation: getblockheader, checked 9 October 2026
- Bitcoin Wiki: Block timestamp, checked 9 October 2026
- Bitcoin Core 27.0 release notes, checked 9 October 2026
- mempool.space: Bitcoin block 970009, checked 9 October 2026
- blockstream.info: Bitcoin block 970009, checked 9 October 2026
- mempool.space: transaction 111204d7…22a7df, checked 9 October 2026
- RFC 3161: Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP), checked 9 October 2026
- eIDAS Regulation (UK version), Article 41: Legal effect of electronic time stamps, checked 9 October 2026
- eIDAS Regulation (UK version), Article 42: Requirements for qualified electronic time stamps, checked 9 October 2026
- Stanford trusted timestamping service, checked 9 October 2026
- Papex record PXH-0BADXVXY7QM3, checked 9 October 2026