Core System Architecture Part 45 — Anonymous Presence, Discovery, Contact Bootstrap & Private Social Graph Architecture
SIAR — Secure, Local-First, Multi-Transport Communication Platform
Series: Core System Architecture
Part: 45
Status: Architecture specification
Primary language: Rust
Builds on: Core System Architecture Parts 34–44
Primary purpose: define the complete privacy-preserving social-graph architecture for SIAR, including contact bootstrap, invitation capabilities, QR/NFC/local exchange, anonymous presence, private contact discovery, graph-hiding identifiers, rendezvous/contact mailboxes, multi-device behavior, blocking/revocation, abuse resistance, recovery, and provider-neutral Rust interfaces.
1. Purpose
A communication system can encrypt messages perfectly and still expose a user's social graph.
Presence and discovery systems commonly reveal:
who has an account
who is online
who talks to whom
who shares contacts
which phone numbers/emails belong to users
which devices belong to one account
when relationships are created
Part 45 defines a model where:
SIAR should establish and maintain relationships through scoped, privacy-preserving capabilities rather than a globally queryable social graph.
2. Architectural Position
User Identity / Account
│
▼
Contact Bootstrap
│
├── QR
├── NFC
├── Invite Link/Code
├── Existing Secure Contact
└── Optional Private Discovery
│
▼
Contact Capability Exchange
│
▼
Private Social Graph
│
├── Presence
├── Messaging
├── Calls
└── Group Invitations
3. Governing Rules
Mandatory:
social graph is local-first
global identity is not a provider-facing routing identifier
presence is capability-scoped
contact discovery is optional
address-book upload is not required
blocking revokes relationship capabilities
4. Core Identity Separation
Distinguish:
Account Identity
Contact Identity
Relationship Identity
Presence Identity
Transport Identity
Mailbox Identity
5. Account Identity
Long-lived identity used for:
trust
verification
multi-device account ownership
6. Contact Identity
The local representation of another user.
#![allow(unused)] fn main() { pub struct ContactId(pub [u8; 32]); }
Local only.
7. Relationship Identity
Each relationship gets a scoped random ID.
#![allow(unused)] fn main() { pub struct RelationshipId(pub [u8; 32]); }
8. Why Relationship IDs
Avoid exposing stable:
AccountId
username
phone
email
to providers.
9. Presence Identity
Ephemeral/rotating identifier.
#![allow(unused)] fn main() { pub struct PresenceId(pub [u8; 32]); }
10. Transport Identity
Anonymous routing uses its own identifiers.
11. Mailbox Identity
Anonymous mailbox IDs remain separate.
12. Social Graph Storage
Recommended local model:
contacts
relationships
verification state
capabilities
presence policy
blocked relationships
13. No Global Contact Table Requirement
SIAR should not require:
server knows every user-to-user relationship
14. Contact Bootstrap Modes
#![allow(unused)] fn main() { pub enum ContactBootstrapMode { Qr, Nfc, InviteCode, ExistingSecureChannel, PrivateDiscovery, ManagedDirectory, } }
15. QR Bootstrap
Best for in-person/private establishment.
16. NFC Bootstrap
Same principle with short-range exchange.
17. Invite Code
Can be shared through another channel.
18. Existing Secure Channel
A verified contact can introduce another capability.
19. Private Discovery
Optional service for users who want discoverability.
20. Managed Directory
Optional organization-managed environment.
Separate from public social discovery.
21. Contact Invite
#![allow(unused)] fn main() { pub struct ContactInvite { pub invite_id: ContactInviteId, pub public_identity: IdentityPublicMaterial, pub relationship_seed: SecretBytes, pub capabilities: ContactCapabilityOffer, pub expires_at: Timestamp, } }
22. Invite ID
#![allow(unused)] fn main() { pub struct ContactInviteId(pub [u8; 16]); }
Random.
23. Invite Secret
Bearer secret.
Never log.
24. Invite Expiry
Bounded.
25. One-Time Invite
Preferred for sensitive bootstrap.
26. Multi-Use Invite
Possible for:
public creator
business support
community organizer
with reduced privacy.
27. Invite Policy
#![allow(unused)] fn main() { pub enum ContactInvitePolicy { OneTime, BoundedUses(u16), UntilExpiry, } }
28. QR Payload
Contains only minimum bootstrap data.
29. No Full Profile Required
QR should not need:
phone number
email
home address
30. QR Integrity
Signed/authenticated.
31. QR Confidentiality
Sensitive invite material can be encrypted if scan context supports it.
32. Contact Acceptance
Flow:
scan/receive invite
→ validate
→ display identity
→ user accepts
→ derive relationship state
→ exchange scoped capabilities
33. Relationship Capability Bundle
#![allow(unused)] fn main() { pub struct RelationshipCapabilities { pub messaging: Option<MessageCapability>, pub presence: Option<PresenceCapability>, pub calling: Option<CallInvitationCapability>, pub file_transfer: Option<FileTransferCapability>, } }
34. Capability Independence
Hard rule.
Granting messaging does not automatically imply:
presence
calls
files
35. Presence Capability
#![allow(unused)] fn main() { pub struct PresenceCapability(SecretBytes); }
36. Presence Capability Scope
Bound to:
relationship
device/account scope
expiry/rotation
37. Presence Semantics
Use coarse states:
#![allow(unused)] fn main() { pub enum PrivatePresenceState { Available, Away, Unknown, } }
38. Avoid False Offline
Unknown means:
no reliable fresh presence information
not:
definitely offline
39. Strict Anonymous Mode
Presence disabled by default.
40. Presence Privacy Levels
#![allow(unused)] fn main() { pub enum PresencePrivacy { Disabled, ContactsOnly, SelectedContacts, Coarse, } }
41. ContactsOnly
Presence available only to valid relationship capability holders.
42. SelectedContacts
Explicit allowlist.
43. Coarse
Avoid precise:
last seen 22:14:08
44. Last-Seen Buckets
If enabled:
recently
today
this week
unknown
45. No Exact Last-Seen by Default
Exact timestamps create correlation risk.
46. Presence Publication
Potential architecture:
client
→ encrypted presence object
→ relationship mailbox/provider
47. Presence Object
#![allow(unused)] fn main() { pub struct EncryptedPresenceObject { pub presence_id: PresenceId, pub epoch: PresenceEpoch, pub ciphertext: Bytes, pub expires_at: Timestamp, } }
48. Presence Epoch
#![allow(unused)] fn main() { pub struct PresenceEpoch(pub u64); }
49. Presence Rotation
Rotate:
presence ID
encryption material
periodically.
50. Presence TTL
Short.
51. Expired Presence
Maps to:
Unknown
52. Presence Delivery Models
#![allow(unused)] fn main() { pub enum PresenceDeliveryMode { PerRelationship, RelationshipMailbox, AnonymousTopic, } }
53. Per-Relationship
Strongest isolation, more bandwidth.
54. Relationship Mailbox
Efficient for small contact sets.
55. Anonymous Topic
Potential larger-scale method.
56. Provider Visibility
Provider should not know:
Account A follows Account B
57. Relationship-Specific Presence IDs
Preferred.
58. Why
If same presence ID is shared to all contacts, provider can correlate the user's social graph.
59. Presence Fanout
For each authorized relationship:
derive unique encrypted update
60. Cost
O(number of presence-enabled relationships).
61. Optimization
Batch publication through mixnet while preserving relationship-specific payloads.
62. No Global Presence Channel
Hard rule for strict architecture.
63. Presence Polling
Recipient fetch should integrate with Part 37 shaping.
64. Presence Push
Push provider can leak timing.
65. Strict Mode
Prefer:
anonymous mailbox/poll
rather than conventional push.
66. Typing State
Typing is more sensitive than presence.
67. Typing Policy
#![allow(unused)] fn main() { pub enum TypingPrivacy { Disabled, EnabledPerConversation, } }
68. Strict Anonymous Mode
Typing disabled.
69. Discovery Problem
Users may want:
find friends
find someone by username
find contacts
without exposing address books.
70. Discovery Modes
#![allow(unused)] fn main() { pub enum ContactDiscoveryMode { Disabled, ExactHandle, PrivateSetIntersection, ManagedDirectory, } }
71. Disabled
Best privacy.
72. Exact Handle
User explicitly searches known handle.
73. Private Set Intersection
Potential future.
Compare contacts without server learning raw entire address book.
74. Managed Directory
Enterprise/school/team environment.
75. Phone/Email Discovery
Should be opt-in.
76. Never Require Full Address Book Upload
Hard rule.
77. Hashing Phone Numbers Is Not Enough
Phone/email spaces are low entropy.
Simple hashes can be brute-forced.
78. Safer Discovery
Potential:
OPRF
Private Set Intersection
rate-limited blind lookup
79. Do Not Invent Cryptography
Use reviewed PSI/OPRF protocol/library.
80. Discovery Server
Should learn minimum possible.
81. OPRF Concept
Client obtains blinded token for identifier.
Server cannot directly see raw identifier.
82. Discovery Token
#![allow(unused)] fn main() { pub struct DiscoveryToken(pub [u8; 32]); }
83. Token Rotation
Protocol-dependent.
84. Exact Handle Discovery
Handle maps to contact bootstrap descriptor.
85. Handle Privacy
Public handle means discoverability tradeoff.
86. Handle Visibility
#![allow(unused)] fn main() { pub enum HandleVisibility { Private, ExactSearch, Public, } }
87. Exact Search
Not enumerable if possible.
88. Public
Suitable for:
business
public creator
support identity
not maximum privacy.
89. Anti-Enumeration
Discovery service must prevent:
download all usernames
probe all phone numbers
90. Defenses
rate limiting
proof-of-work/captcha where appropriate
OPRF/PSI
exact-match API
abuse detection
91. Discovery Result
Return bootstrap descriptor, not social graph.
92. Bootstrap Descriptor
#![allow(unused)] fn main() { pub struct ContactBootstrapDescriptor { pub identity_public: IdentityPublicMaterial, pub invite_endpoint: OpaqueInviteEndpoint, pub expires_at: Timestamp, pub signature: IdentitySignature, } }
93. No Contact List Exposure
A lookup does not reveal who else is connected.
94. Relationship Establishment
Discovery only finds identity.
Relationship requires:
request
acceptance
capability exchange
95. Contact Requests
#![allow(unused)] fn main() { pub struct ContactRequest { pub request_id: ContactRequestId, pub sender_identity: EncryptedIdentityIntroduction, pub requested_capabilities: ContactCapabilityOffer, pub expires_at: Timestamp, } }
96. Unknown Sender
Request arrives in:
Requests Inbox
97. No Presence Before Acceptance
Hard rule.
98. No Auto File Download
Hard rule.
99. Request Abuse
Unknown users may spam requests.
100. Anti-Spam Controls
request capability
rate limit
proof-of-work
invite-only mode
101. Privacy-Preserving Request Token
Could be issued via discovery/bootstrap.
102. Contact Request Policy
#![allow(unused)] fn main() { pub enum ContactRequestPolicy { Nobody, InviteOnly, KnownHandle, AnyoneRateLimited, } }
103. Block
Blocking must revoke relationship capabilities.
104. Blocked Relationship State
#![allow(unused)] fn main() { pub enum RelationshipState { Pending, Active, Muted, Blocked, Revoked, } }
105. Block Effects
Revoke/ignore:
messaging capability
presence capability
call capability
file capability
106. Block Privacy
Do not necessarily send:
you were blocked
107. Presence After Block
Becomes:
Unknown
108. Unblock
Creates fresh capabilities.
109. Do Not Reuse Old Relationship Secrets
Hard rule.
110. Relationship Rotation
Capabilities may rotate periodically.
111. Relationship Epoch
#![allow(unused)] fn main() { pub struct RelationshipEpoch(pub u64); }
112. Rotation Triggers
device loss
contact re-verification
security event
manual reset
113. Verification
Separate:
contact exists
identity verified
device verified
114. Trust Model
#![allow(unused)] fn main() { pub enum ContactTrust { Unverified, VerifiedIdentity, VerifiedDevice, } }
115. Familiarity Is Not Verification
Hard rule.
116. Verification Methods
QR comparison
SAS
fingerprint
in-person
trusted introduction
117. Trusted Introduction
Contact A introduces B to C.
118. Introduction Privacy
A should not learn whether B and C later communicate unless explicitly informed.
119. Introduction Capability
#![allow(unused)] fn main() { pub struct ContactIntroduction { pub subject_identity: IdentityPublicMaterial, pub bootstrap_capability: SecretBytes, pub expires_at: Timestamp, } }
120. No Transitive Trust Automatically
Hard rule.
121. Private Social Graph
Local representation:
#![allow(unused)] fn main() { pub struct SocialGraph { pub relationships: Vec<RelationshipRecord>, } }
122. Relationship Record
#![allow(unused)] fn main() { pub struct RelationshipRecord { pub relationship_id: RelationshipId, pub contact_id: ContactId, pub state: RelationshipState, pub trust: ContactTrust, pub epoch: RelationshipEpoch, pub capabilities: RelationshipCapabilityRefs, } }
123. Provider Must Not Receive SocialGraph
Hard rule.
124. Server Sync
If multi-device sync is enabled:
encrypt graph before server storage
125. Authoritative Graph
User/device E2EE state.
126. Server Role
Opaque encrypted sync blob/object.
127. Graph Sync Key
Separate from:
message keys
backup keys
128. Multi-Device Contacts
All trusted devices may share:
contact metadata
verification state
relationship policy
129. Device-Specific Capabilities
Some receiving capabilities remain device-specific.
130. Presence Across Devices
Need aggregation.
131. Multi-Device Presence Semantics
Account is:
Available
if at least one authorized device is available.
132. Device Presence Hidden
Contacts need not know:
which device
133. Device Count
Do not expose by default.
134. Presence Aggregator
Prefer client/account-controlled logic.
135. Presence Conflict
Use freshest valid signed update.
136. Presence Replay
Old state rejected by epoch/expiry.
137. Lost Device
Revoke device presence/call/message capabilities.
138. Device Revocation
Does not require deleting relationship.
139. Account Recovery
Recovered account should avoid reusing old transport/presence identifiers.
140. Fresh Relationship Transport State
Recommended after high-risk recovery.
141. Contact Reauthorization
Maximum privacy can require contacts to reapprove fresh capabilities.
142. Recovery Policy
#![allow(unused)] fn main() { pub enum SocialGraphRecoveryPolicy { RestoreEncryptedGraph, RestoreAndRotateCapabilities, ReauthorizeSensitiveContacts, } }
143. Maximum Privacy
Prefer:
RestoreAndRotateCapabilities
or stronger.
144. Backup
Can include encrypted:
contact names
notes
verification metadata
145. Backup Exclusions
Do not blindly restore:
live presence secrets
single-use invites
transport session secrets
146. Contact Export
Privacy-sensitive.
147. Export Warning
Export may reveal:
social graph
contact names
verification state
148. Contact Notes
Local only by default.
149. Profile Data
Contact profile may include:
display name
avatar
status
150. Profile Privacy
Each field can be scoped.
151. Profile Field Visibility
#![allow(unused)] fn main() { pub enum ProfileVisibility { Nobody, Contacts, SelectedRelationships, Public, } }
152. Avatar Distribution
Encrypted/capability-gated for private profiles.
153. External Avatar URL
Avoid in strict mode.
154. Status Message
Potential metadata leak.
155. Strict Mode
Disable or relationship-encrypt.
156. Profile Update Fanout
Same privacy principle as presence.
157. Public Profiles
Explicitly trade privacy for discoverability.
158. Private Profiles
No global fetch.
159. Discovery Cache
Local.
160. Negative Lookup Cache
Bounded.
161. Discovery Privacy
Do not retain detailed search history server-side.
162. Local Search History
Optional.
163. Clear Search History
Supported.
164. Directory Queries
Use:
exact-match
privacy-preserving protocol
not broad prefix enumeration in strict modes.
165. Username Prefix Search
High enumeration risk.
166. Recommendation
Do not support public prefix search in initial private architecture.
167. Nearby Discovery
Bluetooth/Wi-Fi proximity can leak physical co-location.
168. Nearby Mode
Separate explicit opt-in.
169. Nearby Identifier
Ephemeral rotating beacon.
170. Nearby Beacon
#![allow(unused)] fn main() { pub struct NearbyBootstrapBeacon(pub [u8; 16]); }
171. Beacon Rotation
Frequent.
172. No Account ID in Beacon
Hard rule.
173. Proximity ≠ Trust
Hard rule.
174. Nearby Flow
discover ephemeral beacon
→ user confirms device/person
→ secure bootstrap
→ optional verification
175. Bluetooth Privacy
OS may expose device metadata.
Minimize application-advertised identity.
176. Wi-Fi LAN Discovery
Same.
177. Local Discovery Scope
Do not automatically add nearby users.
178. NFC
Strong deliberate physical action.
Useful for verification/bootstrap.
179. QR Verification
Can combine:
identity fingerprint
relationship bootstrap
but keep semantics clear.
180. Privacy-Preserving Discovery Provider Trait
#![allow(unused)] fn main() { #[async_trait] pub trait PrivateContactDiscovery: Send + Sync { async fn lookup_handle( &self, handle: &ExactHandle, ) -> Result<Option<ContactBootstrapDescriptor>, DiscoveryError>; async fn private_match( &self, inputs: PrivateDiscoveryInput, ) -> Result<PrivateDiscoveryResult, DiscoveryError>; } }
181. Presence Service Trait
#![allow(unused)] fn main() { #[async_trait] pub trait PrivatePresenceService: Send + Sync { async fn publish( &self, relationship: RelationshipId, state: PrivatePresenceState, ) -> Result<(), PresenceError>; async fn fetch( &self, relationship: RelationshipId, ) -> Result<PrivatePresenceState, PresenceError>; } }
182. Relationship Service Trait
#![allow(unused)] fn main() { pub trait RelationshipService { fn accept( &self, invite: ContactInvite, ) -> Result<RelationshipId, RelationshipError>; fn block( &self, relationship: RelationshipId, ) -> Result<(), RelationshipError>; fn rotate( &self, relationship: RelationshipId, ) -> Result<RelationshipEpoch, RelationshipError>; } }
183. Contact Invite Service
#![allow(unused)] fn main() { pub trait ContactInviteService { fn create( &self, policy: ContactInvitePolicy, ) -> Result<ContactInvite, InviteError>; fn consume( &self, invite: ContactInvite, ) -> Result<ContactBootstrapResult, InviteError>; fn revoke( &self, invite_id: ContactInviteId, ) -> Result<(), InviteError>; } }
184. Social Graph Store
#![allow(unused)] fn main() { pub trait SocialGraphStore { fn upsert_relationship( &self, record: RelationshipRecord, ) -> Result<(), SocialGraphError>; fn get_relationship( &self, id: RelationshipId, ) -> Result<Option<RelationshipRecord>, SocialGraphError>; } }
185. Storage Tables
Potential:
contacts
relationships
relationship_epochs
relationship_capabilities
presence_state
contact_invites
blocked_relationships
verification_records
profile_visibility
discovery_cache
186. Secret Storage
Capability secrets via secure-store references.
187. DB Encryption
Local DB encrypted where platform design supports.
188. Relationship Transaction
Creating relationship should atomically persist:
contact
relationship ID
epoch
capability refs
trust state
189. Partial Relationship
Forbidden.
190. Blocking Transaction
Persist block before destroying/revoking capability references.
191. Crash Recovery
Blocked relationship stays blocked after restart.
192. Presence State
Ephemeral/rebuildable.
193. Contact Graph
Authoritative user data.
194. Invite State
Durable until expiry/revocation.
195. Presence Backpressure
If many relationships:
bounded fanout queue
196. Presence Priority
Lower than:
message
call signaling
security
197. Presence Dropping
Old presence update can be coalesced/replaced by latest.
198. Coalescing
Useful:
Available → Away → Available
before network send can collapse to latest.
199. No Durable Presence Backlog
Generally unnecessary.
200. Discovery Abuse Threats
identifier enumeration
spam
relationship probing
phone/email guessing
invite scraping
201. Enumeration Testing
Attempt large lookup set.
Provider must rate-limit/prevent.
202. Relationship Probing
Attacker should not learn:
is Alice connected to Bob?
203. Discovery Response
Only concerns lookup target.
204. Presence Probing
Without valid capability:
no presence response
205. Block Probing
Blocked user should not receive explicit block bit.
206. Invite Guessing
Use sufficient entropy.
207. Capability Guessing
Cryptographically random.
208. Replay
Consumed one-time invite rejected.
209. Invite Theft
Bearer invite can be stolen.
Short TTL and one-time semantics reduce risk.
210. Invitation Confirmation
UI must show intended identity before acceptance.
211. Contact Impersonation
Verification is separate from discovery.
212. Exact Handle Collision
Handle service must guarantee unique canonical handle.
213. Homograph Risk
UI should surface suspicious Unicode/confusables.
214. Canonicalization
Careful handle normalization.
215. Display Name
Not unique.
216. Handle vs Display Name
Distinct types.
217. Public Handle Change
Old handle mapping expires/redirect policy.
218. Relationship Stability
Handle changes do not alter established relationship identity.
219. Account Key Change
High-risk.
Contacts need security notification/reverification.
220. Trust Reset
Depending cause.
221. Social Graph Correlation Tests
Use Part 42 privacy lab.
222. Test Scenario
Provider observes presence objects from many users.
Goal:
cannot cluster all contacts of one user via stable presence ID
223. Contact Discovery Privacy Test
Ensure server cannot reconstruct raw address book in private matching protocol.
224. Presence Timing Test
Measure relationship correlation from update timing.
225. Cover-Aware Presence
Part 37 may add delay/batching.
226. Presence Rate
Bounded.
227. Presence Noise
Potential future:
dummy relationship presence traffic
expensive.
228. Maximum Anonymity
Simplest strong policy:
presence off
229. Social Graph Metrics
Local-only:
contact count
blocked count
230. Remote Telemetry
Must not include contact graph size in strict mode unless coarse/opted-in.
231. Provider Metrics
Aggregate service health only.
232. Forbidden Telemetry
RelationshipId
ContactId
PresenceId
lookup target
invite secret
233. Support Bundle
Redact:
contact names
handles
capabilities
relationship IDs
presence IDs
234. UI — Contact Add
Modes:
Scan QR
Share Invite
Enter Exact Handle
Nearby
235. UI — Presence
Use:
Available
Away
Unknown
236. UI — Verification
Separate status:
Unverified
Verified
Security changed
237. UI — Discovery Privacy
Explain:
Exact-handle search only
or private contact matching.
238. UI — Address Book
If future PSI matching exists:
Contacts are matched privately; raw address-book entries are not uploaded.
Only if implementation genuinely provides that.
239. No Misleading Claims
Hard rule.
240. Nearby UX
Show:
Nearby does not mean verified.
241. Multi-Account
Relationship graph separated per account/profile.
242. Work/Personal Profiles
No cross-profile graph sharing without explicit action.
243. Managed Organization Directory
May expose organization membership.
Separate privacy contract.
244. Organization Discovery
Could use:
organization-scoped identity
not global public handle.
245. Enterprise Admin
Should not automatically see personal contact graph.
246. Data Portability
Export contacts separately from live capabilities.
247. Import
Imported contacts are not automatically verified.
248. Legacy Migration
Imported phone/email contacts may need explicit discovery.
249. Deletion
Deleting contact locally can:
remove metadata
revoke capabilities
depending action.
250. Remove vs Block
Different semantics.
251. Remove
Relationship ends.
May optionally notify.
252. Block
Relationship invalidated silently where possible.
253. Mute
Local notification behavior only.
Does not revoke capabilities.
254. Privacy-Safe Notification
Presence changes should not generate noisy remote-visible events.
255. Fuzzing
Fuzz:
contact invite
bootstrap descriptor
presence object
discovery response
relationship capability bundle
256. Property Tests
Properties:
blocked relationship cannot publish presence
one-time invite cannot be consumed twice
strict mode never exposes global AccountId as PresenceId
presence without capability returns no state
257. Formal Verification Targets
Good candidates:
relationship state machine
invite consumption
block/revoke transition
capability rotation
258. TLA+ Candidate
Relationship lifecycle:
Pending → Active → Blocked/Revoked
259. Kani Candidate
Invite use-count and expiry invariants.
260. Loom Candidate
Concurrent block vs presence publish.
261. Performance Tests
Measure:
presence fanout
contact graph load
invite generation
discovery lookup
multi-device sync
262. Scale Tests
Synthetic graphs:
100 contacts
1,000 contacts
10,000 contacts
while maintaining bounded queues.
263. Discovery Load Tests
Enumeration attack under rate limits.
264. Offline Tests
Contact graph works locally without server.
265. Recovery Tests
Restore graph + rotate sensitive capabilities.
266. Multi-Device Tests
Presence aggregation and capability sync.
267. Security Invariants
Mandatory:
1. Social graph is authoritative local/E2EE state, not a provider-owned graph.
2. Raw AccountId/DeviceId are never provider-facing presence identifiers.
3. Presence requires an explicit scoped capability.
4. Maximum Anonymity disables presence by default.
5. One-time contact invites cannot be consumed more than once.
6. Block revokes relationship capabilities and survives restart.
7. Unblock creates fresh capabilities rather than restoring old secrets.
8. Simple phone/email hashing is never treated as private discovery.
9. Address-book upload is never required for SIAR operation.
10. Nearby proximity never implies verification.
11. Discovery providers cannot query or expose arbitrary relationship edges.
12. Contact/presence/invite secrets never appear in logs or telemetry.
268. Recommended Crate Layout
crates/
├── siar-social-core/
├── siar-contact-invite/
├── siar-contact-bootstrap/
├── siar-contact-discovery/
├── siar-private-presence/
├── siar-relationship/
├── siar-social-graph/
├── siar-contact-verification/
├── siar-nearby-bootstrap/
├── siar-social-sync/
├── siar-social-observability/
└── siar-social-testkit/
269. siar-social-core
Owns:
ContactId
RelationshipId
trust/state types
errors
270. siar-contact-invite
Invite generation/consumption/revocation.
271. siar-contact-bootstrap
QR/NFC/existing-channel bootstrap.
272. siar-contact-discovery
Exact-handle/PSI provider abstraction.
273. siar-private-presence
Presence capability/publication/fetch.
274. siar-relationship
Lifecycle/rotation/block.
275. siar-social-graph
Local authoritative graph.
276. siar-contact-verification
QR/SAS/fingerprint verification.
277. siar-nearby-bootstrap
Ephemeral Bluetooth/Wi-Fi proximity bootstrap.
278. siar-social-sync
Encrypted multi-device graph sync.
279. siar-social-observability
Privacy-safe diagnostics.
280. siar-social-testkit
Synthetic graph/discovery attacks.
281. Error Taxonomy
#![allow(unused)] fn main() { pub enum SocialGraphError { InviteExpired, InviteAlreadyConsumed, InviteInvalid, RelationshipBlocked, RelationshipRevoked, PresenceUnauthorized, DiscoveryRateLimited, DiscoveryUnavailable, VerificationChanged, CapabilityInvalid, Internal, } }
282. Initial Production Scope
Implement first:
QR invite bootstrap
NFC bootstrap
one-time/bounded invites
local authoritative contact graph
relationship IDs
capability-separated messaging/presence/calls/files
contacts-only presence
Available/Away/Unknown semantics
block/revoke with fresh-unblock secrets
exact-handle discovery
anti-enumeration rate limits
multi-device encrypted graph sync
verification states
privacy-safe diagnostics
Then add:
OPRF/PSI address-book matching
anonymous presence topics
private introductions
managed organization directories
advanced nearby discovery
presence cover traffic
283. Definition of Done
Part 45 is complete when:
- account, contact, relationship, presence, transport, and mailbox identities are separated
- contact bootstrap supports QR/NFC/invite/existing-channel flows
- relationship capabilities are independently scoped for messaging/presence/calls/files
- presence is capability-gated and coarse
Unknownis distinct fromOffline- Maximum Anonymity disables presence by default
- global social graph storage is unnecessary
- exact-handle and future PSI/OPRF discovery boundaries are defined
- raw address-book upload is not required
- contact requests and anti-spam policy are explicit
- blocking/revocation and fresh-unblock capability semantics are defined
- multi-device presence and graph sync are privacy-preserving
- recovery rotates live anonymity-sensitive capabilities
- nearby discovery uses ephemeral IDs and never implies trust
- telemetry/support bundles do not expose graph identifiers
- enumeration, presence correlation, replay, block, recovery, and scale tests are specified
284. Final Architecture
CONTACT BOOTSTRAP
┌──────────┬──────────┬──────────┐
│ │ │ │
QR NFC Invite Discovery
│ │ │ │
└──────────┴──────────┴──────────┘
│
▼
RELATIONSHIP STATE
│
Scoped Capabilities
┌──────────┬─────────┬──────────┐
│ │ │ │
Messaging Presence Calls Files
│ │ │ │
└──────────┴─────────┴──────────┘
│
▼
LOCAL PRIVATE GRAPH
Strict presence model:
relationship-specific capability
+
rotating presence identity
+
encrypted short-lived state
+
anonymous fetch
+
coarse semantics
not:
global account ID
→ centralized online-status database
285. Final Principle
A private social graph must not be treated as a public directory with encryption added later.
The correct model is:
deliberate bootstrap
+
relationship-local identifiers
+
scoped capabilities
+
private verification
+
optional privacy-preserving discovery
+
coarse/disabled presence
+
local authoritative graph
This architecture gives SIAR a way to support familiar contacts, discovery, nearby bootstrap, and presence while preventing those convenience features from becoming a centralized map of who knows, follows, or communicates with whom.