Help

THREAT-WALKTHROUGH.md — what a relay actually learns

Assignment 01, deliverable 3. Per packet type, precisely what a passive relay observes.

The instruction this document is written under, from ASSIGNMENT-01.md:

> Show that a relay observing ROUTE_QUERY + ROUTE_RESPONSE + ENVELOPE cannot identify sender, > recipient, or conversation. *If it can learn something, say so plainly rather than asserting > privacy.*

It can. §5 and §6 say so plainly. Assertions of privacy that do not survive an adversary who is paying attention are worse than useless, because people rely on them.

---

1. Adversary positions

These are genuinely different, and conflating them is how privacy claims become false.

PositionDescription
P1 · First hopThe relay a sender hands a packet to directly
P2 · Middle relayA relay with another relay on both sides
P3 · Final hopThe relay that hands a packet to its destination
P4 · Passive listenerIn radio range, relaying nothing
P5 · Global observerSees many locations at once — out of scope (SPEC-ORIGINAL §32)

With MAX_DISCOVERY_HOPS = 3, P2 frequently does not exist. On a two-hop route A→B→C there is exactly one relay, and it is simultaneously P1 and P3. §6 is about what that means.

---

2. What every relay learns unconditionally

Regardless of packet type, from the fact of the encounter itself:

---

3. Per packet type

PacketWhat a relay learnsWhat it does not
HELLOA protocol versionAnything about the device, user or contacts
CAPABILITYTransport-class bits, storage class, persistent/gateway rolePlatform, model, OS, build. Capabilities are protocol bits, never deviceType = iPhone17 (SPEC-ORIGINAL §15)
PRESENCEExactly 32 opaque 16-byte valuesWho they belong to; and not the contact count, since the set is fixed-size and padded (§7)
ROUTE_QUERYA random query ID, one opaque token, a hop budget ≤ 3Who is asking, who is sought, or whether either is a contact of the relay
ROUTE_RESPONSEThat someone holding the right secret answered; a link-quality figure; a hop countThe path, the responder's identity, or any node between
INVENTORYWhich packet IDs a peer holds, and their destination tokensWho those packets are for. Destination tokens are derived under a different label from presence tokens, so they cannot be matched against any beacon (PROTOCOL.md §4.4)
WANTWhich packet IDs a peer lacksWhy, or for whom
ENVELOPEOnly §2's fields — see §4 belowContent, sender, recipient, conversation, or any permanent identifier
ACKThat a relay took custody of a packet IDThat anyone received or read anything. Delivery receipts are end-to-end encrypted envelopes of their own
GOODBYEThe encounter ended, and loosely whyAnything else

---

4. The Envelope, field by field

FieldVisible to a relayAssessment
protocolVersionYesVersion only
packetIDYesRandom, not derived. Constant along the journey — that is what makes duplicate suppression work, and it means P5 could trace one packet across the network. Accepted; P5 is out of scope
destinationTokenYesOpaque, rotates every 10 minutes, unlinkable across epochs, and cryptographically unrelated to any presence beacon
creationBucketYesAge of the packet, to 10-minute granularity
expiresAfterYesIntended lifetime. A minor leak we accept: an unusually short lifetime may signal something about the sender's intent
transitPolicyYesOne bit. Partitions traffic into two classes — mitigated by defaulting to restrictive, so the large population carries the restrictive value (DECISIONS.md D5)
payloadLengthYesOne of five buckets. Mandatory padding means it does not reveal actual length
fragment*, totalLengthYesThat a message exceeded a bucket, and by roughly how much
nonceYesRandom
hopLimitYesRemaining allowance, so roughly how far it has already travelled
ciphertextYes, as bytesNothing without the key

No display name, device name, OS, model, build, phone number, account identifier, or permanent device identifier appears anywhere in it (SPEC-ORIGINAL §13, §15).

---

5. The combined observation — the assignment's actual question

A relay sees, in sequence:

```

  1. ROUTE_QUERY from peer P { queryID Q, presenceToken X, budget 3 }
  2. ROUTE_RESPONSE toward peer P { queryID Q, quality, hops 2 }
  3. ENVELOPE from peer P { packetID N, destinationToken Y }

```

