Etchernity
Bitcoin-powered proof of existence Etchernity -- "Your moment, carved into forever."
Inspiration
It started with a simple question: how do you prove a photo existed before a certain date?
A journalist captures evidence of a human rights violation. An artist publishes original work online. A researcher makes a discovery. A couple writes wedding vows. In every case, the when matters just as much as the what and yet there's no simple, trustless way for a regular person to prove it.
Cloud services get shut down. Metadata gets stripped. Social media timestamps can be disputed in court. The tools that do exist — notaries, legal deposits, blockchain protocols — require either money, expertise, or both.
I wanted to build something where anyone, with zero crypto knowledge, could drop a file into a browser and walk away with permanent, cryptographic proof that it existed at a specific moment in time. No wallet. No account. No trust required.
What it does
Etchernity timestamps any file on the Bitcoin blockchain in three clicks:
- Drop a file — photo, PDF, text, anything.
- Pick a mode — Instant (dedicated Bitcoin transaction on testnet) or Standard (free, via OpenTimestamps).
- Get your certificate — a beautiful, downloadable proof with a QR code anyone can independently verify.
The critical design choice: your file never leaves your browser. System hash it locally using the Web Crypto API, and only the resulting SHA-256 hash — a 64-character string — ever touches our server. Privacy isn't a feature I added. It's the architecture.
Why Bitcoin?
I needed an anchor that is immutable (no one can alter a confirmed block), public (anyone can verify independently), and persistent (Bitcoin has been running since 2009 with zero downtime). No other system offers all three. A timestamp on Bitcoin isn't a promise from a company — it's a mathematical fact embedded in the most battle-tested distributed ledger in existence.
Two Modes, One Guarantee
Instant Mode embeds your hash directly into an OP_RETURN output of a Bitcoin transaction (currently on testnet). You get a dedicated, permanent on-chain record visible on any block explorer. Confirmed in ~10 minutes.
Standard Mode uses the OpenTimestamps protocol, which aggregates many hashes into a Merkle tree and anchors only the root on-chain. This makes it free while remaining just as cryptographically sound. Takes 1–2 hours.
Both modes produce a verifiable certificate with a QR code that you can download as PNG or PDF.
How I built it
The Core Hash-to-Chain Pipeline
Given a file F, the browser computes:
h = SHA-256(F)
This produces a 256-bit digest — a unique fingerprint. The probability of two different files producing the same hash is approximately:
1 / 2^256
making collisions practically impossible.
That hash h is then anchored to Bitcoin.
- Instant Mode: embedded directly in an
OP_RETURNtransaction output Standard Mode: becomes a leaf in a Merkle tree:
h → H(h || h₂) → H(H(h || h₂) || h₃) → ... → root_tx
Only the Merkle root is written on-chain, so thousands of timestamps can share a single transaction.
The Stack
I built Etchernity as a single Next.js 16 application — no separate client and server repos, no microservices. Everything lives under one src/ directory.
- App Framework: Next.js 16 with App Router for full-stack React — pages, API routes, and SSR all in one codebase.
- UI: React 19 + TypeScript for components and client state, styled with Tailwind CSS v4.
- Hashing: Web Crypto API runs SHA-256 entirely in the browser. The file never touches the server.
- Bitcoin (Instant):
bitcoinjs-lib,ecpair, andtiny-secp256k1for building and signing OP_RETURN transactions. Wallet is a simple WIF key on testnet. - Bitcoin (Standard):
javascript-opentimestampsfor calendar submission, proof upgrades, and verification. - Database: Prisma ORM with SQLite by default (swappable to PostgreSQL for production via
DATABASE_URL). - Certificates: Generated entirely client-side using
html2canvas,html-to-image,jsPDF, andqrcode. No server-side rendering needed.
How status updates work
Instead of WebSockets, I use a polling approach. The useTimestamp hook periodically calls GET /api/timestamp/[id], which also triggers OTS proof upgrade checks and transaction confirmation monitoring on each request. This keeps the architecture simple — no Redis, no background workers, no job queues.
Verification
Each certificate links to /verify/[id], where anyone can upload the original file and verify its hash against the blockchain proof. If the hashes match and the block is confirmed, the proof is valid. No account or API key needed.
Challenges I ran into
Client-side hashing at scale. The Web Crypto API is fast for small files, but hashing a large video in the browser without freezing the UI required chunked reading with FileReader and careful progress callbacks. Getting this smooth across browsers took more iterations than expected.
Bitcoin transaction fee estimation. Fees on Bitcoin fluctuate constantly. I integrated with mempool.space's fee estimation API and built retry logic for when transactions got stuck due to sudden fee spikes.
OpenTimestamps upgrade lifecycle. OTS proofs start as "pending" calendar commitments and only become full Bitcoin proofs after aggregation into a block — which can take 1–2 hours with no webhook or push notification. I handle this by checking for upgrades on each status poll, so the proof gets upgraded the next time the user checks their certificate.
Client-side certificate generation. I wanted certificates that feel real — something you'd frame or share — not a generic receipt. Getting html2canvas and html-to-image to produce consistent, high-quality PNG and PDF output with QR codes and custom styling across different browsers took significant trial and error.
Scoping under pressure. I originally planned an optional file storage system, background job queues, WebSocket live updates, and Docker deployment. I cut all of it to stay focused on the core loop: hash → anchor → certify → verify. Shipping a tight, working product beat shipping a broad, broken one.
Accomplishments that we're proud of
The privacy guarantee is real, not marketing. The file genuinely never leaves the browser. There's no upload endpoint, no storage bucket, no server-side file handling. This isn't a privacy policy — it's an architectural fact you can verify by reading the network tab.
Zero-to-certificate in under 30 seconds. A non-technical user can go from landing page to holding a verifiable Bitcoin-anchored proof without creating an account, installing anything, or understanding what a hash is.
The certificates look beautiful. This sounds superficial, but it matters. A proof-of-existence is only useful if people actually use and share it. I invested heavily in making certificates feel like artifacts worth keeping — clean typography, QR code verification, and downloadable PNG/PDF export.
Dual anchoring modes that serve different needs. Instead of forcing everyone through one path, I built both a dedicated instant path (real OP_RETURN transaction) and a free standard path (OpenTimestamps), letting users choose based on urgency and use case.
One codebase, no infrastructure overhead. By building on Next.js App Router with SQLite and client-side certificate rendering, the entire app runs with npm run dev — no Docker, no Redis, no external services beyond Bitcoin itself. This makes it trivially deployable to Vercel or Railway.
What I learned
- Privacy-first architecture is a design constraint, not a feature toggle. When you commit to "the file never leaves the browser," every decision downstream gets simpler — no upload endpoints, no storage costs, no breach surface. Constraints clarify.
- Bitcoin is surprisingly accessible as a data layer. OP_RETURN makes it trivial to embed small data on-chain. The hard part isn't the protocol — it's the UX around fees, confirmation times, and making all of that invisible to someone who's never thought about blocks.
- The best security is the kind users don't have to think about. If someone has to understand SHA-256 to trust the product, we've failed. The certificate and QR code do the explaining.
- Cutting scope is a feature. Dropping file storage, WebSockets, Docker, and background workers felt like a series of losses in the moment, but it let us polish everything that shipped. The core loop is tight because I protected it.
- Next.js App Router is a genuine full-stack framework. API routes, server components, and client components in one tree eliminated the need for a separate backend entirely. For a hackathon, this was a massive velocity multiplier.
What's next for Etchernity
Mainnet deployment. Instant Mode currently runs on Bitcoin testnet. The next step is mainnet support with real transaction fees and a funding flow for the wallet.
Optional file storage (Make Viewable mode). Let users opt in to uploading their file so the certificate link can display the original content — images rendered inline, other files as downloads. Privacy-first by default, with the file's hash re-verified against the Bitcoin proof on every view.
Background proof upgrades. Replace the current poll-on-request approach with a proper job queue (BullMQ + Redis) so OTS proofs upgrade automatically without waiting for the user to check back.
Real-time status updates. Add WebSocket or Server-Sent Events so users see their proof progress live — from submission to mempool to confirmed — without manual refreshing.
Batch timestamping. Timestamp an entire folder of files at once under a single Merkle root, with individual proofs for each file. Useful for photographers, researchers, or anyone with large archives.
Browser extension. Right-click any image or file on the web to timestamp it instantly — bringing the core flow to wherever content already lives.
Built With
- bitcoin
- next.js
- node.js
- prisma
- react
- sqlite
- tailwind-css
- typescript
Log in or sign up for Devpost to join the conversation.