Verify SDK
The Verify SDK (@succinctlabs/react-native-zcam1) validates the authenticity of C2PA-signed photos with embedded proofs.
Installation
npm i @succinctlabs/react-native-zcam1
cd ios && pod installCore Concepts
The Verify SDK:
- Extracts C2PA manifests from photos
- Verifies the photo hash matches the manifest
- Validates bindings (Apple App Attest signatures) for photos with
succinct.bindings - Validates ZK proofs against a pinned Apple Root CA for photos with
succinct.proof - Extracts capture metadata (device info, camera settings, etc.)
- Confirms the photo was taken on a genuine iOS device
API Reference
VerifiableFile
Class for verifying photo authenticity.
import { VerifiableFile } from "@succinctlabs/react-native-zcam1";
const file = new VerifiableFile(photoUri);uriOrPath- File path or URI to the photo
VerifiableFile.verifyBindings()
Verifies the Apple App Attest bindings for photos that have succinct.bindings but haven't been proven yet. This is useful for verifying photos before proof generation or when using bindings-only verification.
const isBindingsValid: boolean = file.verifyBindings(appAttestProduction);appAttestProduction-trueif the photo was captured in production mode,falsefor development
Returns: true if the bindings are valid
Note: This method works for photos with succinct.bindings. For photos with succinct.proof, use verifyProof() instead.
VerifiableFile.verifyProof()
Parameters:
appId- The app identifier
Validates the embedded ZK proof against the photo hash and Apple Root CA.
const isProofValid: boolean = file.verifyProof();Returns: true if the proof is valid
Throws: Error if the photo doesn't contain a succinct.proof assertion
VerifiableFile.dataHash()
Returns the file's content hash as recorded in the active C2PA manifest.
const hash: string | undefined = file.dataHash();Returns: The manifest data hash (base64-encoded string), or undefined if not available
VerifiableFile.captureMetadata()
Returns the capture metadata from the C2PA manifest, containing device info and camera settings recorded at capture time.
import { CaptureMetadata } from "@succinctlabs/react-native-zcam1";
const metadata: CaptureMetadata | null = file.captureMetadata();Returns: The capture metadata object, or null if not present
action- The capture action typewhen- Timestamp of captureparameters- Photo or video capture settings:-
Photo fields:
deviceMake,deviceModelsoftwareVersionxResolution,yResolutionorientationiso,exposureTimefocalLength,depthOfFieldauthenticityData:isJailBrokenisLocationSpoofingAvailable
depthData(when available):width,heightpixelFormataccuracystatistics:min,max,mean,stdDevvalidPixelCount,sampleStride
-
Video fields:
deviceMake,deviceModelsoftwareVersionformathasAudiodurationSecondsfileSizeByteswidth,heightrotationDegreesframeRatevideoCodecaudioCodecaudioSampleRateaudioChannelsauthenticityData:isJailBrokenisLocationSpoofingAvailable
-
Photo fields:
Complete Example
import { useState } from "react";
import { View, Button, Text, StyleSheet } from "react-native";
import { VerifiableFile } from "@succinctlabs/react-native-zcam1";
export function VerifyScreen({ photoUri }: { photoUri: string }) {
const [status, setStatus] = useState<string>();
const handleVerify = () => {
try {
const file = new VerifiableFile(photoUri);
const appId = "TEAM_ID.com.example.app";
const isValid = file.verifyProof(appId);
setStatus(isValid ? "Authentic" : "Invalid proof");
} catch (err: any) {
setStatus(`Error: ${err.message}`);
}
};
return (
<View style={styles.container}>
<Button title="Verify Photo" onPress={handleVerify} />
{status && <Text style={styles.result}>{status}</Text>}
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 16 },
result: { marginTop: 16, fontSize: 18 },
});What Verification Checks
| Check | What It Validates | Use Case |
|---|---|---|
verifyBindings(production) | Apple App Attest signature is valid and corresponds to the photo hash | For photos with succinct.bindings (before proof generation) |
verifyProof(appId) | ZK proof is valid and chains to the Apple Root CA | For photos with succinct.proof (after proof generation) |
Both methods internally compute and verify the file's content hash against the C2PA manifest.
Verification Flow:For photos with succinct.bindings:
- Call
verifyBindings(production)to verify the Apple App Attest signature and file integrity
For photos with succinct.proof:
- Call
verifyProof(appId)to verify the ZK proof and file integrity
Notes
- Verification is performed locally—no network required
- Use
verifyBindings()for photos withsuccinct.bindings(before proof generation) - Use
verifyProof()for photos withsuccinct.proof(after proof generation) - Photos with only
succinct.bindingswill failverifyProof()(they haven't been proven yet) - Photos with
succinct.proofcan use either verification method, butverifyProof()provides stronger guarantees - The Apple Root CA is pinned in the SDK; proofs must chain to this root
captureMetadata()provides access to device and camera settings recorded at capture time