3-Hop Relay Routing
Technical specification of anonymous message routing in Zentalk.
Overview
Zentalk implements its own 3-hop relay routing system (not Tor) to prevent network observers and servers from correlating senders with recipients. Messages travel through 3 relay nodes, with each hop encrypted using a separate key. This is a native Go implementation optimized for Zentalk’s architecture.
Not Tor: While conceptually similar to onion routing, Zentalk uses its own relay infrastructure with RSA-4096 layer encryption, integrated with E2EE (Double Ratchet), stealth addresses, and traffic padding. Unlike Tor, the exit relay delivers to a stealth address, not cleartext.
Circuit Architecture
3-Hop Design
| Node | Position | Knowledge |
|---|---|---|
| Guard | 1st hop | Knows client IP, not destination |
| Middle | 2nd hop | Knows neither client nor destination |
| Exit | 3rd hop | Knows destination, not client |
No single node can correlate sender with recipient.
Circuit Building
Node Selection
| Step | Action | Criteria |
|---|---|---|
| 1 | Select Guard | From trusted guard set, geographic diversity |
| 2 | Select Middle | Random, exclude Guard’s family |
| 3 | Select Exit | Random, exclude Guard/Middle families |
Guard Node Persistence
| Property | Value |
|---|---|
| Guard set size | 3 nodes |
| Guard rotation | 90 days |
| Selection | Weighted by bandwidth/uptime |
| Fallback | Secondary guard if primary fails |
Rationale: Long-term guards prevent an adversary from observing many different entry points.
Family Exclusion
Nodes operated by the same entity are grouped into “families”:
If Guard in Family A:
- Middle must NOT be in Family A
- Exit must NOT be in Family A
Prevents: Same operator controlling multiple hopsEncryption Layers
Layer Construction
Messages are encrypted in reverse order (exit → middle → guard):
1. Start with E2EE payload: M
2. Exit layer:
C3 = AES-256-GCM(Key_exit, M || "exit_addr")
3. Middle layer:
C2 = AES-256-GCM(Key_middle, C3 || "middle_addr")
4. Guard layer:
C1 = AES-256-GCM(Key_guard, C2 || "guard_addr")
5. Send C1 to GuardPer-Hop Key Establishment
Each hop requires a separate key exchange:
Circuit Extension Protocol:
1. Client → Guard:
- CREATE cell with X25519 ephemeral
- Guard responds with X25519 + derived key
2. Client → Guard → Middle:
- EXTEND cell (encrypted for Guard)
- Guard relays CREATE to Middle
- Middle responds, relayed back
3. Client → Guard → Middle → Exit:
- EXTEND cell (encrypted for Guard, Middle)
- Establish key with ExitKey Derivation
For each hop:
DH_output = X25519(client_ephemeral, node_public)
Key_forward, Key_backward = HKDF(DH_output, "ZentalkCircuit")Message Format
Onion Cell Structure
┌─────────────────────────────────────────┐
│ Circuit ID (4 bytes) │
├─────────────────────────────────────────┤
│ Cell Command (1 byte) │
├─────────────────────────────────────────┤
│ Encrypted Payload (509 bytes, padded) │
├─────────────────────────────────────────┤
│ Nonce (12 bytes) │
├─────────────────────────────────────────┤
│ Authentication Tag (16 bytes) │
└─────────────────────────────────────────┘
Total: 542 bytes (fixed size)Cell Commands
| Command | Code | Purpose |
|---|---|---|
| CREATE | 0x01 | Establish new circuit |
| CREATED | 0x02 | Circuit established |
| EXTEND | 0x03 | Extend circuit to next hop |
| EXTENDED | 0x04 | Extension successful |
| RELAY | 0x05 | Relay data through circuit |
| DESTROY | 0x06 | Tear down circuit |
| PADDING | 0x07 | Dummy traffic |
Traffic Analysis Resistance
Fixed Cell Size
All cells are exactly 542 bytes:
| Content Size | Padding Added |
|---|---|
| 100 bytes | 409 bytes |
| 300 bytes | 209 bytes |
| 509 bytes | 0 bytes |
Constant-Rate Traffic
Traffic Pattern:
├── Real messages (when available)
└── PADDING cells (when idle)
Rate: 1 cell per 100ms (configurable)Prevents: Timing correlation between send and receive.
Traffic Padding Parameters
| Parameter | Value |
|---|---|
| Padding mode | Cover traffic |
| Cell rate | 10 cells/second |
| Burst handling | Queue and send at constant rate |
| Idle padding | 50% of normal rate |
Node Discovery
DHT-Based Discovery
1. Client queries DHT for relay nodes
2. Receives signed node descriptors
3. Verifies signatures against known keys
4. Caches node list locallyNode Descriptor
| Field | Size | Purpose |
|---|---|---|
| Node ID | 32 bytes | Ed25519 public key |
| Addresses | Variable | IP:port pairs |
| Bandwidth | 4 bytes | Self-reported capacity |
| Uptime | 4 bytes | Time since last restart |
| Signature | 64 bytes | Ed25519 signature |
| Timestamp | 8 bytes | Descriptor creation time |
Node Selection Weights
Weight = Bandwidth × Uptime_factor × Diversity_factor
Where:
Uptime_factor = min(uptime_days / 30, 1.0)
Diversity_factor = 1.0 if geographically diverse, 0.5 otherwiseCircuit Lifecycle
States
| State | Description |
|---|---|
| BUILDING | CREATE/EXTEND in progress |
| READY | All hops established |
| ACTIVE | Carrying traffic |
| CLOSING | DESTROY sent |
| CLOSED | Resources released |
Timeouts
| Phase | Timeout |
|---|---|
| Circuit build | 30 seconds |
| Idle circuit | 10 minutes |
| Message relay | 60 seconds |
| Total circuit lifetime | 24 hours |
Circuit Rotation
1. Build new circuit in background
2. Continue using old circuit
3. When new circuit ready:
- Migrate new messages to new circuit
- Let old circuit drain
4. Destroy old circuitSecurity Properties
| Property | Mechanism |
|---|---|
| Sender anonymity | Guard node hides client IP |
| Recipient anonymity | Exit node hides destination |
| Unlinkability | No node sees both endpoints |
| Forward secrecy | Per-circuit ephemeral keys |
| Replay protection | Nonces, circuit IDs |
Attack Mitigations
End-to-End Correlation
| Attack | Mitigation |
|---|---|
| Timing analysis | Constant-rate traffic |
| Volume analysis | Fixed cell size |
| Pattern analysis | Traffic padding |
Node Compromise
| Attack | Mitigation |
|---|---|
| Single node | 3-hop design, limited knowledge |
| Two colluding nodes | Probabilistic, family exclusion |
| All three nodes | Statistical detection (anomalous) |
Sybil Attack
| Attack | Mitigation |
|---|---|
| Fake nodes | Proof-of-stake requirement |
| Bandwidth lying | Measurement by other nodes |
| Eclipse attack | Multiple bootstrap sources |
Performance
| Metric | Value |
|---|---|
| Latency overhead | ~100-300ms |
| Bandwidth overhead | ~10% (headers + padding) |
| Circuit build time | 500ms-2s |
| Max throughput | Limited by slowest hop |
Configuration
| Option | Default | Range |
|---|---|---|
| Hop count | 3 | 3 (fixed) |
| Guard count | 3 | 1-5 |
| Padding rate | 10/s | 1-20/s |
| Circuit lifetime | 24h | 1h-48h |
Related Documentation
- Protocol Specification - E2EE details
- Architecture - System components
- Threat Model - Security analysis