"Hidden services" — now officially called "onion services" — are one of the most misunderstood primitives on the internet. They are not a synonym for crime. They are a way to publish a service whose location is not revealed to clients, with end-to-end encryption and strong authentication built into the address itself. The same protocol that serves ransomware leak sites also serves Facebook (facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion), The New York Times, and ProPublica.

The Address is a Public Key

In v3, the 56-character onion address is a base32 encoding of an Ed25519 public key plus a checksum and version byte. Roughly:

onion_address = base32(pubkey || checksum || version) + ".onion"
checksum = SHA3-256(".onion checksum" || pubkey || version)[:2]

The upshot is that connecting to xyz...onion gives you cryptographic certainty you are talking to the holder of the matching Ed25519 private key. Unlike TLS, there is no CA to trust and no mis-issuance story. The name is the key. This is a beautiful property.

Descriptors and the Rendezvous Protocol

An onion service doesn't sit on a listening IP you connect to. Instead:

  • The service picks a set of introduction points — ordinary Tor relays — and builds circuits to them.
  • It signs a descriptor (listing those intro points) with its long-term key and uploads it to the hash-ring of HSDir relays. In v3, the descriptor is blinded, so HSDirs cannot learn the underlying onion address without already knowing it.
  • A client fetches the descriptor, picks a rendezvous point (another Tor relay), and sends an INTRODUCE cell through an intro point containing the rendezvous cookie.
  • The service connects out to the rendezvous point, and client and service meet there, each at the end of a three-hop Tor circuit. Total: six hops between them.

Neither side ever learns the other's IP address. The rendezvous relay doesn't know who the service is. The intro points don't see the payload. That's the shape of it.

Vanity Addresses

You've probably seen onion addresses that start with a human-readable prefix. Those are generated by brute-forcing Ed25519 keypairs until the base32 encoding of the public key starts with your desired string. The standard tool is mkp224o. Short prefixes (4–6 characters) take seconds to minutes on a CPU. Longer prefixes scale exponentially — an 8-character prefix is hours; 10 is days on fast GPUs; 16 characters is computationally impractical. Facebook's address famously took many CPU-years; they got lucky.

./mkp224o -d output_dir -n 4 macwan

Operational Realities

Running an onion service is technically easy — add two lines to torrc, restart Tor, read hostname. Running one well is a different problem:

  • The hs_ed25519_secret_key file is the service's soul. Lose it and the address is gone forever. Leak it and someone else can impersonate the service.
  • If your web server leaks its real IP via a test page, a misconfigured virtual host, an email header, or a scheduled outbound request, the anonymity property is gone.
  • Onion services have real latency and real DDoS exposure. The Tor Project has done significant work on PoW defenses ("HiddenServiceEnableIntroDoSDefense"), but a popular service still feels the load.

Onion services are a primitive, not a product. Used deliberately — for authenticated internal tools, for whistleblower drop-boxes, for censorship-resistant mirrors — they are one of the most powerful anti-surveillance technologies we have.