Using the Rust library
July 30, 2026 ยท View on GitHub
Supported platforms
The C2PA Rust library has been tested on:
- Windows (Intel only)
- MacOS (Intel and Apple silicon)
- Ubuntu Linux (64-bit Intel and ARM v8)
- WebAssembly (Wasm); see Building for WebAssembly for details.
Requirements
The C2PA Rust library requires Rust version 1.88.0 or newer.
To use the library, add this to your Cargo.toml:
[dependencies]
c2pa = "0.72.0"
Note
The version above is just a placeholder. Find the latest version at https://crates.io/crates/c2pa.
To read or write a manifest file, add the file_io dependency to your Cargo.toml.
Add the add_thumbnails feature to generate thumbnails for JPEG and PNG files. For example:
c2pa = { version = "0.72.0", features = ["file_io", "add_thumbnails"] }
Example code
The sdk/examples directory contains some minimal example code. The client/client.rs file is the most instructive and provides an example of reading the contents of a manifest store, recursively displaying nested manifests.
Features
The crate provides numerous features that you can enable.
These features are enabled by default:
default_http: Enables default HTTP features for sync and async HTTP resolvers (http_req,http_reqwest,http_wasi, andhttp_std).openssl: Uses the vendoredopensslimplementation for cryptography.
Note
One of openssl or rust_native_crypto must be enabled. If both are enabled, rust_native_crypto is used.
To avoid including openssl as a dependency, disable default features when using rust_native_crypto.
Other features:
add_thumbnails: Adds theimagecrate to enable auto-generated thumbnails, if possible and enabled in settings.fetch_remote_manifests: Fetches remote manifests over the network when no embedded manifest is present and that option is enabled in settings.file_io: Enables APIs that use file system I/O.json_schema: Adds theschemarscrate to derive JSON schemas for JSON-compatible structs.pdf: Enables basic PDF read support.rust_native_crypto: Uses Rust native cryptography.
HTTP features
Warning
These features are for advanced users. Most people can ignore them.
These features toggle compilation with different HTTP libraries, depending on the one you use. Some are async-only and others are sync-only. Disabling all of them will disable HTTP, speed up compilation, and decrease build size.
http_ureq: Enablesureqfor sync HTTP requests.http_reqwest: Enablesreqwestfor async HTTP requests.http_reqwest_blocking: Enables theblockingfeature ofreqwestfor sync HTTP requests.http_wasi: Enableswasifor sync HTTP requests on WASI.http_wstd: Enableswstdfor async HTTP requests on WASI.
Features no longer supported
The following features are no longer supported:
v1_api: The old API that this enabled has been removed.serialize_thumbnails: Thumbnails can be serialized by accessing resources directly.
Resource references
A resource reference is a superset of a HashedUri, which the C2PA specification refers to as both hashed-uri-map and hashed-ext-uri-map. In some cases either can be used.
A resource reference also adds local references to things like the file system or any abstracted storage. You can use the identifier field to distinguish it from the URL field, but they are really the same. However, the specification only allows JUMBF and HTTP(S) references, so if the external identifier is not HTTP(S), it must be converted to a JUMBF reference before embedding into a manifest.
When defining a resource for the ManifestStoreBuilder, existing resources in other manifests may be identified via JUMBF URLs. This allows a new manifest to inherit an existing thumbnail and is also used to reference parent ingredients. The API generally does this resolution as needed, so you do not need to know about JUMBF URL references when creating a manifest.
The specification often requires adding a HashedUri to an assertion. Since the JUMBF URIs for a new manifest are not known when defining the manifest, this creates a "chicken and egg" scenario, resolved with local resource references. When constructing the JUMBF for a manifest, the library converts all local URI references into JUMBF references and corrects the associated cross-references.
URI schemes in a resource reference can have the following forms:
self#jumbf- An internal JUMBF referencefile:///- A local file referenceapp://contentauth/- A working store referencehttp://- Remote URIhttps://- Remote secure URI
When file_io is enabled, and a URI is not a JUMBF reference nor a resource loaded from memory, then the library interprets the URI as a file path.
Source asset versus parent asset
The source asset isn't always the parent asset. The source asset is the asset that is hashed and signed. It can be the output from an editing application that has not preserved the manifest store from the parent. In that case, the application should have extracted a parent ingredient from the parent asset and added that to the manifest definition.
- Parent asset: with a manifest store.
- Parent ingredient: generated from that parent asset (hashed and validated).
- Source asset: may be a generated rendition after edits from the parent asset (manifest?).
- Signed output: includes the source asset and the new manifest store with the parent ingredient.
If there is no parent ingredient defined, and the source has a manifest store, the SDK will generate a parent ingredient from the parent.
Remote URLs and embedding
The default operation of C2PA signing is to embed a C2PA manifest store into an asset. The library also returns the C2PA manifest store so that it can be written to a sidecar or uploaded to a remote service.
- The API supports embedding a remote URL reference into the asset.
- The remote URL is stored in different ways depending on the asset, but is often stored in XMP data.
- The remote URL must be added to the asset before signing so that it can be hashed along with the asset.
- Not all file formats support embedding remote URLs or embedding manifest stores.
- If you embed a manifest or a remote URL, the library creates a new asset with the new data embedded.
- If you don't embed, then the original asset is unmodified and there is no need to write one out.
- The remote URL can be set with
builder.remote_url. - If embedding is not needed, set the
builder.no_embedflag totrue.