NotASithLord / NotASithLord/peerd
dweb: per-dwapp derived subidentities — break cross-dwapp linkability of the single mesh DID
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 410
- Forks
- 45
- Avg merge
- 11d 5h
- Merged PRs (30d)
- 1
Description
Problem
There is exactly one Ed25519 mesh identity per browser profile (vault DWEB_IDENTITY_SECRET, held by the offscreen base node — offscreen/dweb-base.js: "one identity per browser"). Every surface reuses it: base-mesh presence, every dwapp's room membership (rosters are DIDs), publishing, and A2A. Consequence: any peer who shares two rooms with you can link your activity across every dwapp you run — the union of your dwapp usage is one globally-correlatable identity. The hello() bridge op hands the DID string to every dwapp, so apps themselves can also correlate out-of-band.
This is invisible now (small mesh) and expensive later: fixing it after the mesh has a population means rotating every user's visible identity in every room at once.
Proposal
Domain-separated derived subidentities, consistent with the codebase's existing discipline (the D-8 rule; content/manifest.js's tagged-signature scheme):
seed_dwapp = HKDF(master_secret, "peerd/dwapp-identity/v1" || dwapp_id)→ per-dwapp Ed25519 keypair → per-dwapp did:key.- Room presence, announce, publish/DM, mute all use the derived DID for that dwapp.
- Publisher identity stays the master DID — publishing is deliberately attributable (
dwapp_id = H(publisher‖slug)depends on it); unlinkability is for usage, not authorship. - The agent envoy (reserved
peerd-agentroom, the dweb actor) keeps the master DID or gets its own fixed derivation — it is the user's addressable agent, so stability there is the point. hello()reports the derived DID, shrinking what a dwapp can correlate.
Derivation is deterministic, so no new vault state: the same master secret yields the same per-dwapp identity on every unlock.
Granularity decision
Per-dwapp (not per-room): the bridge already enforces one room per app, and a stable in-app identity is what users expect socially (your name in the commons shouldn't rotate). Per-room is strictly stronger unlinkability but can be a later knob ("peerd/dwapp-identity/v1" || dwapp_id || roomId) — the versioned info-string leaves room.
Design-through list (the real work)
- DM routing and mute lists key on DID (
offscreen/dweb-base.js, room membership) — the base node must hold N subidentities concurrently and route ch=3 traffic per derived key. dweb_blocksemantics: blocking a peer's publisher DID vs. one of their room subidentities are different acts; decide what the user-facing block means (probably: block the identity you can see; publisher-level ban stays the discovery-plane mechanism).- Signaling/DHT: provider records and rendezvous currently assume the one DID; audit which planes may carry a subidentity without breaking Kademlia bookkeeping.
- Grant keying (
bridge.jsappKey) is content-hash based and orthogonal — unaffected. - Rate caps (
background/dweb-inbound-rate-cap.js) are per-did — per-subidentity caps must not multiply an attacker's budget (cap by master on our side, by observed did for inbound).
Prior art
Cloudflare OS scopes identity per-account-per-vendor and deliberately passes gatekeepers an opaque random observer id instead of a real identity precisely to prevent cross-context correlation. Same instinct, P2P setting.
Do this while the mesh is small; it's a wire-visible identity change.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in offscreen/dweb-base.js, tracing the single identity, hello(), room membership, DM/mute routing, and signaling paths; then inspect content/manifest.js, bridge.js, and background/dweb-inbound-rate-cap.js. Map which operations use the master DID and which must use a derived per-dwapp DID. Done requires a consistent wire-visible identity design, preserved publisher and agent semantics, and resolved block and rate-cap behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- distributed-systems, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100