# ZCAM ## Insurance Claim Verification Insurance companies allow policyholders to file claims using photos from their mobile app. This has led to an increase in fraud where claimants manipulate photos before submission. ZCAM ensures that claim photos were taken on the policyholder's device using the official app, and haven't been edited since capture. The system is comprised of: * Camera functionality within the insurance app using ZCAM for capture * Backend verification that automatically validates all submitted photos * Automated triage that flags claims with suspicious or unverifiable photos **Why it matters**: Automatically detect and reject claims with manipulated photos, reducing fraud and manual review costs. #### Architecture The insurance app integrates ZCAM SDK in two places: 1. **Mobile app**: Policyholders capture verifiable photos during claim filing. 2. **Backend processing**: The insurance company verifies photos automatically during claim triage. #### Mobile App The ZCAM SDK integrates into the claim landing flow: 1. **Installation**: Follow the [Installation guide](/getting-started/installation) to set up the SDK 2. **Camera Integration**: Inject the `` component into the claim flow where users must photograph their vehicle: * The SDK provides camera preview functionality * Call `takePhoto()` to capture a verifiable photo 3. **Proof Generation** (Optional): Use `@succinctlabs/react-native-zcam1/proving` to attach zero-knowledge proofs: * Use `waitAndEmbedProof()` to generate and embed proofs * This provides additional cryptographic guarantees and privacy 4. **Claim Submission**: When the user completes the claim flow, attach verifiable photos to the claim filing and upload to the insurance company's backend #### Backend Processing On the insurance company's backend, verification is integrated into the automated claim triage process: 1. **Automated Verification**: When a claim enters the triage flow, the system automatically verifies all attached photos: * Integrate `@succinctlabs/react-native-zcam1` (or server-side equivalent) into the backend * For each photo, call `verifyBindings()` or `verifyProof()` to validate authenticity * Check that the photo was taken using the insurance company's app 2. **Metadata Analysis**: Leverage metadata from the C2PA manifest: * Verify location data matches the claim location * Check timestamp aligns with the reported incident time * Validate device and app information 3. **Claim Decision**: Based on verification results: * **Verification passes**: Proceed with normal claim processing * **Verification fails**: Flag claim for manual review or deny if photos are inauthentic ## Verifiable News Platform Edited and AI-generated photos are a growing concern for news consumers. A news platform can use ZCAM to let readers independently verify that photos are authentic and unedited. The system is comprised of: * A mobile app for field reporters to capture verifiable photos * Integration with the platform's CMS to store and display photos * Public-facing verification tools so readers can check authenticity themselves **Why it matters**: Readers can independently verify that photos are authentic, building trust in the platform's journalism. ### Architecture The news platform integrates ZCAM SDK in two places: 1. **Mobile app** A lightweight iOS app for reporters to use to capture verifiable photos 2. **Web platform**: For readers to verify photo authenticity directly in articles #### Mobile App The news platform builds a specialized camera app for reporters using the ZCAM SDK: 1. **Installation**: Setup the SDK using the [installation guide](/getting-started/installation) 2. **Camera Setup**: Use `@succinctlabs/react-native-zcam1` to initialize the camera: * Call `initCapture()` to initialize device keys and attestation * Use the `` component to render the camera preview * Call `takePhoto()` to capture a photo with verifiable bindings 3. **Proof Generation** (Optional): Use `@succinctlabs/react-native-zcam1/proving` to generate zero-knowledge proofs: * Wrap your app with `ProverProvider` and use the `useProver()` hook * Call `waitAndEmbedProof()` to generate and embed the proof, or use `requestProof()` + `useProofRequestStatus()` for progress tracking 4. **Upload**: Upload the photo to the news platform's backend for use in articles #### Web Platform On the news platform's website, articles display verifiable photos with verification capabilities: 1. **Photo Display**: Photos embedded in articles include C2PA content credentials * Users with C2PA browser extensions can automatically see content credentials * The platform can display verification status badges 2. **Client-Side Verification**: Integrate `@succinctlabs/react-native-zcam1` (or web equivalent) to enable verification: * Add a "Verify Photo" button for each photo in articles * Call `verifyBindings()` or `verifyProof()` to validate authenticity * Display verification results to readers (e.g., "✓ Verified Authentic") 3. **Metadata Display**: Show readers metadata from the C2PA manifest: * Capture timestamp, device information, app identifier * Allow readers to inspect the full verification chain ## Architecture ### Overview The ZCAM SDK allows an integrating app to: 1. Take a picture 2. Generate and sign a valid C2PA manifest over the photo including bindings of a signature of a photo using a hardware-attested key and associated attestation. 3. Generate a verifiable SP1 proof that the photo signature is valid, was signed using a key bound to the app, and corresponds to the photo, attaching that to a valid C2PA manifest The core flow uses cryptographic keys stored on the device's Secure Enclave to sign and attest that a photo was taken using the device's camera and has not been tampered with. :::info A verifiable photo is defined as a photo that is guaranteed to have been captured on the device camera, using the SDK, and not tampered before it was signed. ::: ### Cryptographic Keys The ZCAM architecture generates and leverages two keys: | Key | Purpose | Attested | | --------------- | ------------------------------ | ----------------------------------------------------------- | | **Device Key** | Signs over a hash of the photo | Yes (App Attest on iOS; Android Key Attestation on Android) | | **Content Key** | Signs the C2PA manifest | No | Both keys live in the device's Secure Enclave. The device key is attested to have been generated on the Secure Enclave and is scoped to the specific app. ### Photo Lifecycle A photo progresses through three states to become a verifiable authentic photo: | State | C2PA Assertion | Description | | -------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Raw** | None | Original photo taken by the device camera, including metadata. No verifiable, attested traits. | | **Verifiable** | `succinct.bindings` | Embeds a C2PA manifest including a signature using a hardware-attested key over the photo and a verifiable attestation of the signing key. These can also be used as inputs to generate a zero knowledge proof. | | **Proven** | `succinct.proof` | Embeds a C2PA manifest including a verifiable zero knowledge proof that the photo was signed using a valid hardware-attested key. | ``` Raw Photo → [Capture] → Verifiable Photo → [Prove] → Proven photo (bindings) (proof) ``` ### Flow #### 1. Initialization The SDK first gets initialized. The main logic here is to generate or load the two necessary keys (device key and content key). #### 2. Capture The capture step allows a user to take a photo and output a *provable* photo. When a user wants to take a photo, the SDK opens the camera screen. After the photo is taken, the SDK embeds a valid C2PA manifest by doing the following: 1. The photo is hashed, then signed using the device key. This outputs a hardware-backed assertion including a signature over the hash. 2. The C2PA manifest is initialized with a *capture* action including metadata: time of photo, OS, device model, software version, etc. 3. A `succinct.bindings` assertion is added to the manifest including data necessary to prove that the photo was signed using a valid hardware-attested key. ![Capture flow diagram](/images/diagram_capture.png) **Output:** A verifiable photo with a valid C2PA manifest containing metadata and an assertion that the photo was signed with a hardware-attested key. :::info Note: A verifiable photo can both be verified on its own by verifying the attestation in the C2PA manifest, and also be used as input to generate a zero knowledge proof to hide the attestation ::: #### 3. Prove The prove step takes the provable photo with C2PA manifest including a `succinct.bindings` assertion and generates a proof verifying its validity. This is done by using the SP1 Prover Network to prove the ZCAM program with the photo (and C2PA manifest) as input. The SDK receives the proof from the network, then updates the photo and C2PA manifest: * The `succinct.bindings` assertion is removed * A `succinct.proof` assertion is added containing the verifiable proof ![Prove flow diagram](/images/diagram_prove.png) **Output:** The final verifiable photo with a valid C2PA manifest including a verifiable proof. #### 4. Verify The SDK includes logic for parsing and verifying the proof from the C2PA manifest: * Extract the manifest from the photo * Verify the proof in the manifest * Verify the photo hash matches the manifest ## FAQs ### Android Support *Does ZCAM work on Android?* Android camera capture is implemented and functional. The remaining work is integrating hardware attestation (Android Key Attestation + Google Play Integrity API) to match the security guarantees provided by Apple App Attest on iOS. Until that is complete, Android captures use mock/development-mode bindings. Currently, only two Android phone companies have their own C2PA implementations: Google with their latest Pixel 10 and Samsung. Google's Pixel 10 has full C2PA support for photos captured on the camera. The design is quite similar to ZCAM's where they use a key generated in the secure enclave to sign the manifest at capture time. Samsung's C2PA implementation is less useful. It only supports attaching C2PA manifests to photos that were generated using AI. On the other hand, Android phones (specifically those that support the Google Play Store) are all equipped with the necessary primitives to support a ZCAM flow. Note that all Androids that support the Google Play Store are required to have some secure enclave support. On the iOS side, ZCAM leverages the Apple App Attest API which provides the following guarantees: 1. A key was generated on the secure enclave and is scoped to the calling app 2. The calling app itself is non-tampered and the binary is trustworthy Android separates these functionalities into two independent APIs: 1. **Android Key Attestation**: API to obtain an attestation that a given key used by an app is indeed hardware-backed 2. **Google Play Integrity API**: API used to ensure a given request is from a valid install of an app By integrating these two APIs in the Android implementation, we will get the same "coverage" that the Apple App Attest API guarantees. The rest of the ZCAM protocol flows as intended, using C2PA and SP1 as necessary. ### Secure Enclave Guarantees *Is there a way to mimic the signature from the enclave? Is it 100% impossible or just unlikely? Does it vary by OS?* With proper use of the App Attest (iOS) and Play Integrity/Key Attestation (Android) APIs, it should be 100% impossible to mimic a signature. This relies on Apple and Google ensuring these APIs work as intended, however. ### Jailbroken Devices *Have we considered more complicated attack vectors, such as jailbroken devices + running a "virtual app" to exploit the signatures?* Yes, the main attack vector is being able to feed in photos that weren't actually captured from the camera into our ZCAM signing protocol. We can protect our SDK as much as possible, including jailbreak/root detection, however this comes with certain drawbacks such as no support for jailbroken or rooted devices. The third party is also responsible to ensure their integrating app doesn't have any glaring security gaps. See the [jailbreak section](/features/security#jailbroken-device-detection) on the Security page for more information. ### Verification Post-edits *Does cropping or editing break the photo verification?* Yes, **both bindings verification and ZK proof verification break when a photo is edited**. This is because: * The Apple App Attest signature (used in bindings verification) is over the hash of the original image * The ZK proof (used in proof verification) also verifies the original photo hash * When a photo is edited, the image bytes change, causing the hash to change * The signature/proof verification fails because the hash no longer matches Even though C2PA edit manifests can preserve the original capture manifest and add edit history, the actual signature verification will fail because the signature is over the hash of the original image bytes. If you remove the metadata entirely or crop in a way that strips the C2PA manifest, the photo will also no longer be verifiable. We're looking into watermarking to insert data which could help with cropping, etc. See the [Editing C2PA Photos](/overview/c2pa#editing-c2pa-photos) section for more details. ### Cross Device Support *Does your solution detect fakes if a photo is taken with another device?* A photo taken by ZCAM can be verified on any device. However, one device with the ZCAM SDK installed cannot detect nor attest to a photo from another device. ZCAM is built on using a device's camera and secure enclave in tandem to guarantee authenticity. ### Photo of Photo *Can it detect a photo of a photo?* No, this is not the intended usecase of ZCAM. What we can do is provide "contextual" metadata, for example metadata around subject depth, brightness, etc. that would indicate a potential photo of a photo. See the [Physical Replay Attacks](features/security#physical-replay-attacks) section for more details. ### Bindings vs Proof verification *What's the difference between bindings verification and ZK proof verification?* **Bindings verification** directly checks the hardware-backed signature (Apple App Attest on iOS) embedded in the C2PA manifest. It can be generated offline, however the attestation data is visible in the manifest. **ZK proof verification** generates a zero-knowledge proof that verifies the attestation without revealing sensitive details. It provides enhanced privacy but requires network access for proof generation. ZK proofs are completely optional. You can use ZCAM with bindings verification alone, which works entirely offline. Choose ZK proof verification when: * Privacy is paramount—you want to verify authenticity without revealing attestation details * You can tolerate network latency for proof generation ### Metadata Stripping *Which platforms preserve C2PA metadata when uploading images?* Short answer, most platforms where a user uploads image files to share strip metadata. Platforms where the service is more to "host files" may keep the metadata. LinkedIn has first class support for C2PA.
Platform Compatibility Table This table documents how different platforms handle C2PA content credentials when images are uploaded and accessed through various methods: | **Platform** | **Upload Method** | **Read Method** | **Maintains Credential?** | **Notes** | | ------------- | -------------------------------------------------- | -------------------------------------------------------- | ------------------------- | ------------------------------------------------- | | **Notion** | Upload using `/file` | Click on link, hosted on `https://file.notion.so/...` | ✅ | | | **Notion** | Upload using `/file` | Download | ✅ | | | **Twitter** | Upload using upload file functionality | Download | ❌ | | | **Twitter** | Link to image | Click on Link | ✅ | Doesn't render properly unless hosting has og tag | | **Instagram** | New post (ensure original ratio/ not cropped etc.) | No way to download, can expect src to get uploaded image | ❌ | | | **LinkedIn** | Upload in post | Natively embedded | ✅ | | | **LinkedIn** | Upload in post | Download image | ❌ | | | **Discord** | Upload file | Open hosted link | ❌ | Strips metadata | | **Discord** | Upload file | Download file from hosted link | ❌ | | | **Gmail** | Attach file to email | Click preview | ❌ | | | **Gmail** | Attach file to email | Download | ✅ | | | **Gmail** | Embed file in email | Download | ✅ | | | **Gmail** | Embed file in email | Click preview | ❌ | | Note: Cloudflare Images also supports C2PA.
## ZK Proof Details The SP1 program proves the following: 1. The photo bytes matches the expected bytes in the C2PA manifest 2. The Apple Attest attestation is valid 3. The assertion (i.e. signature of the photo hash using the attested key) is valid The photo bytes are provided as input to the proof. ### Proof Logic | Step | Operation | Guarantees | | ---- | -------------------------------------------- | ----------------------------------------- | | 1 | Extract manifest from photo bytes | — | | 2 | Extract bindings and data hash from manifest | — | | 3 | Compute photo hash | — | | 4 | Check data hash == photo hash | Manifest corresponds to this photo | | 5 | Validate attestation | The attestation is valid and from Apple | | 6 | Validate assertion | Photo hash was signed by the attested key | ### Attestation Validation Guarantees: * The device key was generated in a genuine Apple Secure Enclave * The key is bound to a specific app (via `app_id` / RP ID) * The device is running a legitimate app (AAGUID = `appattest` or `appattestdevelop`) Validates: * Certificate chain verifies up to Apple Root CA * Nonce matches the challenge * Public key hash matches the key ID * RP ID == SHA256(app\_id) * AAGUID is a valid Apple attestation identifier ### Assertion Validation Guarantees: * The photo corresponding to this hash was signed using the ZCAM SDK Validates: * ECDSA signature over the photo hash using the public key from attestation ### Public Outputs * Photo hash (SHA-256) * Apple Root CA certificate These committed values allow verifiers to confirm the proof corresponds to a specific photo and chains to Apple's actual root certificate. ## Capture SDK The Capture SDK (`@succinctlabs/react-native-zcam1`) takes photos and produces C2PA-signed assets bound to hardware-backed integrity signals. ### Installation ```bash npm i @succinctlabs/react-native-zcam1 # iOS cd ios && pod install # Android: JNI libraries are downloaded automatically during the Gradle build ``` ### Core Concepts The Capture SDK: * Renders a native camera preview via `ZCamera` (AVFoundation on iOS, CameraX on Android) * Generates hardware-backed assertions over photo hashes * Embeds C2PA manifests with `succinct.bindings` assertion * Returns signed photos ready for proof generation ### API Reference #### `initCapture(settings)` Initializes device keys and attestation. Call once on app startup. Requires network access. ```tsx import { initCapture, CaptureInfo, Settings } from "@succinctlabs/react-native-zcam1"; const settings: Settings = { appId: "TEAM_ID.com.example.app", production: false, }; const captureInfo: CaptureInfo = await initCapture(settings); ``` **Parameters:** * `settings.appId` - Your Team ID + Bundle ID * `settings.production` - `false` for development, `true` for production **Returns:** `CaptureInfo` containing: * `appId` - The app identifier * `deviceKeyId` - App Attest device key ID * `contentPublicKey` - Secure Enclave content key * `contentKeyId` - Derived content key identifier * `attestation` - App Attest attestation blob #### `ZCamera` React component that renders the native camera preview. ```tsx import { useRef } from "react"; import { ZCamera, CaptureInfo } from "@succinctlabs/react-native-zcam1"; function CameraScreen({ captureInfo }: { captureInfo: CaptureInfo }) { const camera = useRef(null); return ( ); } ``` **Props:** * `captureInfo` (required) - From `initCapture()` * `position` - Camera to use: `"front"` or `"back"` (default: `"back"`) * `isActive` - Whether camera is running (default: `true`) * `style` - Style for the camera view #### `ZCamera.takePhoto()` Captures a photo and returns a signed `ZPhoto`. ```tsx const photo = await camera.current?.takePhoto({ format: "jpeg", flash: "off", includeDepthData: false, aspectRatio: "4:3", orientation: "auto", }); console.log(photo.originalPath); // Raw capture path console.log(photo.path); // C2PA-signed photo path ``` **Parameters:** * `options.format` - `"jpeg"` or `"dng"` (default: `"jpeg"`) * `options.flash` - `"off"`, `"on"`, or `"auto"` (default: `"off"`) * `options.includeDepthData` - Include depth data when supported (default: `false`). **Android:** always returns `false`; depth capture is not exposed via CameraX. * `options.aspectRatio` - `"4:3"`, `"16:9"`, or `"1:1"` (default: `"4:3"`) * `options.orientation` - `"auto"`, `"portrait"`, or `"landscape"` (default: `"auto"`) **Returns:** `ZPhoto` with: * `originalPath` - Path to the raw captured image * `path` - Path to the C2PA-signed image with `succinct.bindings` ### Complete Example ```tsx import { useEffect, useRef, useState } from "react"; import { View, Button, Text, StyleSheet } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; import { initCapture, ZCamera, CaptureInfo } from "@succinctlabs/react-native-zcam1"; import { FileSystem, Dirs } from "react-native-file-access"; export function CaptureScreen() { const camera = useRef(null); const [captureInfo, setCaptureInfo] = useState(); const [lastPhoto, setLastPhoto] = useState(); useEffect(() => { const settings = { appId: process.env.EXPO_PUBLIC_APP_ID!, production: false, }; initCapture(settings).then(setCaptureInfo); }, []); const handleCapture = async () => { const photo = await camera.current?.takePhoto(); if (!photo) return; // Save to app's document directory const destPath = `${Dirs.DocumentDir}/photos/${Date.now()}.jpg`; await FileSystem.mkdir(`${Dirs.DocumentDir}/photos`); await FileSystem.cp(photo.path, destPath); setLastPhoto(destPath); }; if (!captureInfo) { return ( Initializing camera... ); } return (