Skip to content

Dispatch recipients on bech32 HRP instead of string prefixes#16

Merged
pscheid92 merged 1 commit into
mainfrom
fix/recipient-hrp-dispatch
Jul 23, 2026
Merged

Dispatch recipients on bech32 HRP instead of string prefixes#16
pscheid92 merged 1 commit into
mainfrom
fix/recipient-hrp-dispatch

Conversation

@pscheid92

Copy link
Copy Markdown
Owner

Summary

ParseRecipientLine (and its duplicate in the CLI) matched age1pq as a string prefix to detect ML-KEM recipients. But p and q are bech32 data characters, so roughly 1 in 1024 X25519 recipients legitimately starts with age1pq and was misrouted to the ML-KEM parser, failing with expected HRP 'age1pq', got 'age'. This is what broke the ParseRecipientsFile_MixedWithPlugin ubuntu leg on main (run 30005527741) and explains the sporadic local test failures seen during earlier work — the test generates a fresh random key each run. Plugins whose name starts with pq (age1pqfoo1...) were misrouted the same way.

Fix

  • Dispatch on the true HRP: split at the last 1 (BIP-173 — data never contains 1), mirroring Bech32.Decode. age → X25519, age1pq → ML-KEM, age1<name> → plugin.
  • The CLI's copied dispatch now delegates to AgeKeygen.ParseRecipientLine (made internal + InternalsVisibleTo("Age.Cli")), so the two sites can't drift again.
  • Unparseable recipients now report unrecognized recipient: ... from both paths (previously two different messages).

A plugin literally named pq shares the ML-KEM HRP and remains resolved as native ML-KEM, same precedence as before.

Verification

  • New deterministic regression tests around a brute-forced real X25519 keypair whose recipient begins age1pq (parses as X25519, round-trips encrypt/decrypt) plus a pqtest-named plugin recipient. The vector test reproduces the exact CI failure on the old code.
  • Full suite: 363 unit tests + 143 CCTV vectors pass, zero build warnings.

ParseRecipientLine matched "age1pq" as a string prefix, but 'p' and 'q'
are bech32 data characters: roughly 1 in 1024 X25519 recipients
legitimately starts with "age1pq" and was misrouted to the ML-KEM
parser, surfacing as random test failures (most recently
ParseRecipientsFile_MixedWithPlugin on CI). Plugins whose name starts
with "pq" hit the same misroute.

Split at the last '1' (BIP-173: data never contains '1') and dispatch
on the true HRP, mirroring what Bech32.Decode does. The CLI carried its
own copy of the prefix dispatch; it now delegates to
AgeKeygen.ParseRecipientLine so both paths share the fix.
@pscheid92
pscheid92 merged commit d618cdf into main Jul 23, 2026
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.99%. Comparing base (97fe01a) to head (bb51c89).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #16      +/-   ##
==========================================
+ Coverage   91.97%   91.99%   +0.01%     
==========================================
  Files          41       41              
  Lines        2381     2385       +4     
  Branches      312      312              
==========================================
+ Hits         2190     2194       +4     
  Misses        133      133              
  Partials       58       58              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@pscheid92
pscheid92 deleted the fix/recipient-hrp-dispatch branch July 23, 2026 13:33
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