Core System Architecture Part 35 — Anonymous Mailbox, Offline Receiving & Reply Capability Architecture

SIAR — Secure, Local-First, Multi-Transport Communication Platform

Series: Core System Architecture
Part: 35
Status: Architecture specification
Primary language: Rust
Builds on: Part 34 — Mixnet, Loopix, Sphinx, Nym & High-Anonymity Transport Architecture
Primary purpose: define the complete anonymous mailbox, offline receiving, reply capability, mailbox rotation, multi-device fanout, retention, quota, replay protection, recovery, abuse resistance, and provider-neutral Rust architecture for SIAR's high-anonymity transport plane.


1. Purpose

A high-anonymity transport is not sufficient if recipients must remain continuously online.

SIAR needs a way for:

sender online now
recipient offline now
recipient reconnects later
message still arrives

without exposing:

recipient AccountId
recipient DeviceId
recipient IP address
stable direct endpoint
normal relay address

to the sending side or provider unnecessarily.

The governing principle is:

Anonymous receiving must use unlinkable, rotatable, capability-based mailbox identities that are separate from SIAR's normal account/device identities.


2. Architectural Position

SIAR Messaging
     │
     ▼
Application E2EE
     │
     ▼
Anonymous Routing Layer
     │
     ▼
Anonymous Mailbox Layer
     │
 ┌───┴────────────────────┐
 │                        │
Deposit                 Retrieve
 │                        │
Mixnet                 Mixnet
 │                        │
Provider / Mailbox Service
 │                        │
 └────────────┬───────────┘
              ▼
        Recipient Device

3. Why a Dedicated Mailbox Layer

Anonymous transport addresses three different problems:

1. anonymous path selection
2. anonymous packet forwarding
3. asynchronous recipient availability

The mailbox solves the third.


4. Mailbox Requirements

The mailbox system MUST support:

offline recipients
encrypted-at-rest payloads
anonymous deposit
anonymous retrieval
rotatable mailbox identities
multi-device fanout
bounded retention
deduplication
expiry
quotas
anti-abuse
reply capabilities
provider failover
crash recovery
provider-neutral APIs

5. Non-Goals

The mailbox is not:

the user's primary message database
the application source of truth
a replacement for SIAR local history
a place to store plaintext
a place to expose stable AccountId

6. Authoritative State

Authoritative message state remains:

recipient local message store
+
SIAR delivery state machine

The mailbox is only a transport/storage relay.


7. Mailbox Identity

Each receiving endpoint uses:

#![allow(unused)]
fn main() {
pub struct AnonymousMailboxId(pub [u8; 32]);
}

This is separate from:

AccountId
DeviceId
EndpointId
relay address

8. Mailbox Secret

Mailbox access requires secret material:

#![allow(unused)]
fn main() {
pub struct AnonymousMailboxSecret(SecretBytes);
}

Never expose it to:

UI
plugins
logs
support bundles

9. Mailbox Descriptor

#![allow(unused)]
fn main() {
pub struct AnonymousMailboxDescriptor {
    pub mailbox_id: AnonymousMailboxId,
    pub provider: AnonymousProviderId,
    pub epoch: MailboxEpoch,
    pub expires_at: Timestamp,
    pub capabilities: MailboxCapabilities,
}
}

10. Mailbox Capability Set

#![allow(unused)]
fn main() {
pub struct MailboxCapabilities {
    pub supports_batch_fetch: bool,
    pub supports_ack: bool,
    pub supports_reply_tokens: bool,
    pub supports_rotation_overlap: bool,
}
}

11. Per-Device Mailboxes

Recommended:

Device A → Mailbox A
Device B → Mailbox B
Device C → Mailbox C

Benefits:

independent revocation
reduced correlation
device-local lifecycle
clean rotation

12. Account-Level Delivery

The sender may fan out:

one application message
→ encrypted envelope for Device A
→ encrypted envelope for Device B
→ encrypted envelope for Device C

13. Device Discovery

The sender must not directly fetch stable device endpoints in a privacy-leaking way.

Instead, SIAR should distribute:

anonymous mailbox descriptors

inside trusted E2EE/account metadata channels.


