My Own Onion Router

Anonymous overlay network with 3-hop onion routing, post-quantum hybrid key exchange, hidden services, and traffic analysis resistance. ~40,000 lines of C across 56 source files. Three dependencies. No OpenSSL.

"Privacy is not a privilege granted by the powerful. It is a right exercised by the free." — The MOOR License

Features

What ships in v0.1.0

🛡

Post-Quantum Key Exchange

CKE (Circuit Key Exchange) with identity-bound HKDF + Kyber768 hybrid at every hop. If classical crypto falls to quantum computers, Kyber still protects you. If Kyber has a flaw, Curve25519 still protects you. No regression.

🌐

3-Hop Onion Routing

Guard, Middle, Exit. No single relay can link sender to destination. Bandwidth-weighted relay selection, guard pinning (Prop 271), /16 subnet restriction, Circuit Build Timeout via Pareto fitting.

🔏

ML-DSA-65 Consensus Signatures

Directory Authority signs consensus with Ed25519 + ML-DSA-65 (FIPS 204 Dilithium3) hybrid. Backward-compatible wire format with PQ magic bytes. Post-quantum authenticity for network state.

🎭

Hidden Services

v3-style .moor addresses. AEAD-encrypted descriptors on a Kademlia DHT (k=3 replicas). Vanguards for guard discovery resistance. PoW-based DoS protection. OnionBalance for multi-instance HS.

📡

Traffic Analysis Resistance

Fixed 514-byte cells. Padding machines (constant-rate, adaptive, jitter). Pluggable transports: Scramble (AEAD random stream), Shade (Elligator2 + AEAD), Mirage (fake TLS 1.3). EWMA circuit scheduling.

🚀

Vegas Congestion Control

Prop 324 delay-based congestion control. BDP estimation, RTT-based slow start exit, per-path constants. Authenticated SENDMEs (Prop 289). XON/XOFF stream-level flow control (Prop 344).

Noise_IK Link Protocol

1-RTT handshake. No certificate authority. The relay's Ed25519 identity key is the trust anchor. ChaCha20-Poly1305 + BLAKE2b. ~300 lines of implementation vs. hundreds of thousands for TLS.

📦

Single Binary, Minimal Dependencies

Client, relay, DA, hidden service, BridgeDB, OnionBalance — all one binary. Dependencies: libsodium, zlib, pthreads. No OpenSSL. No runtime. Auditable by one person.

🗳

Multi-DA Consensus Voting

Directory Authority with SRV commit-reveal, consensus diffs + zlib compression, bandwidth authority measurements, statistical flag assignment, descriptor reaping, directory mirrors.

🌉

Censorship Circumvention

Bridge relays not listed in public consensus. BridgeDB distributes bridge addresses via HTTPS. Bridge Authority for trusted bridge management. Pluggable transports disguise MOOR traffic.

Security

21 audit rounds. Zero tolerance.

150
Issues Fixed
344
Unit Tests
20
Fuzz Harnesses
9.8B+
Fuzz Executions
0
Crashes
0
Data Races
0
Memory Errors
0
Undefined Behavior

AFL++ Fuzzing Campaign — 20 Harnesses, 25 Hours

Every parser, protocol handler, and cryptographic operation was fuzz-tested under AFL++ with afl-clang-fast + AddressSanitizer + UndefinedBehaviorSanitizer across two campaigns (24h + 1h). Combined with the LibFuzzer campaign, this provides dual-engine coverage-guided fuzzing.

afl++ campaign — 20 harnesses × 25 hours — ASan + UBSan
  HARNESS                  EXECUTIONS  CRASHES  HANGS    EXEC/S
  hs_addr               1,276,945,688        0      0   20,278
  cell                  1,218,083,299        0      0   19,656
  lspec                 1,208,487,047        0      0   19,286
  fragment              1,207,841,540        0      0   19,361
  config                1,137,107,163        0      0   17,899
  exit_policy           1,003,798,232        0      0   16,031
  transport               802,058,331        0      0   12,227
  microdesc               473,911,207        0      0    9,208
  cke                     294,118,560        0      0   10,078
  consensus               253,203,988        0      0    5,969
  dht                     244,020,428        0      0    7,329
  guard_state             195,467,552        0      0    3,335
  noise                   179,951,757        0      0    6,781
  noise_ik                150,353,571        0      0    3,294
  socks5                  121,853,015        0      0    8,349
  wire                     38,815,561        0      0   10,757
  kyber                    18,635,776        0      0      313
  handshake                16,037,885        0      0    4,449
  mldsa                     3,723,561        0      0       56
  relay_cell                  194,462        0      0       44
  ───────────────────────────────────────────────────────────────
  TOTAL               9,844,608,623        0      0  194,507
