Introduction
btc-vanity is a blazingly fast local vanity-address search tool for Bitcoin, Ethereum, and Solana addresses whose text matches a pattern you choose. It generates candidates locally, derives each candidate's address, and stops when one matches. The result is a normal keypair: the vanity text changes how the address looks, not how the network treats it.
The program offers four execution backends:
| Backend | What it does |
|---|---|
| CPU | Runs worker threads on the processor |
| GPU | Runs an exact-pattern compute pipeline on a graphics adapter |
| Hybrid | Races CPU and GPU work and returns the first valid result |
| Auto | Chooses a backend from the pattern and available build support |
GPU support is experimental. Adapter behavior and responsiveness vary with the operating system, graphics API, driver, and workload. CPU search is the most portable option.
What the program supports
- Bitcoin mainnet P2PKH addresses with compressed public keys
- Lowercase Ethereum addresses, displayed with a
0xprefix by the CLI - Solana public-key addresses
- Prefix, suffix, and substring matching
- CPU regular expressions
- Single searches and line-oriented batch files
- A command-line program and a generic Rust API
Set expectations before a long search
A search samples independent keys until one address matches. It cannot edit an existing address, preserve an existing private key, or guarantee a completion time. Every extra constrained character makes the target rarer, so difficulty usually grows exponentially.
Start with two or three characters, measure your actual machine, and extend the pattern only after the expected wait and energy cost are acceptable. A fast result is possible even for a difficult pattern, but so is a run much longer than the average.
A safe reading path
- Learn what a vanity address is.
- Install only the chain and backend features you need.
- Complete your first search with a short test pattern.
- Read Security before receiving funds at a generated address.
- Use Choosing a backend before committing to a longer search.
What is a vanity address?
A cryptocurrency wallet starts with private key material. Cryptographic curve operations derive a public key from it, and the chain's address format derives the address from that public key.
The private key authorizes spending or signing. The public key and address are safe to share for their intended purpose; the private key is not. Anyone who obtains a generated private key may be able to control assets associated with it.
Why the address cannot be edited
An address is not a profile name stored beside a key. It is the deterministic output of cryptographic operations and an encoding pipeline. Changing one visible character would ordinarily produce a string that no longer corresponds to the original public key, or that fails the format's checksum.
Vanity generation therefore works by brute force:
- Generate candidate private key material.
- Derive its public key.
- Derive and encode the address.
- Compare the address with the requested pattern.
- Keep the first matching keypair and discard the other candidates.
The search does not weaken or reverse the address pipeline. It searches for a keypair whose normal address happens to have the desired text.
Why difficulty grows quickly
Suppose each requested character has A plausible values. A particular
n-character prefix then has probability around 1 / A^n per candidate, and
needs around A^n candidates on average. The exact probability depends on the
chain, position, case rules, and encoding, but the exponential shape remains.
Bitcoin and Solana use the Base58 alphabet, which removes visually ambiguous
characters such as 0, O, I, and l. Ethereum addresses in this project
are hexadecimal, so each digit has 16 possible values. These alphabets are not
interchangeable: a valid hexadecimal pattern can be invalid Base58 and vice
versa.
Prefix and suffix constraints are generally rarer than an equally long substring, because a substring has several possible positions. Case-insensitive matching may also accept more candidates than case-sensitive matching.
What a vanity address does not provide
A memorable address is not proof of identity, ownership, or trustworthy software. It does not make a transaction safer, add a password, or protect the private key. Verify the full address through a trusted channel; similar-looking addresses remain a common source of mistakes.
Installation
btc-vanity requires Rust 1.89 or newer. The default build includes Bitcoin CPU search and no optional features.
Install the command-line program
Install the smallest feature set that covers your use:
# Bitcoin on CPU
cargo install btc-vanity
# Bitcoin with experimental GPU support
cargo install btc-vanity --features gpu
# Add one optional chain
cargo install btc-vanity --features ethereum
cargo install btc-vanity --features solana
# Bitcoin, both optional chains, and GPU
cargo install btc-vanity --features all
The Cargo features are:
| Feature | Adds |
|---|---|
ethereum | Ethereum key and address support |
solana | Solana key and address support |
gpu | Experimental GPU and Hybrid acceleration through wgpu |
all | ethereum, solana, and gpu |
Features are additive. For example, Ethereum with GPU support uses
--features ethereum,gpu.
Build a checkout
git clone https://github.com/Emivvvvv/btc-vanity.git
cd btc-vanity
cargo build --release --features all
./target/release/btc-vanity --help
Use the release binary for meaningful performance measurements. Debug builds favor diagnostics over search throughput.
GPU requirements
The gpu feature uses wgpu, which reaches native Metal, Vulkan, or DirectX 12
backends depending on the platform and driver. Building the feature does not
guarantee that a usable adapter will be available at runtime.
If explicit GPU initialization fails, update the graphics driver or use
--backend cpu. Auto and Hybrid can continue on CPU when GPU work is not
available. See Troubleshooting for specific errors.
Your first search
Use a short, nonvaluable test search first:
btc-vanity --backend cpu --prefix abc
Bitcoin is the default chain and prefix is the default match mode. For Bitcoin
prefix search, btc-vanity accounts for the fixed leading 1, so the command
looks for an address beginning with 1abc.
The program reports the selected settings, searches, and then prints the private key, public key, address, and elapsed time. The values are intentionally not reproduced in this manual: every successful run creates fresh secret material.
Confirm the result without retaining it
For this first test, use a disposable result:
- Check that the printed address has the requested prefix.
- Do not send funds to it.
- Clear terminal scrollback or close the disposable session when finished.
Terminal output contains a private key. Redirecting output, copying the terminal, or recording the session creates additional secret copies.
Try another match mode
btc-vanity --backend cpu --suffix abc
btc-vanity --backend cpu --anywhere abc
These modes search the complete encoded address. Prefix, suffix, and anywhere are exact-pattern modes; regular expressions are a separate CPU-only mode.
Try another chain
The corresponding feature must have been enabled during installation:
btc-vanity --eth --backend cpu --prefix abc
btc-vanity --sol --backend cpu --prefix abc
Ethereum patterns use hexadecimal digits and should omit 0x. Solana patterns
use Base58. Read Bitcoin, Ethereum, and Solana before comparing
their search costs.
Bitcoin, Ethereum, and Solana
The three chains use different curves, address pipelines, alphabets, and display conventions. A pattern valid on one chain may be impossible on another.
| Chain | Curve | Address text in this project | Cargo feature |
|---|---|---|---|
| Bitcoin | secp256k1 | Mainnet P2PKH Base58Check, starts with 1 | built in |
| Ethereum | secp256k1 | 40 lowercase hexadecimal digits; CLI adds 0x | ethereum |
| Solana | Ed25519 | Base58-encoded public key | solana |
Bitcoin
btc-vanity generates a secp256k1 private key, derives a compressed public key,
and produces a mainnet pay-to-public-key-hash (P2PKH) address. Prefix input does
not include the fixed leading 1:
btc-vanity --btc --prefix Ab
This searches for 1Ab by default with ASCII case-insensitive comparison.
Bitcoin exact patterns must use the Base58 alphabet. 0, O, I, and l are
not valid Base58 characters.
Ethereum
btc-vanity derives an uncompressed secp256k1 public key, hashes the 64-byte
coordinates, and uses the last 20 bytes as the address. Internally the address
is 40 lowercase hex digits without a prefix. The CLI adds 0x when displaying
it.
btc-vanity --eth --prefix dead
Patterns must contain only 0-9, a-f, or A-F and must omit 0x. Ethereum
plain matching is case-insensitive; --case-sensitive is rejected. The project
does not generate mixed-case checksum display addresses.
Solana
btc-vanity creates a 32-byte seed, derives an Ed25519 keypair, and encodes the 32-byte public key with Base58:
btc-vanity --sol --suffix Ab
Solana has no fixed leading character. Its exact patterns use the same Base58
alphabet validation as Bitcoin, and matching is case-insensitive unless
--case-sensitive is set.
Length limits
Fast mode is enabled by default as a guard against accidentally requesting a very long search:
| Chain | Fast-mode maximum | Absolute maximum |
|---|---|---|
| Bitcoin | 5 pattern characters | 25 |
| Ethereum | 16 hexadecimal characters | 40 |
| Solana | 5 pattern characters | 25 |
--disable-fast removes the fast-mode limit, not the absolute limit. Passing
validation does not imply that a search is practical. Even much shorter
patterns can require substantial time.
Matching
btc-vanity has three exact-pattern modes and one regular-expression mode.
| Mode | CLI flag | Match location | Backend support |
|---|---|---|---|
| Prefix | --prefix, -p | Start of address | CPU, GPU, Hybrid, Auto |
| Suffix | --suffix, -s | End of address | CPU, GPU, Hybrid, Auto |
| Anywhere | --anywhere, -a | Any position | CPU, GPU, Hybrid, Auto |
| Regex | --regex, -r | Rust regular expression | CPU; Auto/Hybrid route to CPU |
Prefix is the default. Match-mode flags conflict, so select at most one.
Chain adjustments
Bitcoin prefix search prepends the address's fixed 1 to the pattern. A pattern
of abc therefore tests for 1abc. Bitcoin regex patterns beginning with ^
are similarly adjusted to include 1 unless they already begin with ^1.
Ethereum exact matching uses the internal 40-character hexadecimal address.
Do not include 0x in an exact pattern.
Solana performs no prefix adjustment.
Case rules
Exact matching is ASCII case-insensitive by default. Add --case-sensitive for
Bitcoin or Solana when uppercase and lowercase must be distinct.
Ethereum addresses are generated as lowercase hexadecimal. The CLI prevents
combining --eth and --case-sensitive, and the library returns an error for
that combination.
Regular expressions use the regex engine's own case-sensitive semantics. The
plain --case-sensitive setting does not transform a regex.
Pattern validation
Bitcoin and Solana exact patterns accept Base58 characters:
123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
Ethereum exact patterns accept ASCII hexadecimal characters. Invalid alphabet characters fail before the search begins.
Regex patterns are also chain-validated. Alphanumeric literals must belong to the chain's alphabet, and only this metacharacter set is accepted:
^ $ . * + ? ( ) [ ] { } | -
The regex must then compile successfully. This restricted syntax intentionally rejects escapes and other punctuation even if the underlying regex engine would otherwise understand them.
Empty and long patterns
The Rust API treats an empty exact or regex request as a request for one random keypair. The CLI still requires a positional pattern or an input file.
Fast mode rejects exact patterns longer than the chain's fast limit. Use
--disable-fast only after estimating the work. Absolute limits remain 25
characters for Base58 chains and 40 characters for Ethereum.
Choosing a backend
Backend choice is a trade-off among compatibility, startup cost, throughput, and desktop responsiveness.
| Backend | Prefer it when |
|---|---|
| CPU | You use regex, need maximum compatibility, or want to leave the GPU idle |
| Hybrid | You want CPU and GPU to race during an interactive exact-pattern search |
| GPU | You want the exact-pattern GPU path and can tolerate GPU startup and display load |
| Auto | You want runtime selection and CPU fallback |
GPU and Hybrid are experimental.
CLI and library defaults differ
The command-line program defaults to Hybrid. Without the gpu Cargo
feature, that path runs on CPU. With the feature, CPU and GPU workers race.
VanitySearchOptions::default() uses Auto. Auto currently selects:
- CPU for regex or exact patterns of at most 2 adjusted characters;
- Hybrid for exact patterns of 3 or 4 adjusted characters;
- GPU for longer exact patterns; and
- CPU whenever the requested GPU path cannot be initialized.
For Bitcoin prefix search, the adjusted pattern includes the fixed leading
1, which contributes to this internal length decision.
Explicitness and fallback
Use --backend cpu when GPU work is unwanted. Use --backend gpu when GPU
availability is a requirement: a build without GPU support, an unavailable
adapter, or a GPU regex request returns an error instead of silently using CPU.
Auto falls back to CPU after a GPU or Hybrid attempt fails. Hybrid already has a CPU worker and continues on CPU if its GPU worker fails. Regex under Auto or Hybrid is routed directly to CPU.
The alias --backend both means Hybrid.
Threads and Hybrid
--threads controls CPU workers. It has no direct effect on a pure GPU search.
Hybrid may cap its CPU side at four workers when using a GPU-dominant batch
size, reducing competition for host resources. A smaller explicit GPU batch
can allow Hybrid to use the full requested CPU worker count.
A practical sequence
- Use CPU for a short test and for every regex.
- Compare CPU and Hybrid on a representative exact pattern.
- Try explicit GPU only when initialization cost is small relative to the expected search.
- Lower the GPU usage limit if interactive graphics stutter.
Performance depends on the complete chain pipeline, not only elliptic-curve arithmetic. Measure the address and match mode you will actually use.
GPU and Hybrid search
The experimental GPU backend runs candidate derivation, chain-specific hashing, address encoding, and exact matching in compute shaders. wgpu selects a native Metal, Vulkan, or DirectX 12 path according to the platform and driver.
btc-vanity --backend hybrid --gpu-usage-limit 70 abc
btc-vanity --backend gpu --gpu-usage-limit 100 abc
Hybrid defaults to a 70% usage limit. Explicit GPU defaults to 100%. The limit is a best-effort dispatch duty cycle, not a utilization target, power cap, temperature limit, or scheduler guarantee.
Responsiveness and batch latency
At 100%, the engine favors throughput by keeping multiple dispatch slots in flight. Large batches reduce scheduling overhead, but a dispatch that is already running cannot be divided by the application. This can delay display work and increases the time before a CPU winner can stop a Hybrid GPU worker.
Below 100%, the engine:
- caps an individual dispatch at 4,096 candidates;
- keeps one slot in flight;
- waits for the dispatch to complete; and
- sleeps in proportion to the active time.
This produces more scheduling opportunities for other graphics work, but it also lowers throughput and still may not eliminate stutter on every driver.
If the desktop becomes unresponsive:
- lower
--gpu-usage-limit, for example to 50; - reduce
--gpu-batch-size; - choose Hybrid so CPU can also make progress; or
- choose CPU to remove search work from the graphics queue.
Batch-size control
The normal GPU tuning starts at 262,144 candidates with two dispatch slots.
--gpu-batch-size N overrides the requested batch size. Values above the
engine maximum are capped at 2,097,152. Short patterns and active usage
limiting may reduce the effective size further.
Larger is not universally better. It can improve steady-state throughput while worsening time-to-first-result, cancellation latency, and display scheduling. Benchmark a few sizes on the target system instead of assuming the largest value wins.
Supported matching and fallback
GPU shaders support prefix, suffix, and anywhere matching for Bitcoin, Ethereum, and Solana. Regex is CPU-only. Explicit GPU plus regex returns an error; Auto and Hybrid use CPU.
Hybrid starts cancelable CPU and GPU workers and returns the first valid candidate. If GPU initialization or execution fails, CPU work remains available. Explicit GPU reports the failure.
Trust boundary
GPU search places seed material and candidate state in local graphics-device buffers and passes through the system graphics stack. Use CPU when the device or driver is outside the system boundary you are prepared to trust. Regardless of backend, verify and protect the result.
Batch input and output
Use an input file to run several searches in sequence:
btc-vanity --input-file patterns.txt
Each nonempty, noncomment line begins with one pattern. Remaining whitespace-separated tokens are per-line flags:
# patterns.txt
abc --btc --prefix --backend cpu
dead --eth --suffix --backend gpu --gpu-usage-limit 60
Sun --sol --anywhere --case-sensitive --threads 4
There is no shell-style quoting in this format. The pattern is the first token,
so it cannot contain whitespace. Empty lines and lines whose first
non-whitespace character is # are ignored.
Supported line flags
Batch rows recognize the chain, match-mode, case, fast-mode, output, threads, backend, GPU batch size, and GPU usage-limit flags described in the command-line reference. Unrecognized or malformed row options are ignored rather than reported as command-line parse errors, so review batch files carefully.
Flag precedence
Without --force-flags, row settings take precedence:
- a row's chain, mode, backend, output file, GPU settings, or positive thread count overrides the command line;
- omitted optional row values fall back to the corresponding command-line value; and
- case sensitivity and fast-mode disabling are row-local booleans. Put
--case-sensitiveor--disable-faston every row that needs it.
With --force-flags, all row flags are ignored and the command-line
configuration applies to every pattern:
btc-vanity --input-file patterns.txt \
--force-flags --btc --prefix --backend cpu --threads 4
The first token on each row remains the pattern.
Output destinations
Without --output-file, each result is printed to the terminal. With an output
file, wallet details are appended:
btc-vanity --output-file generated-wallets.txt abc
For a batch, a row-level output path overrides the global output path unless
--force-flags is active.
The output includes private key material:
- Bitcoin: WIF private key, compressed public key, and P2PKH address
- Ethereum: hexadecimal private key, uncompressed public key, and address
- Solana: hexadecimal keypair bytes and address
On Unix, a newly created file requests mode 0600. Opening an existing file
does not repair its permissions, and some network or removable filesystems do
not enforce Unix modes. Verify the destination before and after a run. Output
is appended, never replaced.
If any row fails to generate or write, the process continues through the batch but exits with a nonzero status at the end.
Command-line reference
btc-vanity [OPTIONS] [PATTERN]
Provide either PATTERN or --input-file FILE. Bitcoin, prefix matching, and
Hybrid are the CLI defaults.
Chain selection
| Flag | Meaning |
|---|---|
--btc | Bitcoin P2PKH; default |
--eth | Ethereum; requires ethereum |
--sol | Solana; requires solana |
Chain flags conflict. A binary without the requested optional chain feature reports the missing feature when generation begins.
Input and output
| Flag | Meaning |
|---|---|
-i, --input-file FILE | Read one pattern and optional flags per line |
-o, --output-file FILE | Append wallet details to a file |
-f, --force-flags | Ignore row flags and apply CLI flags to every row |
See Batch input and output for syntax, precedence, and secret-file handling.
Match mode
| Flag | Meaning |
|---|---|
-p, --prefix | Match the address start; default |
-s, --suffix | Match the address end |
-a, --anywhere | Match at any position |
-r, --regex | Use a CPU regular expression |
These flags conflict. --regex is a switch; the positional PATTERN contains
the expression:
btc-vanity --backend cpu --regex '^1A.*Z$'
Performance
| Flag | Meaning |
|---|---|
-t, --threads N | CPU worker count; defaults to available parallelism |
-b, --backend NAME | auto, cpu, gpu, hybrid, or alias both |
--gpu-batch-size N | Requested GPU candidates per batch |
--gpu-usage-limit PERCENT | Best-effort GPU dispatch duty cycle, 1..=100 |
Thread count must be at least 1. Hybrid's default limit is 70%; explicit GPU's is 100%. GPU flags have no effect on a CPU-only search.
Matching behavior
| Flag | Meaning |
|---|---|
-c, --case-sensitive | Distinguish ASCII case for Bitcoin or Solana exact matching |
-d, --disable-fast | Remove the short-pattern guard; absolute limits remain |
--case-sensitive conflicts with --eth. Exact Base58 patterns are limited to
5 characters in fast mode and 25 when fast mode is disabled. Ethereum limits
are 16 and 40 hexadecimal characters.
Exit behavior
Argument errors, input-file errors, generation errors, and output-write errors produce a nonzero exit status. In batch mode, processing continues after an individual item fails and the final status is nonzero if any item failed.
Use the installed binary's help for the exact options in that version:
btc-vanity --help
Rust library
Add only the features your application needs:
[dependencies]
btc-vanity = { version = "3.0.0", features = ["ethereum", "gpu"] }
Bitcoin is always available. EthereumKeyPair and SolanaKeyPair are exported
only with their respective features.
Configured exact search
use btc_vanity::{
BitcoinKeyPair, VanityAddr, VanityBackend, VanityMode, VanitySearchOptions,
};
let result = VanityAddr::generate_with_options::<BitcoinKeyPair>(
"abc",
VanitySearchOptions {
threads: 4,
case_sensitive: false,
fast_mode: true,
vanity_mode: VanityMode::Prefix,
backend: VanityBackend::Cpu,
gpu_batch_size: None,
gpu_usage_limit: None,
},
)?;
assert!(
result
.get_comp_address()
.to_ascii_lowercase()
.starts_with("1abc")
);
Ok::<(), btc_vanity::error::VanityError>(())
VanitySearchOptions::default() uses available CPU parallelism, insensitive
exact matching, fast mode, prefix mode, Auto backend, and no GPU overrides.
This Auto default differs from the CLI's Hybrid default.
The older positional VanityAddr::generate method remains available. It uses
Auto and accepts pattern, threads, case_sensitive, fast_mode, and
VanityMode.
Regex search
use btc_vanity::{BitcoinKeyPair, VanityAddr};
let result =
VanityAddr::generate_regex::<BitcoinKeyPair>("^1A.*Z$", 4)?;
assert!(result.get_comp_address().starts_with("1A"));
Ok::<(), btc_vanity::error::VanityError>(())
Use generate_regex_with_options to select a backend explicitly. CPU, Auto,
and Hybrid execute regex on CPU. Explicit GPU returns
VanityError::GpuRegexUnsupported.
Result types
All chain keypair types implement KeyPairGenerator, including
get_address() and get_address_bytes().
BitcoinKeyPairexposes the private key, compressed public key, compressed address, WIF private key, and compressed public-key text.EthereumKeyPairexposes secp256k1 key references and hexadecimal private key, public key, and address helpers.SolanaKeyPairexposes the underlying keypair plus Base58 private-key and public-key helpers.
Treat every private-key accessor as a secret-handling boundary.
Errors
Configured methods return Result<T, VanityError>. Callers should distinguish:
- invalid Base58, hexadecimal, or regex input;
- fast-mode and absolute-length rejections;
- zero threads or an invalid GPU usage limit;
- missing optional chain features;
- unavailable, unsupported, or uninitialized GPU paths;
- GPU regex requests; and
- a GPU result that fails reconstruction.
Auto and Hybrid define CPU fallback. Do not add an automatic fallback around explicit GPU unless that is the application's intended policy.
How a search works
Every search has the same high-level data flow:
pattern and options
|
v
chain validation and adjustment
|
v
candidate private key -> public key -> address text
|
v
prefix / suffix / anywhere / regex comparison
|
v
first valid matching keypair
Validation comes first
The selected chain validates the alphabet, length, case policy, and regex
syntax. Bitcoin then inserts its fixed leading 1 into prefix comparisons.
Ethereum normalizes regex text to lowercase and works on the unprefixed internal
address. Backend selection happens after this chain-specific preparation.
An invalid request fails before workers begin.
Candidate generation
CPU workers generate independent random key material through thread-local random number generators. Each candidate follows the normal chain pipeline; no address characters are patched after derivation.
The GPU path begins with a random 32-byte seed and enumerates candidate scalars or seeds in compute work. Precomputed curve tables accelerate public-key derivation, while the shader performs the chain's hash and encoding operations.
First-result coordination
CPU threads share an atomic stop flag. The first matching worker claims it, sends its owned keypair over a channel, and causes other workers to stop.
GPU work uses an atomic result claim inside each shader result buffer. The host first reads a small winner status. Only when a winner exists does it transfer the complete result. Hybrid adds a shared stop flag between its CPU and GPU workers and returns whichever valid path finishes first.
Defense after a GPU match
The GPU reports candidate private bytes and address text. The host reconstructs the chain keypair from those private bytes using the CPU implementation and requires the reconstructed address to equal the GPU-reported address. A mismatch is returned as an invalid-GPU-result error.
This check detects a bad returned pair; it is not a substitute for independent wallet verification or secure key handling.
Chain pipelines
Search performance and correctness depend on the complete address pipeline. The curve operation alone is not an address.
Bitcoin P2PKH
For each Bitcoin candidate:
- Interpret the private scalar on secp256k1.
- Derive and serialize the compressed 33-byte public key.
- Compute SHA-256 of the compressed public key.
- Compute RIPEMD-160 of that SHA-256 digest.
- Prepend the Bitcoin mainnet P2PKH version byte.
- Add the four-byte checksum derived from double SHA-256.
- Base58-encode the versioned payload and checksum (Base58Check).
The result starts with 1. This project searches legacy mainnet P2PKH
addresses; it does not search Bech32 or script-hash formats.
Ethereum
For each Ethereum candidate:
- Interpret the private scalar on secp256k1.
- Derive the uncompressed 65-byte public key.
- Remove the leading uncompressed-key marker byte.
- Compute Keccak-256 over the remaining 64 bytes.
- Take the final 20 bytes.
- Encode them as 40 lowercase hexadecimal digits.
The library stores the address without 0x; the CLI adds 0x when printing.
Keccak-256 is the Ethereum hash variant, not standardized SHA3-256. This project
does not add mixed-case checksum capitalization.
Solana
For each Solana candidate:
- Begin with a 32-byte seed.
- Derive the Ed25519 keypair and 32-byte public key.
- Base58-encode the public key.
The public-key text is the address. Unlike Bitcoin, Solana does not wrap it in a versioned Base58Check payload.
Base58 and hexadecimal are display encodings
Base58 represents bytes using a 58-character alphabet chosen to avoid ambiguous glyphs. Hexadecimal represents each four bits with one of 16 digits. Neither encoding makes an address editable: decoding, changing bytes, and re-encoding would describe different data and would not preserve the original keypair.
The different alphabets also produce different per-character search probabilities. Compare measured candidate rates and target probabilities per chain rather than transferring an estimate from one format to another.
CPU engine
The CPU engine is the compatibility baseline and the only regular-expression engine.
Workers and batches
The engine creates the requested number of worker threads. Each worker:
- generates an initial array of 256 chain keypairs;
- scans that batch for a match;
- refills the existing array with new candidates; and
- repeats until a shared atomic stop flag is set.
Exact-match scans visit candidates in small unrolled groups. They check the stop flag periodically rather than on every comparison, reducing synchronization overhead. When a worker wins, it swaps the matching value out of the array, claims the atomic flag, and sends the owned keypair to the waiting thread.
Batching reuses storage and keeps generation and matching work local to each worker. It does not mean candidates are written to disk or exposed through the batch-file interface.
Compiled exact matching
The exact pattern is compiled once per search and shared by all workers:
- case-sensitive prefix, suffix, and substring paths use byte-oriented memory comparison;
- case-insensitive patterns are lowercased once through an ASCII lookup table;
- prefix and suffix compare only the relevant address slice;
- one-character substring search uses a direct scan;
- medium case-insensitive substrings use a precomputed bad-character table; and
- other substring lengths use a straightforward bounded scan.
Preparing this state once avoids lowercasing or rebuilding search tables for every candidate.
Regex matching
Regex syntax is validated and compiled before useful work begins. Each regex worker generates the same 256-candidate batches and applies the compiled expression to address text. Regex has its own first-winner atomic and channel.
Regex is more flexible but cannot use the compiled exact matcher or GPU shader path. Prefer prefix, suffix, or anywhere when those modes express the goal.
Thread count
The CLI defaults to the machine's reported available parallelism. More threads can increase throughput until curve, hashing, memory, thermal, or scheduling limits dominate. It can also interfere with other workloads. Measure several worker counts on the target machine rather than assuming all logical CPUs are best.
GPU engine
The experimental GPU engine is a persistent wgpu compute pipeline for exact matching. It supports Metal, Vulkan, and DirectX 12 through wgpu rather than maintaining separate chain implementations for each graphics API.
Shader construction
Curve arithmetic, finite-field operations, hash functions, Base58, and chain-specific search entry points are embedded as WGSL source. At initialization, a template renderer inserts modulus, Montgomery-arithmetic, limb, generator, and window-table constants into complete Bitcoin, Ethereum, and Solana shaders.
The engine creates all three chain pipelines when the shared GPU engine is first initialized. This cold setup includes adapter and device creation, precomputed secp256k1 and Ed25519 tables, shader rendering, and compute-pipeline compilation. The engine is cached for later searches in the same process.
Buffers and transfers
Each chain pipeline keeps a seed buffer, pattern buffer, compute pipeline, and several dispatch slots. Precomputed curve tables remain in storage buffers. Each slot has:
- a candidate counter;
- compact dispatch parameters;
- an atomic result buffer;
- a small status readback buffer; and
- a full result readback buffer.
The host writes seed and pattern data once per search. Per dispatch it updates parameters and resets the winner sentinel. After compute, it copies back only the first result word to learn whether a winner exists. The larger result is transferred only after that status indicates a match.
This avoids transferring every candidate public key or address across the device boundary.
On-device work
For each candidate, the chain shader performs:
- scalar or seed progression;
- secp256k1 or Ed25519 public-key derivation using precomputed tables;
- Bitcoin SHA-256, RIPEMD-160, checksum, and Base58Check; Ethereum Keccak-256 and hexadecimal encoding; or Solana Ed25519 public-key encoding in Base58;
- prefix, suffix, or anywhere comparison; and
- an atomic attempt to claim the result buffer.
Atomic claiming allows only one invocation to publish the winner fields even when many GPU invocations match concurrently.
Dispatch slots and throttling
Normal tuning uses a 256-thread workgroup, several candidates per invocation, a 262,144-candidate batch, and two active slots. Slots let the host submit new work while checking earlier status readbacks.
Short patterns favor a smaller batch and one slot because a result is likely before peak throughput matters. A usage limit below 100% caps the batch at 4,096, uses one slot, and inserts idle time after active work.
Host reconstruction
The winner contains private-key bytes and encoded address data. The host rebuilds the chain keypair on CPU and compares its derived address with the shader result. A disagreement fails the request. Hybrid shares a stop flag so a CPU winner prevents additional GPU submission as soon as the host can observe it; already-running dispatch work still has normal batch latency.
Performance and benchmarking
btc-vanity is engineered to be blazingly fast across multithreaded CPU and experimental GPU backends. However, there is no universal fastest backend or candidate rate for every machine. Results vary with the chain pipeline, match mode, case policy, pattern length, CPU, GPU, driver, graphics API, power mode, temperature, compiler, and whether GPU state is warm.
Measured results: Apple M1 Pro
On July 29, 2026, the version 3 branch was measured at tree
db218489bd9d716814b3648496ffd9f285213bc2 on:
- Apple M1 Pro with 8 CPU cores reported to the process;
- 14-core integrated GPU;
- 16 GiB unified memory;
- macOS 15.7.4; and
- Metal 3.
The comparison used vgen 0.3.0 at revision
a405fcb69032d328318cfacbda9d7fea9d4dcacc.
Both CPU measurements performed a case-sensitive Bitcoin P2PKH candidate loop:
secp256k1 public-key derivation, compressed public-key serialization, address
generation, and prefix comparison. Measurements report Criterion medians
rather than the fastest sample.
| Tool and path | Fixed work and median | Derived throughput |
|---|---|---|
| btc-vanity CPU, one benchmark worker | 304.019 ms / 16,384 candidates | 53,891 candidates/s |
| vgen CPU, one benchmark worker | 21.432 µs / candidate | 46,659 candidates/s |
| btc-vanity Metal, batch 262,144 × ring depth 2 | 5.001 s / 524,288 candidates | 104,837 candidates/s |
For this candidate loop, btc-vanity's one-worker CPU path was approximately 15.5% faster than vgen's one-worker CPU path. btc-vanity's Metal path delivered approximately 1.95× the throughput of its own one-worker CPU path.
These are engine-level results, not a complete application leaderboard. The study did not compare the tools' full multicore CPU schedulers, and it does not show that Metal outperforms btc-vanity's full multithreaded CPU backend.
Excluded comparisons
vgen's 262,144-candidate GPU benchmark could not be measured on this machine: its Metal shader pipeline failed during compilation with an internal compiler error. That failure is an excluded result, not evidence that btc-vanity is faster.
Ethereum was excluded because vgen's CPU generator produced EIP-55 checksummed
addresses while btc-vanity searches lowercase 40-character hexadecimal
addresses, and vgen did not provide the corresponding GPU path. Solana was
excluded because the available solana-keygen grind command exposed neither a
fixed-work mode nor a throughput counter. Comparing random time-to-match runs
would mostly compare luck.
These figures should be replaced or expanded when equivalent full-pipeline, multicore, and cross-platform measurements are available.
Think in candidates and probability
Elapsed time combines two independent questions:
- How many complete candidate addresses can this configuration test per second?
- How many candidates does this pattern distribution require?
A high candidate rate cannot make an exponentially rarer target cheap. Report both rate and pattern assumptions. Do not extrapolate a Base58 prefix from a hexadecimal prefix or an anywhere match from a fixed-position match.
Search completion is random. A single successful run measures luck as well as speed. Throughput benchmarks should perform a fixed amount of work; end-to-end search studies should use many independent runs and report distributions.
Cold and warm measurements
Separate:
- process startup;
- first GPU adapter/device creation;
- precomputed-table upload;
- shader rendering and pipeline compilation; and
- steady-state candidate batches using the cached engine.
Short searches may be dominated by cold GPU cost and can finish sooner on CPU even when the GPU has higher warm throughput.
Compare equivalent work
Use the same revision, release profile, feature set, chain, pattern bytes, case setting, mode, and fixed candidate count. Verify that both paths derive the same addresses from known private inputs and that every reported winner reconstructs correctly.
For Hybrid, measure end-to-end latency as its own behavior. Adding standalone CPU and GPU rates does not capture contention, cancellation, or the first-winner race. Likewise, throttled and unthrottled GPU runs answer different operational questions.
A reproducible study
For every result, record:
- repository revision and whether the tree was clean;
- exact build and benchmark commands;
- Rust compiler and dependency lockfile;
- operating system, CPU, memory, GPU, driver, and wgpu backend;
- power source and power/performance mode;
- chain, mode, case policy, pattern length, worker count, GPU batch size, usage limit, and warm-up procedure;
- sample count and fixed work per sample;
- median and tail values, not only the best run;
- validation failures, adapter errors, and skipped samples; and
- whether the desktop was also driving displays or other GPU applications.
Run with a stable machine: close unrelated compute work, avoid thermal throttling, and keep conditions identical between variants. Randomize or alternate variant order when heat or boost behavior could bias later runs.
The repository's Criterion benchmark suite includes targets for CPU multithreaded scaling (cpu_benchmarks), pattern-matching algorithms (pattern_matching), and GPU candidate pipelines (gpu_end_to_end). Exact commands and contributor verification expectations live in CONTRIBUTING.md; keep generated benchmark artifacts out of secret-bearing output locations.
Interpret results conservatively
Prefer qualitative conclusions tied to the measured configuration:
- CPU avoids GPU setup and display contention.
- GPU amortizes fixed setup better over larger workloads.
- Larger batches may improve throughput while increasing response latency.
- Lower usage limits trade throughput for more scheduling gaps.
- Hybrid may reduce time to the first result but consumes both host and device resources.
Do not present one machine's result as a product guarantee, and do not turn a synthetic candidate loop into a claim about complete wallet-generation speed unless the benchmark includes the full chain pipeline and matching work.
Security
btc-vanity generates private keys. The executable, random-number generation, CPU or GPU path, terminal, output file, backups, and wallet import process all belong to the secret-handling boundary.
Before generating
- Use a reviewed release or revision and build it through a trusted toolchain.
- Run on a machine you control. Avoid shared shells, remote logging, screen recording, and untrusted monitoring software.
- Decide in advance how the result will move into the intended wallet.
- Use CPU if the local graphics device or driver is outside the boundary you are willing to trust.
- Test the complete workflow with a disposable, unfunded result.
No software can guarantee security merely by running locally. Operating-system compromise, weak platform entropy, malicious dependencies, exposed output, and operator mistakes remain relevant.
Handle output as a secret
Without --output-file, private material appears in terminal scrollback. Shell
capture, terminal synchronization, clipboard history, and screenshots may
retain it.
With --output-file, output is appended in plaintext. New files request owner
read/write permissions on Unix, but existing permissions are preserved.
Network, removable, and non-Unix filesystems may apply different semantics.
Inspect the actual file permissions and backup behavior.
Do not place real generated keys in source control, issue reports, chat, benchmark logs, test fixtures, or screenshots.
Verify before funding
Independently derive the public address from the private material using trusted wallet software. Compare the complete address, not only the vanity fragment. First test signing and recovery with no value at risk.
Importing a key into a wallet exposes it to that wallet and its environment. Use software whose key-import format matches the chain and output format.
Backups and disposal
Keep the number of plaintext copies small. If a key will control value, use an appropriate encrypted backup strategy with tested recovery. Deleting a file does not necessarily remove copies from snapshots, cloud synchronization, journals, swap, or storage media.
If a private key may have been exposed, do not rely on changing the vanity pattern or file permissions afterward. Move assets to a newly generated, unexposed wallet according to the chain's normal procedures.
Scope
The project is distributed under the Apache License 2.0 without warranties. Vanity generation changes address appearance only; it does not add authentication or make a wallet safer.
Troubleshooting
Most failures fall into input validation, missing features, backend availability, or output handling.
Input is not Base58 encoded
Bitcoin and Solana patterns cannot contain 0, O, I, or lowercase l.
Use only:
123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
Ethereum patterns are hexadecimal instead.
Input is not Base16 encoded
Enable the ethereum feature, select --eth, and use only 0-9, a-f, or
A-F. Omit the display prefix 0x from exact patterns.
Fast mode enabled, input is too long
Fast mode permits at most 5 characters for Bitcoin and Solana or 16 for
Ethereum. --disable-fast permits longer input up to the absolute limits of 25
and 40 respectively.
This flag removes a guard; it does not make the longer request practical. Estimate or benchmark the cost before continuing.
Invalid Regex or regex alphabet error
The pattern must both compile and pass chain-specific validation. Only alphanumeric literals from the chain's address alphabet and the documented metacharacters are accepted. Regex search is case-sensitive and CPU-only.
Use an exact mode when you only need prefix, suffix, or substring matching.
Ethereum or Solana support is not enabled
Reinstall or rebuild with the matching Cargo feature:
cargo install btc-vanity --features ethereum
cargo install btc-vanity --features solana
Combine a chain feature with gpu when both are required.
GPU backend is unavailable
There are three common cases:
- the binary was built without
gpu; - wgpu could not obtain a compatible adapter; or
- the driver could not create the required device.
Use --backend cpu to continue without GPU. Auto and Hybrid can fall back to
CPU. If GPU is required, update the graphics driver and confirm that the
platform provides a working Metal, Vulkan, or DirectX 12 path.
Regex is not supported by GPU
Choose CPU, Auto, or Hybrid. Explicit GPU deliberately returns an error for regex rather than silently changing the requested backend.
The display stutters
Lower --gpu-usage-limit, reduce --gpu-batch-size, or use CPU. The limit is
best-effort, and driver scheduling can still produce visible stalls. Large
batches also delay Hybrid cancellation.
Search appears to take forever
There is no deterministic completion deadline. Confirm that:
- the pattern uses the selected chain's alphabet;
- the case and match mode are what you intended;
- Bitcoin prefix input omits the fixed leading
1; - the release binary is being used;
- the pattern length is realistic for the measured candidate rate; and
- power saving or thermal throttling has not reduced performance.
Stop and shorten the pattern if the expected resource use is not acceptable.
Output file is missing or too permissive
The parent directory must exist and be writable. Output is appended. On Unix,
mode 0600 is requested only when a file is created; an existing file retains
its mode. Check permissions directly and avoid destinations whose filesystem
cannot enforce the intended access.
Any item-generation or write failure makes the final process status nonzero. In batch mode, inspect standard error for the specific row failure.