14. Mailbox Descriptor Distribution

Possible paths:

existing E2EE conversation state
trusted multi-device sync
QR/device verification exchange
anonymous bootstrap

15. Descriptor Authenticity

Mailbox descriptors must be authenticated by trusted application identity/device state.


16. Mailbox Rotation

Mailboxes should rotate periodically or after security events.


17. Rotation Reasons

time-based privacy rotation
device compromise
provider migration
account recovery
manual reset
high-risk event

18. Mailbox Epoch

#![allow(unused)]
fn main() {
pub struct MailboxEpoch(pub u64);
}

19. Rotation State

#![allow(unused)]
fn main() {
pub enum MailboxRotationState {
    Stable,
    PublishingNew,
    DualReceive,
    RetiringOld,
    Complete,
    Failed,
}
}

20. Dual-Receive Window

During rotation:

old mailbox
+
new mailbox

may both remain active for a bounded overlap.


21. Bounded Overlap

Overlap minimizes:

message loss

but increases:

correlation surface

Therefore it must be short and policy-controlled.


22. Rotation Policy

#![allow(unused)]
fn main() {
pub struct MailboxRotationPolicy {
    pub max_epoch_age: Duration,
    pub overlap: Duration,
    pub rotate_on_provider_change: bool,
    pub rotate_on_security_event: bool,
}
}

23. Anonymous Deposit

Sender flow:

Resolve recipient mailbox
→ E2EE encrypt
→ Wrap anonymous envelope
→ Route through mixnet
→ Deposit to mailbox

24. Deposit API

#![allow(unused)]
fn main() {
#[async_trait]
pub trait AnonymousMailboxProvider: Send + Sync {
    async fn deposit(
        &self,
        mailbox: &AnonymousMailboxDescriptor,
        envelope: AnonymousMailboxEnvelope,
    ) -> Result<MailboxDepositReceipt, MailboxError>;

    async fn fetch(
        &self,
        mailbox: &AnonymousMailboxDescriptor,
        cursor: Option<MailboxCursor>,
    ) -> Result<MailboxBatch, MailboxError>;

    async fn acknowledge(
        &self,
        mailbox: &AnonymousMailboxDescriptor,
        items: &[MailboxItemId],
    ) -> Result<(), MailboxError>;
}
}

25. Mailbox Envelope

#![allow(unused)]
fn main() {
pub struct AnonymousMailboxEnvelope {
    pub version: MailboxEnvelopeVersion,
    pub item_id: MailboxItemId,
    pub created_at: Timestamp,
    pub expires_at: Timestamp,
    pub body: Bytes,
}
}

26. Payload Rule

body contains:

already E2EE-protected SIAR payload

Mailbox provider must never receive plaintext application content.


27. Deposit Receipt

#![allow(unused)]
fn main() {
pub struct MailboxDepositReceipt {
    pub item_id: MailboxItemId,
    pub accepted_at: Timestamp,
    pub retention_until: Timestamp,
}
}

28. Delivery Semantics

Mailbox deposit means:

provider accepted for offline delivery

It does not mean:

recipient device received
recipient user read

29. Delivery State Model

#![allow(unused)]
fn main() {
pub enum AnonymousMailboxDeliveryState {
    Queued,
    Submitted,
    Deposited,
    Retrieved,
    ApplicationAccepted,
    Expired,
    Failed,
}
}

30. User-Facing Simplification

Possible:

Queued
Sending anonymously
Stored for recipient
Delivered
Expired

31. Retrieval

Recipient flow:

start anonymity client
→ fetch mailbox batch
→ validate envelope
→ deduplicate
→ decrypt E2EE
→ persist message
→ acknowledge mailbox item

32. Persist Before ACK

Hard rule:

mailbox item
→ validate
→ persist application state
→ ACK mailbox

Never ACK before durable local persistence.


33. Crash Safety

If crash occurs after persist but before ACK:

item may reappear

Application dedup handles it.


34. Deduplication

Two layers:

MailboxItemId
Application MessageId

35. Mailbox Item Dedup

Prevents repeated processing of same transport item.


36. Application Message Dedup

