Overview
Associates a C2PA Manifest Store with an AI/ML model by writing it into the model container's own metadata slot, so the model stays loadable by its usual runtime. Three formats are supported:
| Format | Metadata slot | Manifest encoding |
|---|---|---|
| GGUF (llama.cpp) | typed key/value metadata | c2pa.manifest as a UINT8 array (raw bytes) |
| SafeTensors | JSON header __metadata__ |
c2pa.manifest as Base64 |
| ONNX | protobuf metadata_props |
c2pa.manifest as Base64 |
A remote (or side-car) manifest can instead be referenced by URI under c2pa.manifest.uri, or both an embedded store and a URI can be written together.
The C2PA Technical Specification defines no dedicated embedding method for model containers; a manifest embedded in a model declares what the asset is with the asset type assertion. This crate provides the canonical c2pa.types.model.* strings for that assertion.
Zero dependencies on native targets; the WebAssembly/npm build uses only wasm-bindgen.
Quick Start
[]
= "0.1"
Embed a manifest
use ;
let model: & = /* .gguf / .safetensors / .onnx bytes */;
let store: = /* C2PA Manifest Store bytes */;
// Embed a Manifest Store directly (format is auto-detected)...
let signed = embed_manifest.unwrap;
// ...or reference a remote manifest by URI...
let signed = embed_manifest.unwrap;
// ...or both.
let signed = embed_manifest.unwrap;
Read a manifest
use ;
let store = read_manifest.unwrap; // embedded Manifest Store bytes
let uri = read_manifest_uri.unwrap; // Option<String>: active manifest URI
Verify presence
use verify;
let report = verify.unwrap;
assert!;
// report.format, report.has_embedded_manifest, report.has_remote_uri
Declare the asset type
use Format;
let model_type = detect.unwrap.model_type;
assert_eq!; // for an ONNX model
Explicit format
ONNX has no magic number, so auto-detection matches it last as a best-effort protobuf shape check. When the format is known in advance, use embed_manifest_as, or call the per-format module (gguf, safetensors, onnx) directly.
use ;
let signed = embed_manifest_as.unwrap;
Other languages
The same API is published for JavaScript and Python from this crate, so it also serves Node, pnpm, and browser/bundler users.
npm / pnpm (WebAssembly)
import from "c2pa-ml";
const signed = ; // Uint8Array in, Uint8Array out
const manifest = ;
PyPI
= # bytes in, bytes out
=
= # "GGUF" | "SafeTensors" | "ONNX" | None
Design
- The Manifest Store and/or manifest URI are stored under the reserved keys
c2pa.manifest/c2pa.manifest.uriin the format's native metadata slot - GGUF: metadata is re-serialized and the tensor-data region is re-padded to
general.alignment; tensor-info offsets are relative to that region, so tensor data is never rewritten - SafeTensors: only the JSON header is rewritten; each tensor's
data_offsetsare relative to the data block and stay valid - ONNX: only the top-level protobuf field stream is rewritten; every other field (
ir_version,graph,opset_import, …) is copied through verbatim - Embedding replaces any existing C2PA entries;
remove_manifestrestores the model to its unembedded bytes
Scope
This crate implements embedding and extraction only. Manifest construction, signing, and content (hard/soft) binding are out of scope; use the official C2PA SDK to build and sign manifests. The c2pa.hash.data assertion should exclude the metadata region carrying the Manifest Store.
Related Crates
| Crate | Description |
|---|---|
| c2pa-fonts | OpenType/TrueType (SFNT) font embedding |
| c2pa-warc | WARC web archive embedding (ISO 28500) |
| c2pa-zip | ZIP-based (OCF) document embedding: EPUB, DOCX, ODT |
| c2pa-structured-text | Structured text embedding via ASCII armour delimiters |
| c2pa-rs | Official C2PA SDK |
License
Licensed under either of Apache License, Version 2.0 or MIT License at your option.
Built by WritersLogic