Skip to content

ISCC C2PA Conformance#

IEP: 0020
Title: ISCC C2PA Conformance
Author: Titusz Pan tp@iscc.io
Comments: https://github.com/iscc/iscc-ieps/issues/28
Status: Draft
Type: Core
Standard: IEP
License: CC-BY-4.0
Created: 2026-09-24
Updated: 2026-10-28

Note

This document is a DRAFT. It specifies the C2PA soft binding algorithm io.iscc.v0, entry 3 of the C2PA Soft Binding Algorithm List.

1. Introduction#

A C2PA Manifest binds provenance information to an asset. Its hard binding is a cryptographic hash of the asset bytes. Platforms often remove the C2PA Manifest when they process an asset. A change to the bytes, for example by resizing or re-encoding, also breaks the hard binding.

A soft binding is a fingerprint or watermark that helps in both cases. A resolver uses it to find the C2PA Manifest of an asset that no longer carries it. A validator uses it to compare an asset with the content from which the soft binding was extracted or generated.

The io.iscc.v0 soft binding value is a sequence of ISCC-UNITs. Each ISCC-UNIT describes a different aspect of an asset.

An equal Instance-Code shows that an asset has exactly the bytes from which the ISCC soft binding was generated. For each other ISCC-UNIT, the distance between two codes indicates how much that aspect has changed. A resolver uses these distances to select candidates from its catalog. A secondary check suited to the use case and media type confirms or rejects each candidate.


2. Scope#

This document specifies the C2PA soft binding algorithm io.iscc.v0.


3. Terminology#

The terms ISCC-UNIT, ISCC-HEADER, ISCC-BODY, ISCC-CODE, MainType, SubType, Version, Length, Meta-Code, Semantic-Code, Content-Code, Image-Code, Data-Code and Instance-Code apply as defined in ISO 24138:2024 and IEP-0001. The terms asset, assertion, soft binding, claim generator, validator, C2PA Manifest, C2PA Manifest Store, claim signature, hashed URI and hard binding apply as defined in the C2PA Technical Specification.

resolver : service that returns C2PA Manifests for a soft binding query

ISCC-SEQ : byte string formed by concatenating the byte representations of one or more ISCC-UNITs

ISCC soft binding : ISCC-SEQ in a blocks[].value of a c2pa.soft-binding assertion with alg equal to io.iscc.v0

source : complete byte stream into which a claim generator embeds a C2PA Manifest Store, including any C2PA Manifest Store that the byte stream already contains

query asset : asset for which C2PA Manifests are searched by soft binding

exact match : equality of a 256-bit Instance-Code of an ISCC soft binding and an Instance-Code of another ISCC-SEQ

candidate match : similarity of a Semantic-Code, Content-Code or Data-Code of an ISCC soft binding and an ISCC-UNIT of another ISCC-SEQ, at or above the threshold that the validator or resolver applies to that MainType and SubType

featureless Image-Code : Image-Code whose ISCC-BODY, divided from its first bit into consecutive 64-bit segments, has at least one complete segment with fewer than 8 bits set to 1


4. Soft Binding Value#

4.1 ISCC-SEQ Format#

An ISCC-SEQ shall satisfy all of the following:

  1. It shall consist of one or more ISCC-UNITs of MainType META (0), SEMANTIC (1), CONTENT (2), DATA (3) or INSTANCE (4).
  2. Each ISCC-UNIT shall be coded as its ISCC-HEADER immediately followed by its ISCC-BODY.
  3. Each ISCC-HEADER shall use the variable-length nibble encoding of ISO 24138:2024.
  4. Each Length field shall have a value from 0 to 7, for an ISCC-BODY of 32 × (Length + 1) bits.
  5. The ISCC-UNITs shall be concatenated without separators, length prefixes or trailing bytes.

The order of the ISCC-UNITs is not significant. An ISCC-SEQ may contain several ISCC-UNITs with the same MainType, SubType and Version.

The canonical form of an ISCC-SEQ is ISCC: followed by the Base32 encoding of its bytes, as for any ISCC (see IEP-0001). An ISCC soft binding contains the bytes. The Soft Binding Resolution API uses their base64 encoding.

4.2 Decoding#

A decoder shall process an ISCC-SEQ from offset 0 as follows:

  1. Decode the ISCC-HEADER at the current offset. Reject the ISCC-SEQ if the bytes end before the ISCC-HEADER is complete, or if the ISCC-HEADER bytes are not the encoding of the decoded fields as specified in ISCC-SEQ Format, item C.
  2. Reject the ISCC-SEQ if ISCC-SEQ Format, item A does not permit the MainType, or if the Length field is greater than 7.
  3. Reject the ISCC-SEQ if fewer bytes remain than the ISCC-BODY requires.
  4. Output the ISCC-UNIT and move the offset to the end of its ISCC-BODY. If bytes remain, continue with step A.

