Skip to content

fix(nymauth)!: convert main to rulebook v0.4 - #839

Open
leifj wants to merge 1 commit into
SUNET:mainfrom
sirosfoundation:fix/nymauth-v04-on-main
Open

leifj wants to merge 1 commit into
SUNET:mainfrom
sirosfoundation:fix/nymauth-v04-on-main

Conversation

@leifj

@leifj leifj commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

pkg/nymauth and seed_recover reached main through #793, and that code predates two rulebook v0.4 decisions — it is the pre-rename, pre-inversion copy. This converts it, independently of the verifier stack (#827 → #832), which carries the same change further up.

Why now, rather than waiting for the stack

On main this code is reachable from exactly one place: developer_tools/scripts/seed_recover, the tool whose job is deciding whether a reported pseudonym belongs to a given subject.

As merged it refuses the prefixed verifier_id and hashes the bare DNS name. Against a v0.4 Verifier it therefore computes a pseudonym nobody reports, and answers "no match" for the right subject — a wrong answer about a person, and the answer the tool exists to give. Nothing errors.

The change

BREAKING. verifier_input is SHA-256 of the prefixed verifier_id, the whole string:

SHA256("x509_san_dns:verifier.example") = 6eae85a0…6bab   (MUST)
SHA256("verifier.example")              = be6a6400…4a41   (the bare DNS name, which is NOT a verifier_id)

Both are recomputed in the test rather than copied as constants. This pair was inverted once already, and a digest is not something a reader can check by eye.

Rulebook v0.4 defines two forms and no others — x509_san_dns:<dns name> and semantic_id:<identifier> — and anything else is refused rather than repaired. The bare DNS name was correct until 2026-10-20, so a script or runbook written before then still passes one and it still looks entirely plausible.

The documentation was worse than the code

docs/issuer/SEED_COMMITMENTS.md told operators to pass the bare value in three places, including the main worked command line, and published the inverted digests as the rule. Someone following that page could not run the tool at all after this change — and before it, would have been handed the wrong answer silently.

So the page is now checked rather than proofread. Two guards, each proved by restoring the defect:

  • every -verifier-id the document shows is run through CheckVerifierID. It found the third bare example — the worked command line — which this change had otherwise missed.
  • the worked digests are recomputed, and the page must mark the prefixed form as the one hashed. Both digests appear on the page, so finding one proves nothing about which it recommends.

Also

A comment in pseudonym_test.go still asserted the bare form in prose while the test below it asserted the prefixed one; it survived the inversion. Replaced rather than deleted, because this is the kind of reversal a reader assumes is a mistake and "fixes" back.

Nothing is normalised — not case, not a trailing dot, not an IDN. Where v0.4 is silent, this hashes the bytes it was given; those questions are filed with the rulebook author as items 24–27 of sirosfoundation/nym_auth_rulebook#10 rather than answered locally.

Testing

go build ./..., and go test ./pkg/... ./internal/... ./developer_tools/... green. Both new guards were verified non-vacuous by reintroducing the defect and watching them fail with the message that names it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AB3apg5kCEGNPozrhSggum

main gained pkg/nymauth and seed_recover through SUNET#793, and that code
predates two v0.4 decisions. It is the pre-rename, pre-inversion copy.

BREAKING: verifier_id is now the PREFIXED string, and SHA-256 of the
whole thing - prefix included - is verifier_input:

	SHA256("x509_san_dns:verifier.example") = 6eae85a0…6bab   (MUST)
	SHA256("verifier.example")              = be6a6400…4a41   (not a
	                                                           verifier_id)

Both recomputed here rather than copied. The pair was inverted once
already, and a digest is not something a reader checks by eye.

Why this is worth doing before the verifier stack lands. On main this
code is reachable from exactly one place: developer_tools/scripts/
seed_recover, the tool whose job is deciding whether a reported
pseudonym belongs to a given subject. As merged it refuses the
prefixed verifier_id and hashes the bare DNS name, so against a v0.4
Verifier it computes a pseudonym nobody reports - and answers "no
match" for the right subject. That is a wrong answer about a person,
and it is the answer the tool exists to give.

The documentation was worse than the code. SEED_COMMITMENTS.md told
operators to pass the bare value in three places, including the main
worked command line, and published the inverted digests as the rule.
Someone following that page could not run the tool at all after this
change - and before it, would have been quietly given the wrong
answer.

So the page is now checked rather than proofread. Two guards, each
proved by restoring the defect:

- every `-verifier-id` the document shows is run through
  CheckVerifierID. It found the third bare example, in the worked
  command line, which this change had otherwise missed.
- the worked digests are recomputed and the page must mark the
  PREFIXED form as the one hashed - both digests appear on the page,
  so finding one proves nothing about which it recommends.

Also corrects a comment in pseudonym_test.go that still asserted the
bare form in prose while the test below it asserted the prefixed one.
It survived the inversion; it is replaced rather than deleted, because
this is the kind of reversal a reader assumes is a mistake and "fixes"
back.

Nothing is normalised - not case, not a trailing dot, not an IDN. Where
v0.4 is silent, this hashes the bytes it was given; the questions are
filed with the rulebook author as items 24-27 of
sirosfoundation/nym_auth_rulebook#10 rather than answered locally.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AB3apg5kCEGNPozrhSggum
Copilot AI balanced review requested due to automatic review settings October 21, 2026 17:50
@sonarqubecloud

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused validation change, recovery callers, documentation, and regression guards are consistent, with no unresolved findings.

No open issues 🎉

What changed in this PR

Aligns pseudonym recovery with rulebook v0.4 so valid prefixed verifier identifiers no longer produce false mismatches.

Changes:

  • Accepts the two defined identifier forms and rejects bare identifiers.
  • Updates CLI guidance and operator examples.
  • Adds regression guards for documented identifiers and digest guidance.
File Description
pkg/​nymauth/​pseudonym.go Enforces v0.4 identifier forms and exposes shared validation.
pkg/​nymauth/​pseudonym_test.go Checks prefixed hashing and rejected identifiers.
docs/​issuer/​SEED_COMMITMENTS.md Corrects recovery examples and hashing guidance.
developer_tools/​scripts/​seed_recover/​main.go Updates flag help.
developer_tools/​scripts/​seed_recover/​main_test.go Uses prefixed identifiers in recovery tests.
developer_tools/​scripts/​seed_recover/​doc_verifier_id_test.go Guards documentation examples and digest recommendations.

Review effort: Balanced

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.

2 participants