Last active
March 10, 2023 10:15
-
-
Save ObjSal/33c74ce2648b95d486e38a2aece0fba6 to your computer and use it in GitHub Desktop.
vanity-miners scripts to generate bitcoin addresses (p2pkh) based on a prefix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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