Post
Topic
Board Bitcoin Discussion
Re: Bitcoin puzzle transaction ~32 BTC prize to who solves it
by
user_not_here
on 28/05/2025, 19:56:26 UTC
what kind of speed should i expect when using python to brute force 12 word bip39 seed phrase from word list?
Pure Python implementation should get you maybe like a dozen or two per second, that's all.

it shows around 10000h/s
Sounds like you are doing part of the work only. I was testing the whole thing like getting a list of deterministic keys/addresses and so on.

atleast it found test phrase.
now playing with https://privatekeys.pw/puzzles/0.2-btc-puzzle

Code:
import itertools
import time
from multiprocessing import Pool, cpu_count
from mnemonic import Mnemonic
from Crypto.Hash import HMAC, SHA512
import hashlib, struct, base58
from ecdsa import SigningKey, SECP256k1

TARGET_ADDRESS = "1KfZGvwZxsvSmemoCmEV75uqcNzYBHjkHZ"
REPORT_INTERVAL = 3  # seconds
mnemo = Mnemonic('english')

# Position-specific word candidates
position_words = {
    1: ["black", "this", "day", "subject", "food", "real", "liberty", "time",
        "proof", "receive", "tower", "moon", "order", "police", "change",
        "vote", "future", "world", "mask"],
    2: ["black", "this", "day", "subject", "food", "real", "liberty", "time",
        "proof", "receive", "tower", "moon", "order", "police", "change",
        "vote", "future", "world", "mask"],
    3: ["black", "this", "day", "subject", "food", "real", "liberty", "time",
        "proof", "receive", "tower", "moon", "order", "police", "change",
        "vote", "future", "world", "mask"],
    4: ["black", "this", "day", "subject", "food", "real", "liberty", "time",
        "proof", "receive", "tower", "moon", "order", "police", "change",
        "vote", "future", "world", "mask"],
    5: ["black", "this", "day", "subject", "food", "real", "liberty", "time",
        "proof", "receive", "tower", "moon", "order", "police", "change",
        "vote", "future", "world", "mask"],
    6: ["black", "this", "day", "subject", "food", "real", "liberty", "time",
        "proof", "receive", "tower", "moon", "order", "police", "change",
        "vote", "future", "world", "mask"],],
    7: ["black", "this", "day", "subject", "food", "real", "liberty", "time",
        "proof", "receive", "tower", "moon", "order", "police", "change",
        "vote", "future", "world", "mask"],,
    8: ["black", "this", "day", "subject", "food", "real", "liberty", "time",
        "proof", "receive", "tower", "moon", "order", "police", "change",
        "vote", "future", "world", "mask"],,
    9: ["black", "this", "day", "subject", "food", "real", "liberty", "time",
        "proof", "receive", "tower", "moon", "order", "police", "change",
        "vote", "future", "world", "mask"],
    10: ["black", "this", "day", "subject", "food", "real", "liberty", "time",
        "proof", "receive", "tower", "moon", "order", "police", "change",
        "vote", "future", "world", "mask"],
    11:["black", "this", "day", "subject", "food", "real", "liberty", "time",
        "proof", "receive", "tower", "moon", "order", "police", "change",
        "vote", "future", "world", "mask"],
    12: ["black", "this", "day", "subject", "food", "real", "liberty", "time",
        "proof", "receive", "tower", "moon", "order", "police", "change",
        "vote", "future", "world", "mask"],

def hmac_sha512(key, data):
    return HMAC.new(key, data, digestmod=SHA512).digest()

def derive_bip44_key(seed):
    hardened = 0x80000000
    key = b'Bitcoin seed'
    I = hmac_sha512(key, seed)
    priv_key, chain = I[:32], I[32:]
    for index in [44 + hardened, 0 + hardened, 0 + hardened, 0, 0]:
        data = b'\x00' + priv_key + struct.pack('>L', index)
        I = hmac_sha512(chain, data)
        priv_key, chain = I[:32], I[32:]
    return priv_key

def private_to_address(priv):
    sk = SigningKey.from_string(priv, curve=SECP256k1)
    pub = b'\x04' + sk.verifying_key.to_string()
    sha = hashlib.sha256(pub).digest()
    ripe = hashlib.new('ripemd160', sha).digest()
    prefixed = b'\x00' + ripe
    checksum = hashlib.sha256(hashlib.sha256(prefixed).digest()).digest()[:4]
    return base58.b58encode(prefixed + checksum).decode()

def bip39_seed_to_addr(seed_words):
    phrase = ' '.join(seed_words)
    seed = mnemo.to_seed(phrase, passphrase="")
    priv = derive_bip44_key(seed)
    return private_to_address(priv)

def check_combination(combo):
    # Reject combinations with duplicate words
    if len(set(combo)) < len(combo):
        return None

    phrase = ' '.join(combo)
    if not mnemo.check(phrase):
        return None

    try:
        address = bip39_seed_to_addr(combo)
        if address == TARGET_ADDRESS:
            return combo
    except Exception:
        return None

    return None

def scan_positional_combinations():
    all_combinations = itertools.product(
        position_words[1], position_words[2], position_words[3],
        position_words[4], position_words[5], position_words[6],
        position_words[7], position_words[8], position_words[9],
        position_words[10], position_words[11], position_words[12]
    )
    total = 6**12
    print(f"Scanning {total:,} combinations using {cpu_count()} cores...")

    start = time.time()
    last_report = start
    pool = Pool(cpu_count())

    for i, result in enumerate(pool.imap_unordered(check_combination, all_combinations, chunksize=100)):
        now = time.time()
        if now - last_report >= REPORT_INTERVAL:
            elapsed = now - start
            speed = i / elapsed
            progress = (i / total) * 100
            print(f"[{elapsed:.1f}s] Checked: {i:,} | Speed: {speed:,.0f}/s | Progress: {progress:.8f}%")
            last_report = now

        if result:
            print("\nSUCCESS! Valid mnemonic found:")
            print(" ".join(result))
            print(f"Address: {TARGET_ADDRESS}")
            pool.terminate()
            return

    print("\nDone. No matching mnemonic found.")

if __name__ == "__main__":
    scan_positional_combinations()