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-09-24

Note

This document is a DRAFT. It specifies how the ISCC is used within the C2PA framework. This revision covers the value format of the C2PA soft binding algorithm io.iscc.v0 (entry 3 of the C2PA Soft Binding Algorithm List). Later revisions will add further requirements, for example for resolution services.

1. Introduction#

A C2PA soft binding is a fingerprint that identifies content after its manifest has been removed or the content has been re-encoded. The C2PA Technical Specification delegates the value format of each soft binding algorithm to its registry entry, and the entry for io.iscc.v0 defines none.

This document defines that format. The value is an ISCC-SEQ, a byte string that concatenates one or more 256-bit ISCC-UNITs of one asset. The C2PA Soft Binding Resolution API carries the same bytes in base64.


2. Scope#

This document specifies:

  1. the ISCC-SEQ byte format and its decoding;
  2. the value format of c2pa.soft-binding assertions with alg equal to io.iscc.v0;
  3. the value format of io.iscc.v0 queries to the C2PA Soft Binding Resolution API.

The requirements apply to claim generators that write ISCC soft bindings and to validators and resolvers that read them. The selection of ISCC-UNITs, the inputs from which they are generated, comparison rules and matching thresholds are out of scope.


3. Terminology#

The terms ISCC-UNIT, ISCC-HEADER, ISCC-BODY, ISCC-CODE, MainType, SubType, Version and Length apply as defined in ISO 24138:2024 and IEP-0001. The terms soft binding, block, claim generator, validator and resolver apply as defined in the C2PA Technical Specification.

ISCC-SEQ : Byte string formed by concatenating one or more ISCC-UNITs, each encoded as its ISCC-HEADER followed by its ISCC-BODY, without separators.


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 encoded 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, padded with one zero nibble where the number of nibbles is odd.
  4. Each Length field shall have a value from 0 to 7, denoting 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 ISCC-UNITs is not significant. An ISCC-SEQ may contain several ISCC-UNITs with the same MainType, SubType and Version.

NOTE 1: For the permitted MainTypes the ISCC-BODY length depends on the Length field only, so a decoder can delimit an ISCC-UNIT whose SubType or Version it does not know.

NOTE 2: An ISCC-SEQ with a single ISCC-UNIT is the byte encoding of that ISCC-UNIT as defined in ISO 24138:2024. For display, an ISCC-SEQ can be shown as ISCC: followed by the base32 encoding of the byte string, in the same way as a single ISCC-UNIT.

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 differ from the encoding of the decoded fields according to ISCC-SEQ Format, item 3.
  2. Reject the ISCC-SEQ if the MainType is not permitted by ISCC-SEQ Format, item 1, or if the Length field is greater than 7.
  3. Reject the ISCC-SEQ if fewer bytes remain than the ISCC-BODY requires.
  4. Emit the ISCC-UNIT, advance the offset past its ISCC-BODY and repeat while bytes remain.

A decoder shall not reject an ISCC-UNIT solely 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 carries 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[].value shall be a CBOR byte string (major type 2) whose content is an ISCC-SEQ
alg-params shall be absent

Every ISCC-UNIT in an io.iscc.v0 value shall have Version 0 and a 256-bit ISCC-BODY (Length field 7). A validator or resolver shall ignore, for matching, any ISCC-UNIT whose SubType it does not support or whose ISCC-BODY is shorter than 256 bits.

NOTE: io.iscc.v0 identifies the Version 0 algorithms of ISO 24138:2024. ISCC-UNITs of another Version require a new registry entry.

Whole-asset value with Meta-, Content-, Data- and Instance-Code (256 bits each)

blocks[].value is the 136-byte ISCC-SEQ of Test Vector 1; its CBOR encoding starts with 58 88 (byte string, length 136). With the reference implementation:

import base64
import iscc_core as ic

units = [
    "ISCC:AADVPDD4R6733NMPFH3D57VTQ4KVH6VHL74XIWGUT37V5ZG56NV3NSI",  # Meta-Code
    "ISCC:EAD2RASIYU5IKLENP2OFI4CHZGRWYQCSW2WKX3Y6FJGOCXSYNYGLGBI",  # Content-Code Text
    "ISCC:GADQLNA7GRZESMRF2J7NZPNWGI3II2ST5YUN5SS6GVQ2ZQGJXPPYDNI",  # Data-Code
    "ISCC:IAD2KIVPJIWJZP3KQCESJL6SVT5APEZUPOJWM6HVTAXCF7OT3VFA4NY",  # Instance-Code
]

# Claim generator: content of blocks[].value (CBOR byte string)
value = ic.encode_seq(units)  # 136 bytes