Prevents duplicate user-visible messages across:

mailbox retry
provider retry
multi-device sync
route duplication

37. Batch Retrieval

Use bounded batches.

Example:

32–128 mailbox items

benchmark-dependent.


38. Batch Limits

Bound:

item count
total bytes
processing time

39. Retrieval Cursor

#![allow(unused)]
fn main() {
pub struct MailboxCursor {
    pub opaque: Bytes,
}
}

Provider-specific opaque cursor hidden behind adapter.


40. Cursor Privacy

Do not encode:

AccountId
DeviceId
contact identity

into provider-visible cursor if avoidable.


41. Retention

Mailbox items must expire.


42. Retention Policy

#![allow(unused)]
fn main() {
pub struct MailboxRetentionPolicy {
    pub default_ttl: Duration,
    pub max_ttl: Duration,
    pub max_items: u32,
    pub max_bytes: u64,
}
}

43. Expiry

Expired transport item:

deleted from mailbox

Application may still retain sender-side local message state.


44. Expired Delivery UX

Correct:

Message expired before the recipient retrieved it.

45. Mailbox Capacity

Each mailbox has bounded:

item count
bytes
retention
rate

46. Queue Full

Sender may receive:

MailboxFull

47. Queue Full Behavior

Do not:

silently switch to direct path

under strict anonymity.


48. Mailbox Quota Error

#![allow(unused)]
fn main() {
pub enum MailboxError {
    Unavailable,
    Full,
    Expired,
    InvalidDescriptor,
    AuthenticationFailed,
    RateLimited,
    Unsupported,
    Internal,
}
}

49. Sender-Side Retry

Use durable outbox.


50. Retry Backoff

Exponential/jittered retry.


51. Expiry-Aware Retry

Stop retry once application expiry reached.


52. Anonymous Reply Capability

A recipient should be able to reply without learning sender's network location.


53. Reply Capability Model

#![allow(unused)]
fn main() {
pub struct AnonymousReplyCapability {
    pub id: ReplyCapabilityId,
    pub provider: AnonymousProviderId,
    pub secret: SecretBytes,
    pub expires_at: Timestamp,
    pub max_uses: u32,
}
}

54. Reply Capability Properties

Desired:

unforgeable
bounded
expiring
non-guessable
minimally linkable

55. SURB-Style Replies

Where provider supports:

Single-Use Reply Blocks

should be preferred for one-shot anonymous replies.


56. Reply Capability Use

incoming anonymous message
→ includes reply capability
→ recipient sends response
→ sender receives without revealing stable address

57. Reply Capability Storage

Sensitive local storage.


58. Never Sync Blindly

Reply capabilities should not be automatically replicated across devices.


59. Reply Capability State

#![allow(unused)]
fn main() {
pub enum ReplyCapabilityState {
    Available,
    Reserved,
    Consumed,
    Expired,
    Invalid,
}
}

60. Reserve Before Use

To avoid concurrent double-use:

Available
→ Reserved
→ Consumed

61. Crash During Use

If outcome uncertain:

mark capability spent

for single-use capability unless provider supports safe replay semantics.


62. Reply Pool

Sender may pre-generate a bounded pool.


63. Reply Pool Policy

#![allow(unused)]
fn main() {
pub struct ReplyPoolPolicy {
    pub target_size: u32,
    pub min_size: u32,
    pub max_size: u32,
    pub refill_threshold: u32,
}
}

64. Refill Timing

Avoid:

refill immediately after each incoming message

because that may create timing correlation.

Use:

background batched replenishment

65. Reply Capability Rotation

Expired/unused capabilities are discarded.


66. Reply Capability Revocation

Usually not guaranteed after distribution.

Therefore:

short lifetimes
single-use
limited use-count

are preferred.


67. Bidirectional Conversation

For ongoing anonymous conversation:

each side periodically supplies fresh reply capabilities

68. Avoid Stable Anonymous Address When Possible

Stable anonymous addresses increase correlation.

Use:

rotating mailbox descriptors
reply capabilities

where practical.


69. Anonymous Invitation

A contact invitation may include:

temporary mailbox descriptor
reply capabilities
ephemeral identity proof

