Generating Solana vanity addresses at 17 billion per second with caveman's `vanity`
Don't grind ed25519 keypairs. cavemanloverboy's vanity grinds CreateAccountWithSeed inputs (SHA-256) at ~1.3B searches/sec per 4090. Trade-offs explained.
Solana vanity addresses — the kind that start with your project's name, your initials, or just a lot of 1s — have always been a brute-force problem. The classic recipe: generate ed25519 keypairs in a tight loop, check whether the public key starts with your target prefix, throw it away if not. Repeat until you get lucky.
That works. It's also slow. Each iteration is a full ed25519 keygen, and even on a fast machine you're looking at tens of thousands of attempts per second. A 7-character prefix can take hours; an 8-character one can take days.
cavemanloverboy/vanity takes a different shape. Instead of grinding keypairs, it grinds CreateAccountWithSeed inputs — and on a single RTX 4090, it does 1.2-1.3 billion searches per second. On a 14-GPU rig: ~17 billion/sec. That puts 9-10 character prefixes inside a coffee break.
Why it's so much faster
A normal Solana address comes from an ed25519 keypair: you generate a random 32-byte private key, derive the 32-byte public key via scalar-multiplication on the curve, and that's your address. Expensive — there's a curve operation per iteration.
CreateAccountWithSeed works differently. The address is derived deterministically from three inputs:
address = SHA-256(base_pubkey || seed_string || owner_program_id)You fix the base and owner, then iterate over seed strings. Each iteration is just a single SHA-256 hash — no curve math, no keypair generation. SHA-256 is exactly the kind of inner loop GPUs eat for breakfast (it's the bitcoin mining workload, after which billions of dollars of silicon has been optimized).
That's the whole trick. Different primitive, different math, orders of magnitude faster.
Install
# CPU version
cargo install vanity
# GPU version (requires CUDA toolkit)
cargo install vanity --features=gpuUsage
vanity \
--base <YOUR_BASE_PUBKEY> \
--owner <OWNER_PROGRAM_ID> \
--target <PREFIX> \
[--case-insensitive]For a vanity SPL token mint owned by the Token program, that would look like:
vanity \
--base 3CZv6CUmrZqEC4o5GxJk3M1aLrFmZ7CCu5gXcKfQGgsq \
--owner TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA \
--target METASAL \
--case-insensitiveIt prints the seed string that, when plugged into SystemProgram.createAccountWithSeed, produces an address starting with METASAL....
Using the result on-chain
Once you have the seed, you create the account with web3.js (or any Solana SDK) like this:
import {
Connection,
Keypair,
PublicKey,
SystemProgram,
Transaction,
} from "@solana/web3.js"
const baseKp = Keypair.fromSecretKey(/* your base keypair */)
const owner = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
const seed = "the-seed-vanity-printed"
// This is the vanity address — computed deterministically from (base, seed, owner)
const newAccount = await PublicKey.createWithSeed(baseKp.publicKey, seed, owner)
console.log("vanity address:", newAccount.toBase58())
// Create the account at that address
const tx = new Transaction().add(
SystemProgram.createAccountWithSeed({
fromPubkey: baseKp.publicKey,
basePubkey: baseKp.publicKey,
seed,
newAccountPubkey: newAccount,
lamports: await connection.getMinimumBalanceForRentExemption(82),
space: 82,
programId: owner,
})
)
await connection.sendTransaction(tx, [baseKp])The signer is the base keypair, not the vanity address itself. That's the key conceptual shift, and it's what makes the whole approach work.
The catch
You don't get a vanity keypair. You get a vanity address that is owned by a program of your choosing. The base keypair is the only thing that can sign for it. That's perfect for:
- Token mints — vanity mint address, owned by the Token program. Authority is your base key.
- Program-deployed data accounts — vanity addresses for storage your program reads/writes.
- NFT/collection accounts — make the metadata or collection address itself a brand asset.
It's not a drop-in replacement for a wallet-style vanity address where you want a real, exportable Ed25519 private key behind it. For that, you still need the classic keypair grind (tools like solana-keygen grind or the various GPU-accelerated keypair grinders). Slower, but produces a normal signable keypair.
Benchmark numbers
caveman's own benchmarks from the repo (as of mid-2025):
- 1 × RTX 4090: ~1.2-1.3B searches/sec
- 14 × RTX 4090 rig: ~17B searches/sec total
Practical implication: a 6-character case-insensitive prefix on a single 4090 finishes in roughly a second. 8 characters is a few minutes. 10 characters is hours. Beyond that you're renting GPU time on Vast.ai or RunPod and budgeting in dollars-per-character.
When to reach for it
Use vanity: when you want a token mint, program data account, NFT collection, or any program-owned account at a memorable address.
Use a keypair grinder: when you need a vanity wallet — something the user holds the private key for, can import into Phantom, can use to sign arbitrary transactions.
The repo
- github.com/cavemanloverboy/vanity — Apache-2.0, ~48% C / 37% CUDA / 15% Rust (the language ratios themselves tell you where the speed comes from)
- Author: @cavemanloverboy — Solana-native, prolific shipper of low-level performance tooling
If your project ever wanted a token mint starting with its own name, this is the right tool, used the right way.