Back

Security

Onionloom

I wanted a custom .onion address and nothing out there was fast enough. So I built my own, and it turned into the fastest Tor v3 onion vanity generator there is. Zero unsafe Rust, automatic GPU acceleration, and every single key independently verified before it ever touches your disk.

Here is the problem: you want an onion address that starts with a word. Maybe "loom" or "daddy" or your brand. Tor v3 addresses are 56 characters of base32. Getting a specific prefix is pure brute force: generate random secret keys, compute the Ed25519 public key, encode it, check the first few characters, repeat. Billions of times. The only thing that matters is how fast you can do that loop. Every cycle counts, every memory access counts, every wasted inversion costs you hours.

I built Onionloom to win that loop. It measures your exact hardware, picks the best CPU setup, checks if your GPU can help, and then runs at full tilt until it finds your prefix. No config files, no network, no bullshit. Just a single binary that does one thing as fast as your silicon can go.

How it works

The CPU engine

The standard way to search is: generate a secret, scalar-multiply the curve generator, encode the result, check the prefix. Repeat. The scalar multiplication dominates everything.

Onionloom flips this around. Instead of multiplying each candidate independently, it picks a center point once and precomputes a table of affine offset points that every worker shares. Each candidate is evaluated as a pair: y(P + Q) and y(P - Q), using twisted Edwards addition formulas that share a precomputed product. Evaluating both costs barely more than one. Then an entire batch of 512 paired candidates shares one single field inversion across the whole block using parallel-prefix product chains. Sixteen independent chains feed into one inversion. That is where the speed comes from.

The field arithmetic is pure Rust. Four 64-bit limbs, exact u128 products, a specialized squaring routine that uses ten wide multiplies instead of the usual sixteen. No assembly, no intrinsics, not a single line of unsafe in the entire codebase.

The prefilter

Full base32 encoding is slow, so Onionloom does not do it for most candidates. The first 51 characters of an onion address depend only on the compressed y-coordinate of the public key. One bit, the x-coordinate sign, matters for character 50. The prefilter masks that bit for long prefixes, so nothing slips through. First-character buckets handle up to eight non-overlapping prefixes before the masked comparison even runs. No allocation, no encoding, no hashing in the hot loop.

GPU acceleration

The GPU path runs the same coordinate-symmetry search, just massively parallel. Each 128-lane workgroup owns a center point, pairs 127 offsets, and checks 255 candidates per round. A product tree batch-inverts all denominators in one pass.

Here is the part I care about: the GPU never touches your secret key. It gets public points and public masks. When it returns a candidate offset, the CPU recomputes the full public key through curve25519-dalek and verifies the prefix before anything gets saved. A driver bug or a bad shader compile cannot produce a wrong key. Automatic mode validates exact GPU arithmetic against the CPU, tunes the workgroup count, and only enables the GPU when it actually helps. If anything fails, it falls back to CPU without you noticing.

What works where:

  • Linux: any Vulkan GPU with 64-bit integer shaders and 128+ lanes (NVIDIA 900 series and up, AMD GCN 2+, Intel Arc)
  • Windows: same hardware, DirectX 12 or Vulkan, whichever your driver prefers
  • macOS: Metal on Apple Silicon, AMD, or Intel GPUs

Key output

A prefix match is only a candidate. Before writing to disk, Onionloom applies the offset, checks clamp bits, recomputes the public key through an independent Dalek multiplication, validates the onion address checksum, and confirms the exact prefix. The output directory is built as a temporary, all three files are synced and read back, and only then is it renamed to its final hostname. Existing keys are never overwritten. You will not wake up to find your live onion service replaced.

What you get:

output directory
onions/loom4skeblahblahblah.onion/
  hostname              # your .onion address
  hs_ed25519_public_key # Tor tagged public key
  hs_ed25519_secret_key # keep this safe

Drop that folder into your Tor daemon's HiddenServiceDir and your site is live.

The limits

Prefix length is the lever. Four characters takes minutes. Seven can take days. Every extra character multiplies the work by 32, and there is no shortcut. That is the math, not a limitation of the tool. Onionloom shows you the probability, the expected wait, and the 95th percentile before it starts, so you know exactly what you are signing up for.

Checkpoints contain your secret key. They let you pause and resume a week-long search, which is exactly what they are for. Keep them on encrypted storage and never sync them anywhere.

Install

Pre-built binaries for Linux, macOS, and Windows on GitHub. Or build from source for your exact CPU.

shell
cargo install onionloom --locked

# or clone and build (faster, targets your CPU)
git clone https://github.com/chrisch88dev/onionloom
cd onionloom
./build.sh

Usage

Measure your machine, then search.

shell
./onionloom evaluate          # measure this machine
./onionloom guess loom        # estimate without generating
./onionloom search loom       # generate a key
./onionloom search loom --continuous
./onionloom search longname --gpu force
./onionloom verify            # validate all generated keys

Open source under Apache 2.0. The crate is on crates.io.

github.com/chrisch88dev/onionloom

crates.io/crates/onionloom