A decoder shall not reject an ISCC-UNIT only because its SubType or Version is unknown to it. A decoder shall not alter, reorder or drop ISCC-UNITs.

4.3 Assertion#

A c2pa.soft-binding assertion that contains ISCC soft bindings shall satisfy Table 1.

Table 1 – c2pa.soft-binding fields for io.iscc.v0

Field Requirement
alg shall be io.iscc.v0
blocks[].scope shall be an empty map; a validator or resolver shall ignore a block with a non-empty scope
blocks[].value shall be a CBOR byte string (major type 2) whose content is the bytes of an ISCC-SEQ of 256-bit ISCC-UNITs, or a CBOR array of unsigned integers from 0 to 255 whose items are these bytes in order
alg-params not defined for io.iscc.v0; a validator or resolver shall ignore it
bindingMetadata shall contain the member io.iscc.generator

A claim generator should write blocks[].value as a byte string. A validator or resolver shall accept both forms. It shall ignore a block whose value has any other form. Neither form shall contain a text encoding of the ISCC-SEQ, such as its canonical form.

NOTE

c2pa-rs up to at least version 0.91.7 writes the array form for a soft binding assertion given as JSON in a manifest definition (c2pa-rs issue 2689). JSON reports show a byte string in two ways: c2pa-rs up to version 0.91.7 shows it as a list of numbers, like the array form, and crJSON shows it as a text string b64'…' that holds its base64 encoding.

The member io.iscc.generator shall be a map that contains at least these two text string members:

  1. name: the name of the software that generated the ISCC-UNITs, for example iscc-sdk;
  2. version: the version of that software, for example 0.9.7.

If bindingMetadata contains the member informationalUrl, its value should be https://ieps.iscc.codes/iep-0020/.

A validator or resolver shall not reject an assertion because its bindingMetadata is absent or because of its content.

A claim generator that computes an ISCC soft binding should list its c2pa.soft-binding assertion in created_assertions. A validator or resolver shall not ignore or reject an ISCC soft binding because it is listed in gathered_assertions.

A C2PA Manifest should contain at most one ISCC soft binding.

EXAMPLE

This is the assertion that iscc-sdk soft-binding --no-semantic prints for the file image/demo.jpg of iscc-samples. It has the form of an assertion in a JSON manifest definition of c2pa-rs, as used by c2patool and c2pa-python. value holds the 136 bytes of the ISCC-SEQ as integers: Meta-Code, Content-Code, Data-Code and Instance-Code. "created": true makes c2pa-rs list the assertion in created_assertions.

{
  "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,
          118, 143, 170, 251, 253, 93, 231, 225, 98, 214, 134, 87, 54, 167, 209, 171,
          148, 63, 33, 7, 195, 67, 48, 158, 60, 158, 142, 103, 104, 225, 249, 124,
          134, 105, 26, 150, 198, 100, 50, 204, 114, 218, 229, 51, 71, 147, 201, 142,
          225, 201, 147, 101, 48, 7, 236, 234, 169, 93, 249, 226, 143, 208, 172, 164,
          43, 108, 46, 160, 17, 94, 154, 40, 108, 192, 116, 72, 30, 164, 16, 119,
          174, 199, 222, 2, 96, 30, 64, 7, 85, 82, 155, 250, 229, 189, 179, 213,
          48, 197, 47, 68, 209, 60, 205, 106, 124, 113, 15, 99, 98, 13, 194, 219,
          28, 67, 197, 89, 42, 226, 220, 151
        ]
      }
    ],
    "bindingMetadata": {
      "informationalUrl": "https://ieps.iscc.codes/iep-0020/",
      "io.iscc.generator": {
        "name": "iscc-sdk",
        "version": "0.9.7"
      }
    }
  }
}

5. Soft Binding Generation#

A claim generator shall generate each ISCC-UNIT of an ISCC soft binding from the source. It shall include the Data-Code and the Instance-Code of the source in each ISCC soft binding. It should include a Content-Code if the source contains text, image, audio or video content. It may include a Semantic-Code and a Meta-Code. It shall not include a featureless Image-Code.

NOTE 1

A Meta-Code is thus generated from metadata embedded in the source, such as its title, not from a file name. iscc-sdk leaves it out if the source has no embedded title.

NOTE 2

