Inspiration
Two regulations landed almost together: India's IT Rules Amendment 2026, which legally defines "synthetically generated information" and requires visible labeling plus embedded provenance metadata, and the EU AI Act's Article 50 marking obligations, in force from August 2, 2026. Neither generative tools nor object storage on their own answer the question a marketing lead, journalist, or compliance officer actually asks: is this exact file the one we approved, and can I prove it to someone else? We wanted a Genblaze + B2 project that produced a receipt for every asset, not just an asset
What it does
Notary generates AI images and video, and for every output it locks a tamper-evident provenance record in Backblaze B2 with Object Lock (provider, model, prompt, parameters, timestamp) so it can never be altered, not even by us.
On top of that record it adds three things neither Genblaze nor B2 give you out of the box: a Compliance Engine that scores every asset against India's IT Rules 2026 (5 checks) and EU AI Act Article 50 (4 checks) with concrete remediation, not a checkbox; AI Forensic Verification, where a hash mismatch triggers a Gemini Vision comparison against the canonical original that explains what changed instead of just saying "no match"; and a Public Verification Portal, a no-login link anyone can open and drag a file into, hashed client-side so nothing has to leave the browser unless verification fails.
Beyond that: a navigable remix/lineage DAG (every regeneration links to its parent via Genblaze's from_result()), a downloadable HTML provenance certificate, an embeddable SVG trust badge, a live dashboard tracking per-provider success rate and latency, and an admin tool that re-verifies every manifest across the whole B2 bucket on demand.
How we built it
FastAPI backend, React/Vite frontend. Every generation goes through Genblaze's Pipeline/Step/Run abstraction, writing through an ObjectStorageSink into a B2 bucket created with File Lock enabled at creation (the one B2 setting that can't be retrofitted, so it was step one).
Image generation runs a resilience cascade: Google Gemini (multi-key rotation) first, then NVIDIA NIM FLUX.1 Schnell, then a Hugging Face Space running FLUX.2-klein-4B, then Pollinations FLUX as a last resort. A dead key or rate limit on one provider never fails the request. Video runs through Veo on the same pipeline.
Image provenance needed a two-record chain, because embedding a manifest into a file changes the file's bytes, which changes its hash. We write M0 (the raw generation manifest) first, embed it into the image, then write M1, a locked receipt whose parent is M0 and whose hash covers the actual final bytes the user gets. Verification always checks against M1. Everything durable lives in B2; a SQLite cache is a disposable read-index, rebuildable from B2 on demand via genblaze index. B2, not the cache, is the source of truth.
Challenges we ran into
The manifest/hash paradox (embedding a record changes the hash it would need to describe) was the hardest design problem; we tried a couple of wrong approaches before landing on the M0/M1 chain, and wrote regression tests around a deliberately corrupted file to confirm a single-byte change after embedding always fails cleanly. Provider reliability during a live build is genuinely unpredictable: free-tier keys hit quota mid-test, a Hugging Face Space goes cold. The fallback cascade wasn't optional polish; it was required to have a working app at all. We were also careful not to overclaim: it would've been easy to imply C2PA-standard signing when we don't do that, so the compliance module reports gaps as gaps by default rather than silently passing.
Accomplishments that we're proud of
Every claim is enforced in code, not just described in a doc: a blocked policy prompt never reaches a provider or B2, a failed hash is never marked verified. The public verification portal needs no account at all; an outside stranger can independently confirm provenance on any asset we generate. We shipped meaningfully past our original plan: the lineage DAG, certificate export, trust badge, and dashboard weren't in scope originally, but B2 + Genblaze made them cheap to add once the core chain worked.
What we learned
How much a two-record manifest chain simplifies tamper-evidence once you accept that a file's hash and its own embedded provenance can never describe each other. That resilience against provider failure has to be designed in from day one: a generative app with a single provider is a demo, not a product. How much daylight there still is between "we stored a manifest" and "we're actually compliant," which is exactly the gap the Compliance Engine exists to make explicit.
What's next for Notary
Embed a real C2PA content credential inside the file itself, closing the one gap we currently report honestly as partial. Batch/API access for teams notarizing AI media at pipeline scale. Webhook alerts when a public verification fails, so a brand finds out about a tampered asset before their audience does.
Log in or sign up for Devpost to join the conversation.