Verification & Share
Public verification page, PDQ lookup, and selective disclosure proof display.
Everything described so far — C2PA extraction, ZK proof generation, on-chain commitment, selective disclosure — converges on a single user-facing feature: the verification page. This is where someone checks whether an image or video is authentic, sees what the uploader chose to disclose, and can independently verify the cryptographic proof chain.
How verification works
The verification page supports two modes: file verification (upload or drag-and-drop an image or video) and proof verification (upload a selective disclosure proof bundle). Both run entirely in the browser — the file never leaves the user's device.
Step 1 — hash computation
When a file is dropped onto the verification page, the browser computes perceptual hashes without uploading the file. For images, this is a single PDQ hash (256-bit). For videos, the browser extracts keyframes via WebCodecs, computes a PDQ hash per keyframe, and generates a TMK temporal fingerprint.
Step 2 — backend lookup
The hashes are sent to the backend for matching — not the file itself. Three lookup endpoints run in parallel:
| Endpoint | Input | Used for |
|---|---|---|
| PDQ lookup | Single PDQ hash (64 hex chars) | Image matching — finds exact or perceptually similar images |
| vPDQ batch lookup | Up to 128 keyframe hashes | Video frame matching — matches individual keyframes against stored media |
| TMK lookup | TMK fingerprint (~257 KB) | Video temporal matching — finds re-encoded or speed-changed videos |
Step 3 — match determination
The backend returns Hamming distances (number of differing bits between two 256-bit PDQ hashes). The verification page classifies the result:
| Match tier | Condition | Meaning |
|---|---|---|
| Exact | Hamming distance = 0 | Byte-identical to a verified original |
| Similar | Hamming distance ≤ 31 | Same perceptual content — likely a crop, resize, or re-encode of a verified original |
| No match | Hamming distance > 31 or no match found | Not found in the verified content database |
Step 4 — Merkle proof verification
If a match is found and the content has been committed to the transparency log, the backend returns a Merkle inclusion proof. The browser verifies this independently:
- Leaf hash. Compute
SHA-256(pdq_hash + salt)from the returned PDQ hash and random salt. - Path reconstruction. Walk up the sibling hashes, combining at each level:
SHA-256(min(left, right) + max(left, right)). The canonical ordering prevents position-dependent manipulation. - Root check. Compare the reconstructed root against the on-chain root. If they match, the PDQ hash was genuinely included in the tree at the claimed position.
The Merkle proof state machine tracks four states: none (no proof available), pending (proof exists but not yet committed on-chain), valid (cryptographically verified), and invalid (verification failed).
What the viewer sees
The verification result displays different information depending on the match tier and the uploader's disclosure preferences. The uploader's choices — made at upload time — are locked into the ZK proof and cannot be changed by the viewer.
Disclosed metadata
Each metadata category is displayed only to the granularity the uploader chose:
| Category | Disclosure levels | Example at each level |
|---|---|---|
| Location | hidden → continent → country → city → neighbourhood → exact | Hidden / Europe / United Kingdom / London / Westminster / 51.5007° N, 0.1246° W |
| Time | hidden → year → quarter → month → day → exact | Hidden / 2026 / Q1 2026 / January 2026 / 28 January 2026 / 28 Jan 2026 14:32:07 UTC |
| Device | hidden → category → manufacturer → full | Hidden / Smartphone / Google / Google Pixel 8 Pro |
| Software | hidden → type → name → full | Hidden / Camera app / ProofMode / ProofMode v49.2 |
| Author | hidden → has_author → type → full | Hidden / Has author / Organisation / reuters.com |
| Provenance | hidden → summary → steps → full | Hidden / 2 edits / Camera → Lightroom → Photoshop / Full edit chain with timestamps |
Fields marked "verified" have been cryptographically proven — the ZK circuit verified that the disclosed value is consistent with the C2PA manifest's signed data. Fields that are hidden are blinded with Poseidon2 commitments — the viewer cannot learn the hidden values, and the prover cannot fabricate disclosed values that weren't in the original manifest.
Uploader identity
Alongside the image metadata, the verification page shows any identity signals the uploader chose to attach:
- Organisation. "Verified member of reuters.com" — proven via JWT identity proof, reveals only the email domain.
- Verified Human. "Verified Human" badge — proven via passport NFC scan, reveals no personal details.
- Nationality. Country flag and name — optional disclosure from passport verification.
Provenance status
Every verified piece of content carries a provenance status derived from the C2PA manifest analysis:
| Status | Meaning | Detection method |
|---|---|---|
| Camera | Pure camera capture, no AI involvement | Hardware device origin, no AI claims or generative actions |
| AI Generated | Entirely AI-generated | AI generator claim (DALL-E, Midjourney, Firefly) or c2pa.ai_generated assertion |
| Camera + AI Edit | Camera origin with AI modifications | Ingredient chain traces to real camera, but generative actions found |
| Unknown | C2PA present but origin unclear | Manifest exists but origin device not determinable |
| Failed | Verification failed | Signature invalid, certificate expired, or trust list mismatch |
Selective disclosure proof verification
The second verification mode accepts a selective disclosure proof bundle — a JSON file that cryptographically proves specific claims about an image without revealing the image itself.
Proof bundle structure
The browser verifies this proof using the same Barretenberg WASM backend that generated it. If the proof is valid, the disclosed fields are guaranteed to match the original C2PA manifest data — the prover could not have fabricated them.
Sharing verified content
Verify link
The simplest way to share verification is a link to the verify page with a pre-populated hash:
When someone opens this link, the verify page automatically runs the hash lookup against the backend — the viewer doesn't need to upload the file. The link is safe to share on social media, messaging apps, or in articles because it contains only a hash, not the image data.
Proof export
For stronger guarantees, users can export a selective disclosure proof as a downloadable JSON file. This provides cryptographic proof of specific claims without depending on Apertrue's backend availability:
- Download. The proof bundle is saved as
apertrue-proof-{commitment}.json. The recipient loads it on the verify page for independent verification. - Copy to clipboard. The JSON is copied for pasting into messages, emails, or documents.
- Share via URL. The proof can be stored in the browser's localStorage and shared via a URL containing a reference ID:
?sd_id={uuid}. This avoids embedding the full proof (which can be several kilobytes) in the URL.
Verification badges
Throughout the Apertrue interface — in the gallery, on the verify page, and in shared links — verified content carries a verification badge. The badge variant communicates the provenance status at a glance:
| Badge | Provenance | Displayed as |
|---|---|---|
| Camera verified | Pure camera capture | Camera icon, green |
| AI generated | Fully AI-generated | Sparkle icon |
| Camera + AI edit | Camera origin, AI edits applied | Camera + sparkle icons |
| Unknown origin | C2PA present but origin unclear | Circle outline |
| Failed | Verification failed | Warning icon |
| Blocked | Content blocked by moderation | X icon |
Badges are rendered in five size variants (extra-small through large) for different contexts — inline text, gallery cards, and full verification pages. Clicking a badge opens the verification page for that content.
Video verification display
Video verification shows additional information beyond what images display:
- Keyframe match statistics. The number of matched keyframes out of the total extracted, with the overall match percentage. This tells the viewer how much of the video's visual content matches verified originals.
- Temporal fingerprint scores. TMK Level 1 (cosine similarity) and Level 2 (temporal alignment) scores, showing how closely the video's temporal structure matches the original.
- Video metadata. Duration, resolution, codec, and container format — displayed alongside the standard C2PA metadata.
What verification does not require
The verification system is designed to minimise trust assumptions:
- No account needed. Anyone can verify content without registering or signing in. The verify page is publicly accessible.
- No file upload. The image or video never leaves the browser during verification. Only perceptual hashes are sent to the backend.
- No trust in Apertrue. Merkle proofs are verified client-side against on-chain roots. Selective disclosure proofs are verified using the public verification circuit. The backend provides data, but the browser independently checks it.
- No trust in the viewer. The uploader's disclosure choices are cryptographically enforced. A viewer cannot learn hidden fields or change what is disclosed — the ZK proof constrains exactly what is revealed.
The next section covers content moderation and compliance — how Apertrue screens content before it enters the platform while maintaining user privacy.