Writing, 30 Sept 2026, 3 min read

VeritasChain: prove when a file existed, using Ethereum and IPFS

VeritasChain anchors a file's fingerprint on Ethereum with your wallet and a timestamp, so anyone can verify it later without trusting a platform.

A screenshot proves nothing. A file’s metadata can be rewritten, its timestamp forged, its origin disputed. The usual answer is to trust someone, a platform, a notary or a vendor, to vouch for it. I built VeritasChain, an open-source file provenance tool, to remove that someone: it records a file’s fingerprint on Ethereum so anyone can check it later, even if this project disappears.

The problem

Say you capture a photo or a document that might matter later: evidence, a design, a report. Months later someone claims you changed it, or that it didn’t exist yet. How do you prove what the file looked like, and when?

Most content authenticity tools ask you to trust an issuer: a platform badge, a signing service, a timestamping company. That works until the issuer shuts down, gets acquired, or decides your file is no longer convenient. The proof lives and dies with the vendor.

What it does

  • Stamps a file. You connect a wallet and drop a file. Its fingerprint is written to Ethereum with your wallet address and the block’s timestamp.
  • Verifies without an account. Anyone can check a file with just its fingerprint. No sign-up, no wallet, no API key.
  • Works from scripts. A developer API lets you stamp files from CI, a cron job or a camera rig.
  • Has no user table. No email, no password, no session to steal. Your wallet is your identity.

The claim it makes is simple and strong: this wallet published these exact bytes no later than this block.

How it works

The fingerprint is the file’s IPFS content ID (CID). IPFS hashes the bytes, so an identical file always gets the same CID, and a single changed pixel gives a completely different one. That CID is what goes on-chain.

sequenceDiagram
    actor U as You + MetaMask
    participant B as FastAPI backend
    participant I as IPFS
    participant E as Ethereum
    U->>B: upload file + wallet address
    B->>I: pin the file
    I-->>B: CID (content hash)
    B->>E: uploadFile(CID, name) from your wallet
    E-->>B: transaction receipt
    B-->>U: certificate: CID + transaction ID

The smart contract, UserFileStorage.sol, stores the hash, file name, sender address and block timestamp. State is keyed by the sender, so one wallet cannot read or change another wallet’s records at the contract level.

The stack is a React 19 frontend, a FastAPI backend that owns both the IPFS client and the web3 provider, a Kubo IPFS node, and a Solidity contract deployed with Truffle. The browser never talks to IPFS or Ethereum directly.

Try it

With Docker, one script brings up a local Ethereum chain (Ganache), IPFS, the contract, the backend and the frontend:

git clone https://github.com/Parthkomalwad/VeritasChain && cd VeritasChain
./start_all.sh

Then open http://localhost:3000, connect MetaMask, and stamp a file. The API docs are at http://localhost:8000/docs.

What’s broken right now

This part matters, so I will be direct. VeritasChain is alpha. The stamp-and-verify loop works end to end on a local chain, and the contract’s per-wallet scoping is sound. The trust boundary around it is not finished.

Anyone can stamp a file as anyone else. The upload endpoint takes the wallet address as a plain form field and passes it to the contract. Nothing proves the caller controls that wallet, so a forged record could attribute a file to any address.

API keys can be minted for any wallet. The key endpoint issues a working key for whatever address you send, with no ownership check. The code that binds a key to a wallet is correct, but the minting endpoint in front of it bypasses it.

Both have the same fix: the browser signs a random message with MetaMask, the backend recovers the signer’s address from the signature, and trusts that instead of the typed-in string. That change also replaces server-held keys with properly signed transactions, which is what unblocks real networks like a testnet.

A smaller one, from building the docs: GitHub refused to render one of my architecture diagrams with “Lexical error on line 10”. A node label starting with [/ looked to Mermaid like the start of a different shape. Quoting every label fixed it.

What’s next

  • Wallet signature checks on upload and key minting, closing both gaps above
  • Signed transactions, then a public testnet deployment
  • Hashed API keys with rotation, instead of a flat JSON file

The code is on GitHub, MIT licensed, and the full documentation covers the architecture and API. See my other work, or read about Archon, which also verifies files with checksums before trusting them.

#blockchain#ipfs#ethereum#fastapi#react

Comments

All writing RSS Reply by email