Cryptographically, X and Y are unlinkable. They are HMACs under different labels, and no party without routingSecret can connect them. The design does what it was meant to do at the level of values.

Temporally, they link trivially. All three arrive from the same immediate peer within seconds. A relay does not need to break any cryptography to conclude: the envelope P just handed me is for whoever P was looking for.

So state it plainly. A first-hop relay learns:

What it still does not learn:

The honest summary: the protocol conceals identity; within a single epoch, adjacency to a sender still reveals the existence of a correspondence. Sealed sender protects who, not that.

---

6. Two-hop routes: the single relay sees both ends

On A → B → C, B is P1 and P3 at once. So B learns:

This is not fixable within this architecture and we do not claim otherwise. Someone must deliver the packet to the destination, and that someone necessarily knows which radio peer received it. Onion routing would address it, at the cost of becoming an anonymity network rather than a messenger — explicitly out of scope for v1 (DECISIONS.md D7).

Context that matters for the flagship scenario: on an aircraft, B is a passenger seated within a few metres of A and C and can simply look at them. Radio-layer correlation is not the binding privacy constraint in the environment this was designed for. It matters much more in a dense public space among strangers, and that is the case to be honest about.

---

7. A leak found while writing this, and fixed

Checkpoint 2 moved presence tokens off the broadcast channel into a post-connection PRESENCE packet, precisely so the number of tokens could not fingerprint a user (PROTOCOL.md §4.6).

The leak came straight back on the unicast channel. Presence tokens are pairwise, so a PRESENCE list of length N discloses that the sender has N contacts — to anyone who connects, including a stranger in a queue.

PROTOCOL.md §6.3 now requires the list to be exactly PRESENCE_SET_SIZE (32) entries always, padded with CSPRNG values indistinguishable from real tokens, or randomly sampled and re-sampled each encounter when a node has more. Contact count is no longer observable.

Recorded rather than quietly patched, because it is a useful demonstration that the fingerprint moved when the channel moved, and the same mistake is available anywhere else a list length depends on a user's contacts.

---

8. Leaks we accept, and why

LeakWhy accepted
packetID traceable end to endRequired for duplicate suppression. Only exploitable by P5, which is out of scope
Correspondence visible to an adjacent relay (§5)Inherent to relaying; mitigated by rotating pseudonyms and 10-minute tokens
Both endpoints visible on a two-hop route (§6)Inherent; onion routing is the only fix and it is out of scope
Message size to bucket granularityPadding buckets are a deliberate trade against bandwidth
Fragment injection destroys a messageA fragmented message has one AAD (PROTOCOL.md §3.2), so per-fragment index and length are unauthenticated. Corrupting reassembly makes the tag fail. It is a denial of service, never a break — and it grants nothing, since anyone able to inject fragments can already just drop them, which is simpler and equally effective
Hop count to the senderNeeded for route selection; discloses coarse proximity of a contact to that contact only (DECISIONS.md D3)
Packet age and intended lifetimeNeeded for expiry enforcement by nodes that cannot read the packet
Radio-layer fingerprintingOutside application control entirely (SPEC-ORIGINAL §3)
A persistent node discloses that a node lives at that locationInherent to fixed infrastructure. Rotating the advertisement ID does not conceal a device that is always present in one place from an observer who is also in one place. One reason the persistent node is optional, and a reason not to run one somewhere the household's presence is itself sensitive
Install base, if broadcast push is ever enabledPush is off by default and targeted push is a permanent non-goal (DECISIONS.md B1)

---

9. Structural properties that do hold

---

10. What we do not claim

Carried from SPEC-ORIGINAL §32 and SPEC-REVISION §3, plus what this walkthrough added:

What we do claim, and what SPEC-REVISION §3 permits: the protocol discloses no device model, operating system, telephone number, account identifier, or permanent device identifier — and no message content, to anyone but its destination.

English is the reference text; any translation is a convenience. Help is stored on this phone and never contacts anyone.