§5 Redaction (ADR-0006 — decided)
5.1 The problem
1.0 §7.5's literal { redacted: true, reason, salted_sha256 } is rejected by the metadata.redactions[] schema (which requires field and forbids redacted) and accepted by the unconstrained metadata.normalized object. The specification's own normative shape is legal only where nothing checks it. E15 resolved which shape belongs where. What E15 could not resolve is whether the proof is mandatory — the prose said the proof was the point, the schema made it optional, and one of the two had to change.
ADR-0006 is now decided: revised Option A, version-gated. It was the only open decision on the VER standards track, and it is closed.
5.2 Normative text (DRAFT)
In the reconciled view. A value removed under 1.0 §7.5 is replaced in place by a redacted-value object:
redactedMUST be the literaltrue;reasonis REQUIRED;commitment_sha256andcommitment_algare present together or not at all; no other member is permitted. The key is retained inmetadata.normalizedso that a Consumer can tell “removed by the Producer” from “never present”, which is the entire point of theredactedavailability state (1.0 §7.2). The shape is schema-encoded for any top-level value ofmetadata.normalizedthat carries aredactedmember; nested occurrences are profile-checked, because the rest of that view's vocabulary belongs to IPTC and not to VER (§15.4).In the ledger. The corresponding
metadata.redactions[]entry is the record-level ledger. In 1.1 it carries:
stateis REQUIRED and isproducer_performedorupstream_withheld.- **
state: "producer_performed"REQUIREScommitment_sha256andcommitment_alg** (schema-encoded). The Producer held the value; a commitment is therefore possible, and a redaction claim without one is a claim with nothing behind it.state: "upstream_withheld"MUST NOT carry either (schema-encoded). The Producer never received the value, so any commitment over it would be a fabrication. This is the case Option A could not express and Option B answered by weakening everything: a platform stripped the field before acquisition, and the honest statement is “this is absent, and here is why”, not a proof of something never held.commitment_algis"ver-redaction-commitment/1"— the construction is intrinsic to the identifier (§5.3), as withbundle_digest_alg.normalized_pointeris an RFC 6901 JSON Pointer, relative tometadata.normalized, addressing the redacted-value object. Where both carry a commitment, the two values MUST be equal (profile-enforced — comparing two members is outside JSON Schema).- The availability state and the ledger MUST agree. A
producer_performedentry's family isredacted; anupstream_withheldentry's family isupstream_withheld.VER1001enforces the pairing.
metadata.availabilitygainsupstream_withheld(§10.3), a 1.1 enum extension alongside the existing five states. It is distinct fromstripped_suspected, which is a belief about what an upstream did, and fromabsent, which says nothing about why.The in-view object for an
upstream_withheldfield carriesredacted: trueand itsreason, and no commitment:
redacted: truemarks the key as deliberately empty — the reason a Consumer can tell “nothing is stated here, and here is why” from “this key was never considered”. Which kind of emptiness it is comes from the ledger'sstateand the family's availability state, not from the in-view object, which is why the object needs no fourth member.The E15 carve-out is restated normatively for 1.1: a Record MUST NOT preserve a raw segment that still contains a value the Record claims to have redacted.
Two consequences of the carve-out, stated because the audit found each one assumed rather than written. Omission is family-granular for a multi-segment family: a family whose segments are partially omitted re-assembles to bytes the Producer never held — partial evidence wearing a byte-exact claim — so a redaction that requires omitting any segment of a family omits every segment of it, and §10.1's contiguity rule therefore never meets a legitimately gapped family. And
reasoncarries the reason, never the value: neither the ledger entry'sreasonnor the in-view object's MUST contain the redacted value or a recoverable transform of it — a redaction annotated with its own preimage is not a redaction.
Redaction and raw segments. E15's carve-out has exactly one conformant execution in 1.0.x and in 1.1: the segment is omitted from raw[] entirely. Scrubbing the value inside the segment and preserving the scrubbed bytes is not representable, because nothing in the Record distinguishes a scrubbed segment from acquired evidence — a scrubbed segment would masquerade as a byte-exact acquisition record, which is worse than an absent one. Whether 1.1 adds an explicit scrubbed-segment carriage — a marker on the raw[] entry, with the entry's sha256 computed over the scrubbed bytes and the availability state saying so — remains a ratification item (§17, RELEASE.md). This draft does not decide it, and until it is decided the 1.0.1 rule stands unchanged for 1.1 Records.
5.3 ver-redaction-commitment/1
where:
"VER-REDACTION-COMMITMENT-1"is the 26 ASCII octets of that string, with no terminator — the domain tag, so a commitment digest can never collide with a digest computed for any other purpose in this standard;len8(x)is the octet length ofxas an **8-octet big-endian unsigned integer**. Both lengths are present because a preimage that concatenates two variable-length fields without framing is ambiguous — the same defect this standard eliminated forpixel_hashand for the bundle manifest (SC-03);saltis the raw salt octets, at least 16 octets (128 bits), unique per(producer, field, asset)or better, and never derived from the redacted value;JCS(value)is the RFC 8785 canonical serialization of the value **as it appeared in the normalized view** — so a string value is serialized with its JSON quoting and escaping, and a structured value is serialized as the object or array it was. Hashing a bare unquoted string would make the commitment depend on a serialization nobody wrote down.The salt MUST NOT appear in any Record, in any form, including inside
extensions.
What this is, and what it is not — stated because the 1.0 prose overclaimed.
A commitment binds the Producer to a value no later than the moment the Record is signed. Given the salt and a candidate value, any holder of the Record can confirm or refute that the Producer committed to that value.
A commitment is not proof that the value ever existed in the Asset. A Producer can commit to anything it likes; the digest attests to a commitment, not to a history. 1.0 §7.5's “prove a value existed” is an overstatement, and 1.1 does not repeat it. Evidence that a value was in the Asset requires a signature over the Asset's metadata by a party the Consumer trusts — which is what C2PA is for.
Third-party verification requires controlled salt disclosure to an authorized challenger. There is no way around this: the salt is what makes the digest non-invertible, and without it a challenger cannot compute anything. The protocol for disclosing a salt to an authorized challenger — who is authorized, over what channel, with what audit trail, and with what protection against a challenger who guesses low-entropy values — is explicitly out of scope for VER 1.1. Producers deploying redaction in a regulated context need that protocol and MUST NOT assume this standard supplies it.
1.0.x is unchanged. salted_sha256 keeps its 1.0.x spelling, stays optional there, and VER1002 remains a warning for 1.0.x Records. The rename to commitment_sha256 and the requirement bind Records declaring ver_version: "1.1" and no others — the same version-gated mechanism ADR-0008 uses, permitted by VERSIONING.md §2.2.
5.4 Redaction reaches derived artifacts (ADR-0009)
The machinery above is metadata-plane machinery, and the 30–31 August audit demonstrated that a removed value survives it through channels §5.2 never reaches: a contextual embedding computed from the redacted caption inverts to an approximation of the text; source.text_sha256 — a REQUIRED, unsalted, undomained digest of the source text — is a confirmation oracle sitting one member away from a commitment construction (§5.3) whose framed, salted preimage exists to prevent exactly that; a fused vector carries the same leak one recipe hop away. A redaction the derived artifacts undo is annotated, not performed.
A Record MUST NOT carry an artifact derived from a value the Record redacts. In particular:
- an
embeddings[]entry whosesourcetext is, or contains, a redacted value MUST be omitted — itssourceblock andtext_sha256with it. An unsalted digest of a withheld value is a confirmation oracle, and carrying one beside a §5.3 commitment defeats the commitment's design;- a
fusedembedding whoserecipeconsumed such an embedding MUST be omitted, or recomputed without that input and re-declared;- no other member of the Record —
metadata.trust[],conflicts[], eitherreasonmember (§5.2),extensions(§13) — may restate the redacted value or a recoverable transform of it.Profile enforcement is necessarily partial (§15.4). Where a redacted normalized field maps by exact name to contextual source classes, a carried embedding of that class is mechanically decidable and draws
VER1011:
Redacted normalized field source.classvalues withdrawn with itdc:titletitledc:descriptiondescription,caption_auto,caption_humanIptc4xmpExt:AltTextAccessibilityalt_textThe map is deliberately small and exact: growing it is additive registry-style work, never inference from a field name's shape. Every derivation the map does not reach — vendor field names,
surrounding_textandpage_contextsources, fused recipes, values burned into pixels that anocr_pixelsembedding reads back out — remains the Producer's duty under the MUST above, undetectable from the Record alone and recorded as such in §15.4.
An upstream_withheld field admits no derived artifact either, for the simpler reason that there was nothing to derive from: a carried embedding whose source class maps to a field the Producer claims never to have received contradicts the Record's own account, and draws the same VER1011.
5.5 Privacy considerations (informative)
Nothing in this section is a conformance requirement; it is the analysis a deployer is owed in one place, consolidated here because 1.1 is where every new privacy surface lives.
- Pixels are not anonymized by metadata removal. Faces, documents, license plates, storefronts and skylines live in the pixel data the canonical embedding is computed from; the
ocr_pixelssource class exists precisely because text lives there too. Removing every metadata byte leaves all of it. Nothing in this standard de-identifies an image, and no conformance claim should be read as saying otherwise. - The identity tier is a correlation surface by design.
pixel_hashis a cross-producer rendered-identity grouping key (E27): that is the standard's purpose, and it cuts both ways. A producer that redacts every metadata field and publishes the identity tier has published the key that links its record to every other producer's record of the same rendered image — including ones carrying everything it withheld.content_hashis additionally a confirmation oracle for anyone holding candidate bytes, and perceptual digests widen the join to near-duplicates. A deployment for which that linkage is itself sensitive has one lever: publish less (the wire profile's restrictive modes), because the linkage cannot be published and prevented at once. - A preserved raw segment is a container. Byte-exact preservation (E11) carries everything inside the container: EXIF
IFD1embedded thumbnails — which can show a pre-crop, pre-edit image — maker notes bearing serials and firmware detail, XMP history with usernames and tool paths. E15's remedy is segment-granular precisely because partial scrubbing masquerades as evidence (§5.2); the Producer deciding whether a segment is safe to preserve is deciding for the whole container, named parts included. - Non-metadata channels carry identity. Acquisition and chain URIs (§2.3.2) name locations — and locations name usernames, tenants and internal hosts. A chain
uriis a Producer's claim about where, not an integrity binding (§15.3), so publishing a generalized location is conformant, and URIs SHOULD NOT carry credentials, tokens, or private-infrastructure detail.actorstrings can name people. Lineage parents (§3) disclose the existence, location and digests of assets that may themselves be private. A preservedc2pasegment carries the signer's certificate chain by C2PA's own design, and a JWS header carries akid. A publishing Producer reviews these with the same eyes as metadata. - References resolve to the unredacted world.
source_bytes_refnames the original Asset bytes — E25 binds its digest tocontent_hash— and a segment'sbytes_refnames bytes the inline form omitted. A Record that declares redactions SHOULD NOT carry openly resolvable references to the unredacted material; access control at the reference target is the deployment's lever. A Consumer MUST NOT treat the presence of a reference as authorization to fetch, cache, or republish its target; §10.1 already makes an unresolvable reference "unavailable, not absent", and that rule is this one's complement. - Sensitive-by-default guidance, non-exhaustive: precise location; device and hardware serials; owner and account identifiers; biometric and person-identifying annotations; private captions and notes; acquisition paths or URLs bearing usernames or tenant identifiers; maker notes; embedded thumbnails.
reasonstays free text (§2.4's registry logic does not govern it), and §5.4 already forbids the one abuse that matters: the reason must never carry the value. - No legal equivalence. Conformance with this standard — this section included — is not compliance with GDPR, CCPA, HIPAA, biometric-privacy law, or any other regime. A commitment digest does not de-identify a value and a salted hash is not anonymous by default; whether a digest of personal data is itself personal data is a legal question this standard does not answer. Deletion from the normalized view is not deletion from the Record — that asymmetry is E15's entire subject.
- Published examples publish their preimages. Every commitment in this repository's examples and fixtures documents its salt or preimage so that the digests are reproducible (E26); that makes them dictionary-invertible by construction, which is acceptable for illustrative values and fatal for real ones. A real deployment's salt is never written anywhere a reader of the Record can reach (§5.3).
