TrueFrame
Content Authenticity Gateway with 4-layer cryptographic provenance and multi-provider AI generation
4-layer provenance
4-tier verification
Multi-provider AI
Public verification
Overview
Content Authenticity Gateway for AI-generated media. Generates images through a multi-provider pipeline (Cloudflare FLUX primary, Gemini fallback), stamps every asset with four independent layers of cryptographic provenance (SHA-256, LSB watermark, perceptual hash fingerprint, C2PA signing), stores them durably on Backblaze B2, and enables public verification even after metadata stripping. Built for the Backblaze Generative Media Hackathon ($10K prize). The system solves a real problem: AI-generated media spreads without any record of how it was created, and social platforms strip metadata on upload. TrueFrame embeds proof at redundant layers so provenance can always be recovered.
Architecture Diagram
Design Decisions
- →Chose a 4-layer stamping pipeline (SHA-256, watermark, fingerprint, C2PA) over single-method provenance. Each layer covers a different failure mode: exact-match lookup, metadata-stripped recovery, heavy-edit recovery, and cryptographic tamper proof. Losing any one still leaves three others.
- →C2PA signing applied last in the pipeline, not first. Watermarking re-encodes pixel data, which would invalidate an existing C2PA hard binding. The signature must cover the final bytes that get stored and served.
- →Content-addressable storage on B2. The SHA-256 hash is the filename. Deduplication is free, tamper detection is trivial (any modification changes the key), and there is no collision risk with SHA-256.
- →FastAPI background tasks for generation instead of Celery/Redis. The hackathon scale (under 100 concurrent users) doesn't justify a message broker. The HTTP response returns immediately with a run ID; the client polls for progress.
- →LSB steganography watermark over frequency-domain methods. Simpler to implement, survives JPEG quality 70+ and PNG re-saves. Recovery is byte-level extraction with no ML model needed.
- →Perceptual hashing (pHash) for the fingerprint layer rather than deep embedding. At hackathon scale (under 10K assets), a brute-force nearest-neighbor scan over hex-encoded hashes is sub-millisecond. No vector database needed.
Deployment
Frontend deployed on Vercel with auto-deploys from GitHub push to main. Backend deployed on Render as a Python web service (uvicorn). Storage on Backblaze B2 private bucket with pre-signed URL serving. Self-signed ECDSA P-256 certificate chain for C2PA signing. GitHub Actions CI/CD with path-filtered workflows (frontend / backend / keep-warm). Keep-warm cron job hits /health every 14 minutes to prevent Render cold starts. Three base64-encoded certificate env vars, B2 credentials via standard S3 env vars, JWT secret shared between NextAuth and FastAPI, Cloudflare AI token for FLUX Schnell image generation.
Lessons Learned
The c2pa-python library wraps Adobe's native C2PA Rust library via CFFI. On Linux (Render), passing ta_url as an empty bytes value triggers a URI parse error at the Rust layer that surfaces as an opaque error message. Took 15+ attempts to isolate: the fix is constructing C2paSignerInfo via __new__() and leaving ta_url as a zeroed pointer. An earlier debugging commit generated RSA-2048 certificates in /tmp at startup. This worked once, but the signer declares alg=es256 so production silently used an RSA key with an ECDSA algorithm declaration. The error only appeared on the next deploy because /tmp persisted across Render deploys. Lesson: never mutate signing material in a startup hook; validate it, don't generate it. Watermark embedding re-encodes the image as PNG (lossless, preserves LSBs). This changes the mime type from the provider's output (usually JPEG). The SHA-256 stored in the database must be computed after watermarking, not before.