70. Invitation Expiry

Short-lived.


71. Anonymous Bootstrap State

#![allow(unused)]
fn main() {
pub enum AnonymousBootstrapState {
    Created,
    Waiting,
    Contacted,
    Authenticated,
    Upgraded,
    Expired,
}
}

72. Upgrade to Persistent Relationship

Once peers establish trust:

rotate/bootstrap mailbox
→ issue conversation-specific mailbox descriptors

73. Mailbox Scope

Possible:

#![allow(unused)]
fn main() {
pub enum MailboxScope {
    Device,
    Conversation,
    Invitation,
    EphemeralSession,
}
}

74. Device-Scoped Mailbox

Simplest.

One anonymous receiving mailbox per device.


75. Conversation-Scoped Mailbox

Stronger separation.

Each conversation gets separate anonymous address.

Tradeoff:

more privacy
more key/state management

76. Invitation-Scoped Mailbox

Temporary.


77. Ephemeral Session Mailbox

Short-lived for sensitive exchanges.


78. Recommended Initial Scope

Start with:

per-device mailbox

Then add:

conversation-scoped

for Maximum Anonymity.


79. Multi-Device Fanout

Application determines target device set.


80. Fanout Policy

#![allow(unused)]
fn main() {
pub enum AnonymousFanoutPolicy {
    AllTrustedDevices,
    ActiveDevicesOnly,
    PrimaryDeviceOnly,
    ExplicitDevices,
}
}

81. Privacy Tradeoff

Sending to many mailboxes increases:

traffic volume
correlation possibilities

82. Maximum Anonymity Fanout

May prefer:

single privacy-designated receiving device

or carefully batched fanout.


83. Device Capability

Each device advertises whether it supports:

anonymous receive
anonymous replies
cover traffic
background mailbox fetch

84. Capability Negotiation

#![allow(unused)]
fn main() {
pub struct AnonymousDeviceCapabilities {
    pub mailbox_receive: bool,
    pub reply_capability: bool,
    pub background_fetch: bool,
    pub provider_ids: Vec<AnonymousProviderId>,
}
}

85. Provider Compatibility

Two peers need not use same normal transport stack.

Anonymous delivery requires at least one compatible provider path.


86. Provider Migration

Mailbox descriptors are provider-specific.


87. Migration Flow

create new provider mailbox
→ publish new descriptor
→ dual receive
→ retire old mailbox

88. Migration Invariant

No message loss during valid overlap where possible.


89. Provider Failure

If provider mailbox unavailable:

sender outbox waits
recipient fetch retries

90. Multi-Provider Redundancy

Possible advanced mode:

publish descriptors for Provider A and Provider B

91. Redundancy Tradeoff

Improves availability but increases:

traffic
metadata surface
complexity

92. Multi-Provider Policy

#![allow(unused)]
fn main() {
pub enum MailboxProviderPolicy {
    SinglePreferred,
    Failover,
    Redundant,
}
}

93. Failover

Try another approved anonymous provider.


94. No Cross-Class Failover

Never fail over to:

ordinary relay
direct endpoint

under strict anonymity.


95. Polling

Mailbox retrieval can create timing fingerprints.


96. Retrieval Scheduling

Options:

continuous provider-native receive
Poisson-like polling
batched periodic polling
push-assisted anonymous wake

provider dependent.


97. Push Wake

Ordinary push notifications can leak metadata.


98. Push Policy

If used, push should contain:

opaque wake hint only

and never:

sender
message ID
conversation ID
mailbox content

99. Maximum Anonymity Push

May disable ordinary push entirely.


100. Background Fetch Android

Must respect:

Doze
battery saver
foreground-service limits
network restrictions

101. Background Fetch Desktop

Daemon can maintain receive loop.


102. Fetch Scheduler

#![allow(unused)]
fn main() {
pub trait AnonymousMailboxScheduler {
    async fn schedule_fetch(
        &self,
        mailbox: AnonymousMailboxId,
        policy: MailboxFetchPolicy,
    ) -> Result<(), MailboxError>;
}
}

103. Fetch Policy

