Skip to content

Instantly share code, notes, and snippets.

@ObjSal
Last active March 10, 2023 10:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ObjSal/33c74ce2648b95d486e38a2aece0fba6 to your computer and use it in GitHub Desktop.
Save ObjSal/33c74ce2648b95d486e38a2aece0fba6 to your computer and use it in GitHub Desktop.
vanity-miners scripts to generate bitcoin addresses (p2pkh) based on a prefix
// Compile command:
// g++ -o vanity-miner vanity-miner.cpp -std=c++11 $(pkg-config) -I/path/to/libbitcoin/include -L/path/to/libbitcoin/lib -lbitcoin-system -lsecp256k1 -lboost_program_options -lboost_regex -lboost_thread -lgmp
// NOTE: After getting the secret use the following command to get the wif-compressed private key:
// $ bx base58check-encode <secret_key> --version 128
///////////////////////////////////////////////////
// DEPENDENCIES
// https://github.com/libbitcoin/libbitcoin-system
// - Follow instructions how to install mac, example:
// $ wget https://raw.githubusercontent.com/libbitcoin/libbitcoin/version3/install.sh
// $ chmod +x install.sh
// $ ./install.sh --prefix=/path/to/libbitcoin --build-boost --disable-shared
/////////////////////////////////////////////////////////////////////////////////
// REFERENCES
// https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch04.asciidoc
// https://github.com/petertodd/python-bitcoinlib
// https://github.com/bitcoinbook/bitcoinbook/blob/develop/code/vanity-miner.cpp
// https://github.com/bitcoinbook/bitcoinbook/blob/develop/code/ec-math.py
// https://github.com/bitcoinbook
////////////////////////////////////////////////////////////////////////
// Time to get a matching address:
// ======================================================================
// Length Pattern Frequency Average search time
// ======================================================================
// 1 1K 1 in 58 keys < 1 milliseconds
// 2 1Ki 1 in 3,364 50 milliseconds
// 3 1Kid 1 in 195,000 < 2 seconds
// 4 1Kids 1 in 11 million 1 minute
// 5 1KidsC 1 in 656 million 1 hour
// 6 1KidsCh 1 in 38 billion 2 days
// 7 1KidsCha 1 in 2.2 trillion 3–4 months
// 8 1KidsChar 1 in 128 trillion 13–18 years
// 9 1KidsChari 1 in 7 quadrillion 800 years
// 10 1KidsCharit 1 in 400 quadrillion 46,000 years
// 11 1KidsCharity 1 in 23 quintillion 2.5 million years
#include <random>
#include <algorithm>
#include <cctype>
#include <bitcoin/system.hpp>
// Generate a random secret key. A random 32 bytes.
bc::ec_secret random_secret(std::default_random_engine& engine);
// Extract the Bitcoin address from an EC secret.
std::string bitcoin_address(const bc::ec_secret& secret);
// Case insensitive comparison with the search string.
bool match_found(const std::string& address, const std::string& prefix);
int main(int arvc, char* argv[]) {
if (arvc < 2) {
std::cout << "Send at least one prefix, example: './vanity-miner 1shaba'" << std::endl;
return 1;
}
std::string prefix = argv[1];
// To lower, except non-alphabet chars
std::transform(prefix.begin(), prefix.end(), prefix.begin(), [](char c) -> char {
if (std::isalpha(c)) {
return std::tolower(c);
}
return c;
});
// Fix prefix if it's not prefixed with 1
if (prefix.at(0) != '1') {
prefix = '1' + prefix;
}
// random_device on Linux uses "/dev/urandom"
// CAUTION: Depending on implementation this RNG may not be secure enough!
// Do not use vanity keys generated by this example in production
std::random_device random;
std::default_random_engine engine(random());
// Loop continuously...
while (true) {
// Generate a random secret.
bc::ec_secret secret = random_secret(engine);
// Get the address.
std::string address = bitcoin_address(secret);
// Does it match our search string?
if (match_found(address, prefix)) {
// Success!
std::cout << "Found vanity address! " << address << std::endl;
std::cout << "Secret: " << bc::encode_base16(secret) << std::endl;
return 0;
}
}
// Should never reach here!
return 0;
}
bc::ec_secret random_secret(std::default_random_engine& engine) {
// Create new secret...
bc::ec_secret secret;
// Iterate through every byte setting a random value...
for (uint8_t& byte: secret) {
byte = engine() & 255;
}
return secret;
}
std::string bitcoin_address(const bc::ec_secret& secret) {
// Convert secret to payment address
bc::wallet::ec_private private_key(secret);
bc::wallet::payment_address payaddr(private_key);
return payaddr.encoded();
}
bool match_found(const std::string& address, const std::string& prefix) {
auto addr_it = address.begin();
// Loop through the prefix string comparing it to the lower case
// character of the supplied address.
for (auto it = prefix.begin(); it != prefix.end(); ++it, ++addr_it) {
if (*it != std::tolower(*addr_it)) {
return false;
}
}
return true;
}
#!/usr/bin/env python3
##################################
# DEPENDENCIES
# $ pip install ecdsa
# $ pip install python-bitcoinlib
##################################
# REFERENCES
# https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch04.asciidoc
# https://github.com/petertodd/python-bitcoinlib
# https://github.com/bitcoinbook/bitcoinbook/blob/develop/code/vanity-miner.cpp
# https://github.com/bitcoinbook/bitcoinbook/blob/develop/code/ec-math.py
# https://github.com/bitcoinbook
##################################
# Time to get a matching address, this table is from the C++ code,
# in pythin it's much slower.
# ======================================================================
# Length Pattern Frequency Average search time
# ======================================================================
# 1 1K 1 in 58 keys < 1 milliseconds
# 2 1Ki 1 in 3,364 50 milliseconds
# 3 1Kid 1 in 195,000 < 2 seconds
# 4 1Kids 1 in 11 million 1 minute
# 5 1KidsC 1 in 656 million 1 hour
# 6 1KidsCh 1 in 38 billion 2 days
# 7 1KidsCha 1 in 2.2 trillion 3–4 months
# 8 1KidsChar 1 in 128 trillion 13–18 years
# 9 1KidsChari 1 in 7 quadrillion 800 years
# 10 1KidsCharit 1 in 400 quadrillion 46,000 years
# 11 1KidsCharity 1 in 23 quintillion 2.5 million years
import sys
import ecdsa
import os
import time
from bitcoin.core import x
from bitcoin.core.key import CPubKey
from bitcoin.wallet import P2PKHBitcoinAddress
# secp256k1, http://www.oid-info.com/get/1.3.132.0.10
_p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
_r = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
_b = 0x0000000000000000000000000000000000000000000000000000000000000007
_a = 0x0000000000000000000000000000000000000000000000000000000000000000
_Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
_Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
curve_secp256k1 = ecdsa.ellipticcurve.CurveFp(_p, _a, _b)
generator_secp256k1 = ecdsa.ellipticcurve.Point(curve_secp256k1, _Gx, _Gy, _r)
oid_secp256k1 = (1, 3, 132, 0, 10)
SECP256k1 = ecdsa.curves.Curve("SECP256k1", curve_secp256k1, generator_secp256k1, oid_secp256k1)
ec_order = _r
curve = curve_secp256k1
generator = generator_secp256k1
def random_secret():
# Collect 256 bits of random data from the OS's cryptographically secure
# random number generator
# Do not use vanity keys generated by this example in production
byte_array = (os.urandom(32)).hex()
return int(byte_array, 16)
def get_point_pubkey(point):
if (point.y() % 2) == 1:
key = '03' + '%064x' % point.x()
else:
key = '02' + '%064x' % point.x()
return key
def match_found(p2pkh, prefix):
return p2pkh.lower().startswith(prefix)
def find_match(prefix):
while True:
# Generate a random secret.
secret = random_secret()
# Get the address.
point = secret * generator
pubkey = get_point_pubkey(point)
p2pkh = str(P2PKHBitcoinAddress.from_pubkey(CPubKey(x(pubkey))))
# Does it match our search string? (1kid)
if match_found(p2pkh, prefix):
# Success!
print("Found vanity address!", p2pkh)
print("Secret:", hex(secret))
return
if __name__ == "__main__":
if len(sys.argv) < 2 :
print('Send at least one prefix, example: "./vanity-miner.py 1shaba"')
exit(1)
print('searching for p2pkh with prefix', sys.argv[1])
start = time.time()
prefix = sys.argv[1].lower()
if prefix[0] != '1':
prefix = '1' + prefix
find_match(prefix)
stop = time.time()
print("runtime:", stop - start)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment