Overview
Implements the Embedding Manifests into Structured Text section of the C2PA Technical Specification, which associates a C2PA Manifest Store with source code, configuration files, markup, and other text formats that support comment syntax or front matter conventions.
The manifest block uses fixed ASCII armour-style delimiters modelled on RFC 4880:
-----BEGIN C2PA MANIFEST----- <reference> -----END C2PA MANIFEST-----
This crate owns three things:
- Embed / Extract — place a reference or an inline manifest as a comment or front matter block, and locate and resolve it again.
- Hard binding — define and compute the exact
c2pa.hash.datacoverage for structured text, and verify it. - A validation bridge to
c2pa-rsfor signature, trust, and assertion validation — which this crate does not reimplement.
This crate is not certified or conformance-tested by the C2PA. It implements the structured-text embedding and hard binding as specified, and delegates cryptographic validation to
c2pa-rs.
Quick Start
[]
= "0.1"
Embed a manifest reference
use ;
let signed = embed_manifest;
// # -----BEGIN C2PA MANIFEST----- https://example.com/manifests/abc.c2pa -----END C2PA MANIFEST-----
// print('hello')
embed_manifest_at_end places the block on the last line (for files whose first line is reserved, e.g. a shebang or XML declaration), and embed_front_matter writes the multi-line form inside YAML/TOML front matter.
Extract a manifest reference
use ;
let text = "# -----BEGIN C2PA MANIFEST----- https://example.com/m.c2pa -----END C2PA MANIFEST-----
print('hello')
";
let result = extract_manifest.unwrap;
assert_eq!;
// A `data:application/c2pa;base64,` reference decodes to the manifest bytes;
// anything else is treated as an external URI.
match classify_reference.unwrap
The Hard Binding
A structured-text manifest is bound with a c2pa.hash.data assertion carrying a single exclusion range covering the entire manifest block. The hash is computed over the raw bytes of the file with that range removed.
Unlike the Unicode Variation Selector method for unstructured text, this binding applies no Unicode normalization: structured text files are byte-stable on disk, and normalizing to NFC would create false mismatches for files that legitimately contain NFD content. Files must be read in binary mode, preserving exact line terminators; bare CR line endings are unsupported.
#
The exclusion-range and covered-byte primitives (manifest_exclusion, hashed_bytes) are always available and dependency-free; compute_data_hash / verify_data_hash require the hard-binding feature (which pulls sha2).
Fragility — and the soft-binding recovery path
This is a byte-exact binding, and it is meant to be. Any change to the covered bytes — reformatting, re-indentation, transcoding, or an LF↔CRLF conversion outside the block — breaks it. Where durability across such transformations matters, pair it with the perceptual soft binding in c2pa-text-binding, which re-associates transformed content with its provenance after the hard binding is lost. Do not treat the structured-text hard binding as robust to editing.
Validating with c2pa-rs
Enable the c2pa feature to validate the signature, trust chain, and hard binding via c2pa-rs. This crate extracts and resolves the reference; c2pa-rs does the cryptography.
use bridge;
// Inline (data:) references are decoded automatically; URL references are
// fetched with the `remote` feature (or resolve them yourself and call
// `bridge::validate_with_manifest`).
let reader = validate?;
println!;
Features
| Feature | Adds | Pulls |
|---|---|---|
| (none) | embed, extract, exclusion-range and covered-byte primitives | — |
hard-binding |
compute_data_hash / verify_data_hash (SHA2-256/384/512) |
sha2 |
c2pa |
the bridge to c2pa-rs for signature/trust/assertion validation |
c2pa |
remote |
HTTP(S) resolution of URL references in the bridge | c2pa, ureq |
No feature is enabled by default; the core API has no dependencies.
Supported Formats
Any text format with a comment syntax or front matter convention:
| Comment Style | Formats | Example |
|---|---|---|
# |
Python, Ruby, Shell, YAML, TOML | # -----BEGIN C2PA MANIFEST----- ... -----END C2PA MANIFEST----- |
// |
JavaScript, TypeScript, Go, Rust, C++ | // -----BEGIN C2PA MANIFEST----- ... -----END C2PA MANIFEST----- |
-- |
SQL, Lua, Haskell | -- -----BEGIN C2PA MANIFEST----- ... -----END C2PA MANIFEST----- |
/* */ |
CSS, C, Java | /* -----BEGIN C2PA MANIFEST----- ... -----END C2PA MANIFEST----- */ |
<!-- --> |
Markdown, XML (non-HTML) | <!-- -----BEGIN C2PA MANIFEST----- ... -----END C2PA MANIFEST----- --> |
| Front matter | Markdown (YAML), TOML | Multi-line form between front matter delimiters |
WebVTT is structured text per the specification, but it is owned by the dedicated c2pa-vtt crate, not this one.
c2pa-vttplaces theNOTEblock immediately after theWEBVTTheader, where it survives HLS/DASH segmentation. Usec2pa-vttfor.vttfiles.HTML and SVG have their own C2PA embedding methods and are out of scope here.
Related Crates
| Crate | Description |
|---|---|
| c2pa-vtt | Canonical owner of WebVTT captions/subtitles (streaming-safe placement) |
| c2pa-text-binding | Soft binding and content fingerprinting for text assets (recovery path) |
| c2pa-text | Unstructured text embedding via Unicode Variation Selectors |
| c2pa-rs | Official C2PA SDK |
License
Licensed under either of Apache License, Version 2.0 or MIT License at your option.
Built by WritersLogic