npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

c2pa-fonts

v0.3.0

Published

C2PA manifest embedding, hard binding, and verification for OpenType/TrueType (SFNT) fonts

Readme

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 specification marks this table format as preliminary: "The C2PA table format is not yet defined in the OFF nor OTF specification; the following definition is preliminary." The layout below tracks that definition and will follow it if it changes.

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 C2PA font 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 version 0.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 C2PA SFNT 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.checkSumAdjustment recomputed
  • verify checks C2PA table well-formedness and SFNT checksum integrity; more than one C2PA table is rejected
  • validate (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

Part of a family of single-purpose crates, one per C2PA embedding method. Each is standalone and independently versioned.

| Crate | Description | |---|---| | c2pa-structured-text | Structured text: ASCII-armoured manifest in a comment or front matter | | c2pa-unstructured-text | Unstructured text: invisible Unicode variation-selector run | | c2pa-html | HTML: script and link elements in the document head | | c2pa-http | HTTP: the c2pa-manifest Link header, with a Tower middleware | | c2pa-text-binding | Soft binding and content fingerprinting for text assets | | c2pa-vtt | WebVTT caption and subtitle embedding | | c2pa-zip | ZIP-based documents: EPUB, DOCX, ODT, OXPS | | c2pa-warc | WARC web archive embedding (ISO 28500) | | c2pa-ml | ML model containers: GGUF, SafeTensors, ONNX | | c2pa | Official C2PA SDK |

Security

Found a vulnerability? Please report it privately — see SECURITY.md.

License

Licensed under either of Apache License, Version 2.0 or MIT License at your option.

Built by WritersLogic