c2pa-ml
C2PA manifest embedding for AI/ML model container formats: GGUF, SafeTensors, and ONNX
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 | Specified? |
|---|---|---|---|
| ONNX | protobuf metadata_props |
c2pa:manifest as Base64 |
yes |
| SafeTensors | JSON header __metadata__ |
c2pa:manifest as Base64 |
yes |
| GGUF (llama.cpp) | typed key/value metadata | c2pa:manifest as a UINT8 array (raw bytes) |
no |
ONNX and SafeTensors each have a normative clause in the C2PA Technical Specification, including the c2pa:manifest key, the hard binding, and a per-format multipleManifests failure code. This crate implements them as written.
GGUF has no specified embedding method. It is supported here as a crate extension, following the same shape so a dispatcher can treat all three alike — but there is no specified exclusion range for it, so binding::manifest_exclusion declines to invent one and returns UnknownFormat. Embedding and reading work; only the hard binding is unavailable.
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 specification defines no remote-URI key for these formats, so that too is a crate extension, namespaced to match.
A manifest embedded in a model should also declare what the asset is with the asset type assertion; this crate provides the canonical c2pa.types.model.* strings for that.
Zero dependencies on native targets; the WebAssembly/npm build uses only wasm-bindgen.
Quick Start
[dependencies]
c2pa-ml = "0.1"
Embed a manifest
use c2pa_ml::{embed_manifest, ManifestSource};
let model: &[u8] = /* .gguf / .safetensors / .onnx bytes */;
let store: Vec<u8> = /* C2PA Manifest Store bytes */;
// Embed a Manifest Store directly (format is auto-detected)...
let signed = embed_manifest(model, &ManifestSource::embedded(store)).unwrap();
// ...or reference a remote manifest by URI...
let signed = embed_manifest(model, &ManifestSource::remote("https://example.com/m.c2pa")).unwrap();
// ...or both.
let signed = embed_manifest(model, &ManifestSource::both("https://example.com/m.c2pa", vec![/* ... */])).unwrap();
Read a manifest
use c2pa_ml::{read_manifest, read_manifest_uri};
let store = read_manifest(&signed).unwrap(); // embedded Manifest Store bytes
let uri = read_manifest_uri(&signed).unwrap(); // Option<String>: active manifest URI
Verify presence
use c2pa_ml::verify;
let report = verify(&signed).unwrap();
assert!(report.is_compliant());
// report.format, report.has_embedded_manifest, report.has_remote_uri
Declare the asset type
use c2pa_ml::Format;
let model_type = Format::detect(&signed).unwrap().model_type();
assert_eq!(model_type.as_str(), "c2pa.types.model.onnx"); // 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 c2pa_ml::{embed_manifest_as, Format, ManifestSource};
let signed = embed_manifest_as(model, Format::Onnx, &ManifestSource::embedded(store)).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)
npm install c2pa-ml # or: pnpm add c2pa-ml
import { embedManifest, readManifest, detectFormat } from "c2pa-ml";
const signed = embedManifest(model, store); // Uint8Array in, Uint8Array out
const manifest = readManifest(signed);
PyPI
pip install c2pa-ml
import c2pa_ml
signed = c2pa_ml.embed_manifest(model, store) # bytes in, bytes out
manifest = c2pa_ml.read_manifest(signed)
fmt = c2pa_ml.detect_format(model) # "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
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-fonts | OpenType/TrueType (SFNT) font embedding |
| 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
Metadata
Release files for c2pa-ml 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| c2pa_ml-0.2.0.tar.gz | 52.7 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| c2pa_ml-0.2.0-cp39-abi3-win_amd64.whl | CPython 3.9 | abi3 | Windows x86-64 | Details |
| c2pa_ml-0.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.9 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| c2pa_ml-0.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.9 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| c2pa_ml-0.2.0-cp39-abi3-macosx_11_0_arm64.whl | CPython 3.9 | abi3 | macOS 11.0+ ARM64 | Details |
| c2pa_ml-0.2.0-cp39-abi3-macosx_10_12_x86_64.whl | CPython 3.9 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 1.2 MB
Release files / c2pa_ml-0.2.0.tar.gz
| Download URL | c2pa_ml-0.2.0.tar.gz |
|---|---|
| Size | 52.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f468cc1c31bf24b73945d186e45c9c6a495313256daeecec0193a2b65d32831c
|
|
BLAKE2b-256 checksum How to use checksums |
0ac0369809a06dd8aabd850608a2a51024926d20d84d6bbece91d197c47c92be
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency logRelease files / c2pa_ml-0.2.0-cp39-abi3-win_amd64.whl
| Download URL | c2pa_ml-0.2.0-cp39-abi3-win_amd64.whl |
|---|---|
| Size | 136.3 kB |
| Tags | CPython 3.9 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
a557fc4a4b940dffb151fa3aecf8d1029225fc82fb050aad427fcb62da62e070
|
|
BLAKE2b-256 checksum How to use checksums |
6705290984a824328a2e39478094d78b8ffba4f2567a5d00850f67457563b85a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency logRelease files / c2pa_ml-0.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | c2pa_ml-0.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 270.4 kB |
| Tags | CPython 3.9 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
641e0e29d249b927dabe23c8feb83a8203fbb1bd3aa7b33a16539ed3e6d4fe45
|
|
BLAKE2b-256 checksum How to use checksums |
1b6634c92446657e8effb48224a53db3553dfb8ccb9a1339c8ffa5dcb47f5433
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency logRelease files / c2pa_ml-0.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | c2pa_ml-0.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 267.0 kB |
| Tags | CPython 3.9 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
26cfce28faab5ea9d10d8d2284703cb2a75c4ac480720690e528dc38251c8167
|
|
BLAKE2b-256 checksum How to use checksums |
722cdecf0760ff92825086955081c42835b6bbed95ab6ed2b37b7af35a1b69f9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency logRelease files / c2pa_ml-0.2.0-cp39-abi3-macosx_11_0_arm64.whl
| Download URL | c2pa_ml-0.2.0-cp39-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 238.5 kB |
| Tags | CPython 3.9 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
d64d61e8014acbd6e00b5262c774c259d90528067f402e3307a96efd997df2ef
|
|
BLAKE2b-256 checksum How to use checksums |
7b08286c05155ff78092a36a3be20abeb789a0771150bbb316dce6e173c30c54
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency logRelease files / c2pa_ml-0.2.0-cp39-abi3-macosx_10_12_x86_64.whl
| Download URL | c2pa_ml-0.2.0-cp39-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 241.0 kB |
| Tags | CPython 3.9 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
ca90ff8e21223f18ce48a26a5c557e8f9206bb26e924bb974fe394f3549a94b3
|
|
BLAKE2b-256 checksum How to use checksums |
b8944e0f48f9e7357bf945567917adb7f1e10ac87e2c73b8c3a94c69e6f98e4e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency log