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

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

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),

) 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
