Skip to content

Compare 51Did factor words ignoring case, and name the version of a short payload - #141

Merged
jwrosewell merged 2 commits into
rcfrom
fix/did-spec-divergences
Nov 15, 2026
Merged

jwrosewell merged 2 commits into
rcfrom
fix/did-spec-divergences

Conversation

@jwrosewell

@jwrosewell jwrosewell commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Two places where the 51Did package differs from the specification, found by a conformance check of this package against specifications at 706de1f0.

1. Factor words were compared with case

package-surface.md lines 94 to 97 say:

The server sends these as the lower case words verified, mismatch, misconfigured and notrecorded. The comparison ignores case, as .NET does, so a package whose language compares exactly, such as Java, MUST lower-case the word before it compares.

RedeemResult.Factor.fromValue compared the word exactly, so Verified or NotRecorded read as a mismatch, which reports a difference the identifier never claimed. It now lower-cases the word in the root locale before comparing, so a Turkish default locale cannot turn the I of VERIFIED into a dotless i. A word it does not know still reads as a mismatch.

The specification states the case rule for the factor words only. The signature and context words (Signature.fromValue and Context.fromValue in the same file) are still compared exactly, as the specification says nothing about their case.

2. A short payload was refused without naming its version

identifier-layout.md lines 260 to 262 say:

A reader MUST refuse a Payload whose version it does not know. It MUST report it the way it reports a Payload it cannot read, naming the version it found, and it MUST NOT read the fields as though the version were 0.

FodId.read checked that the payload held the five byte header before it read the version from the first byte, so a payload of one to four bytes whose Flags byte names version 1, 2 or 3 was refused as too short, without naming the version. The version is now read first, so such a payload is refused as UNSUPPORTED_PAYLOAD_VERSION, and the throwing readers' message names the version. A short payload of version 0 is still too short, and an empty payload is too short as it has no Flags byte.

Tests

Tests first, in 59c099f3.

  • DidClientTests.redeem_FactorWordsInOtherLetters_ReadAsTheirOutcome sets the default locale to tr-TR, has the redeem answer give Verified, NotRecorded, MISCONFIGURED, VERIFIED and Mismatch, and expects each to read as its own outcome.
  • FodIdParseTests.version_ShortPayload_IsRefusedNamingTheVersion gives signed payloads of one to four bytes, expects version 0 refused as too short, and versions 1, 2 and 3 refused as UNSUPPORTED_PAYLOAD_VERSION with that version, no value, and a thrown message naming the version.

Red 43614985773 on 59c099f plus a throwaway workflow, Java 17. Exactly the two new tests fail, DidClientTests 1 of 87 with "expected: but was:" and FodIdParseTests 1 of 39 with "length 1 version 1 expected:<UNSUPPORTED_PAYLOAD_VERSION> but was:<PAYLOAD_TOO_SHORT>".

Green 43614986008 on the fix a200585e plus the same workflow. DidClientTests 87 of 87 and FodIdParseTests 39 of 39.

Full build

Run 43615412005 built a200585 merged with rc (b33daa0) on nine configurations, Ubuntu x64 with Java 8, 11, 17 and 21, Ubuntu arm64 with Java 17, and Windows with Java 8, 11, 17 and 21, and every job passed. DidClientTests passed 87 of 87 and FodIdParseTests 39 of 39 in all nine jobs. Each of its ten Setting 'PullRequestSha' lines names a200585, and its Configure job printed "Left out 6 macOS entries".

macOS was left out of this draft's full build under the 9 November decision. The rc head is built with macOS before it merges into main.

Before you upgrade

  • A factor word that a redeem answer gives in other letters, such as Verified or NotRecorded, now reads as its own outcome, where it read as MISMATCH. The specification says the server sends the words in lower case, so an application sees a change only when a word reaches it in other letters.
  • A payload of one to four bytes whose Flags byte names version 1, 2 or 3 is now refused as UNSUPPORTED_PAYLOAD_VERSION, naming that version, where it was refused as PAYLOAD_TOO_SHORT. Code that looks for PAYLOAD_TOO_SHORT to spot a cut short identifier should also look for UNSUPPORTED_PAYLOAD_VERSION. A short payload of version 0, and an empty one, are still PAYLOAD_TOO_SHORT.

What it releases

pipeline.did changes, which is in Monday's plan under version per package (#63) already.

Base branch

rc at b33daa0. A trial merge of the head with rc at 2eebbff is clean.

What remains

  • Three requirements of the same pages are met by the code but no test would fail if they changed (the offsets, lengths and payload version kept package-private, and the field-setting constructor kept private). #157 adds those tests, as a draft of its own, because it changes only tests.

…d names its version

redeem_FactorWordsInOtherLetters_ReadAsTheirOutcome sends each factor
word in other letters under a Turkish default locale and expects its own
outcome. version_ShortPayload_IsRefusedNamingTheVersion gives payloads
of one to four bytes whose first byte names version 1, 2 or 3 and
expects the version refused and named, and version 0 too short.
…re its length

The specification's package surface says the factor words are compared
ignoring case, so a language that compares exactly lower-cases the word
first. Factor.fromValue now lower-cases it in the root locale.

The identifier layout says a reader refuses a payload whose version it
does not know, naming the version it found. A payload of one to four
bytes was refused as too short before its version was read, so the
version is now read from the first byte before the header's length is
checked.
@jwrosewell
jwrosewell marked this pull request as ready for review November 15, 2026 04:32
@jwrosewell
jwrosewell merged commit 67a4e56 into rc Nov 15, 2026
4 checks passed
@jwrosewell
jwrosewell deleted the fix/did-spec-divergences branch November 15, 2026 04:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant