Camera Validation

How BlockFact ensures images come from camera devices only

Why Camera-Only?

BlockFact only accepts images captured directly from camera devices. This prevents:

  • ❌ Screenshots being passed off as original photos
  • ❌ Edited images from Photoshop/GIMP
  • ❌ Downloaded images from the internet
  • ❌ AI-generated images
  • ❌ Gallery/library images

Validation Layers

1. EXIF Data Validation

Camera devices embed EXIF metadata in photos:

{
  "Make": "Apple",
  "Model": "iPhone 15 Pro",
  "DateTime": "2026:03:06 17:24:30",
  "GPSLatitude": 40.7128,
  "GPSLongitude": -74.0060,
  "LensModel": "iPhone 15 Pro back camera",
  "Software": "iOS 17.3"
}

BlockFact validates:

  • ✅ EXIF data exists
  • ✅ Camera make/model present
  • ✅ Capture timestamp is recent
  • ✅ GPS coordinates match location

2. Timestamp Freshness

Images must be registered within 30 seconds of capture.

⚠️ Why 30 seconds?

This prevents users from capturing an image, editing it, and then registering the edited version. The tight window ensures authenticity at source.

3. Device Attestation

Platform-level verification that the app is running on a real device:

  • iOS DeviceCheck: Apple's hardware-backed attestation
  • Android Play Integrity: Google's device verification

These APIs verify:

  • ✅ App is running on genuine hardware
  • ✅ Device is not jailbroken/rooted
  • ✅ App binary hasn't been tampered with

4. No Fallback Policy

If device attestation fails, registration is rejected. No insecure fallbacks. This is a security feature, not a bug.

Implementation

Capture with EXIF

import * as ImagePicker from 'expo-image-picker';

const photo = await ImagePicker.launchCameraAsync({
  exif: true,        // ✅ Required: Include EXIF data
  quality: 1,        // ✅ Full quality
  allowsEditing: false  // ✅ No editing
});

// photo.exif contains camera metadata

Register Immediately

const result = await registerContent({
  imageUri: photo.uri,
  exifData: photo.exif,              // ✅ Camera EXIF
  captureTimestamp: new Date().toISOString(),  // ✅ Fresh timestamp
  latitude: location.coords.latitude,
  longitude: location.coords.longitude
});

// Must be called within 30 seconds of capture

Common Errors

Error: EXIF data required

Cause: Image doesn't have EXIF metadata

Fix: Ensure exif: true when capturing

Error: Image too old

Cause: More than 30 seconds elapsed since capture

Fix: Call registerContent() immediately after capture

Error: DeviceCheck not available

Cause: Native module not implemented

Fix: Implement DeviceCheck/Play Integrity native modules (see SDK docs)

Security Benefits

Why This Matters

  • Insurance: Prevents fraudulent claims with edited photos
  • Journalism: Ensures news photos are authentic
  • Legal: Creates admissible evidence with chain of custody
  • Enterprise: Compliance with audit requirements

Comparison

FeatureBlockFactTruepicC2PA
Camera-Only
30s Freshness~
Device Attestation
No Fallback~