#![allow(unused)]
fn main() {
pub enum MailboxFetchPolicy {
    Continuous,
    Adaptive,
    BatterySaving,
    MaximumAnonymity,
}
}

104. Adaptive Fetch

Uses:

battery
foreground state
network cost
provider health

without switching to lower privacy transport.


105. Cover Traffic Interaction

Mailbox polling should be integrated with cover traffic.


106. Loop Traffic

A Loopix-inspired implementation may use loop messages to:

measure health
maintain cover
mask activity

107. Keepalive Privacy

Avoid direct heartbeat pattern tied to user activity.


108. Mailbox ACK Privacy

ACK behavior itself can leak timing.


109. Batched ACK

Potentially:

batch acknowledgements

if provider semantics allow.


110. ACK Delay

Can be randomized within bounded window.


111. Read Receipt Separation

Mailbox ACK is:

transport acknowledgement

not:

read receipt

112. Delivery Receipt Separation

Application may send separate E2EE delivery receipt later.


113. Replay Protection

Required at multiple layers.


114. Replay Sources

malicious provider
malicious sender
network duplication
retry duplication

115. Replay Cache

Bounded cache:

#![allow(unused)]
fn main() {
pub struct ReplayCachePolicy {
    pub max_entries: u32,
    pub retention: Duration,
}
}

116. Replay Key

Use:

MailboxItemId
anonymous envelope nonce/id
MessageId

as appropriate.


117. Expired Replay Entries

Evict after safe retention.


118. Abuse Resistance

Mailbox service must survive hostile senders.


119. Threats

mailbox flooding
large-message flooding
fragment exhaustion
reply-token abuse
CPU exhaustion
storage exhaustion

120. Anonymous Quotas

Quota should avoid requiring stable real-world identity.


121. Capability-Based Deposit

Preferred:

deposit token
mailbox capability
invitation capability

122. Deposit Capability

#![allow(unused)]
fn main() {
pub struct MailboxDepositCapability {
    pub token: SecretBytes,
    pub expires_at: Timestamp,
    pub quota_class: MailboxQuotaClass,
}
}

123. Unknown Senders

For anonymous requests:

small quota
no auto-download
request inbox

124. Trusted Contacts

Can receive higher capability quota.


125. Rate Limit State

#![allow(unused)]
fn main() {
pub enum MailboxQuotaClass {
    Unknown,
    Contact,
    Trusted,
    System,
}
}

126. Attachment Quotas

Anonymous unknown sender attachment defaults:

metadata only
manual download
strict size bound

127. Fragment Flood Defense

Bound incomplete assemblies per:

mailbox
source capability class
time window

128. CPU Budget

Decrypt/validate in bounded worker pool.


129. Mailbox Storage Budget

Never allow mailbox processing to exhaust device storage.


130. Local Staging

Fetched encrypted items may be staged temporarily before validation.


131. Staging Limits

Bound bytes/count/time.


132. Invalid Envelope

Drop/quarantine according to security policy.


133. Corrupt Envelope

Do not retry forever.


134. Authentication Failure

Treat as security event if repeated.


135. Unknown Version

unsupported

not parse heuristically.


136. Versioning

#![allow(unused)]
fn main() {
pub struct MailboxEnvelopeVersion(pub u16);
}

137. Forward Compatibility

Unknown optional fields ignored only if authenticated schema permits.


138. Backward Compatibility

Maintain explicit migration matrix.


139. Backup

Do not blindly back up:

live mailbox secrets
live reply tokens
provider session keys

140. Backup-Safe State

Can include:

mailbox policy
provider preference
rotation metadata
non-secret descriptor history

141. Restore to New Device

Generate fresh:

MailboxId
MailboxSecret
reply pool
provider identity

142. Same-Device Restore

May preserve more state if secure key-store continuity is verified.


143. Recovery

Account recovery does not imply old anonymous mailbox recovery.


144. Recovery Policy

Recommended:

fresh anonymous identity after account recovery

145. Lost Device

Revoke device and retire its mailbox where provider supports.


146. Revocation Limit

Provider may not be able to erase already-delivered/distributed descriptors immediately.

Therefore rotation/expiry remain important.


147. Device Revocation Event

