Summary
Currently the discovery polling loop stops after the first KeyExchangeInit is received, making each QR/invite link effectively single-use. This is a client-side policy choice, not a cryptographic constraint — the underlying protocol already supports multiple independent sessions from one QR with zero changes to the crypto layer.
Proposed Enhancement
Keep the discovery polling loop alive for a configurable window (e.g., until the user closes the "Add Friend" screen, or a time-based TTL) rather than terminating after the first successful KeyExchangeInit. Each scanner would still produce a fully independent, cryptographically isolated session with its own EK_B, SK, and Double Ratchet state.
Why This Is Safe
- Each
KeyExchangeInit uses a fresh EK_B from the scanner, producing an independent SK per session — no session state is shared between scanners.
- The
discovery_secret can still be fresh per QR display (no persistent identity key needed).
- Routing tokens and ratchet state are all derived per-session from each independent
SK, so sessions are fully unlinkable from each other at the crypto layer.
- No changes required to §4 (Key Exchange), §5 (Ratchet), §8 (Wire Format), or §9 (Server).
Changes Required
- Client only: Process all
KeyExchangeInit messages returned from GET /inbox/{discovery_token_A} in the polling loop, rather than stopping after the first.
- UX: Define the window during which Alice accepts inits — simplest option is UI-driven (polling stops when "Add Friend" screen is dismissed). A time-based
exp field could optionally be encoded in the QR payload for client-side enforcement.
- Simultaneous inits: The server already returns an array from
GET /inbox/{token}, so multiple concurrent KeyExchangeInit messages are naturally handled; the client loop just needs to iterate over all of them.
Use Cases
- Sharing a QR at a social event where multiple people want to add you at once.
- Sharing an invite link (Option B, §4.3) in a group chat where multiple recipients may tap it.
References
- §4.2 (Option A: QR Code Exchange) — discovery token polling loop
- §4.3 (Option B: URI / Manual) — same applies to link-based invites
docs/e2ee-location-sync.md — "The discovery token is single-use and ephemeral: implementations MUST discard it after aliceProcessInit completes."
Summary
Currently the discovery polling loop stops after the first
KeyExchangeInitis received, making each QR/invite link effectively single-use. This is a client-side policy choice, not a cryptographic constraint — the underlying protocol already supports multiple independent sessions from one QR with zero changes to the crypto layer.Proposed Enhancement
Keep the discovery polling loop alive for a configurable window (e.g., until the user closes the "Add Friend" screen, or a time-based TTL) rather than terminating after the first successful
KeyExchangeInit. Each scanner would still produce a fully independent, cryptographically isolated session with its ownEK_B,SK, and Double Ratchet state.Why This Is Safe
KeyExchangeInituses a freshEK_Bfrom the scanner, producing an independentSKper session — no session state is shared between scanners.discovery_secretcan still be fresh per QR display (no persistent identity key needed).SK, so sessions are fully unlinkable from each other at the crypto layer.Changes Required
KeyExchangeInitmessages returned fromGET /inbox/{discovery_token_A}in the polling loop, rather than stopping after the first.expfield could optionally be encoded in the QR payload for client-side enforcement.GET /inbox/{token}, so multiple concurrentKeyExchangeInitmessages are naturally handled; the client loop just needs to iterate over all of them.Use Cases
References
docs/e2ee-location-sync.md— "The discovery token is single-use and ephemeral: implementations MUST discard it afteraliceProcessInitcompletes."