Overview
Implements the font embedding method from the C2PA Technical Specification and its c2pa.hash.data hard binding, for fonts that conform to the OpenType or OFF (ISO/IEC 14496-22) specification.
The manifest is stored in a dedicated SFNT table with the tag C2PA, which may carry an embedded Manifest Store, a remote manifest URI, or both:
| Field | Type | Description |
|---|---|---|
majorVersion / minorVersion |
uint16 |
Version of the C2PA font table |
activeManifestUri |
Offset32 + uint16 |
URI of the active manifest (offset + length; 0 when absent) |
manifestStore |
Offset32 + uint32 |
Embedded C2PA Manifest Store (offset + length; 0 when absent) |
The
C2PAfont table is preliminary. The C2PA specification states the table format "is not yet defined in the OFF nor OpenType specification; the following definition is preliminary." There is no stable, ratified conformance requirement for fonts. This crate tracks the preliminary definition and emits table version0.1.
What this crate does — and does not
Validating a font's provenance is a fixed pipeline. Only two steps are font-specific; this crate owns exactly those:
| Step | Owner |
|---|---|
| 1. Locate + extract the Manifest Store | c2pa-fonts |
| 2. Parse the JUMBF/CBOR manifest | c2pa-rs |
| 3. Verify the COSE signature | c2pa-rs |
| 4. Evaluate the X.509 trust chain | c2pa-rs |
5. Hard binding: c2pa.hash.data exclusion geometry over the font |
c2pa-fonts |
| 6. Validate assertions / ingredients | c2pa-rs |
This crate does not build manifests, sign, or implement COSE/trust — that is the official c2pa SDK's job. With the validation feature it delegates steps 2–4 and 6 to c2pa-rs, so an application using both can act as a C2PA generator and verifier for fonts. (This crate is a building block; C2PA conformance certification is a separate program for products, which this crate makes no claim to.)
Font collections (.ttc/ttcf) and WOFF/WOFF2 are rejected explicitly; decompress WOFF to SFNT first.
Quick Start
[]
= "0.2"
# Hard-binding hashers and the c2pa-rs validation bridge:
= { = "0.2", = ["validation"] }
Bindings for the zero-dependency core (embed, extract, hard-binding geometry) ship for JavaScript and Python:
Embed an already-signed manifest
use ;
let font: & = /* .ttf / .otf bytes */;
let signed = embed_manifest.unwrap;
// or ManifestSource::remote("https://example.com/m.c2pa") / ManifestSource::both(uri, store)
Generate with a hard binding (placeholder-then-fill)
The manifest signs over the font, so the font must be laid out before signing. Reserve the store, hash over the returned exclusions, sign a manifest that fits, then fill:
use ;
// 1. Reserve space; get the font-with-placeholder and its exclusions.
let reserved = reserve_manifest.unwrap;
// 2. Hash reserved.font over reserved.exclusions and sign a data-hashed manifest
// with the c2pa SDK (see tests/roundtrip.rs for the full flow).
// data_hash_ranges(&reserved.font) yields the ranges as c2pa `HashRange`s.
// 3. Fill the reserved region with the signed manifest (<= reserved size).
let final_font = fill_manifest.unwrap;
The exclusions cover the manifest store and the two checksum fields that depend on it (the C2PA table's directory checksum and head.checkSumAdjustment), so filling never invalidates the hash.
Read and verify
use ;
let manifest = read_manifest.unwrap; // embedded store bytes
let uri = read_manifest_uri.unwrap; // Option<String>
let report = verify.unwrap; // structural, zero-dep
assert!;
// End-to-end (feature = "validation"): hard binding here, signature/trust via c2pa-rs.
let result = validate.unwrap;
assert!;
// result.state, result.success_codes, result.failure_codes, result.manifest_json
Design
- The Manifest Store and/or active manifest URI live in a single
C2PASFNT table - Embedding normalizes the font: the table directory is re-sorted by tag, offsets re-aligned to 4-byte boundaries, and per-table checksums plus
head.checkSumAdjustmentrecomputed verifychecksC2PAtable well-formedness and SFNT checksum integrity; more than oneC2PAtable is rejectedvalidate(feature) extracts the store and delegates COSE/trust/assertion validation to c2pa-rs; trust uses c2pa-rs default settings — inspect the returned state and status codes- Single fonts only; collections and WOFF are rejected
Related Crates
| Crate | Description |
|---|---|
| c2pa-warc | WARC web archive embedding (ISO 28500) |
| c2pa-structured-text | Structured text embedding via ASCII armour delimiters |
| c2pa-text-binding | Soft binding and content fingerprinting for text assets |
| c2pa-rs | Official C2PA SDK |
License
Licensed under either of Apache License, Version 2.0 or MIT License at your option.
Built by WritersLogic