C2PA manifest embedding, hard binding, and verification for OpenType/TrueType (SFNT) fonts
Project description
c2pa-fonts
C2PA manifest embedding, hard binding, and verification for OpenType/TrueType (SFNT) fonts
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
[dependencies]
c2pa-fonts = "0.2"
# Hard-binding hashers and the c2pa-rs validation bridge:
c2pa-fonts = { version = "0.2", features = ["validation"] }
Bindings for the zero-dependency core (embed, extract, hard-binding geometry) ship for JavaScript and Python:
npm install @writerslogic/c2pa-fonts # wasm-bindgen, camelCase API
pip install c2pa-fonts # PyO3 abi3 wheel
Embed an already-signed manifest
use c2pa_fonts::{embed_manifest, ManifestSource};
let font: &[u8] = /* .ttf / .otf bytes */;
let signed = embed_manifest(font, ManifestSource::embedded(manifest_store)).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 c2pa_fonts::{reserve_manifest, fill_manifest, data_hash_ranges};
// 1. Reserve space; get the font-with-placeholder and its exclusions.
let reserved = reserve_manifest(font, 30_000, None).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(&reserved.font, &signed_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 c2pa_fonts::{read_manifest, read_manifest_uri, verify, validate};
let manifest = read_manifest(&final_font).unwrap(); // embedded store bytes
let uri = read_manifest_uri(&final_font).unwrap(); // Option<String>
let report = verify(&final_font).unwrap(); // structural, zero-dep
assert!(report.is_compliant());
// End-to-end (feature = "validation"): hard binding here, signature/trust via c2pa-rs.
let result = validate(&final_font).unwrap();
assert!(result.hard_binding_valid);
// 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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file c2pa_fonts-0.2.0.tar.gz.
File metadata
- Download URL: c2pa_fonts-0.2.0.tar.gz
- Upload date:
- Size: 51.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ec6aab70415d152726a21fee148edc70ff8ca3a13bc2365674c5eb55e404667
|
|
| MD5 |
9bd2860664781e4f2e3fbf946e94daa4
|
|
| BLAKE2b-256 |
51de5c82a312d7666ae542d5ef2b7cdc24b68f3420d74b33ef5a890b279b1598
|
Provenance
The following attestation bundles were made for c2pa_fonts-0.2.0.tar.gz:
Publisher:
release.yml on writerslogic/c2pa-fonts
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
c2pa_fonts-0.2.0.tar.gz -
Subject digest:
8ec6aab70415d152726a21fee148edc70ff8ca3a13bc2365674c5eb55e404667 - Sigstore transparency entry: 2165066127
- Sigstore integration time:
-
Permalink:
writerslogic/c2pa-fonts@4e668a5618976d82f21d1f0bdabc08eb0ea8dd8a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/writerslogic
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4e668a5618976d82f21d1f0bdabc08eb0ea8dd8a -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file c2pa_fonts-0.2.0-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: c2pa_fonts-0.2.0-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 129.8 kB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8baca510225d876872c86fb7e93ffa757b437ef7d1ccb29b0650d3c680b0ee0c
|
|
| MD5 |
ba50ca8b614419b386a1a9a1f1eeaca8
|
|
| BLAKE2b-256 |
27f8cd98632f5cbf13bb91350ede8a5ffb96a7d9684a23a58b06a464708b1801
|
Provenance
The following attestation bundles were made for c2pa_fonts-0.2.0-cp39-abi3-win_amd64.whl:
Publisher:
release.yml on writerslogic/c2pa-fonts
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
c2pa_fonts-0.2.0-cp39-abi3-win_amd64.whl -
Subject digest:
8baca510225d876872c86fb7e93ffa757b437ef7d1ccb29b0650d3c680b0ee0c - Sigstore transparency entry: 2165066164
- Sigstore integration time:
-
Permalink:
writerslogic/c2pa-fonts@4e668a5618976d82f21d1f0bdabc08eb0ea8dd8a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/writerslogic
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4e668a5618976d82f21d1f0bdabc08eb0ea8dd8a -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file c2pa_fonts-0.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: c2pa_fonts-0.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 265.2 kB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
696fd4928616a5f8bfc65d43758971b83b049a0788c6661294c9491f7ecbf365
|
|
| MD5 |
65952c3abeb4be794ca0d5a550076a53
|
|
| BLAKE2b-256 |
d9bbaca9fc6933c3c90d5181f434661e326de534f29022dfc9c4bec9c39eec30
|
Provenance
The following attestation bundles were made for c2pa_fonts-0.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release.yml on writerslogic/c2pa-fonts
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
c2pa_fonts-0.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
696fd4928616a5f8bfc65d43758971b83b049a0788c6661294c9491f7ecbf365 - Sigstore transparency entry: 2165066142
- Sigstore integration time:
-
Permalink:
writerslogic/c2pa-fonts@4e668a5618976d82f21d1f0bdabc08eb0ea8dd8a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/writerslogic
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4e668a5618976d82f21d1f0bdabc08eb0ea8dd8a -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file c2pa_fonts-0.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: c2pa_fonts-0.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 260.3 kB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
756cbae4166d072e87a9ed2eeb89e14cb262ce46a375643d1a6b27a549f4cad3
|
|
| MD5 |
dec320a7eb5dcc700283941b2288d300
|
|
| BLAKE2b-256 |
1560db4ba4defc1666c39ac7b19806b8d5453cf2b1b98a3c466cb0af2c0b991c
|
Provenance
The following attestation bundles were made for c2pa_fonts-0.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
release.yml on writerslogic/c2pa-fonts
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
c2pa_fonts-0.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
756cbae4166d072e87a9ed2eeb89e14cb262ce46a375643d1a6b27a549f4cad3 - Sigstore transparency entry: 2165066202
- Sigstore integration time:
-
Permalink:
writerslogic/c2pa-fonts@4e668a5618976d82f21d1f0bdabc08eb0ea8dd8a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/writerslogic
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4e668a5618976d82f21d1f0bdabc08eb0ea8dd8a -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file c2pa_fonts-0.2.0-cp39-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: c2pa_fonts-0.2.0-cp39-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 234.8 kB
- Tags: CPython 3.9+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
044ed044b67ceb46e7ffb5e5a89a9846396a47c9e4935077f87bb7d697267ccc
|
|
| MD5 |
4ca7a93d7d2862912f677c99b3517deb
|
|
| BLAKE2b-256 |
62f7489375526e87df0d2f446281869046ff909f9499cd6c57b48e9030327e40
|
Provenance
The following attestation bundles were made for c2pa_fonts-0.2.0-cp39-abi3-macosx_11_0_arm64.whl:
Publisher:
release.yml on writerslogic/c2pa-fonts
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
c2pa_fonts-0.2.0-cp39-abi3-macosx_11_0_arm64.whl -
Subject digest:
044ed044b67ceb46e7ffb5e5a89a9846396a47c9e4935077f87bb7d697267ccc - Sigstore transparency entry: 2165066182
- Sigstore integration time:
-
Permalink:
writerslogic/c2pa-fonts@4e668a5618976d82f21d1f0bdabc08eb0ea8dd8a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/writerslogic
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4e668a5618976d82f21d1f0bdabc08eb0ea8dd8a -
Trigger Event:
workflow_dispatch
-
Statement type: