Spike: relay-side sealed fan-out, and why it is declined (relay#27) #105

Merged
paulhitt merged 1 commits from spike/relay-side-sealed-fanout into main 2026-09-04 20:41:08 +00:00
paulhitt commented 2026-09-04 15:57:06 +00:00 (Migrated from gitlab.com)

The issue named the design question exactly — "the relay would learn the
fan-out shape unless the tokens hide it, and hiding it is the entire design
question". This answers it, in docs/FANOUT.md, with the measurements pinned by
GroupFanOutTests.

The premise was wrong twice, and both are now tests. /e2e/messages takes one
account and a LIST of that account's devices, so ten people with two devices is
ten requests, not twenty (relay#38 found this). And the blob is not what
repeats at all: an attachment is uploaded ONCE and named from inside every
recipient's sealed envelope by a token any member can fetch with — one 64 KB
picture sent to six people leaves exactly one row in attachments, and all six
download it.

So what a sender repeats is the envelope, measured at 572 bytes per member.
The entire prize is ~17.7 KB at the 32-member cap, not nineteen copies of a
photo.

And the tokens cannot hide the shape, for a structural reason rather than a
cryptographic one. Relay-side fan-out requires the relay to hold, at one
moment, a mapping from one blob to N destinations — and that mapping IS the
fan-out shape. It is not a leak beside the feature that might be engineered
away; it is the feature, described. Delivery tokens already do the part they
can, making destinations unlinkable to accounts; they cannot make the relay not
notice that N destinations are getting the same bytes, because copying is the
act of knowing that. Splitting it across N requests reassembles the same
mapping and pays the round trips being optimised. Blinding the reference needs
proxy re-encryption or oblivious storage, which is a different project with the
same §21.4 prerequisites. Delay obscures timing, not the row.

What would be given up is asserted as a test, so anyone implementing this has
to delete a passing test whose name says what they are deleting: nothing in the
database links the envelopes of one group message today. That matters more than
17 KB because sealed rosters (§8.9b) exist so a dump does not reveal your
groups — the claim /metadata makes in those words — and this would put the
group back in a row.

Precise about what is not claimed: a RUNNING relay can already infer a lot
from an identified send. The protection is against reading it later out of
stored rows, and against sealed sends where there is no sender to correlate on.

If round trips ever become the real complaint — a different issue from the one
filed — the narrow answer is recorded: batch several accounts per request on
the IDENTIFIED path only, where the relay already sees the sender and can
correlate the burst by timing, and never on the sealed one.

Everything is bounded by Group.maxMembers == 32, and the test fails if that
moves, so the document cannot go stale behind a raised cap.

650 relay tests in 58 suites green, core paths 7/7.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

The issue named the design question exactly — "the relay would learn the fan-out shape unless the tokens hide it, and hiding it is the entire design question". This answers it, in docs/FANOUT.md, with the measurements pinned by GroupFanOutTests. The premise was wrong twice, and both are now tests. /e2e/messages takes one account and a LIST of that account's devices, so ten people with two devices is ten requests, not twenty (relay#38 found this). And the blob is not what repeats at all: an attachment is uploaded ONCE and named from inside every recipient's sealed envelope by a token any member can fetch with — one 64 KB picture sent to six people leaves exactly one row in `attachments`, and all six download it. So what a sender repeats is the envelope, measured at 572 bytes per member. The entire prize is ~17.7 KB at the 32-member cap, not nineteen copies of a photo. And the tokens cannot hide the shape, for a structural reason rather than a cryptographic one. Relay-side fan-out requires the relay to hold, at one moment, a mapping from one blob to N destinations — and that mapping IS the fan-out shape. It is not a leak beside the feature that might be engineered away; it is the feature, described. Delivery tokens already do the part they can, making destinations unlinkable to accounts; they cannot make the relay not notice that N destinations are getting the same bytes, because copying is the act of knowing that. Splitting it across N requests reassembles the same mapping and pays the round trips being optimised. Blinding the reference needs proxy re-encryption or oblivious storage, which is a different project with the same §21.4 prerequisites. Delay obscures timing, not the row. What would be given up is asserted as a test, so anyone implementing this has to delete a passing test whose name says what they are deleting: nothing in the database links the envelopes of one group message today. That matters more than 17 KB because sealed rosters (§8.9b) exist so a dump does not reveal your groups — the claim /metadata makes in those words — and this would put the group back in a row. Precise about what is not claimed: a RUNNING relay can already infer a lot from an identified send. The protection is against reading it later out of stored rows, and against sealed sends where there is no sender to correlate on. If round trips ever become the real complaint — a different issue from the one filed — the narrow answer is recorded: batch several accounts per request on the IDENTIFIED path only, where the relay already sees the sender and can correlate the burst by timing, and never on the sealed one. Everything is bounded by Group.maxMembers == 32, and the test fails if that moves, so the document cannot go stale behind a raised cap. 650 relay tests in 58 suites green, core paths 7/7. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
paulhitt commented 2026-09-04 15:57:06 +00:00 (Migrated from gitlab.com)

assigned to @paulhitt

assigned to @paulhitt
paulhitt commented 2026-09-04 15:57:25 +00:00 (Migrated from gitlab.com)

mentioned in issue #27

mentioned in issue #27
paulhitt commented 2026-09-04 20:41:06 +00:00 (Migrated from gitlab.com)

deleted the feat/attachment-range-requests branch. This merge request now targets the main branch

deleted the `feat/attachment-range-requests` branch. This merge request now targets the `main` branch
paulhitt commented 2026-09-04 20:41:08 +00:00 (Migrated from gitlab.com)

mentioned in commit 8146ce02f0

mentioned in commit 8146ce02f0099a3b07be61514fe825a54d933c7d
paulhitt (Migrated from gitlab.com) merged commit 8146ce02f0 into main 2026-09-04 20:41:08 +00:00
paulhitt commented 2026-09-09 18:59:05 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
Sign in to join this conversation.