ISCC - C2PA Soft Bindings#
A C2PA manifest is attached to an asset by a hard binding (a cryptographic hash). When the manifest gets stripped, for example by a platform that re-encodes uploads, a soft binding lets you find the manifest again from the content alone.
iscc-sdk creates ISCC soft bindings with the algorithm io.iscc.v0, as specified by
IEP-0020. It does the media extraction, the ISCC generation and
the byte encoding for you, and gives you the finished c2pa.soft-binding assertion. You only add it
to your manifest and sign as usual.
Quick start#
Run the command on the file you are about to sign:
It prints the assertion for a C2PA manifest definition as JSON on stdout:
{
"label": "c2pa.soft-binding",
"created": true,
"data": {
"alg": "io.iscc.v0",
"blocks": [
{
"scope": {},
"value": [0, 7, 104, 227, 117, 199, 163, 217, 54, 188, 109, 0, 98, 225, 117, 146, ...]
}
],
"bindingMetadata": {
"informationalUrl": "https://ieps.iscc.codes/iep-0020/",
"io.iscc.generator": {
"name": "iscc-sdk",
"version": "0.9.7"
}
}
}
}
The value (shortened above) is the ISCC-SEQ: the ISCC-UNITs of the asset as bytes. The units
themselves go to stderr, one per line, so stdout stays clean for piping:
ISCC:AADWRY3VY6R5SNV4NUAGFYLVSJ3I7KX37VO6PYLC22DFONVH2GVZIPY
ISCC:CEDQYWTPK2Q7ZTK47HPOYUUTO3TCAZ6KNVUZODFMMY42S6O7RDCWFEA
ISCC:EED4GQZQTY6J5DTHNDQ7S7EGNENJNRTEGLGHFWXFGNDZHSMO4HEZGZI
ISCC:GAD6Z2VJLX46FD6QVSSCW3BOUAIV5GRINTAHISA6UQIHPLWH3YBGAHQ
ISCC:IADVKUU37LS33M6VGDCS6RGRHTGWU7DRB5RWEDOC3MOEHRKZFLRNZFY
Add --no-semantic to leave out the Semantic-Codes. This needs no c2pa extra:
The command exits with a non-zero code and a message on stderr if anything goes wrong.
Python API#
import iscc_sdk as idk
sb = idk.soft_binding("photo.jpg") # semantic=True by default
sb.units # ("ISCC:AAD...", "ISCC:CED...", "ISCC:EED...", "ISCC:GAD...", "ISCC:IAD...")
sb.value # bytes, the ISCC-SEQ (content of blocks[].value)
assertion = idk.soft_binding_definition(sb) # dict, the JSON shown above
Install the extra for Semantic-Codes with pip install "iscc-sdk[c2pa]", or pass semantic=False.
Signing with a C2PA SDK#
Put the assertion into the assertions of your manifest definition and sign the same file you
created the soft binding from:
import json
import iscc_sdk as idk
manifest = {
"claim_generator_info": [{"name": "my-app", "version": "1.0"}],
"assertions": [idk.soft_binding_definition(idk.soft_binding("photo.jpg"))],
}
with open("manifest.json", "w") as f:
json.dump(manifest, f)
The same manifest definition works with the c2pa-rs Builder and its bindings, such as
c2pa-python. "created": true lists the assertion in created_assertions, so it is attributed to
the signer, as IEP-0020 requires.
Value encoding
C2PA SDKs before c2pa-rs PR 2757 store the value integer array as a CBOR array of integers,
later versions as a CBOR byte string. IEP-0020 requires readers to accept both, so the same JSON
works with old and new SDKs.
What goes into the soft binding#
Every ISCC-UNIT is Version 0 with a 256-bit body, always in this order:
| Order | ISCC-UNIT | Included |
|---|---|---|
| 1 | Meta-Code | only if the embedded metadata has a title |
| 2 | Semantic-Code | image and text, unless --no-semantic / semantic=False |
| 3 | Content-Code | image, audio, video and text (see the exceptions below) |
| 4 | Data-Code | always |
| 5 | Instance-Code | always |
- Whole file, as signed. The file is processed as it is, nothing is removed or normalized first. Create the soft binding from the final rendition you sign, not from the original you edited.
- No file name fallback. Without an embedded title there is no Meta-Code, so renaming a file does not change its soft binding.
- Featureless images. Uniform colors, plain gradients and similar images get an Image-Code that
matches unrelated images. It is left out with a warning (see
is_featureless_image_code). - Unsupported file types get a Data-Code and an Instance-Code only, with a warning. They can be matched at byte level only.
- Documents without text. If no text can be extracted (a scanned or blank PDF), the Semantic- and Content-Code are left out with a warning, because an empty text would match every other empty document.
- Semantic-Codes are never dropped silently. If they are on and
iscc-sci(images) oriscc-sct(text) is missing, the command fails with an install hint, so the same file always gives the same soft binding. - Default settings only. Soft bindings ignore settings from environment variables or settings
files (
iscc-sdk.env,.env), such asISCC_SDK_IMAGE_TRIM_TOLERANT,ISCC_SDK_VIDEO_FPSorISCC_SCT_MAX_TOKENS. The units are always created with the default settings of iscc-sdk, iscc-sci and iscc-sct, so every party derives the same soft binding from the same file. - Binding metadata.
bindingMetadatalinks to IEP-0020 (informationalUrl), so viewers can explain the value, and namesiscc-sdkand its version. Each iscc-sdk version pins the minor version of the semantic models, so the version also tells which models created the Semantic-Codes.
Test vectors#
Test vectors for implementers ship with the package as
iscc_sdk/c2pa_vectors.json.
Each vector names an input file from iscc-samples (or embeds
the input bytes) with its SHA-256, and gives the expected ISCC-UNITs, the value as hex, and the
value as base64 (the form used by the Soft Binding Resolution API). They are created without
Semantic-Codes, because neural network models can differ in single bits across platforms.
The four image_trim_* vectors embed small PNGs with borders. They test the tolerant border trim of
the Image-Code, the step that is easiest to get wrong. Each also gives the expected crop box as
image_crop (left, upper, right, lower), so you can check the trim on its own:
image_trim_noisy_background: a textured product on a faintly noisy white background is cropped to the product. A faint yellow detail next to it differs from the background in the blue channel only and is kept, because the trim compares each RGB channel, not grey values.image_trim_black_frame: the same image in an uneven black frame. The first pass removes the frame, the second the background, so the Image-Code is the same as without the frame.image_trim_gradient_kept: a sky gradient above texture is a one-sided border that is not flat, so nothing is cut.image_trim_caption_bar: a faintly noisy white caption bar above texture is a flat one-sided border and is cut.
API Reference#
C2PA soft bindings with ISCC-UNITs (io.iscc.v0) as specified by IEP-0020.
SoftBinding
#
ISCC soft binding of an asset.
Attributes:
| Name | Type | Description |
|---|---|---|
units |
tuple[str, ...]
|
ISCC-UNITs in fixed order (Meta, Semantic, Content, Data, Instance) |
value |
bytes
|
ISCC-SEQ bytes of the units (content of |
soft_binding(fp, semantic=True)
#
Create an ISCC soft binding (IEP-0020) for a file.
Every ISCC-UNIT is Version 0 with a 256-bit body. The units are, in this order:
- Meta-Code: only if the embedded metadata yields a title (never from the file name)
- Semantic-Code: image and text mode, if
semanticis True - Content-Code: image, audio, video and text mode (a featureless Image-Code is left out)
- Data-Code and Instance-Code: always
Unsupported media types and documents without extractable text get only a Data-Code and an Instance-Code (plus a Meta-Code if there is a title).
All units are created with the default settings of iscc-sdk, iscc-sci and iscc-sct. Settings
from environment variables or settings files (iscc-sdk.env, .env) do not change a soft
binding, so every party derives the same units from the same file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fp
|
Filepath of the asset, processed as a whole exactly as it will be signed. |
required | |
semantic
|
Include Semantic-Codes (requires iscc-sci for images, iscc-sct for text). |
True
|
Returns:
| Type | Description |
|---|---|
|
Soft binding with ISCC-UNITs and ISCC-SEQ value. |
Raises:
| Type | Description |
|---|---|
idk.EnvironmentError
|
If |
soft_binding_definition(sb)
#
Create the c2pa.soft-binding assertion for a c2pa-rs manifest definition.
The value is a list of integers (0-255). c2pa-rs releases with PR 2757 store it as a CBOR byte string, earlier releases as a CBOR array of integers. IEP-0020 readers accept both.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sb
|
Soft binding from |
required |
Returns:
| Type | Description |
|---|---|
|
Assertion definition with label, created flag and data. |