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-puzzleimport 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()