The framing I keep coming back to for this project: HTTPS doesn’t tell you a website is trustworthy, it tells you the connection hasn’t been tampered with and you’re talking to who you think you’re talking to. SourceProof does the same job for video. It answers “does this file match what the publisher actually signed”, not “is this video true”. Conflating those two is where a lot of content-provenance efforts go wrong, and I wanted to be deliberate about not doing that.
Origin and integrity, not truth
A publisher signs a video with an Ed25519 key. Anyone can then verify that a given file matches the signed original. That’s the entire trust claim. It says nothing about whether the video’s content is accurate, misleading, or out of context, only that the bytes haven’t been altered since the person holding that key signed them. Scoping the problem this tightly is what makes it tractable. Truth is a much harder, much more subjective problem, and bolting it onto a verification tool would make the tool worse at the one thing it can actually do well.
Why Ed25519
Publishers need to sign a lot of manifests without the signing operation becoming a bottleneck, and verifiers need to check signatures fast, often at scale. Ed25519 gives you small keys and signatures, fast verification, and it’s deterministic, no random nonce per signature to get wrong. For a system whose entire security model rests on the signing step being done correctly every time, removing a foot-gun like nonce reuse (the thing that’s sunk more than one ECDSA implementation) is worth the choice on its own.
Current shape
Early days, but the core is real, not a prototype:
server, a Go API covering publishers, keys, manifests, and verification endpointsserver, a Postgres schema backing publishers, keys, manifests, and a hash index for lookupstools/sign, a dev signing tool for generating keypairs and running the full sign-and-verify flow end to end
Everything runs through Docker Compose for local dev. The API and Postgres come up together, wired to each other, no manual setup:
docker compose up
curl http://localhost:8080/api/health
# → {"service":"sourceproof","status":"ok"}
Where this is going
Planned components (a CLI signing agent, a publisher onboarding UI, a public verifier UI, and a shared Go library) are all designed to be independently buildable and deployable against the same core API. That separation matters more here than in most projects. A verification tool only has value if the verification path is something you can audit and trust independently of whoever built the pretty frontend around it. Keeping the server, the signing tool, and the UIs as separate deployables means the verification logic doesn’t have to trust, or depend on, anything sitting in front of it.