Attestation bundles
An attestation bundle is the signed record produced at capture. It's what the device's secure enclave emits and what the API verifies.
Image bundle
{
"schema": "https://provenance.io/claims/v1",
"attestation_id": "<uuidv4>",
"device_id": "<uuidv4>",
"device_cert": "<X.509 PEM string>",
"claim_id": "<carrier claim ID | null>",
"capture_type": "image",
"capture_timestamp": "<RFC3339>",
"sensor_hash": "<SHA-256 hex of raw image bytes>",
"gps": { "lat": 42.3601, "lng": -71.0589, "accuracy_m": 15 },
"biometric_present": true,
"biometric_type": "face",
"carrier_id": "<carrier UUID | null>",
"signature": "<base64url ECDSA-P256 signature over canonical JSON>",
"signature_algorithm": "ECDSA-P256-SHA256",
"schema_version": "1.1.0"
}
Fields
attestation_id— UUIDv4, unique per capture; also the idempotency key on attest.device_id/device_cert— the enrolled device and its X.509 certificate. The cert chain is validated against the root CA.capture_type—imageorvideo.sensor_hash— SHA-256 of the raw sensor bytes. Verification recomputes this from the submitted bytes.gps— capture location and accuracy;nullor0,0scoresgps_absent.biometric_present/biometric_type— whether a live biometric was present at capture.signature/signature_algorithm— ECDSA P-256 over the canonical pre-image.
The signing rule
The signature covers the canonical JSON of the bundle with signature set to "", keys sorted alphabetically, no whitespace. The SHA-256 of that pre-image is signed with the device private key (ECDSA P-256). Node's built-in crypto only — no third-party crypto.
Any change to any field after signing, even reformatting, invalidates the signature, producing signature_invalid at verify time.
Where the bundle lives
For images, the bundle is embedded in the JPEG's XMP metadata under provenance:AttestationBundle, so the proof travels with the pixels. For video, it's a sidecar manifest — containers have no clean XMP equivalent.
Video variant
For capture_type: "video", sensor_hash becomes the chain root of a chunk hash chain and the bundle gains a session_nonce and a video_manifest. See video attestation.
C2PA interop
C2PA (Content Credentials) is the emerging content-provenance standard. The attestation bundle exports to a C2PA-style manifest — a COSE-Sign1 signature over a CBOR claim carrying our assertions (capture time, GPS, device id, the sensor-hash hard binding), signed by the claim-signer cert. The bundle stays the source of truth; the manifest is an export of it (it also carries product semantics C2PA can't).
- Export —
toC2paManifest(bundle)in@provenance/core, orprovenance-c2pa export. - Verify (inbound) —
POST /v1/media/verify-c2pavalidates a manifest's signature and surfaces it as an advisory signal (c2pa_present_valid/c2pa_invalid). Like synthetic-media screening, this external evidence never merges into an attestation's cryptographic risk score.
Limitations: the export targets manifest well-formedness and claim-signature validity. C2PA conformance-program certification and trust-list membership are in progress, so a C2PA verifier sees a valid-but-unlisted signer.