revoke device
→ stop fetch
→ rotate account mailbox descriptors
→ invalidate future fanout

148. Multi-Device Sync

Sync only:

public mailbox descriptors
capability metadata
rotation epochs

through E2EE.


149. Do Not Sync Mailbox Secrets

Hard rule unless architecture explicitly requires shared mailbox.


150. Conversation-Specific Mailbox Secrets

Remain device-local.


151. Database Schema

Potential local tables:

anonymous_mailboxes
anonymous_mailbox_epochs
anonymous_outbox
anonymous_inbox_staging
anonymous_replay_cache
anonymous_reply_capabilities
anonymous_reply_pool
anonymous_provider_state

152. anonymous_mailboxes

Fields:

mailbox_id
provider_id
scope
epoch
state
created_at
expires_at
secret_ref

153. Secret Reference

Database stores:

secure-store reference

not raw secret.


154. anonymous_outbox

Stores:

delivery_id
recipient mailbox ref
encrypted payload ref
state
retry metadata
expiry

155. anonymous_inbox_staging

Stores only bounded temporary transport state.


156. anonymous_reply_capabilities

Stores:

capability id
provider
state
expiry
max uses
secret ref

157. Transactionality

Critical transitions:

fetch
persist message
mark dedup
ACK

must be crash-safe.


158. Transaction Flow

Recommended:

begin local transaction
→ validate mailbox item
→ dedup check
→ persist E2EE envelope/message
→ mark MailboxItemId processed
→ commit
→ send mailbox ACK

159. ACK Failure

If local commit succeeded:

safe to retry ACK

160. Duplicate Fetch After ACK Failure

Dedup suppresses user duplicate.


161. Metrics

Privacy-safe:

mailbox fetch success
mailbox deposit success
queue depth
batch size bucket
expired items
replay drops
provider availability

162. Forbidden Metrics

Do not record:

peer mailbox ID
peer AccountId mapping
reply token
full timing trace per contact

163. Logs

Allowed:

provider unavailable
mailbox fetch batch count
retry scheduled

164. Logs Must Redact

mailbox IDs
secrets
reply capabilities
provider routes

165. Diagnostics UX

Normal:

Anonymous receiving: Ready
Messages waiting: 2
Provider: Available

166. Advanced Diagnostics

Could show:

mailbox epoch
queue depth
last fetch success
provider state
reply pool health

with identifiers truncated or omitted.


167. No Route Hop Display

Still forbidden.


168. Health Model

#![allow(unused)]
fn main() {
pub enum MailboxHealth {
    Healthy,
    Degraded,
    Unavailable,
    RotationRequired,
    QuotaLimited,
}
}

169. Reply Pool Health

#![allow(unused)]
fn main() {
pub enum ReplyPoolHealth {
    Healthy,
    Low,
    Empty,
    Replenishing,
}
}

170. UI Warning

If reply pool exhausted:

Anonymous replies may be delayed while reply capabilities are replenished.

171. Offline UX

Recipient offline is normal.

Do not show sender:

recipient offline

if anonymity mode avoids presence disclosure.


172. Sender UX

Use:

Stored for delivery

not:

Recipient is offline

173. Presence Independence

Mailbox status must not become a hidden presence oracle.


174. Fetch Timing Privacy

Sender should not learn exact mailbox retrieval timestamp unless application receipt policy allows.


175. Delivery Receipt Delay

High-anonymity mode may batch/delay application-level delivery receipts.


176. Read Receipt

Off by default in Maximum Anonymity.


177. Group Messaging

Anonymous group delivery may require:

fanout to device mailboxes

or future group-anonymity protocol.


178. Group Fanout Cost

Potentially expensive:

N members × devices

179. Initial Group Scope

Recommend:

small groups only

for anonymous mailbox fanout.


180. Large Groups

Require separate architecture later.


181. Broadcast

Do not treat mailbox system as unbounded broadcast system.


182. Emergency Messaging

Anonymous mailbox may be too latent for emergency-critical delivery.


183. Emergency Policy

Use only if user explicitly selects anonymity over reachability.


184. File Attachments

Small files may be fragmented through mailbox.


