c2pa-binding §4.8 to §4.10 and §6.4: after its three assertions a store of wai.asset.c2pa may carry wai-mark:tent64 as a C2PA soft-binding assertion naming its robustness claim, the envelope's ISCC identifier, and the Creator Assertions Working Group's identity assertions (1.3, cawg.x509.cose); a verifier may hold its anchors as trust lists in the C2PA Trust List's form, pinned by the SHA-256 of their bytes. The algorithm-list entries for tent64 and band64 are written in extensions/c2pa-soft-binding-entries.json. extensions/iscc.md: ISO 24138's codec, ISCC-SEQ, Instance-, Image- and Audio-Codes and the ISCC-CODE from the IEP texts, replaying the public test vectors; WAI's integer pre-processing. extensions/detection.md: wai.media.detection, a detector's signed verdict at an operating point named by digest, its evidence a robustness record of binding type detector; refused as provenance, never a change to an origin claim's class. Corpora c2pa-identity/, iscc/ and detection/, each with a second implementation in Python. Co-Authored-By: Claude Opus 5.5 <[email protected]>
16 KiB
WAI Extension: ISCC Content Identifiers
Status: Draft. The International Standard Content Code of ISO 24138:2024 as WAI computes it from the standard's public texts: the codec of an ISCC (its header, its canonical form and the ISCC-SEQ of IEP-0020), the Instance-Code of any bytes, the Image-Code of a picture, the Audio-Code of a Chromaprint fingerprint, the composite ISCC-CODE, and the matching of an ISCC soft binding against an asset. The Image-Code's transform is written out here, with a pinned table of cosines, so that every implementation that follows this text gets the same bits; the 32 × 32 picture it reads is WAI's own pre-processing of a decoded picture, in integers. Every code replays the standard's public test vectors. A store of c2pa-binding carries an envelope's codes as its ISCC identifier (§4.9 there). No record is registered and no transport changes. The reference implementation is the
isccmodule ofwai-rs(featureiscc); the corpus islive-conformance/iscc/, and its second implementation islive-conformance/iscc_verify.py. Keywords MUST, MUST NOT, SHOULD, MAY are RFC 2119/8174.Texts read for this revision, each pinned to the version named, as fetched on 10 November 2026: the ISCC Enhancement Proposals that are the drafts contributed to ISO TC 46/SC 9/WG 18 for ISO 24138:2024 — IEP-0001 (ISCC Structure and Format, updated 2026-07-03), IEP-0003 (Text-Code, updated 2026-01-19), IEP-0004 (Image-Code, updated 2026-10-21), IEP-0005 (Audio-Code, updated 2026-01-19), IEP-0006 (Video-Code), IEP-0008 (Data-Code), IEP-0009 (Instance-Code) and IEP-0010 (ISCC-CODE), each updated 2026-01-19 — and IEP-0020 (ISCC C2PA Conformance, a draft updated 2026-10-28), which specifies the C2PA soft-binding algorithm
io.iscc.v0; the conformance data of the ISCC reference implementation, version 1.5.0, a JSON file of test vectors whose SHA-256 is1609adb921983baf83f9aaf049ab8dc23f828c214f57c29e2bf852346c678eff; the C2PA soft-binding algorithm list's entry 3,io.iscc.v0; and RFC 4648. The text of ISO 24138:2024 itself was not read. A section number of an IEP in this text is that IEP's.
1. Scope
In scope: the header and the canonical form of an ISCC (§3.1, §3.2); the ISCC-SEQ (§3.3); the Instance-Code (§4.1), the Image-Code (§4.2) and the picture it reads (§4.3), the Audio-Code (§4.4) and the ISCC-CODE (§4.5); matching an ISCC soft binding against an asset (§5); and conformance (§6).
Out of scope: the Meta-, Text-, Video-, Mixed- and Data-Codes, and the Semantic-Codes. The texts read state their algorithms in prose and leave their tables (the minhash permutations of the Text- and Data-Codes, the content-defined chunking table of the Data-Code, the winner-take-all permutations of the Video-Code) to the reference implementation's source and to ISO 24138's text, neither of which this revision reads, so it computes none of them; an ISCC that holds one is read, carried and compared as §5 says. Also out of scope: computing a Chromaprint fingerprint or an MPEG-7 video signature from samples (the inputs IEP-0005 and IEP-0006 name), extracting text from a document, the ISCC-ID (IEP-0011), and ISCC metadata (IEP-0012).
2. Terms
- ISCC-UNIT: an ISCC of one algorithm: MainType META (0), SEMANTIC (1), CONTENT (2), DATA (3) or INSTANCE (4) (IEP-0001 §4.1).
- ISCC-CODE: an ISCC of MainType ISCC (5): headerless units composed under one header (§4.5).
- ISCC-SEQ: units, each with its header, concatenated (IEP-0020 §4.1).
- Picture: an image's 8-bit RGB samples, row-major; a grey sample stands for R = G = B.
- A digest named BLAKE3 is BLAKE3's 256-bit output; base32 is RFC 4648 §6's alphabet without padding; base64 RFC 4648 §4's with padding.
3. The codec
3.1 The header
An ISCC is its header and its body (IEP-0001 §3). The header is four fields in order,
MainType, SubType, Version and Length, each an integer from 0 to 4679 written as nibbles: from 0
to 7 as one nibble 0xxx; from 8 to 71 as 10 and six bits of the value less 8; from 72 to 583
as 110 and nine bits of the value less 72; from 584 to 4679 as 1110 and twelve bits of the
value less 584 (IEP-0001 Table 1). The nibbles are written high nibble first, and a header of an
odd number of nibbles ends with a zero nibble. A header is read only if its bytes are exactly the
encoding of the fields read: a padding nibble other than zero is refused.
The SubTypes of CONTENT, SEMANTIC and ISCC are TEXT (0), IMAGE (1), AUDIO (2), VIDEO (3) and MIXED (4); an ISCC-CODE adds SUM (5) and NONE (6); META, DATA and INSTANCE have SubType 0. Every Version is 0.
3.2 The canonical form
The body of a unit holds 32 × (Length + 1) bits, Length from 0 to 7 (IEP-0001 §4.4.1). The body
of an ISCC-CODE holds 128 bits and 64 more for each set bit of its Length, Length from 0 to 7
(§4.4.2 there). The canonical form of an ISCC is ISCC: and the base32 of its header and
body (§6.1 there); one is read only if it decodes to exactly one ISCC and its last character
carries no bit beyond the bytes.
3.3 The ISCC-SEQ
An ISCC-SEQ (IEP-0020 §4.1) is one or more units of MainType 0 to 4, each its header immediately
followed by its body, with nothing between, before or after them. Its order is not significant,
and a sequence may hold several units of one type. It is read from its first byte (§4.2 there):
the header at the offset, refused where the bytes end before it is complete (header_truncated)
or are not its fields' encoding (header_not_canonical); its MainType, refused above 4
(main_type); its Length, refused above 7 (length); its body, refused where fewer bytes remain
(body_truncated); then the next unit, until no byte remains. An empty sequence is refused
(no_unit). A unit of a SubType or Version this text does not name is read as it is, never
dropped or reordered.
4. The codes
4.1 The Instance-Code
The Instance-Code of bytes at n bits (a multiple of 32 from 32 to 256) is the unit (INSTANCE, 0, 0, n/32 − 1) whose body is the first n/8 bytes of the bytes' BLAKE3 digest (IEP-0009 §5). Two equal Instance-Codes of 256 bits show the same bytes.
4.2 The Image-Code
The Image-Code of a 32 × 32 grey picture p (row-major, one byte a pixel) at n bits (64, 128, 192 or 256) is the unit (CONTENT, IMAGE, 0, n/32 − 1) whose body is (IEP-0004 §5):
- the transform M of p: the transform below of each row, then of each column of the result, every value a binary64 number;
- for each square in this order, as many as n/64: the 8 × 8 values of M whose column and row begin at (0, 0), (8, 0), (0, 8) and (8, 8), the quadrants of M's first 16 × 16 (IEP-0004 §5, Clarification): taken row by row, their median is the mean, (a + b) / 2, of the 32nd and 33rd of them in ascending order, and each gives the bit 1 where it is greater than the median and 0 otherwise;
- the bits in that order, eight to a byte, the first bit the most significant.
The transform of a list v of length N (32, 16, 8, 4, 2 or 1) is the unscaled DCT-II, Xₖ = Σₙ vₙ cos(π (n + ½) k / N), computed by this recursion and no other, so that its rounding is the same everywhere: for N = 1, v; otherwise, with h = N/2, αᵢ = vᵢ + v{N−1−i} and βᵢ = (vᵢ − v{N−1−i}) / (2 c(N, i)) for i below h, their transforms A and B, and the output A₀, B₀ + B₁, A₁, B₁ + B₂, …, A{h−2}, B{h−2} + B{h−1}, A{h−1}, B_{h−1}. Every operation is binary64 arithmetic, rounded to nearest, in the order written; c(N, i) is cos(π (i + ½) / N), taken from this table of binary64 bit patterns rather than computed:
| N | c(N, 0) … c(N, N/2 − 1) |
|---|---|
| 32 | 3feff621e3796d7e 3fefa7557f08a517 3fef0a7efb9230d7 3fee212104f686e5 3feced7af43cc773 3feb728345196e3e 3fe9b3e047f38741 3fe7b5df226aafb0 3fe57d69348cec9f 3fe30ff7fce17036 3fe073879922ffed 3fdb5d1009e15cc2 3fd58f9a75ab1fdd 3fcf19f97b215f1e 3fc2c8106e8e613a 3fa91f65f10dd824 |
| 16 | 3fefd88da3d12526 3fee9f4156c62dda 3fec38b2f180bdb1 3fe8bc806b151741 3fe44cf325091dd6 3fde2b5d3806f63e 3fd294062ed59f05 3fb917a6bc29b438 |
| 8 | 3fef6297cff75cb0 3fea9b66290ea1a3 3fe1c73b39ae68c9 3fc8f8b83c69a60d |
| 4 | 3fed906bcf328d46 3fd87de2a6aea964 |
| 2 | 3fe6a09e667f3bcd |
Each is within one unit in the last place of the cosine. A constant row has, by this recursion, every value but the first exactly zero, which IEP-0004's vectors of a uniform picture require.
4.3 The picture an Image-Code reads
IEP-0004 makes the Image-Code's behaviour normative only from the 32 × 32 grey picture (§6 there) and leaves the way to it to the implementation. WAI's is a function of a decoded picture's samples alone, in integers:
- each pixel's grey is (77 R + 150 G + 29 B + 128) >> 8;
- the picture of W × H (both at least 1) becomes 32 × 32 by area: output pixel (x, y) covers the source area from x W/32 to (x + 1) W/32 across and from y H/32 to (y + 1) H/32 down; each source pixel weighs the area it shares with it, measured in thirty-seconds of a pixel along each axis; and the output is the weighted sum of the greys plus ⌊W H/2⌋, divided by W H, rounded down, the weights of every output pixel summing to W H.
IEP-0004 §5's steps turn a picture by its orientation tag, put a transparent one on white, crop uniform borders and resize by bicubic interpolation. A WAI picture is decoded from a PNG without an orientation tag or an alpha channel; this pre-processing crops nothing and resizes by area. Another tool's 32 × 32 picture of the same picture may differ, and so may its Image-Code: the Image-Code this text writes is reproduced by this pre-processing, and compared with another tool's by similarity (§5).
4.4 The Audio-Code
The Audio-Code of a Chromaprint fingerprint f, a list of 32-bit signed integers, at n bits (a multiple of 32 up to 256) is the unit (CONTENT, AUDIO, 0, n/32 − 1) whose body is the first n/8 bytes of the concatenation of the 4-byte hash of (IEP-0005 §5): f; each of f's four consecutive quarters; and each of three consecutive thirds of f sorted in ascending order. A list of L values is split into k parts of which the first L mod k hold ⌊L/k⌋ + 1 values and the rest ⌊L/k⌋. The hash of a list of m values, each read as its 32 bits, is the 32-bit word whose bit b is 1 where at least half of the values have bit b set (2 c ≥ m), written most significant byte first; of no value, four zero bytes.
4.5 The ISCC-CODE
Units compose to an ISCC-CODE (IEP-0010 §6): at most one of each MainType, among them a Data-Code and an Instance-Code, each of at least 64 bits, and a Semantic-Code and a Content-Code, where both are given, of one SubType. In the order META, SEMANTIC, CONTENT, DATA, INSTANCE, each unit's first 64 bits make the body. The header is (ISCC, S, 0, L): S the Content-Code's SubType, else the Semantic-Code's, else NONE where a Meta-Code is given, else SUM; L's three bits, from the most significant, a Meta-Code, a Semantic-Code and a Content-Code given. This text computes no Data-Code (§1), so it composes an ISCC-CODE from units it is given.
5. Matching
An ISCC soft binding (IEP-0020 §4.3) is an ISCC-SEQ in a block of a C2PA soft-binding assertion of
algorithm io.iscc.v0. Matching one against an asset (§6 there) compares, for each unit of the
binding of Version 0 and 256 bits that this text computes, the unit of the same type and length
computed from the asset, and ignores every other unit:
- an Instance-Code with the asset bytes' Instance-Code: equal is an exact match;
- an Image-Code with the Image-Code of the asset's picture (§4.3), unless either is featureless — at least one complete 64-bit segment of its body has fewer than eight bits set (§3 there) — by similarity S = ⌊100 (n − d) / n⌋, d the bits in which the bodies differ and n the bits of a body: S at or above the threshold is a candidate match. A validator with no threshold of its own uses 80.
The binding matches where a pair is an exact or a candidate match. Its score is 100 for an exact match, and otherwise the highest similarity of a compared pair other than the Instance-Codes, at most 99; with nothing compared, there is no score. A match reports each pair compared, its similarity, and whether the Instance-Codes are equal. A similar Image-Code shows a similar picture, not the same one; only the Instance-Code shows the same bytes (§8 there).
6. Conformance
live-conformance/iscc/ holds:
public.json, the public test vectors, transcribed and not generated, whose SHA-256 isab7589bdaddd974b4ff68924cc7b50ac9299f6171f60d7d3f1eb7c1704635db3: the cases of the reference implementation's conformance data, version 1.5.0, for the Image-Code from 32 × 32 grey pictures, the Audio-Code from Chromaprint fingerprints, the Instance-Code from bytes, the ISCC-CODE from units, and the ISCC-SEQ's encoding and decoding; and IEP-0020 §10.1's sequence with its canonical form and base64, Table 2's sequences a decoder refuses, the sequence it accepts of a SubType ISO 24138 does not define, and Table 3's featureless Image-Codes;vectors.jsonandpictures/, written from fixed seeds bywai_iscc_vectors gen: pictures the generator draws, among them sizes prime to 32, a strip, a single pixel and a picture smaller than 32 each way, each with the SHA-256 of its 32 × 32 picture (§4.3), its Image-Code and whether it is featureless; and soft bindings matched against pictures (§5): the same picture, the picture at half size, the picture after one pixel of it was altered (no exact match), another picture, a featureless binding, and a binding of units this text ignores.
A conforming implementation gives every case the code, the units, the refusal or the match the
corpus states. wai_iscc_vectors verify and the test tests/iscc.rs check that every generated
file regenerates byte for byte, that no other file but README.md and public.json is there,
that every public vector replays, that every case gets its outcome, and that public.json is the
file this section pins. live-conformance/iscc_verify.py is the second implementation, written
from this text and the texts it reads: it shares no code with wai-rs; it decodes the PNGs with
an inflater of its own, hashes with BLAKE3 from claim-conformance/_blake3.py, replays every
public vector, gives every case the same outcome, and requires every mutated copy of a case to be
refused or to change its outcome.
7. Security and privacy considerations
- Similar is not the same. Only the Instance-Code is a cryptographic hash. Unrelated pictures can have similar Image-Codes, a featureless one most of all, which is why it is never compared, and content can be altered until its codes come near another's (IEP-0020 §8). A candidate match is a lead for a check suited to the content, never a binding.
- A copied code. An Instance-Code in a store is public, and anyone can copy it into another store. The ISCC identifier of c2pa-binding §4.9 is signed into its store's claim and recomputed from the envelope the store binds, so a copied identifier does not verify beside other bytes.
- Pre-processing. An Image-Code is as stable as the 32 × 32 picture it reads. Two tools that pre-process one picture differently can give codes further apart than two pictures give one tool; a party matching across tools sets its threshold for that.
- Privacy. A code identifies content, not a person. It can tell that two copies are the same or alike, which is what it is for: publishing a code of content publishes that ability.