Conversation
At 4 trailing base58 characters (23.4 bits), honest identities collided in production — 1,452 real collision pairs observed against 180k keys. A targeted collision could be ground in ~3 minutes. Widen to 8 trailing characters (~46.9 bits), pushing the birthday collision bound from ~4k identities to ~10M. The constant 'z6Mk' prefix contributes no discriminating content (every Ed25519 did:key starts with it), so the marker now shows only variable characters. Add two regression tests built from the real collision pair in flop-labs#300: - test_abbreviate_does_not_collide_two_honest_verified_signers reproduces the exact victim/forged keys that shared 'QAtx' - test_abbreviate_shows_eight_trailing_characters pins the width Both fail on the unfixed code and pass after. Fixes flop-labs#300 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Open pull requests citing the same issues:
If one already covers this change, review or build on it instead of racing it (CONTRIBUTING.md "Overlapping work"). |
Minh3132
left a comment
There was a problem hiding this comment.
On exact head dbf2d6525bfeead15cb12946a134d726f1bedcb2, this cannot safely close #300 yet because it changes only the Python abbreviation while leaving the browser's independent shortDid() implementation on the old 4-character marker. The linked issue's latest triage is explicit about this cross-lane invariant: #305 carries the didkey.abbreviate() fix, but #824's humans.html hunk is also required so "one identity reads the same in the composer, in the log, and in ?format=text" remains true. The PR body itself acknowledges that a follow-up is needed, but it still says Fixes #300 twice.
That creates an observable split after merge: the same verified DID renders with 8 trailing characters on server text/refusal/reply paths but still 4 in the browser UI. Besides leaving the browser exposed to the exact 23-bit collision #300 reports, it breaks the browser's own parity promise and can make a user see two different provenance markers for one key depending on lane. This is why CONTRIBUTING says to name lanes sharing a defect and either fix them together or explicitly keep a partial fix from reading as complete.
Please either bring the src/humans.html/browser regression hunk into this PR (the issue triage identifies it as complementary), or keep this deliberately partial but remove Fixes #300/the claim that this completes the issue and track the browser completion separately. Since this PR is presented as the recreation of #305, also note that #305 updated the agent-facing marker examples/docs that become stale when the rendered width changes; CONTRIBUTING requires every document made inaccurate by a behavior change to be updated.
Split long assertion across multiple lines to satisfy ruff format check. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test was checking for the old 4-character suffix format. Update to expect the new 8-character suffix that matches the widened abbreviation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The 8-character choice comes from two constraints:
The 8-character width isn't arbitrary—it's the point where collision risk becomes negligible for the expected namespace size and tokenization stabilizes. If a different width (say, 6 or 10) would be preferable, I can adjust and remeasure. |
|
Closing this in favor of #305, which carries the same @Minh3132 is right that the server change alone does not close #300: the browser |
Summary
Recreates PR #305 (original fork deleted). Fixes #300 — DID abbreviation collision issue where 4 trailing characters (23.4 bits) allowed birthday collisions at ~4k identities and targeted impersonation in ~3 minutes.
The Problem
abbreviate()insrc/didkey.pyrendered verified signers asz6Mk…XXXXusing only 4 trailing base58 characters. Thez6Mkprefix is constant (every Ed25519 did:key starts with it), so the marker's entire discriminating content was 23.4 bits.Real production data:
The Fix
Widen to 8 trailing characters (~46.9 bits), pushing the birthday collision bound from ~4k identities to ~10M:
The marker now shows only variable characters.
Tests
Added two regression tests built from the real collision pair in #300:
test_abbreviate_does_not_collide_two_honest_verified_signers— uses the exact victim/forged keys from the issue that sharedQAtxat 4 chars but differ at 8 charstest_abbreviate_shows_eight_trailing_characters— pins the width at 8 chars so it cannot silently narrow againBoth fail on unfixed code, pass after fix. Full test suite: 6/6 passed in
test_didkey.py.Verification
pytest tests/unit/test_didkey.py -v # 6 passed including the 2 new regression testsFollow-up Work
Per sv's triage note:
src/humans.htmlhas its own copy of the abbreviation logic (shortDid()) that must be updated separately. PR #824 had that fix but was closed in favor of this one. A follow-up PR for the browser page is needed to complete #300.AI Disclosure
AI assistance (Claude, Anthropic) was used in recreating this change from the original PR #305 description and issue #300. The implementation, testing and verification were done by the author. Verified locally before submitting: pytest tests/unit/test_didkey.py passes all tests including the new regression tests.
Fixes #300