185. Large Files

Use Part 34 anonymous attachment policy.


186. Attachment Mailbox Quota

Strict.


187. Preview Fetch

No automatic external preview fetch.


188. Plugin Access

Plugins cannot read:

MailboxId
MailboxSecret
ReplyCapability

189. Plugin Event

At most:

anonymous transport available/unavailable

if capability permits.


190. API Layer

Core mailbox service:

#![allow(unused)]
fn main() {
#[async_trait]
pub trait AnonymousMailboxService: Send + Sync {
    async fn create_mailbox(
        &self,
        scope: MailboxScope,
        provider: AnonymousProviderId,
    ) -> Result<AnonymousMailboxDescriptor, MailboxError>;

    async fn rotate_mailbox(
        &self,
        mailbox: AnonymousMailboxId,
    ) -> Result<AnonymousMailboxDescriptor, MailboxError>;

    async fn send_to_mailbox(
        &self,
        request: AnonymousMailboxSendRequest,
    ) -> Result<AnonymousDeliveryId, MailboxError>;

    async fn fetch_pending(
        &self,
        mailbox: AnonymousMailboxId,
    ) -> Result<MailboxFetchResult, MailboxError>;

    async fn retire_mailbox(
        &self,
        mailbox: AnonymousMailboxId,
    ) -> Result<(), MailboxError>;
}
}

191. Reply Service

#![allow(unused)]
fn main() {
#[async_trait]
pub trait AnonymousReplyService: Send + Sync {
    async fn generate(
        &self,
        policy: ReplyCapabilityPolicy,
    ) -> Result<Vec<AnonymousReplyCapability>, ReplyError>;

    async fn send_reply(
        &self,
        capability: ReplyCapabilityId,
        envelope: Bytes,
    ) -> Result<AnonymousDeliveryId, ReplyError>;

    async fn replenish(
        &self,
    ) -> Result<(), ReplyError>;
}
}

192. Reply Policy

#![allow(unused)]
fn main() {
pub struct ReplyCapabilityPolicy {
    pub single_use: bool,
    pub lifetime: Duration,
    pub max_uses: u32,
}
}

193. Mailbox Resolver

#![allow(unused)]
fn main() {
pub trait AnonymousMailboxResolver {
    async fn resolve_for_device(
        &self,
        device: DeviceId,
    ) -> Result<Vec<AnonymousMailboxDescriptor>, ResolveError>;
}
}

194. Resolver Privacy

Resolution occurs from:

trusted locally available E2EE metadata

where possible.


195. No Public Account Lookup

Maximum anonymity should avoid:

AccountId → public mailbox query

if it creates stable correlation.


196. Capability Distribution

Preferred:

directly inside established E2EE conversation

197. Testkit

Create:

siar-anonymity-mailbox-testkit

or include in:

siar-anonymity-testkit

198. Fake Mailbox Provider

Supports:

deposit
fetch
ack
drop
duplicate
delay
quota
expiry
rotation

199. Unit Tests

Test:

mailbox creation
rotation
retention
quota
dedup
ACK ordering
reply reservation

200. Crash Tests

Critical:

crash after fetch
crash after local persist
crash before ACK
crash during rotation
crash during reply use

201. Replay Tests

same item twice
same reply capability twice
same E2EE message via two mailboxes

202. Expiry Tests

expired mailbox
expired item
expired reply capability

203. Quota Tests

mailbox full
sender rate-limited
fragment quota exceeded

204. Provider Failure Tests

deposit unavailable
fetch unavailable
ACK unavailable
rotation unavailable

205. Rotation Tests

new descriptor published
dual receive
old mailbox retired
late message on old mailbox

206. Multi-Device Tests

two mailboxes
one device revoked
one device offline
dedup across devices

207. Recovery Tests

new device gets fresh mailbox
old mailbox not restored blindly

208. Leak Tests

Canary secrets must never appear in:

logs
support bundle
UI
plugin event

209. Correlation Tests

Verify no obvious field maps:

AccountId
→ MailboxId

in provider-facing protocol metadata.


210. Fuzzing

Fuzz:

mailbox envelope parser
batch parser
reply capability parser
cursor parser
rotation metadata