9.8B AFL++ executions
25h continuous runtime
0 crashes or hangs
2 fuzz engines (LibFuzzer + AFL++)

Formal Verification & Analysis

0 Infer security issues
4/4 CBMC proofs verified
PASS dudect constant-time
18/18 NIST KAT tests

Compiler & Runtime Hardening

-fstack-protector-strong — stack canaries
-D_FORTIFY_SOURCE=2 — runtime buffer overflow checks
-fPIE -pie — full ASLR
-Wl,-z,relro,-z,now — GOT hardening (full RELRO)
-fno-strict-aliasing — defense-in-depth for crypto paths
sodium_memcmp() — constant-time comparison (40+ sites)
sodium_memzero() — key material wiped before every free
mlockall() — prevent key material from being swapped
PR_SET_DUMPABLE=0 — prevent core dumps
chmod 0600 — key file permissions enforced

Architecture

Protocol overview

Client Guard Middle Exit Destination Phase 1 Noise_IK 1-RTT link handshake CREATE (CKE + Kyber768) CREATED Phase 2 EXTEND Noise_IK + CREATE CREATED EXTENDED Phase 3 EXTEND Noise_IK + CREATE CREATED EXTENDED 3-hop encrypted tunnel — ChaCha20-Poly1305 per hop Data RELAY_BEGIN TCP connect connected RELAY_CONNECTED RELAY_DATA (onion-encrypted, peeled at each hop)

Fixed-Size Cells

Every cell is exactly 514 bytes on the wire. 4-byte circuit ID, 1-byte command, 509-byte payload. Relay cells carry an 11-byte header leaving 498 bytes for data. No variable-length records. No size-based traffic analysis.

CKE + Hybrid Key Exchange

Each CREATE/CREATED exchange performs CKE (Circuit Key Exchange) with identity-bound HKDF salt and Kyber768 KEM simultaneously. HKDF extract+expand combines both DH outputs into forward/backward ChaCha20-Poly1305 session keys. Kyber ciphertexts (1088 bytes) are fragmented across multiple cells.

Event-Driven I/O

epoll on Linux, poll fallback elsewhere. Single-threaded event loop with a pthread crypto worker pool. Expensive knot/Kyber operations are offloaded to workers, which signal completion via pipe fd back to the event loop.

Hidden Service Rendezvous

Client builds a 3-hop circuit to a rendezvous point. HS builds a 3-hop circuit to the same point. Result: a 6-hop tunnel. Vanguards (L2/L3 restricted middle hops) protect the HS guard from discovery attacks.

Wire Traffic

Captured from a live MOOR network

Below is a real packet capture from a MOOR client fetching http://example.com through a 3-hop circuit. The left panel shows what you sent. The right panel shows what an observer on the network actually sees between you and the guard relay.

