Errata 2 for BRC-145: verifier verdict vocabulary, adopter-name profile, and dated forgery costs - #243
Open
RexStarBSV wants to merge 1 commit into
Open
Errata 2 for BRC-145: verifier verdict vocabulary, adopter-name profile, and dated forgery costs#243RexStarBSV wants to merge 1 commit into
RexStarBSV wants to merge 1 commit into
Conversation
…pe validation, the adopter-name profile, and dated forgery costs Section 7.3 enumerates a closed set of three statuses, so a verifier built from this text has nowhere to put a key or signature that did not parse and routes it into INVALID, which asserts a signature check ran and failed. This adds MALFORMED for inputs that did not parse and UNSUPPORTED for a record version the verifier does not implement, and requires that v be checked. Section 7.2 documents the record fields without requiring a verifier to validate the shape, so a record of the wrong shape reads OK. Shape validation is now required before OK, with MALFORMED as its verdict. Section 6 constrains the adopter name: printable UTF-8, no NUL, and no nkan/ prefix, which closes a preimage that would parse both as a fingerprint and as a glyph seed. Section Security Considerations date-stamps the visual-forgery figures as 2026 classical compute and adds the erosion note. No anchor, code, canonical seal, canonical record or signature changes value. Every test vector stands unaltered. An existing conformant writer stays conformant; the changes bind what a verifier checks and what it may report.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR amends
apps/0145.md. It follows PR #212, which merged three verification errata on 2026-08-10: rejection of a kind that is not encodable as valid UTF-8 (§4), the every-pixel check on an integer downscale (§5), and rejection of rendering-affecting ancillary PNG chunks (§5). Those three closed every divergence that touched a presented image. What remains is the signed-record verifier, plus three prose items, and this PR closes them.Scope statement first, because it is the important one. Every change below is verifier-side reporting or prose. No anchor, no
ik1code, no canonical seal, no canonical record byte and no signature changes value under any entry in this PR. Test vectors TV1 through TV7 stand unaltered, and an existing conformant writer stays conformant without touching a line. What changes is what a verifier is required to check before it speaks, and what verdict it is permitted to report when a check could not be performed.The reference implementation already behaves as described here. The defect is that a second implementation built strictly from the published text would not, and in two places the published text actively directs it to the wrong verdict.
1. §7.3 has no verdict for a check that never ran, and routes one into
INVALID(high)As merged. §7.3 opens a closed enumeration: "A verifier reports exactly one of:" followed by
INVALID,STALE,OK.INVALIDis defined by outcome: "the signature does not verify against the published key overSHA-256(canonical_record_bytes)."Why this is wrong. A truncated public key, a DER blob that will not decode, or an
OP_RETURNcontainer whose pushes do not parse (§7.1 already requires rejecting that container) all fail to verify, so §7.3's own definition sends them toINVALID.INVALIDis the maximum-severity verdict and it asserts a specific fact: a signature check ran and the signature was wrong. For what is nearly always a truncated paste, that is a false accusation of forgery. The Security Considerations section already states the correct principle, "INVALIDmeans a signature check was performed and failed", and then supplies no status for the case where no check was performed. The document is at odds with itself, and §7.3 wins for an implementer.Amendment. Add a
MALFORMEDstatus to §7.3 and make it fail-closed. Combined with §§2 and 3 below, §7.3 becomes:One clarification travels with this rewrite. §7.3 evaluates the signature against "the published key", while §7.1 pushes a public key into the output. The amendment makes the intent explicit: the key the status is evaluated against is the operator's out-of-band published key, and the on-chain key push is material for offline re-derivation, never the authority for
OK. A verifier that accepts the presenter's own key makesOKself-certifying.2. Nothing requires a verifier to check the record version, and an unknown version reports
OK(high)As merged.
vappears once, as a row in the §7.2 field table: "v| int | record version (1)". No sentence anywhere obliges a verifier to read it. §7.3 defines "OK, signature valid and fresh", with no version predicate, and §8's summary requires only that an on-chain record "be re-verified offline (signature + freshness) after parsing".Why this is wrong. A well-signed, fresh record of version 2, whose fields a version-1 verifier does not understand, reports
OKunder the merged text. The version-checking discipline the document applies rigorously to codes (§3, "the reader MUST reject it rather than assume SHA-256") is absent for records. The second half of this erratum, the obligation on an unavailable signature backend, is already present and correct in Security Considerations and needs no change.Amendment. Add
UNSUPPORTEDto §7.3 as above, and add to §7.2:3. The seven-field record shape is described, never required (high)
As merged. §7.2 introduces the field table with "The reference canary record has fields:". That is descriptive. §7.1 says the container is general. Nothing requires a verifier to reject a record with a missing field, an extra field, or a field of the wrong type, and §7.3 gives it no verdict to report if it tried.
Why this is wrong. A wrong-shaped record cannot be forged, since the signature covers whatever fields are present. It can be emitted by mistake, and under the merged text every verifier reports
OKwhile downstream readers disagree about what they are reading. A record missingblock_hashloses the anti-backdate binding §7.2 relies on, and still reportsOK.Amendment. Make the table normative and give it a verdict, by appending to §7.2:
4. The adopter name in the tamper fingerprint has no character profile (medium)
As merged. §6 constrains the adopter name only by normalization and length: "where
adopter_bytes = utf8(NFC(adopter)),len(adopter_bytes) ≤ 255(reject otherwise), andversiondefaults to1."Why this is wrong. The length prefix closes the adopter/payload boundary, which Security Considerations correctly credits. It does not close a cross-context shape.
u8(len(adopter_bytes))is a single byte chosen by the adopter name's own length, so a 105-byte adopter name beginningnkan/v1followed by a NUL yields a length byte0x69, which is ASCIIi. The fingerprint preimage then opens with the exact nine bytes ofINKAN_DOMAINand parses as a glyph seed under §2. One digest is simultaneously a valid fingerprint and a valid anchor. Every honest adopter name already conforms to the fix, so nothing in the field breaks.Amendment. Append to §6, after the length and normalization sentence:
Add the matching bullet to §8: "An adopter name MUST satisfy the §6 profile before it is used as a fingerprint domain."
5. Visual comparison has no ceiling, and no verdict rule below the full digest (medium)
As merged. §3 carries the label half correctly: "A short code is a label only; trust decisions MUST use the full 32-byte anchor." Security Considerations adds "Implementers MUST NOT market a seal as human-proof". Missing is any rule binding the GENUINE verdict itself, and the tier guidance "value-at-risk kinds SHOULD use
t1" reads as though a high tier makes a visual check adequate for a value-at-risk decision. It does not, at any tier.Amendment. Append to §5, after the verification paragraph:
6. The forgery-cost figures carry no epoch (medium)
As merged. Security Considerations states "a perfect visual collision costs on the order of
2^16 / 2^28 / 2^40renders (birthday) fort3 / t2 / t1", with no date and no decay note. The only occurrence of "quantum" in the document is the reserved signature-algorithm identifier in §7.2, which concerns signatures, not seal-forgery cost. A reader in 2036 has no notice that these numbers age.Amendment. Append to the "Seal forgery economics" bullet:
Not included
One erratum in the underlying standard's list has no counterpart here and needs no amendment: the audit-evidence pointer correction is internal repo hygiene, and
apps/0145.mdmakes no audit claim and carries no evidence path, so there is nothing to retarget. The pixel-level seal construction and the PNG palette and filter conventions remain deliberately out of scope per §5, and this PR does not reopen that decision.Test vectors
No test vector changes, and none is required. TV1 through TV7 are reproduced unchanged by an implementation carrying every amendment above, because every amendment constrains what a verifier reads and reports, never what a writer produces. TV7's canonical record already carries exactly the seven fields §7.2 now requires, its 222 canonical bytes and its DER signature are untouched, and the 339-byte
OP_RETURNscript is byte-identical before and after.The new obligations are exercised by inputs that no current vector contains and that produce no signed bytes: a public key truncated by one byte, a DER signature with a corrupted length octet, a record with
vset to 2, a record withblock_hashremoved, a record withseqcarried as a string, and an adopter name beginningnkan/. Each has a single correct verdict under the amended §7.3 and §6, and each is reportable without any new canonical form. Reviewers who want them pinned in the document can have a TV8 covering the five status outcomes; it would add no new signing material, only expected verdicts.To restate the guarantee in one line: this PR changes what a verifier is required to check and what it is permitted to say, and it changes nothing that anyone has ever hashed, rendered, signed or broadcast.