ISO 24138:2024 does not define an algorithm for the Semantic-Code. The Version 0 Semantic-Codes for text and image are those of iscc-sct and iscc-sci. They are generated with neural network models. Semantic-Codes generated from the same content on different platforms or by different implementations can therefore differ in some bits.


6. Matching#

A validator or resolver shall ignore, for matching, each ISCC-UNIT that it does not support or whose ISCC-BODY is shorter than 256 bits.

To verify an ISCC soft binding against an asset, a validator shall generate from the asset an ISCC-UNIT with the same MainType, SubType, Version and Length for each ISCC-UNIT of the ISCC soft binding that it does not ignore.

A validator or resolver shall compare two ISCC-SEQs by pairs of ISCC-UNITs, one from each, with the same MainType, SubType, Version and Length: Instance-Codes for equality, all others by their similarity in percent, S = ⌊100 × (n − d) / n⌋, where d is the number of bit positions in which the two ISCC-BODYs differ and n is the length of an ISCC-BODY in bits. It shall not compare a pair of Image-Codes if either is featureless.

NOTE 1

Featureless Image-Codes occur for uniform images, brightness gradients along one axis and plain stripes. Featureless Image-Codes of unrelated images can be as close as Image-Codes of the same image.

An ISCC soft binding and an ISCC-SEQ match if there is an exact match or a candidate match between them. A validator or resolver without thresholds of its own should apply a threshold of 80 (d ≤ 51).

NOTE 2

S is 100 for equal ISCC-BODYs and about 50 for unrelated inputs. Suitable thresholds depend on the MainType and SubType, the content and the catalog size.

A c2pa.soft-binding assertion with alg equal to io.iscc.v0 matches if one of its ISCC soft bindings matches. This is the matching to which Validating Soft Binding Matches of the C2PA Technical Specification refers.

The score of a match is 100 for an exact match. Otherwise, it is the highest similarity of a pair of Semantic-Codes, Content-Codes or Data-Codes, but at most 99. A validator should report for each match the similarity of every compared pair and whether the Instance-Codes are equal.

Validating a Match of the C2PA Technical Specification applies to each matching C2PA Manifest.

NOTE 3

An exact match shows that the query asset has the bytes from which the ISCC soft binding was generated. The hard binding of the C2PA Manifest can still fail for the query asset, because these bytes lack the C2PA Manifest Store that the claim generator embedded.


7. Soft Binding Resolution API#

In a query to the C2PA Soft Binding Resolution API with alg equal to io.iscc.v0, value shall be the base64 encoding of an ISCC-SEQ with padding characters, as specified in RFC 4648, section 4.

A resolver shall return the score of each match (see Matching) as similarityScore. It should list the matches in descending order of score.


8. Security Considerations#

The claim signature protects an ISCC soft binding through the hashed URI of its assertion. An ISCC-SEQ has no integrity protection of its own.

Only the Instance-Code is a cryptographic hash. A match of any other ISCC-UNIT shows that two inputs are similar, not that they are identical. Unrelated content can have similar ISCC-UNITs, and an attacker can alter content until its ISCC-UNITs come close to those of other content. A secondary check of each candidate match, suited to the media type, guards against both.

An Instance-Code in a C2PA Manifest is public, and anyone can copy it into another C2PA Manifest. An exact match therefore does not show that the other assertions of the matching C2PA Manifest apply to the query asset, or who created the content.


9. Reference Implementation#

iscc-core 1.5.0 encodes and decodes ISCC-SEQs (encode_seq, decode_seq). Earlier versions generate 256-bit Image-Codes that differ from those of the test vectors.

iscc-sdk 0.9.7 generates ISCC soft bindings as specified in this document. The Python function iscc_sdk.soft_binding() returns the ISCC-UNITs and the ISCC-SEQ. The command iscc-sdk soft-binding FILE prints the assertion, as in the EXAMPLE in Assertion. Its option --no-semantic leaves out Semantic-Codes. The function is_featureless_image_code() tests whether an Image-Code is featureless.


10. Test Vectors#

10.1 ISCC-SEQ#

Conforming encoders shall produce the ISCC-SEQ of the following ISCC-UNITs, in this order. Conforming decoders shall accept this ISCC-SEQ and return these ISCC-UNITs in this order.

