Skip to main content

crates.io docs.rs CI OpenSSF Scorecard License

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:

  1. Embed / Extract — place a reference or an inline manifest as a comment or front matter block, and locate and resolve it again.
  2. Hard binding — define and compute the exact c2pa.hash.data coverage for structured text, and verify it.
  3. A validation bridge to c2pa-rs for 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

[dependencies]
c2pa-structured-text = "0.1"

Embed a manifest reference

use c2pa_structured_text::{embed_manifest, ManifestRef};

let signed = embed_manifest(
    "print('hello')\n",
    ManifestRef::Url("https://example.com/manifests/abc.c2pa"),
    "#",   // comment prefix
    None,  // no comment suffix
);
// # -----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 c2pa_structured_text::{extract_manifest, classify_reference, Reference};

let text = "# -----BEGIN C2PA MANIFEST----- https://example.com/m.c2pa -----END C2PA MANIFEST-----
print('hello')
";
let result = extract_manifest(text).unwrap();
assert_eq!(result.reference, "https://example.com/m.c2pa");

// A `data:application/c2pa;base64,` reference decodes to the manifest bytes;
// anything else is treated as an external URI.
match classify_reference(&result.reference).unwrap() {
    Reference::Url(url) => { /* fetch it */ }
    Reference::Embedded(bytes) => { /* raw JUMBF manifest store */ }
}

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.

# #[cfg(feature = "hard-binding")] {
use c2pa_structured_text::hardbinding::{compute_data_hash, verify_data_hash, Algorithm};

let signed = c2pa_structured_text::embed_manifest(
    "print('hello')\n",
    c2pa_structured_text::ManifestRef::Url("https://example.com/m.c2pa"),
    "#",
    None,
);
let data_hash = compute_data_hash(&signed, Algorithm::Sha256).unwrap();
verify_data_hash(&signed, &data_hash).unwrap();
# }

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 c2pa_structured_text::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 = bridge::validate(&signed, bridge::DEFAULT_FORMAT)?;
println!("{:?}", reader.validation_state());

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

The crate is format-agnostic: it does not hard-code a fixed list of languages. Any text/* asset with a comment introducer or a front matter convention works — you supply the comment prefix/suffix (or front matter fence). The table above is illustrative, not exhaustive.

Applicability and exclusions

Per the specification, the structured-text method applies to any text/* (or plain-text) asset not already covered by a format-specific embedding method, provided it has a comment syntax or front matter. The following are out of scope and will not round-trip through this crate:

Not supported Why Use instead
JSON, CSV No comment or front matter syntax — nothing to carry the block none (embed in a container)
HTML Has its own C2PA embedding method the HTML embedding method
SVG, TTML Have their own C2PA embedding methods the SVG / TTML methods
WebVTT Structured text, but streaming placement is specialised c2pa-vtt
Unstructured/plain prose No stable comment location; use invisible codepoints c2pa-text

Line endings must be LF or CRLF (bare CR is rejected). When structured text is carried inside a container (MP4, PDF, ZIP), prefer embedding in the container.

Related Crates

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

Crate Description
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-fonts OpenType/TrueType (SFNT) font embedding
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

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

c2pa_structured_text-0.3.0.tar.gz (55.5 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

c2pa_structured_text-0.3.0-cp39-abi3-win_amd64.whl (174.1 kB view details)

Uploaded CPython 3.9+Windows x86-64

c2pa_structured_text-0.3.0-cp39-abi3-manylinux_2_34_x86_64.whl (313.3 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.34+ x86-64

c2pa_structured_text-0.3.0-cp39-abi3-macosx_11_0_arm64.whl (272.3 kB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

File details

Details for the file c2pa_structured_text-0.3.0.tar.gz.

File metadata

  • Download URL: c2pa_structured_text-0.3.0.tar.gz
  • Upload date:
  • Size: 55.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for c2pa_structured_text-0.3.0.tar.gz
Algorithm Hash digest
SHA256 3c4a9c8dc97de367e49219522cf5d4db433f19b2fba915a2b792bfbc156b5258
MD5 66ee76a9a97d7659e7d71ea1ec0e3993
BLAKE2b-256 d4be2e01faa302b4113b78a6dc1175870eb6a9a3f8afe8df974c9d3074dacac4

See more details on using hashes here.

Provenance

The following attestation bundles were made for c2pa_structured_text-0.3.0.tar.gz:

Publisher: release.yml on writerslogic/c2pa-structured-text

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file c2pa_structured_text-0.3.0-cp39-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for c2pa_structured_text-0.3.0-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 e2eab977220f06743e6bc0ff69836bb8c79289b3d6c7a2090064e570d2cd0f31
MD5 5ba3e8732f2be4691c94048354bc2314
BLAKE2b-256 d7efae75a0f3394a1560358d7d341be351f0c5295021a519a21c9c91158c63ea

See more details on using hashes here.

Provenance

The following attestation bundles were made for c2pa_structured_text-0.3.0-cp39-abi3-win_amd64.whl:

Publisher: release.yml on writerslogic/c2pa-structured-text

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file c2pa_structured_text-0.3.0-cp39-abi3-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for c2pa_structured_text-0.3.0-cp39-abi3-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 d3460399857fd223d3f99510339feedfa5d9b4051273f0a71c80e4b892526e90
MD5 84c3211224421410fa823da7c2498d4d
BLAKE2b-256 140bec58f8170c8dd637e6e66aeecdb38e22104c3b6f6b4fe762ab83eecd17f6

See more details on using hashes here.

Provenance

The following attestation bundles were made for c2pa_structured_text-0.3.0-cp39-abi3-manylinux_2_34_x86_64.whl:

Publisher: release.yml on writerslogic/c2pa-structured-text

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file c2pa_structured_text-0.3.0-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for c2pa_structured_text-0.3.0-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 be6b4fb8f8db0169ee38b43b7efa39869ad45a32f9f5769d86c42f84c65fbaf2
MD5 cd7ed6e9117110d691bb2fdb458708b2
BLAKE2b-256 cb79ae78fcf03bc10e1d5fab8a6de3eec83cc0e91f38eb8a76d6d52a5bf9d693

See more details on using hashes here.

Provenance

The following attestation bundles were made for c2pa_structured_text-0.3.0-cp39-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on writerslogic/c2pa-structured-text

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.3.0 This release

4 files

0.2.0

4 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page