btc-vanity is A Bitcoin vanity address generator written with the Rust programming language.
See the documentation or crates.io page.

What is a vanity address?

A Vanity Address is a special address that contains a specific pattern or word. For example, the Vanity Address of a Bitcoin belonging to a user may contain a pattern or word such as “1BTC” or “1Emiv”. Vanity Addresses are often used personally or for promotional purposes.

What btc-vanity can do?

With btc-vanity, you can find a private key that has a compressed Bitcoin pay address that has a custom prefix, suffix, or a string at somewhere in the address.

You can easily run the btc-vanity terminal application locally or use it as a library to create your vanity keypair securely.

btc-vanity implementation

src
|- lib.rs
|- main.rs
|- cli.rs
|- decoration.rs
|- error.rs
|- file.rs
|- flags.rs
|- keys_and_addresses.rs
|- vanity_addr_generator.rs

despite there are a lot of files, the real magic happens in keys_and_addresses.rs and vanity_addr_generator.rs, and others that serve CLI operations.

let’s dive into some core implementations.

keys_and_addresses.rs

secp256k1 refers to the parameters of the elliptic curve used in Bitcoin’s public-key cryptography. Currently, Bitcoin uses secp256k1. So we also need to use it. The main struct used in keys_and_addresses.rs is KeysAndAdress struct. Here we use bitcoin::crypto::key for storing keys and normal good old friend String for our compressed address that will have out vanity string.

pub struct KeysAndAddress {  
    private_key: PrivateKey,  
    public_key: PublicKey,  
    comp_address: String,  
}

To generate a random Key pair and their address, you need to initialize a bitcoin::secp256k1::Secp256k1 to pass it generate method of KeysAndAddress, or just call KeysAndAddress::generate_random_heavy() if you’re not going to use secp256k1 anywhere else. Here is how genereate_random() is implemented

pub fn generate_random(secp256k1: &Secp256k1<All>) -> Self {  
    let (secret_key, pk) = secp256k1.generate_keypair(&mut rand::thread_rng());  
    let private_key = PrivateKey::new(secret_key, Bitcoin);  
    let public_key = PublicKey::new(pk);  
  
    KeysAndAddress {  
        private_key,  
        public_key,  
        comp_address: Address::p2pkh(public_key, Bitcoin).to_string(),  
    }  
}

You can also within a certain range by using KeysAndAddress::generate_within_range(). Refer to docs for further information; I’ll stop here to keep it simple.

vanity_addr_generator.rs

All of the other files are helpers of this file, this is the place where the real magic happens. The main struct used in vanity_addr_generator.rs is VanityAddr struct. Here is how VanityAddr::generate() implemented

/// Checks all given information's before passing to the vanity address finder function.  
/// Returns Result<KeysAndAddressString, VanityGeneratorError>  
/// Returns OK if a vanity address found successfully with keys_and_address::KeysAndAddress struct  
/// Returns Err if the string is longer than 4 chars and -d or --disable-fast-mode flags are not given.  
/// Returns Err if the string is not in base58 format.  
pub fn generate(  
    string: &str,  
    threads: u64,  
    case_sensitive: bool,  
    fast_mode: bool,  
    vanity_mode: VanityMode,  
) -> Result<KeysAndAddress, BtcVanityError> {  
    let secp256k1 = Secp256k1::new();  
  
    Self::validate_input(string, fast_mode)?;  
  
    if string.is_empty() {  
        return Ok(KeysAndAddress::generate_random(&secp256k1));  
    }  
  
    Ok(SearchEngines::find_vanity_address(  
        string,  
        threads,  
        case_sensitive,  
        vanity_mode,  
        secp256k1,  
    ))  
}

as it is quite self-explanatory, you pass some parameters, it checks it first, then searches your vanity string for you.
Another important struct in the file is SearchEngines. Real work is done by SearchEngines struct. VanityAddr’s main purpose is to provide a safe wrapper for finding a vanity address. Refer to docs or GitHub repository for complete implementation. However, I’ll give the overall steps on how the magic happens.

1- create a mpsc::channel()
2- clone sender and the flags as many as requested.
3- now each thread will generate a randomly generated KeysAndAdress struct and check if it satisfies the flags
4- if a thread finds a KeysAndAdress that meets the needs, it sends it via the sender. When a thread sends a KeysAndAdress, the other threads are killed.
5- during this time receiver is trying to receive with .try_recv() in a loop, when a thread finds a keypair, this will catch it and return it.

Calling btc-vanity as a library

let’s find a vanity address

 use btc_vanity::vanity_addr_generator::{VanityAddr, VanityMode};  
  
 let vanity_address = VanityAddr::generate(  
             "Emiv", // the string that you want your vanity address to include.  
             16, // number of threads  
             false, // case sensitivity (false ex: eMiv, true ex: Emiv)  
             true, // fast mode flag (set false to use a string longer than 4 chars)  
             VanityMode::Anywhere, // vanity mode flag (prefix, suffix, anywhere available)  
             ).unwrap(); // this function returns a result type  
  
 println!("private_key (wif): {}\n\  
           public_key (compressed): {}\n\  
           address (compressed): {}\n\n",  
                 vanity_address.get_wif_private_key(),  
                 vanity_address.get_comp_public_key(),  
                 vanity_address.get_comp_address())

incase you need to look for certain range, we also got you covered. Here is an example to look for a certain private key range

fn main() {  
    // Define the minimum range for the private key in hexadecimal format.  
    let range_min = BigUint::from_str_radix("0000000000000000000000000000000000000000000000100000000000000000", 16).unwrap();  
  
    // Define the maximum range for the private key in hexadecimal format.  
    let range_max = BigUint::from_str_radix("00000000000000000000000000000000000000000000001FFFFFFFFFFFFFFFFF", 16).unwrap();  
  
    // Generate a vanity address with the desired pattern within the specified range.  
    let vanity_address = VanityAddr::generate_within_range(  
        "abc",          // The string that you want your vanity address to include (as a prefix in this case).  
        range_min,      // The minimum value of the private key range.  
        range_max,      // The maximum value of the private key range.  
        16,             // The number of threads to use for faster processing.  
        true,           // Case sensitivity flag: true means exact match, false means case-insensitive match.  
        true,           // Fast mode flag: enables fast mode, limiting the string length to 4 characters.  
        VanityMode::Prefix, // Where to match the string in the address (Prefix in this case).  
    ).unwrap();         // Unwrap the result to get the generated address or panic on error.  
  
    // Print the generated private key, public key, and address in their respective formats.  
    println!(  
        "private_key (wif): {}\n\  
        public_key (compressed): {}\n\  
        address (compressed): {}\n\n",  
        vanity_address.get_wif_private_key(),  
        vanity_address.get_comp_public_key(),  
        vanity_address.get_comp_address()  
    )  
}

Examples of usage from terminal

install btc-vanity with cargo

cargo install btc-vanity

and then you can see possible usage with command

btc-vanity -h

here are some example screenshots

example examples-input-file

Thanks for reading till the end. I hope you like the project. If you would like to test btc-vanity, before using it please read the DISCLAIMER for your security.