Delivery & relays
How ciphertext moves through social relays: store-and-forward mailboxes, optional onion entry hops, and metadata splitting.
Phase 1: single-hop delivery
The simplest path. Alice posts directly to Bob's mailbox relay. The relay sees the mailbox tag and ciphertext size, but not who sent the message or what it says.
sequenceDiagram participant Alice participant Relay as Bobs Mailbox Relay participant Bob Alice->>Relay: POST /v1/blobs tag, expiry, ciphertext Relay->>Relay: validate and store opaque blob Note over Bob: offline... Bob->>Relay: GET /v1/blobs by tag Relay-->>Bob: ciphertext blob list Bob->>Bob: decrypt and check valid_until
Phase 2: two-hop onion
No single honest relay observes both the upload and the fetch. Alice sends to an entry relay, which decrypts one onion layer and forwards to the mailbox relay without learning the mailbox tag.
flowchart LR A[Alice] -->|POST /v1/relay<br/>onion packet| E["Entry Relay<br/>Carol"] E -->|decrypt layer 1<br/>POST /v1/ingest| M["Mailbox Relay<br/>Dave"] M -->|store blob| DB[(Blob DB)] B[Bob] -->|GET /v1/blobs/tag| M
Phase 3: path rotation
Each message may use a different entry→mailbox relay pair from the contact's profile descriptors, reducing long-term correlation on a single route.
flowchart TB P["Contact delivery profile<br/>relay_descriptors"] --> R1["Route A: entry1 to mailbox1"] P --> R2["Route B: entry2 to mailbox2"] P --> R3["Route C: entry3 to mailbox3"] MSG1[Message seq=1] --> R1 MSG2[Message seq=2] --> R2 MSG3[Message seq=3] --> R3
Phase 5: direct P2P + profile fallback
When both peers are online on the same LAN, the client tries direct HTTP delivery first. If that fails within two seconds, it falls back to relay descriptors from the signed profile.