your request (plaintext)
GET / HTTP/1.1
Host: example.com
User-Agent: curl/8.5.0
Accept: */*

<!doctype html>
<html>
<head>
    <title>Example Domain</title>
    <meta charset="utf-8" />
    ...
</head>
<body>
<h1>Example Domain</h1>
<p>This domain is for use in
illustrative examples...</p>
</body>
</html>
3 layers ChaCha20
client → guard (tcpdump capture)
198.51.100.47:52670 → 203.0.113.82:9001
length 532  |  Noise_IK + 3× ChaCha20-Poly1305

0212 053d 72b2 cc8f 27c0 cce7 0e2b 6e39
ae5b 2696 6bbd e0cf 8c9a 5365 863e 43d6
2ee3 70b8 20d5 bd13 7af6 e66d 0d95 ba57
943b a40f 731d 287a 33e3 ba59 fd85 7d79
2dd2 9c99 c981 a563 d908 f049 b16e 4880
1f91 0fba dc3e 8b14 4b93 e2a1 aef2 d0b5
be84 1e88 fd40 31f3 c711 f032 6973 5880
7b59 271a 4514 dbfe 9154 3dd3 20d4 71ff
b9cc c3bb c6b5 b93a 5931 209e 6d26 11f3
c0ea da05 6c0c 1d95 5ad4 1d43 f5c5 22f0
9e6f b649 3247 ca28 6ed1 e0db 673e e1c1
43d3 d617 7836 81cf ce90 9feb b891 ecc1
f13f da0f ab7e 1939 cddc 8e65 52ee 0f3f
b922 d8bd dedb 375e d9c4 4b74 ba63 836f
607c 9ce9 1fe2 4e62 5b4c 5145 92b1 f9ea
fa30 831f 8480 e36b 473c 2bbb .... ....
532
bytes per cell
fixed size, every packet identical length
7.987
bits/byte entropy
out of 8.000 maximum (perfect random)
256/256
byte values present
uniform distribution, no structure
PASS
Chi-squared test
χ² = 270.3 < 293 (p > 0.05)

No readable content

HTTP headers, HTML, hostnames, URLs — nothing survives three layers of ChaCha20-Poly1305 encryption wrapped in a Noise_IK transport. An observer sees only random bytes.

No size fingerprinting

Every cell is exactly 514 bytes (532 on the wire with Noise framing). A 10-byte ping and a 498-byte data transfer produce identical packet sizes. No variable-length records, ever.

Statistically indistinguishable from random

Shannon entropy of 7.987 bits/byte and a passing χ² test at p > 0.05 confirm that MOOR wire traffic is indistinguishable from a random byte stream by any statistical test.

Quick Start

Build and run a network

Build from source
# Install dependencies (Ubuntu/Debian)
$ sudo apt install build-essential libsodium-dev zlib1g-dev pkg-config

# Build
$ ./configure
$ make -j$(nproc)
$ make check            # 344 tests, 31 suites
$ sudo make install
Start a network
# Directory Authority
$ moor --mode da --bind 0.0.0.0 --dir-port 9030

# Guard relay
$ moor --mode relay --bind 0.0.0.0 --or-port 9001 \
     --da-address <DA_IP> --da-port 9030 --guard --daemon

# Middle relay
$ moor --mode relay --bind 0.0.0.0 --or-port 9001 \
     --da-address <DA_IP> --da-port 9030 --daemon

# Exit relay
$ moor --mode relay --bind 0.0.0.0 --or-port 9001 \
     --da-address <DA_IP> --da-port 9030 --exit --daemon
Browse through MOOR
# Start client
$ moor --mode client --da-address <DA_IP> --da-port 9030 --socks-port 9050

# Browse through the SOCKS5 proxy
$ curl --socks5-hostname 127.0.0.1:9050 https://example.com
<!doctype html>...

# Hidden service
$ curl --socks5-hostname 127.0.0.1:9050 http://<address>.moor/

Bridges

Censorship circumvention

In censored environments where connections to known MOOR relays are blocked, bridge relays provide an alternative entry point. Bridges are not listed in the public consensus, making them harder for censors to discover and block. Combined with pluggable transports, bridge connections are indistinguishable from normal HTTPS traffic.

Run a Bridge Relay

A bridge is a regular relay that isn't listed in the public consensus. Run one to help users in censored regions:

moor --mode relay --bind 0.0.0.0 --or-port 443 --da-address <DA_IP> --da-port 9030 --bridge --daemon

Use port 443 to blend with HTTPS traffic. Add a pluggable transport for deeper obfuscation.

BridgeDB Distribution

BridgeDB distributes bridge addresses to users via HTTPS. It rate-limits requests and partitions bridges across distribution strategies to resist enumeration.

moor --mode bridgedb --config bridgedb.conf --bind 127.0.0.1 --daemon

Request bridges from this network using the widget below, or run your own BridgeDB for a private deployment.

Connect via Bridge

Configure the client to use a bridge instead of connecting directly to guard relays:

moor --mode client --bridge-address <BRIDGE_IP> --bridge-port 443 --da-address <DA_IP> --da-port 9030 --socks-port 9050

The client connects to the bridge, which forwards traffic into the MOOR network.

Pluggable Transports

Layer a pluggable transport over the bridge connection to defeat deep packet inspection:

Shade — Elligator2-style key obfuscation + AEAD framing. Full DPI resistance.

Mirage — fake TLS 1.3 handshake with real x25519 DH. Looks like normal HTTPS.

Scramble — random-byte stream with AEAD framing + probe resistance.

Request Bridges

Get a set of bridge addresses to connect to the MOOR network from a censored location.

Download

v0.1.0 — Initial release

moor-0.1.0
March 21, 2026
Download .tar.gz

SHA-256: 91c98a042fa2f0118b5c6facca6ef62ef1ec9c0d85636fba3e121690a8d803c5

License

The MOOR License (MIT-compatible)

Privacy is not a privilege granted by the powerful. It is a right exercised by the free. This software exists because surveillance is the default state of the internet, and the only antidote is code that runs, ships, and works.

Cypherpunks write code.

Permission is hereby granted, free of charge, to any person, group, collective, organization, or autonomous entity obtaining a copy of this software and associated documentation, to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, subject to inclusion of the copyright notice.

You are encouraged to: fork this project and make it better. Run a relay — even one relay makes the network stronger. Break the code and tell us how. Teach someone how onion routing works. Deploy this in places where the internet is not free.

"Privacy is necessary for an open society in the electronic age." — Eric Hughes, A Cypherpunk's Manifesto, 1993