211. Property Tests

Properties:

ACK never precedes durable persist
duplicate mailbox item never duplicates application message
expired reply capability cannot be used
retired mailbox cannot accept new sends after retirement policy completes

212. Performance Tests

Measure:

batch fetch throughput
dedup lookup
reply pool replenishment
rotation overhead
storage growth

213. Battery Tests

Android:

continuous receive
adaptive fetch
Doze
battery saver

214. Scale Tests

Synthetic:

10k pending mailbox items
1k mailboxes
large replay cache
large outbox

within configured supported limits.


215. Security Invariants

Mandatory:

1. Mailbox IDs never equal AccountId or DeviceId.
2. Mailbox secrets never leave secure storage.
3. E2EE payload exists before mailbox deposit.
4. Local durable persist occurs before ACK.
5. Application MessageId handles duplicate transport delivery.
6. Reply capabilities are secret, bounded, expiring, and preferably single-use.
7. Strict anonymity never falls back to ordinary direct/relay delivery.
8. Rotation overlap is bounded.
9. Account recovery creates fresh anonymous receiving identity.
10. Plugins never receive mailbox secrets or reply capabilities.

216. Initial Production Scope

Implement first:

per-device mailbox
Nym-backed provider adapter
durable deposit/fetch
batch retrieval
persist-before-ACK
MailboxItemId + MessageId dedup
bounded retention
quota handling
rotation epochs
single-use reply capabilities
privacy-safe diagnostics

Then add:

conversation-scoped mailboxes
multi-provider failover
adaptive fetch
reply pools
anonymous invitation mailboxes
advanced cover-aware polling

217. Definition of Done

Part 35 is complete when:

  • anonymous mailbox identity is separate from account/device identity
  • per-device anonymous mailbox lifecycle is defined
  • deposit/fetch/ack APIs are provider-neutral
  • offline recipient delivery works without direct endpoint exposure
  • fetched messages are persisted before mailbox ACK
  • duplicate transport delivery cannot create duplicate user-visible messages
  • mailbox retention, expiry, quotas, and capacity limits are explicit
  • mailbox rotation includes bounded overlap and retirement
  • reply capabilities/SURB-style replies are bounded, secret, and replay-safe
  • reply pool replenishment avoids obvious timing correlation
  • multi-device fanout and revocation behavior are defined
  • provider migration and optional redundancy are defined
  • Android background/Doze constraints and desktop daemon receiving are defined
  • backup/recovery never blindly restores stale live mailbox secrets
  • plugin access to mailbox secrets is forbidden
  • diagnostics and metrics are privacy-safe
  • crash, replay, quota, rotation, multi-device, recovery, fuzz, leak, and performance tests are defined

218. Final Architecture

                        SENDER
                          │
                          ▼
                    Application E2EE
                          │
                          ▼
                 Anonymous Transport
                          │
                          ▼
                 Anonymous Mailbox
                    ┌─────┴─────┐
                    │           │
                 Deposit     Retention
                    │           │
                    └─────┬─────┘
                          ▼
                  Recipient Fetch
                          │
                          ▼
                    Validate/Dedup
                          │
                          ▼
                    Persist Locally
                          │
                          ▼
                     Mailbox ACK

Reply path:

Sender
  │
  ├─ includes bounded reply capability
  │
  ▼
Recipient
  │
  └─ replies using capability
          │
          ▼
       Mixnet
          │
          ▼
        Sender

Rotation path:

Old Mailbox
    │
    ├──── bounded overlap ────┐
    │                         │
    ▼                         ▼
Retiring                 New Mailbox
                              │
                              ▼
                           Stable

219. Final Principle

Anonymous offline delivery should not require stable public addressing.

The correct model is:

rotatable anonymous mailbox
+
E2EE payload
+
bounded retention
+
persist-before-ACK
+
single-use reply capabilities
+
strict separation from AccountId/DeviceId

not:

public user ID
→ permanent mailbox address
→ provider tracks everything

This gives SIAR durable asynchronous messaging over the high-anonymity transport plane while preserving offline delivery, multi-device support, crash safety, and strong metadata separation.