Python code performs brute force search over Bitcoin private keys, generating and checking multiple types of Bitcoin addresses for matches against prefixes (masks). It supports the following address formats:
- Legacy (uncompressed) - Addresses starting with 1
- Legacy (compressed) - Addresses starting with 1 (using compressed public keys)
- P2SH-P2WPKH - Addresses starting with 3 (nested SegWit)
- Bech32 (SegWit v0) - Addresses starting with bc1q

import ecdsa
import hashlib
import base58
import time
import re
from concurrent.futures import ProcessPoolExecutor
from multiprocessing import Manager
import threading
import os
print(f"PID: {os.getpid()}\n")
print(f"Starting the search!")
print(f"{'Private key (HEX)':<72}{'Address type':<16}{'Mask':<16}{'Bitcoin address':<48}{'Time'}")
# Parameters:
WORDS_FILE = 'words.txt' # File with masks
START_VALUE = 7577381717558400147389304571969250473512863125367244766130873951541158995895 # Private key in DEC
NUM_TRIALS = 10000000 # Number of checks in order
INTERVAL = 5 # File write interval
CASE_SENSITIVE = True
STEP = 1 # Search step
NUM_PROCESSES = 1 # Number of threads
OUTPUT_FILE = 'found_addresses.txt' # File of found addresses
# Load masks
with open(WORDS_FILE, 'r', encoding='utf-8') as f:
masks = [line.strip() for line in f if line.strip()]
if not CASE_SENSITIVE:
masks = [m.lower() for m in masks]
pattern = re.compile(r'^(?:' + '|'.join(map(re.escape, masks)) + ')')
def hash160(data: bytes) -> bytes:
return hashlib.new('ripemd160', hashlib.sha256(data).digest()).digest()
def base58_check(prefix: bytes, payload: bytes) -> str:
data = prefix + payload
checksum = hashlib.sha256(hashlib.sha256(data).digest()).digest()[:4]
return base58.b58encode(data + checksum).decode()
CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'
def bech32_polymod(values):
GENERATORS = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
chk = 1
for v in values:
top = chk >> 25
chk = ((chk & 0x1ffffff) << 5) ^ v
for i in range(5):
if (top >> i) & 1:
chk ^= GENERATORS[i]
return chk
def bech32_hrp_expand(hrp: str):
return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp]
def bech32_create_checksum(hrp: str, data: list) -> list:
values = bech32_hrp_expand(hrp) + data
polymod = bech32_polymod(values + [0,0,0,0,0,0]) ^ 1
return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]
def convertbits(data: bytes, from_bits: int, to_bits: int, pad: bool=True):
acc = 0
bits = 0
result = []
maxv = (1 << to_bits) - 1
for b in data:
acc = (acc << from_bits) | b
bits += from_bits
while bits >= to_bits:
bits -= to_bits
result.append((acc >> bits) & maxv)
if pad and bits:
result.append((acc << (to_bits - bits)) & maxv)
return result
def bech32_encode(hrp: str, data: list) -> str:
combined = data + bech32_create_checksum(hrp, data)
return hrp + '1' + ''.join([CHARSET[d] for d in combined])
def generate_addresses(dec: int) -> dict:
priv = bytes.fromhex(format(dec, '064x'))
sk = ecdsa.SigningKey.from_string(priv, curve=ecdsa.SECP256k1)
vk = sk.get_verifying_key().to_string()
pub_uncompressed = b"\04" + vk
x = vk[:32]
y = vk[32:]
prefix = b'\x02' if y[-1] % 2 == 0 else b'\x03'
pub_compressed = prefix + x
addr_legacy = base58_check(b'\x00', hash160(pub_uncompressed))
addr_legacy_c = base58_check(b'\x00', hash160(pub_compressed))
redeem_script = b'\x00\x14' + hash160(pub_compressed)
addr_p2sh = base58_check(b'\x05', hash160(redeem_script))
witprog = hash160(pub_compressed)
data = [0] + convertbits(witprog, 8, 5)
addr_bech32 = bech32_encode('bc', data)
return {
'Legacy_UNC': addr_legacy,
'Legacy_CMR': addr_legacy_c,
'P2SH': addr_p2sh,
'BECH32': addr_bech32
}
def search_chunk(start, step, trials, queue):
buffer = []
last_dump = time.time()
for i in range(trials):
dec = start + i * step
addrs = generate_addresses(dec)
ts = time.strftime('%H:%M:%S', time.localtime())
hex_priv = format(dec, '064X')
for typ, addr in addrs.items():
addr_to_check = addr if CASE_SENSITIVE else addr.lower()
m = pattern.match(addr_to_check)
if m:
orig_mask = m.group(0)
# Trim prefix for printing
if orig_mask.startswith('bc1q'):
disp_mask = orig_mask[4:]
elif orig_mask.startswith(('1','3')):
disp_mask = orig_mask[1:]
else:
disp_mask = orig_mask
msg = f"{hex_priv}\t{typ:<13}\t{disp_mask:<15}\t{addr:<47}\t{ts}"
queue.put(msg)
buffer.append(msg + "\n")
if buffer and time.time() - last_dump >= INTERVAL:
with open(OUTPUT_FILE, 'a') as out:
out.writelines(buffer)
buffer.clear()
last_dump = time.time()
if buffer:
with open(OUTPUT_FILE, 'a') as out:
out.writelines(buffer)
def printer(queue, sentinel):
while True:
line = queue.get()
if line == sentinel:
break
print(line)
def main():
open(OUTPUT_FILE, 'w').close()
manager = Manager()
queue = manager.Queue()
sentinel = "__DONE__"
t = threading.Thread(target=printer, args=(queue, sentinel), daemon=True)
t.start()
block_size = NUM_TRIALS/ NUM_PROCESSES
with ProcessPoolExecutor(max_workers=NUM_PROCESSES) as exe:
for i in range(NUM_PROCESSES):
start = START_VALUE + i * block_size * STEP
if i == NUM_PROCESSES - 1:
trials = NUM_TRIALS - block_size * (NUM_PROCESSES - 1)
else:
trials = block_size
exe.submit(search_chunk, start, STEP, trials, queue)
queue.put(sentinel)
t.join()
if __name__ == "__main__":
main()
List of masks (words.txt):
https://drive.google.com/file/d/1PPqfD6UETawVwqrf4TKx29CaRJZu-4B2Screens:
https://i.postimg.cc/nL5Qhxtm/1.jpghttps://i.postimg.cc/0QTWmh7M/2.jpg