The network that forgets.
Anonymous peer-to-peer communication where no node — not even one controlled by a nation-state with full backbone access — can determine who is talking to whom.
# Install
go install github.com/Operative-001/lethe/cmd/lethe@latest
# One command to start
lethe keygen && lethe daemonSet your browser's SOCKS5 proxy to 127.0.0.1:1080. Done.
| Tool | What They Know About You |
|---|---|
| Signal | Your phone number. Who you message. When. How often. |
| Tor | Guard node sees your IP. Exit node sees your destination. |
| I2P | Entry/exit guards. NetDB directory servers. Complex tunnel metadata. |
| VPN | Your provider sees everything. One subpoena away from full exposure. |
| Telegram | Your phone, IP, all messages. Contacts graph. Location metadata. |
The root problem: every existing system has asymmetry. There is a "client" (identified) connecting to a "server" (known). Anonymity tools try to hide one or the other, but the structural asymmetry remains.
Lethe eliminates the asymmetry entirely.
Every node does three things, always, unconditionally:
Node A: ████████████████████████████████ (10 packets/sec, always)
Node B: ████████████████████████████████ (10 packets/sec, always)
Node C: ████████████████████████████████ (10 packets/sec, always)
Most of these packets are dummies — cryptographically indistinguishable from real messages. When a real message exists, it replaces a dummy in the pre-committed queue. From the outside: constant noise, forever. There is no traffic spike when you send. There is no silence when you don't.
Every packet goes to every node. There are no routing tables, no paths, no circuits, no guards, no exits. The network topology is flat. Every node is simultaneously a sender, relay, and potential recipient.
Alice sends → every node receives the same packet
↓
Each node tries to decrypt with its private key
Only Bob's key produces a valid authentication tag
Bob receives. Alice is invisible.
Your public key is your address. Messages are encrypted to your key using ECIES (X25519 + ChaCha20-Poly1305). Every node receives every packet and attempts decryption. For 99.99% of nodes, decryption fails — expected and normal. For the recipient, it succeeds.
No node ever knows who a packet is addressed to. Not the relays. Not the ISP watching the wire. Not a global passive adversary watching all traffic simultaneously.
Sending a message directly would expose your IP as the origination point. Lethe prevents this with double-layer encryption:
Alice wants to message Bob:
1. Alice encrypts inner payload to Bob's key
2. Alice wraps it in an outer layer encrypted to Relay R's key
Outer payload = { "forward": <inner packet> }
3. Alice sends the outer packet to R
→ From the network's view: R is the origin of the inner packet
4. R decrypts outer layer, sees "forward this"
→ Re-broadcasts inner packet at its own next scheduled tick
→ Indistinguishable from R's own outbound traffic
5. Every node receives inner packet
→ Bob decrypts successfully
→ No node knows Alice originated this
Since all nodes are always doing wrap-and-forward as part of their normal operation, Alice's outbound packet is invisible in the constant stream.
All nodes emit constant traffic regardless of real message load. There is no signal in volume.
The network-observable origin of any packet is the wrap-and-forward relay, not the true sender. Multiple relays can be chained.
No store-and-forward. If the recipient is offline, the message is not delivered. There is no "Bob came online and processed queued messages" signal to observe.
Because every node re-broadcasts every packet regardless of whether they could decrypt it, no node's behavior changes on receipt. The recipient's re-broadcast is indistinguishable from the relay's re-broadcast.
Every node randomly selects different relays per message. No persistent Alice→Relay relationship exists to observe statistically.
When first joining, a new node must contact bootstrap peers (revealing IP to those specific peers). Mitigated by bootstrapping over Tor or using multiple bootstrap nodes across jurisdictions.
If a node sends messages but never maintains cover traffic (violates protocol), statistical timing attacks are possible over thousands of messages. The protocol mandates constant traffic; compliant nodes are protected.
go install github.com/Operative-001/lethe/cmd/lethe@latestOr build from source:
git clone https://github.com/Operative-001/lethe
cd lethe
make install# Generate your identity (one time)
lethe keygen
# Start the node — proxy is immediately available on :1080
lethe daemon
# With bootstrap peers (to join an existing network)
lethe daemon --bootstrap "peer1.example.com:4242,peer2.example.com:4242"Firefox: Settings → Network → Manual proxy → SOCKS5: 127.0.0.1:1080
Chrome/Chromium:
chromium --proxy-server="socks5://127.0.0.1:1080"From the daemon interactive console, or in a separate terminal:
# Register your name (broadcasts to network)
lethe register alice
# Send to a registered name
lethe send bob "hello"
# Send to a raw public key
lethe send a3f4b2c1d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2 "hello"Host a Hidden Service
Run any local HTTP server and expose it anonymously through the network:
# Start your content server
python3 -m http.server 8080
# or: nginx, node, flask, anything on any port
# Expose it via Lethe (no server, no domain, no IP revealed)
lethe daemon --expose 8080
# Register a human-readable name
# (from the daemon console type:)
> register mysiteAnyone with your public key (printed on daemon start) can now reach your service:
- Set SOCKS5 →
127.0.0.1:1080in browser - Navigate to
http://<your-pubkey>.lethe/ - Or if you registered:
http://mysite.lethe/
No DNS. No CDN. No registrar. No IP address ever leaves your machine.
# Terminal 1 — Host: runs an HTTP server exposed via Lethe
lethe keygen --data /tmp/host
python3 -m http.server 8080 &
lethe daemon --data /tmp/host --listen 0.0.0.0:4242 --expose 8080
# Terminal 2 — Client: browses the hidden service
lethe keygen --data /tmp/client
lethe daemon --data /tmp/client --listen 0.0.0.0:4243 --proxy 127.0.0.1:1080 \
--bootstrap 127.0.0.1:4242
# Set browser SOCKS5 → 127.0.0.1:1080
# Navigate to http://<host-pubkey>.lethe/
# You're browsing via the anonymous tunnel — host never saw your IP| Property | Value |
|---|---|
| Packet size | Fixed 1024 bytes (uniform, no size leakage) |
| Symmetric encryption | ChaCha20-Poly1305 |
| Key agreement | X25519 ECDH (ephemeral per message) |
| Key derivation | HKDF-SHA256 |
| Signing | Ed25519 (directory entries only) |
| Transport | TCP (pluggable) |
| Broadcast rate | 10 packets/sec per node (configurable) |
| TTL | 8 hops default |
| Deduplication | 32-byte nonce ring buffer, 60s expiry |
| Directory | Local bbolt DB, broadcast-synchronized |
| Identity | X25519 pubkey = address (no username required) |
Full specification: PROTOCOL.md
┌─────────────────────────────────────────────────────────┐
│ lethe daemon │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌───────────┐ │
│ │ Broadcast │ │ Node │ │ SOCKS5 │ │
│ │ Scheduler │◄───│ Engine │───►│ Proxy │ │
│ │ 10 pkt/s │ │ │ │ :1080 │ │
│ └─────────────┘ └──────┬───────┘ └───────────┘ │
│ │ │
│ ┌────────┴────────┐ │
│ │ │ │
│ ┌─────┴───┐ ┌────────┴──┐ │
│ │ Seen │ │ Directory │ │
│ │ Cache │ │ (bbolt) │ │
│ └─────────┘ └───────────┘ │
└─────────────────────────┬───────────────────────────────┘
│ TCP transport
┌──────┴──────┐
│ Peer mesh │
└─────────────┘
What Lethe protects against:
- Network-level observers (ISPs, backbone taps)
- Compromised relay nodes
- Statistical traffic analysis
- Confirmation attacks by active adversaries
- Timing correlation for compliant nodes
What Lethe does NOT protect against:
- Endpoint compromise (if your device is owned, you're owned)
- Bootstrap phase IP exposure (mitigate: bootstrap over Tor)
- Long-term statistical attacks against non-compliant nodes (nodes that don't maintain cover traffic)
- Quantum computers breaking X25519 (future: upgrade to post-quantum KEM)
# Run all tests
make test
# Run tests with race detector
make test-race
# Build binary
make build
# Install
make installinternal/crypto — ECIES roundtrip, wrong key, key save/load
internal/protocol — packet encode/decode, size invariant
internal/seen — add/has, expiry, concurrent access
internal/directory — signature verification, timestamp ordering
internal/node — direct delivery, wrap-and-forward, deduplication, TTL
- v0.1 (current): Core protocol, CLI, SOCKS5 proxy, TCP-over-Lethe tunneling, hidden service hosting (
--expose), anonymous messaging - v0.2: Daemon IPC socket for
lethe sendwithout console, multi-hop relay chaining UI, persistent peer list - v0.3: Mobile library (iOS/Android via gomobile)
- v0.4: Post-quantum key encapsulation (ML-KEM / Kyber-1024)
- v0.5: Chaumian batch mixing mode for maximum anonymity (adds latency)
Lethe (λήθη) — in Greek mythology, one of the five rivers of the underworld. Souls who drank from it forgot all earthly memories. The network forgets everything: who sent, who received, when, how often.
MIT