Post
Topic
Board Bitcoin Discussion
Re: Bitcoin puzzle transaction ~32 BTC prize to who solves it
by
Denevron
on 30/03/2025, 11:56:18 UTC
Bit flipping (mutation) helps to find a solution faster, since there are fewer options than in the general range, and if you split it into 20 people, say from 30 to 50 (change one bit option for each), then you can find it even faster, even on the CPU! But for some reason you don’t want to add my idea to Cyclone  Grin

Just one moment. If I understand correctly, we don't actually have to search the whole range—just from the last private key onward ?   Tongue

Code:
import sys
import time
import multiprocessing
from itertools import combinations
from concurrent.futures import ProcessPoolExecutor, as_completed
import os
from functools import partial

sys.path.append(r'E:\Work\python\secp256k1')
import secp256k1 as ice

NUM_WORKERS = 1
TARGET_ADDRESS = "b907c3a2a3b27789dfb509b730dd47703c272868"

stop_event = multiprocessing.Event()
key_found = multiprocessing.Value('b', False)

# Original key (from puzzle 19)
KEY_67_HEX = "000000000000000000000000000000000000000000000000000000000005749f"

# We fix the senior 236 bits (zero bits)
KEY_67_BIN = bin(int(KEY_67_HEX, 16))[2:].zfill(256)
FIXED_BITS = KEY_67_BIN[:236]  # Fixed 236 bits
CHANGING_BITS = list(KEY_67_BIN[236:]) # Changeable bits (68 bits)


def mutate_fixed_bits(start_index, num_workers):
    for i, bit_indices in enumerate(combinations(range(20), 8)):
        if (i % num_workers) == start_index:
            mutated_bits = CHANGING_BITS[:]
            for index in bit_indices:
                mutated_bits[index] = '1' if mutated_bits[index] == '0' else '0'
           
            mutated_key_bin = FIXED_BITS + "".join(mutated_bits)
            mutated_key_hex = hex(int(mutated_key_bin, 2))[2:].zfill(64)
            yield mutated_key_hex


def check_key(worker_id, num_workers, keys_checked, lock):
    local_counter = 0 
    start_time = time.time()

    for mutated_key_hex in mutate_fixed_bits(worker_id, num_workers):
        if key_found.value or stop_event.is_set():
            return None

        generated_address = ice.privatekey_to_h160(0, True, int(mutated_key_hex, 16)).hex()

        if generated_address.startswith(TARGET_ADDRESS[:7]):
            print(f"  Private Key: {mutated_key_hex}")
            print(f"  Generated Hash: {generated_address}")
            print(f"  Target Hash: {TARGET_ADDRESS}")

        if generated_address == TARGET_ADDRESS:
            with lock:
                if not key_found.value:
                    print(f"\n Key found {worker_id}: {mutated_key_hex} to address {TARGET_ADDRESS}!")
                    with open("key.txt", "w") as f:
                        f.write(f"Key found: {mutated_key_hex}\n")
                    key_found.value = True
                    stop_event.set()
            return mutated_key_hex
       
        local_counter += 1 
        if time.time() - start_time >= 300:
            with lock:
                keys_checked.value += local_counter
            local_counter = 0 
            start_time = time.time() 

    with lock:
        keys_checked.value += local_counter 

    return None 


def print_status(start_time, keys_checked, lock):
    while not stop_event.is_set():
        time.sleep(300)
        with lock:
            checked = keys_checked.value 
        elapsed_time = time.time() - start_time
        print(f"Full time: {elapsed_time:.2f} sec. | Total Key: {checked}")


def main():
    start_time = time.time()

    with multiprocessing.Manager() as manager:
        keys_checked = manager.Value('i', 0)
        lock = manager.Lock()

        tracker_process = multiprocessing.Process(target=print_status, args=(start_time, keys_checked, lock))
        tracker_process.start()

        check_key_partial = partial(check_key, num_workers=NUM_WORKERS, keys_checked=keys_checked, lock=lock)

        with ProcessPoolExecutor(max_workers=NUM_WORKERS) as executor:
            futures = {executor.submit(check_key_partial, i): i for i in range(NUM_WORKERS)}

            for future in as_completed(futures):
                result = future.result()
                if result:
                    break

        stop_event.set()
        tracker_process.terminate()
        tracker_process.join()

    end_time = time.time()
    if not key_found.value:
        print("Key not found")

    print(f"⏳ Full time: {end_time - start_time:.2f} sec.")
    os._exit(0)


if __name__ == "__main__":
    multiprocessing.freeze_support()
    main()

run it, this is an example of how to find 20 (others are possible) here you only need to change 8 bits, if you put (range(20), Cool) here - 9 instead of 8, you won't find the key, put 7, you won't find it either) here you need to change exactly 8 bits), and so on for many puzzles, only part of the bits in the key changes, mostly from 3 to 45 bits, depends on the puzzle number  Grin