open-standards/wai/extensions/iscc.md
Transaction Science 1ff71887ff
Some checks failed
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 30s
wai-audit collector and player integration / does this change touch it (push) Successful in 24s
wai-app and Create / wai-app · does this change touch it (push) Successful in 21s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 28s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 33s
wai-key-proxy / does this change touch it (push) Successful in 27s
wai-fleet service / does this change touch it (push) Successful in 16s
WAI operation catalogue / does this change touch it (push) Successful in 24s
wai-ledger service / does this change touch it (push) Successful in 26s
wai-quantum for JavaScript / does this change touch it (push) Successful in 26s
wai-sink-android native sink library / does this change touch it (push) Successful in 32s
WAI Studio / does this change touch it (push) Successful in 32s
wai-quantum studio and desktop / does this change touch it (push) Successful in 44s
wai-sink-swift native sink package / does this change touch it (push) Successful in 34s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Successful in 2m16s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Failing after 7m31s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 6m13s
joule-moq-room room service / joule-moq-room, every target (push) Successful in 9m1s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 23s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 17s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Successful in 57s
wai-audit collector and player integration / collector · linux (push) Successful in 2m24s
wai-key-proxy / proxy · linux (push) Successful in 2m32s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m42s
wai-ledger service / service · linux (push) Successful in 3m21s
wai-fleet service / service · linux (push) Successful in 5m24s
wai-quantum for JavaScript / javascript · linux (push) Successful in 5m33s
wai-quantum studio and desktop / studio · browser (push) Successful in 5m13s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 9m58s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 12m36s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 13m27s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 11m10s
WAI Studio / Studio in WebKit · linux (push) Successful in 13m50s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 47s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 1m55s
wai-fleet service / service · macos (push) Successful in 1m5s
wai-ledger service / service · macos (push) Successful in 1m38s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 8m20s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 8m5s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Successful in 16m45s
wai-quantum studio and desktop / desktop app · macos (push) Failing after 12m13s
WAI Studio / Studio in Chromium and Firefox · macos (push) Failing after 12m25s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 17m39s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 2m42s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 7m51s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 8m29s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 9m9s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 18m57s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 7m7s
C2PA stores carry identity assertions, soft bindings and the ISCC identifier, trust lists are pinned by digest, and a detection verdict is a claim of its own
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]>
2026-11-10 15:25:49 -05:00

16 KiB
Raw Permalink Blame History

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 iscc module of wai-rs (feature iscc); the corpus is live-conformance/iscc/, and its second implementation is live-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 is 1609adb921983baf83f9aaf049ab8dc23f828c214f57c29e2bf852346c678eff; 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):

  1. the transform M of p: the transform below of each row, then of each column of the result, every value a binary64 number;
  2. 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;
  3. 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:

  1. each pixel's grey is (77 R + 150 G + 29 B + 128) >> 8;
  2. 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 is ab7589bdaddd974b4ff68924cc7b50ac9299f6171f60d7d3f1eb7c1704635db3: 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.json and pictures/, written from fixed seeds by wai_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.