# Soft Binding Resolution API: value parameter or body member
query = base64.b64encode(value).decode("ascii")  # RFC 4648 section 4, padded

# Validator or resolver: back to ISCC-UNITs
assert ic.decode_seq(value) == units
assert ic.decode_seq(base64.b64decode(query)) == units

# Display
text = "ISCC:" + ic.encode_base32(value)

5. Soft Binding Resolution API#

  1. The alg parameter or member shall be io.iscc.v0.
  2. The value parameter of GET /matches/byBinding and the value member of the POST /matches/byBinding request body shall be the RFC 4648 section 4 (base64) encoding of the ISCC-SEQ byte string, with padding characters.
  3. In a GET request the base64 string shall be percent-encoded.
  4. A query ISCC-SEQ may contain any non-empty subset of the ISCC-UNITs stored for an asset.

NOTE: The C2PA specification requires "a base64-encoded string" without naming an alphabet or padding. All other base64 uses in the C2PA specification and its reference implementation are RFC 4648 section 4 with padding.


6. Security Considerations#

An ISCC-SEQ is a fingerprint, not a proof of integrity. The Decoding rules reject malformed framing without attempting recovery. They do not detect changes that preserve structural validity. Integrity protection within a C2PA manifest depends on claim signature validation. Unsigned Resolution API queries lack this protection.


7. Rationale#

  • Byte string, not text. The C2PA CDDL declares value as a byte string and the Resolution API base64-encodes it. Text inside the byte string would add a second encoding layer and enlarge the value by two thirds.
  • Plain concatenation. The ISCC-HEADER makes each ISCC-UNIT self-delimiting, so no envelope, count, separator or version field is needed, and a single ISCC-UNIT is a valid ISCC-SEQ. A format change requires a new registry entry.
  • 256-bit ISCC-UNITs. Soft binding resolution is a lookup in a catalog of unbounded size, where shorter ISCC-UNITs collide at random. IEP-0013 relies on 256-bit ISCC-UNITs for matching declarations across ISCC-HUBs for the same reason.
  • Standard base64 with padding. It is the only base64 form used by the C2PA specification and its reference implementation.

8. Reference Implementation#

iscc-core, the reference implementation published with ISO 24138:2024, already decomposes the base32 form of concatenated ISCC-UNIT bytes into its ISCC-UNITs (iscc_decompose). Version 1.4.0 adds encode_seq (ISCC-UNIT strings to ISCC-SEQ bytes) and decode_seq (ISCC-SEQ bytes to ISCC-UNIT strings) as strict byte-level helpers, together with conformance test vectors. Entry 3 of the C2PA Soft Binding Algorithm List should reference this document as its informationalUrl.


9. Test Vectors#

Conforming encoders shall produce, and conforming decoders shall accept, the following byte strings.

Vector 1 – the four ISCC-UNITs of the example above, in the given order:

bytes (hex):
0007578c7c8fbfbdb58f29f63efeb3871553faa75ff97458d49eff5ee4ddf36bb6c92007a88248c53a852c8d7e9c547047c9a36c4052b6acabef1e2a4ce15e586e0cb305300705b41f3472493225d27edcbdb63236846a53ee28deca5e3561acc0c9bbdf81b54007a522af4a2c9cbf6a808924afd2acfa0793347b936678f5982e22fdd3dd4a0e37

Resolution API value:
AAdXjHyPv721jyn2Pv6zhxVT+qdf+XRY1J7/XuTd82u2ySAHqIJIxTqFLI1+nFRwR8mjbEBStqyr7x4qTOFeWG4MswUwBwW0HzRySTIl0n7cvbYyNoRqU+4o3speNWGswMm734G1QAelIq9KLJy/aoCJJK/SrPoHkzR7k2Z49ZguIv3T3UoONw==

Vector 2 – mixed lengths with two CONTENT SubTypes, ISCC:EEAYYNMFG5XOELK2 (Image, 64 bits), ISCC:EIBZ6B7T76PAAYP7H334X77754376 (Audio, 128 bits) and ISCC:GADQLNA7GRZESMRF2J7NZPNWGI3II2ST5YUN5SS6GVQ2ZQGJXPPYDNI (Data, 256 bits):

21018c3585376ee22d5a22039f07f3ff9e0061ff3ef7cbffffef37ff300705b41f3472493225d27edcbdb63236846a53ee28deca5e3561acc0c9bbdf81b5

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 ISCC-ID (MainType 6)

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

NOTE: Vector 2 and the 32-bit acceptance test exercise the ISCC-SEQ codec only. Neither is a conforming io.iscc.v0 value, which requires 256-bit ISCC-UNITs.


10. References#

10.1 Normative#

10.2 Informative#