Build the manifest
Before signing an image, you are required to generate a minimal C2PA manifest and compute its hash.
Required inputs
Image file path - Used as the title and for hash computation.
Author name - Entered manually.
Author email - Entered manually.
Both author name and email are typically fetched from your user certificate using the DigiCert credentials info API.
Process
Compute the SHA256 hash of the input image (base64-encoded).
Build a minimal manifest that includes:
A unique manifest UUID and instance ID.
Basic metadata such as title, format, and author details.
Assertions describing the image hash and creative work metadata.
Save the manifest to a local file (manifest.json).
Pretty-print the manifest JSON to the console.
Compute and display the SHA256 hash of the manifest (base64-encoded).
Output
A manifest.json file containing the to-be-signed manifest.
The SHA256 hash of the manifest string to be used for signing.
Python example
# This Python script generates a minimal C2PA manifest for a given image, saves it as #...manifest.json, prints the manifest then computes and displays its SHA256 hash in base64.      
import json  import hashlib  
import base64  from datetime 
import datetime  
import uuid    
def compute_sha256(file_path):      
    """Compute SHA256 hash of a file and return base64-encoded string"""      
    sha256 = hashlib.sha256()      
    with open(file_path, "rb") as f:          
        while chunk := f.read(8192):              
            sha256.update(chunk)      
    return base64.b64encode(sha256.digest()).decode('utf-8')  
def compute_sha256_of_string(input_str):      
    """Compute SHA256 hash of a string and return base64-encoded string"""    
    sha256 = hashlib.sha256()      
    sha256.update(input_str.encode('utf-8'))      
    return base64.b64encode(sha256.digest()).decode('utf-8')    
def main():      
    print("=== Minimal C2PA Manifest Generator ===\n")            
    # Ask for required inputs      
    image_path = input("Enter path to the image file: ").strip()      
    author_name = input("Enter author name: ").strip()      
    author_email = input("Enter author email: ").strip()  
    # Generate UUIDs for manifest and instance      
    manifest_uuid = str(uuid.uuid4())      
    instance_id = f"xmp:iid:{uuid.uuid4()}"            
    # Compute SHA256 hash of the image      
    image_hash = compute_sha256(image_path)            
    # Build minimal assertions      
    assertions = [          
        {              
            "label": "c2pa.hash.data",              
            "kind": "Json",              
            "data": {                  
               "alg": "sha256",                  
               "hash": image_hash,                  
               "name": "jumbf manifest",                  
               "pad": ""              
        }          
     }, 
     {              
            "label": "stds.schema-org.CreativeWork",              
            "kind": "Json",              
            "data": {                  
               "@context": "https://schema.org",                  
               "@type": "CreativeWork",                  
               "author": [                      
                   {                          
                       "@type": "Person",                          
                       "name": author_name,                          
                       "email": author_email                      
                   }                  
               ],                  
               "dateCreated": datetime.utcnow().isoformat() + "Z",                  
               "name": image_path              
       }          
    }      
]  
    # Build manifest     
    manifest = {         
       "active_manifest": f"urn:uuid:{manifest_uuid}",          
       "manifests": {              
          f"urn:uuid:{manifest_uuid}": {                  
             "claim_generator": "Custom C2PA Manifest Generator",                  
             "title": image_path,                  
             "format": "image/jpeg",                  
             "instance_id": instance_id,                  
             "ingredients": [],                  
             "assertions": assertions,                  
             "label": f"urn:uuid:{manifest_uuid}"              
          }          
       },          
       "validation_status": []      
    }   
    # Convert manifest to pretty JSON string      
    manifest_json_str = json.dumps(manifest, indent=2)      
    manifest_file_path = "manifest.json"      
    with open(manifest_file_path, "w") as f:          
       f.write(manifest_json_str)            
    # Print manifest      
    print("\n=== Generated To-Be-Signed Manifest ===\n")      
    print(manifest_json_str)            
    # Compute SHA256 hash of the manifest itself      
    manifest_hash = compute_sha256_of_string(manifest_json_str)      
    print("\n=== SHA256 Hash of the Manifest (base64) ===\n")      
    print(manifest_hash)    
if __name__ == "__main__":      
    main()