Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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:

BackendWhat it does
CPURuns worker threads on the processor
GPURuns an exact-pattern compute pipeline on a graphics adapter
HybridRaces CPU and GPU work and returns the first valid result
AutoChooses 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 0x prefix 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

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

  1. Learn what a vanity address is.
  2. Install only the chain and backend features you need.
  3. Complete your first search with a short test pattern.
  4. Read Security before receiving funds at a generated address.
  5. 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:

  1. Generate candidate private key material.
  2. Derive its public key.
  3. Derive and encode the address.
  4. Compare the address with the requested pattern.
  5. 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:

FeatureAdds
ethereumEthereum key and address support
solanaSolana key and address support
gpuExperimental GPU and Hybrid acceleration through wgpu
allethereum, 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:

  1. Check that the printed address has the requested prefix.
  2. Do not send funds to it.
  3. 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.

ChainCurveAddress text in this projectCargo feature
Bitcoinsecp256k1Mainnet P2PKH Base58Check, starts with 1built in
Ethereumsecp256k140 lowercase hexadecimal digits; CLI adds 0xethereum
SolanaEd25519Base58-encoded public keysolana

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:

ChainFast-mode maximumAbsolute maximum
Bitcoin5 pattern characters25
Ethereum16 hexadecimal characters40
Solana5 pattern characters25

--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.

ModeCLI flagMatch locationBackend support
Prefix--prefix, -pStart of addressCPU, GPU, Hybrid, Auto
Suffix--suffix, -sEnd of addressCPU, GPU, Hybrid, Auto
Anywhere--anywhere, -aAny positionCPU, GPU, Hybrid, Auto
Regex--regex, -rRust regular expressionCPU; 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.

BackendPrefer it when
CPUYou use regex, need maximum compatibility, or want to leave the GPU idle
HybridYou want CPU and GPU to race during an interactive exact-pattern search
GPUYou want the exact-pattern GPU path and can tolerate GPU startup and display load
AutoYou 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

  1. Use CPU for a short test and for every regex.
  2. Compare CPU and Hybrid on a representative exact pattern.
  3. Try explicit GPU only when initialization cost is small relative to the expected search.
  4. 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:

  1. lower --gpu-usage-limit, for example to 50;
  2. reduce --gpu-batch-size;
  3. choose Hybrid so CPU can also make progress; or
  4. 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-sensitive or --disable-fast on 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

FlagMeaning
--btcBitcoin P2PKH; default
--ethEthereum; requires ethereum
--solSolana; requires solana

Chain flags conflict. A binary without the requested optional chain feature reports the missing feature when generation begins.

Input and output

FlagMeaning
-i, --input-file FILERead one pattern and optional flags per line
-o, --output-file FILEAppend wallet details to a file
-f, --force-flagsIgnore row flags and apply CLI flags to every row

See Batch input and output for syntax, precedence, and secret-file handling.

Match mode

FlagMeaning
-p, --prefixMatch the address start; default
-s, --suffixMatch the address end
-a, --anywhereMatch at any position
-r, --regexUse 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

FlagMeaning
-t, --threads NCPU worker count; defaults to available parallelism
-b, --backend NAMEauto, cpu, gpu, hybrid, or alias both
--gpu-batch-size NRequested GPU candidates per batch
--gpu-usage-limit PERCENTBest-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

FlagMeaning
-c, --case-sensitiveDistinguish ASCII case for Bitcoin or Solana exact matching
-d, --disable-fastRemove 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.

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.

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().

  • BitcoinKeyPair exposes the private key, compressed public key, compressed address, WIF private key, and compressed public-key text.
  • EthereumKeyPair exposes secp256k1 key references and hexadecimal private key, public key, and address helpers.
  • SolanaKeyPair exposes 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:

  1. Interpret the private scalar on secp256k1.
  2. Derive and serialize the compressed 33-byte public key.
  3. Compute SHA-256 of the compressed public key.
  4. Compute RIPEMD-160 of that SHA-256 digest.
  5. Prepend the Bitcoin mainnet P2PKH version byte.
  6. Add the four-byte checksum derived from double SHA-256.
  7. 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:

  1. Interpret the private scalar on secp256k1.
  2. Derive the uncompressed 65-byte public key.
  3. Remove the leading uncompressed-key marker byte.
  4. Compute Keccak-256 over the remaining 64 bytes.
  5. Take the final 20 bytes.
  6. 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:

  1. Begin with a 32-byte seed.
  2. Derive the Ed25519 keypair and 32-byte public key.
  3. 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:

  1. generates an initial array of 256 chain keypairs;
  2. scans that batch for a match;
  3. refills the existing array with new candidates; and
  4. 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 pathFixed work and medianDerived throughput
btc-vanity CPU, one benchmark worker304.019 ms / 16,384 candidates53,891 candidates/s
vgen CPU, one benchmark worker21.432 µs / candidate46,659 candidates/s
btc-vanity Metal, batch 262,144 × ring depth 25.001 s / 524,288 candidates104,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:

  1. How many complete candidate addresses can this configuration test per second?
  2. 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.