How ItsGoin works

A technical overview of the networking, encryption, and sync mechanisms. For the full design rationale, see the design document.

Networking: QUIC mesh over iroh

ItsGoin uses iroh (v0.96) for peer-to-peer networking. iroh provides QUIC transport with built-in NAT traversal, hole punching, and mDNS LAN discovery. Every node has a persistent ed25519 identity key.

Connection types

TypeSlotsLifetimePurpose
Mesh101 (desktop), 15 (mobile)Long-livedStructural backbone for routing and propagation
Session20 (desktop), 5 (mobile)MinutesActive interactions: DMs, delivery, peer discovery
EphemeralUnlimitedSingle requestOne-off sync or blob fetch

Mesh architecture (101 slots)

Desktop nodes maintain 101 mesh connections divided into:

  • 10 Preferred — bilateral agreements with close peers, protected from eviction
  • 71 Local — discovered through N2 diversity scoring
  • 20 Wide — random connections for network-wide reach

New mesh connections require bilateral agreement: the connector sends an InitialExchange message, and the acceptor either grants a slot or sends RefuseRedirect with an alternative peer suggestion.

Growth loop

Nodes reactively grow their mesh using diversity scoring. When a slot opens, the node evaluates N2 candidates (peers reported by mesh connections) and selects the one that maximizes reach into new parts of the network. The scoring formula:

score = 1/reporter_count + 0.3 if not_already_in_N3

Low reporter count means fewer of your existing peers know this candidate — connecting to them brings the most new reach. The growth loop backs off after 3 consecutive failures to avoid wasting resources on unreachable candidates.

Knowledge layers: N1 / N2 / N3

Each node has three layers of network awareness, built passively from mesh peer exchanges:

LayerContainsSourceShared?
N1 (Mesh)Live connections + social contactsDirectYes (merged, no addresses)
N2 (Reach)Peers' N1 shares1 hopYes (NodeIds only)
N3 (Search)Peers' N2 shares2 hopsNever

Privacy guarantee: N1 shares merge mesh peers with social contacts into one list, making it impossible for outsiders to distinguish infrastructure connections from social relationships. Addresses are never shared — they're resolved on-demand through the chain.

Discovery cascade when connecting to a specific peer:

  1. Social route cache — cached addresses for follows/audience
  2. Peers table — stored addresses from previous connections
  3. N2: ask reporter — ask the mesh peer who reported the target
  4. N3: chain resolve — 2-hop chain through reporters
  5. Worm search — fan-out to all mesh peers, bloom to wide referrals
  6. Relay introduction — hole punch via intermediary
  7. Own-device relay — route through your own devices (e.g. home computer to phone) when direct connection fails

Encryption: envelope model

ItsGoin uses 1-layer envelope encryption for all private content. The design preserves content addressing (PostId = BLAKE3 of ciphertext) while allowing visibility updates without changing the PostId.

Per-post encryption

Each private post gets a random Content Encryption Key (CEK). The post body is encrypted with ChaCha20-Poly1305 using this CEK. The CEK is then wrapped separately for each intended recipient using X25519 Diffie-Hellman derived from ed25519 identity keys.

PostId = BLAKE3(ciphertext)
CEK = random 256-bit key
ciphertext = ChaCha20-Poly1305(post_body, CEK)
wrapped_key[i] = X25519_DH(author_ed25519, recipient_ed25519[i]) XOR CEK

Visibility is separate metadata — re-wrapping the CEK for new recipients doesn't change the PostId or require re-encrypting the content.

Group keys for circles

Circles (private groups) use per-circle ed25519 keypairs instead of per-recipient wrapping. A single DH operation wraps the CEK for the entire group, keeping overhead constant regardless of group size (~100 bytes vs. ~500 bytes per recipient).

Epoch rotation: when a member is removed, the circle generates a new keypair (new epoch). The new seed is distributed to remaining members. Old posts remain readable with old keys; new posts use the new epoch. Forward secrecy without re-encrypting history.

Visibility levels

LevelEncryptionAudience
PublicNoneAnyone
FriendsPer-recipient CEK wrappingMutual follows
CircleGroup key CEK wrappingCircle members
DirectPer-recipient CEK wrappingSpecified recipients

Sync protocol (v3)

The protocol uses a single ALPN (distsoc/3) with 37+ message types multiplexed over QUIC bi-streams and uni-streams.

Pull-based sync

Every 5 minutes, nodes pull posts from connected peers. The sender filters posts before sending — only posts the requester is authorized to see (based on follows, encryption recipients, and audience membership). This means the requester never learns about posts they can't decrypt.

Push for immediacy

Real-time push via uni-streams for instant delivery:

  • PostNotification (0x42) — lightweight "new post" alert to mesh peers
  • PostPush (0x43) — direct encrypted delivery to recipients
  • ProfileUpdate (0x50) — instant profile propagation
  • DeleteRecord (0x51) — signed deletion propagation
  • VisibilityUpdate (0x52) — re-wrap CEK without changing PostId

Files & content distribution

Content-addressed blobs

Files are stored as content-addressed blobs: BlobId = BLAKE3(file_bytes). Stored on the filesystem in 256 shards (blobs/{hex[0..2]}/{hex}) with metadata in SQLite. Max 4 attachments per post, 10MB each.

CDN hosting tree

Each blob has a hosting tree: 1 upstream source + up to 100 downstream nodes. AuthorManifest (ed25519-signed) carries the author's 10 most recent posts as a neighborhood, traveling with blob responses. ManifestPush propagates updates down the tree.

When a node evicts a blob, it sends BlobDeleteNotice so the tree can heal — downstream nodes find a new upstream.

Eviction priority

When storage fills up, blobs are evicted using a social-aware scoring formula:

priority = pin_boost + relationship * recency * freshness / (peer_copies + 1)

Your own blobs are auto-pinned and never evicted. Blobs from people you follow score higher. Blobs with many copies elsewhere score lower (safe to drop).

Anchors: always-on peers

Anchors are standard ItsGoin nodes running on stable servers. They're regular peers that happen to be always on, which makes them useful for two things:

Anchors maintain a referral list of recently-seen peers with tiered usage caps (3/2/1 uses depending on list size). When an anchor's mesh is full, it keeps session connections for matchmaking so it remains useful as a bootstrap point.

Anchors run the same code as every other node. No special protocol, no special trust, no special services. They're just peers that are always on.

Technology stack

ComponentTechnology
Core libraryRust
P2P networkingiroh 0.96 (QUIC + mDNS)
Local storageSQLite (rusqlite 0.32)
Content addressingBLAKE3
EncryptionChaCha20-Poly1305 + X25519 (from ed25519)
Desktop/mobile shellTauri v2
FrontendPlain HTML/CSS/JS (no build step)
PlatformsAndroid, Linux (AppImage)