ISCC-UNITs
ISCC:AADVPDD4R6733NMPFH3D57VTQ4KVH6VHL74XIWGUT37V5ZG56NV3NSI
ISCC:EAD2RASIYU5IKLENP2OFI4CHZGRWYQCSW2WKX3Y6FJGOCXSYNYGLGBI
ISCC:GADQLNA7GRZESMRF2J7NZPNWGI3II2ST5YUN5SS6GVQ2ZQGJXPPYDNI
ISCC:IAD2KIVPJIWJZP3KQCESJL6SVT5APEZUPOJWM6HVTAXCF7OT3VFA4NY
ISCC-SEQ bytes (hex)
0007578c7c8fbfbdb58f29f63efeb3871553faa75ff97458d49eff5ee4ddf36bb6c92007a88248c53a852c8d7e9c547047c9a36c4052b6acabef1e2a4ce15e586e0cb305300705b41f3472493225d27edcbdb63236846a53ee28deca5e3561acc0c9bbdf81b54007a522af4a2c9cbf6a808924afd2acfa0793347b936678f5982e22fdd3dd4a0e37
ISCC-SEQ canonical form
ISCC:AADVPDD4R6733NMPFH3D57VTQ4KVH6VHL74XIWGUT37V5ZG56NV3NSJAA6UIESGFHKCSZDL6TRKHAR6JUNWEAUVWVSV66HRKJTQV4WDOBSZQKMAHAW2B6NDSJEZCLUT63S63MMRWQRVFH3RI33FF4NLBVTAMTO67QG2UAB5FEKXUULE4X5VIBCJEV7JKZ6QHSM2HXE3GPD2ZQLRC7XJ52SQOG4
Resolution API value (base64)
AAdXjHyPv721jyn2Pv6zhxVT+qdf+XRY1J7/XuTd82u2ySAHqIJIxTqFLI1+nFRwR8mjbEBStqyr7x4qTOFeWG4MswUwBwW0HzRySTIl0n7cvbYyNoRqU+4o3speNWGswMm734G1QAelIq9KLJy/aoCJJK/SrPoHkzR7k2Z49ZguIv3T3UoONw==

Conforming decoders shall reject the byte strings in Table 2.

Table 2 – Byte strings that decoders shall reject

Bytes (hex) Reason
(empty) no ISCC-UNIT
28000100000000 nonzero header padding nibble (valid form 28000000000000)
200800 followed by 36 zero bytes Length field 8
3000000000 ISCC-BODY truncated (32-bit Data-Code with 3 body bytes)
30000000000000 trailing byte after a complete ISCC-UNIT
5005578c7c8fbfbdb58fa88248c53a852c8d05b41f3472493225a522af4a2c9cbf6a ISCC-CODE (MainType 5)
60100000000000000000 MainType 6

Conforming decoders shall accept 270000000000 (CONTENT, SubType 7, Version 0, 32 bits) and return ISCC:E4AAAAAAAA, although ISO 24138:2024 does not define SubType 7.

NOTE

The 32-bit acceptance test exercises the ISCC-SEQ codec only. It is not a conforming ISCC soft binding, which requires 256-bit ISCC-UNITs that include a Data-Code and an Instance-Code.

10.2 Featureless Image-Codes#

Conforming claim generators, validators and resolvers shall identify featureless Image-Codes as shown in Table 3.

Table 3 – Featureless Image-Codes

Image-Code Bits set to 1 per segment Featureless
ISCC:EEDYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 1, 0, 0, 0 yes
ISCC:EED74AAAAAAAAAAAVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKQ 7, 32, 32, 32 yes
ISCC:EED76AAAAAAAAAAAVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKQ 8, 32, 32, 32 no
ISCC:EED2VKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKAAAAAAAAAAAAA 32, 32, 32, 1 yes
ISCC:EED2VKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKVKQ 32, 32, 32, 32 no

10.3 Sample Inputs#

The file c2pa_vectors.json of iscc-sdk gives, for each input, its SHA-256 hash, the expected ISCC-UNITs and the ISCC-SEQ in hex and base64. An input is either a file of iscc-samples, given by its path relative to the files/ directory, or an embedded image. One embedded image is featureless, so its ISCC soft binding has no Image-Code. Four embedded images test the border trim. For each of them, image_crop gives the box (left, upper, right, lower) to which the image is cropped before Image-Code generation. One of these boxes is the full image, because the trim keeps its gradient border.

A claim generator should generate the same Meta-Codes, Content-Codes, Data-Codes and Instance-Codes from these inputs. The vectors contain no Semantic-Codes (see NOTE 2 in Soft Binding Generation).

NOTE

IEP-0004 specifies Image-Code conformance for the pre-processed 32 × 32 pixel input only. The Image-Codes of the vectors use the border trim of iscc-sdk 0.9.7 (image_trim_tolerant). Their Meta-Codes use the metadata that iscc-sdk 0.9.7 extracts from each file.


11. References#

11.1 Normative#

11.2 Informative#