Attaching and signing a manifest
- JavaScript
 - Python
 - Node.js
 - C++
 - Rust
 
You can't currently attach a manifest to an asset and sign the claim using the JavaScript library. You need to use a language that runs on the "back-end," such as Python, Node.js, C++, or Rust.
This is an example of how to assign a manifest to an asset and sign the claim using Python.
Use a Builder object to add a manifest to an asset.
# Import the C2PA Python package.
from c2pa import *
# Import standard general-purpose packages.
import os
import io
import logging
import json
import base64
try:
  # Define a function to sign the claim bytes.
  # In this case we are using a pre-defined sign_ps256 method, passing in our private cert.
  # Normally this cert would be kept safe in some other location.
  def private_sign(data: bytes) -> bytes:
    return sign_ps256(data, "tests/fixtures/ps256.pem")
  # Read our public certs into memory.
  certs = open(data_dir + "ps256.pub", "rb").read()
  # Create a signer from the private signer, certs and a time stamp service URL.
  signer = create_signer(private_sign, SigningAlg.PS256, certs, "http://timestamp.digicert.com")
  # Create a builder add a thumbnail resource and an ingredient file.
  builder = Builder(manifest_json)
  # Add the resource from a stream.
  a_thumbnail_jpg_stream = open("tests/fixtures/A_thumbnail.jpg", "rb")
  builder.add_resource("image/jpeg", a_thumbnail_jpg_stream)
  # Add the resource from a file.
  # The URI provided here, "thumbnail", must match an identifier in the manifest definition.
  builder.add_resource_file("thumbnail", "tests/fixtures/A_thumbnail.jpg")
  # Define an ingredient, in this case a parent ingredient named A.jpg, with a thumbnail.
  ingredient_json = {
    "title": "A.jpg",
    "relationship": "parentOf", # "parentOf", "componentOf" or "inputTo"
    "thumbnail": {
        "identifier": "thumbnail",
        "format": "image/jpeg"
    }
  }
  # Add the ingredient from a stream.
  a_jpg_stream = open("tests/fixtures/A.jpg", "rb")
  builder.add_ingredient("image/jpeg", a_jpg_stream)
  # At this point archive or unarchive Builder to continue later.
  # This example uses a bytearray for the archive stream.
  # All ingredients and resources are saved in the archive.
  archive = io.BytesIO(bytearray())
  builder.to_archive(archive)
  archive.seek()
  builder = builder.from_archive(archive)
  # Sign the builder with a stream and output it to a stream.
  # This returns the binary manifest data that could be uploaded to cloud storage.
  input_stream = open("tests/fixtures/A.jpg", "rb")
  output_stream = open("target/out.jpg", "wb")
  c2pa_data = builder.sign(signer, "image/jpeg", input_stream, output_stream)
except Exception as err:
  print(err)
note
The Node.js library is being revised. The documentation will be updated as soon as possible with the latest changes.
This is an example of how to assign a manifest to an asset and sign the claim using C++:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdexcept>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include "c2pa.hpp"
#include "test_signer.hpp"
using namespace std;
namespace fs = std::filesystem;
using namespace c2pa;
const std::string manifest_json = R"{
    "claim_generator": "c2pa_c_test/0.1",
    "claim_generator_info": [
      {
        "name": "c2pa-c example",
        "version": "0.1"
      }
    ],
    "assertions": [
    {
      "label": "cawg.training-mining",
      "data": {
        "entries": {
          "cawg.ai_generative_training": { "use": "notAllowed" },
          "cawg.ai_inference": { "use": "notAllowed" },
          "cawg.ai_training": { "use": "notAllowed" },
          "cawg.data_mining": { "use": "notAllowed" }
        }
      }
    }
  ]
 };
auto builder = Builder(manifest_json);
This is an example of how to assign a manifest to an asset and sign the claim using Rust.
This example is from c2pa-rs/sdk/examples/v2api.rs:
use std::io::{Cursor, Seek};
use anyhow::Result;
use c2pa::{
    crypto::raw_signature::SigningAlg, settings::Settings, validation_results::ValidationState,
    Builder, CallbackSigner, Reader,
};
use serde_json::json;
let json = manifest_def(title, format);
let mut builder = Builder::from_json(&json)?;
builder.add_ingredient_from_stream(
    json!({
        "title": parent_name,
        "relationship": "parentOf"
    })
    .to_string(),
    format,
    &mut source,
)?;
let thumb_uri = builder
    .definition
    .thumbnail
    .as_ref()
    .map(|t| t.identifier.clone());
// add a manifest thumbnail ( just reuse the image for now )
if let Some(uri) = thumb_uri {
    if !uri.starts_with("self#jumbf") {
        source.rewind()?;
        builder.add_resource(&uri, &mut source)?;
    }
}
// write the manifest builder to a zipped stream
let mut zipped = Cursor::new(Vec::new());
builder.to_archive(&mut zipped)?;
// unzip the manifest builder from the zipped stream
zipped.rewind()?;
let ed_signer =
    |_context: *const (), data: &[u8]| CallbackSigner::ed25519_sign(data, PRIVATE_KEY);
let signer = CallbackSigner::new(ed_signer, SigningAlg::Ed25519, CERTS);
let mut builder = Builder::from_archive(&mut zipped)?;
// sign the ManifestStoreBuilder and write it to the output stream
let mut dest = Cursor::new(Vec::new());
builder.sign(&signer, format, &mut source, &mut dest)?;