Can anyone solve, say, puzzle 50 in Python in 10 seconds?

Why does it have to be Puzzle 50? Of course I can — but I'll use a random seed.
import systime
import os
import timesys
import random
import hashlib
import gmpy2
from gmpy2 import mpz
import multiprocessing
from math import log2, sqrt, log
from multiprocessing import Pool, cpu_count
os.system("cls||clear")
t = time.ctime()
# Constantssys.stdout.write(f"\033[?25l")
MODULO = gmpy2sys.mpzstdout.write(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2Ff"\033[01;33m[+]\033[32m KANGAROO: \033[01;33m{t}\n")
ORDER = gmpy2sys.mpzstdout.flush(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141)
GX = gmpy2.mpz(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798)
GYmodulo = gmpy2.mpz(0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B80xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
Gx = gmpy2.mpz(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798)
# Define Point classGy = gmpy2.mpz(0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8)
class Point:PG = (Gx, Gy)
def __init__(self, x=0, y=0):
Z = (0, 0) self.# zero-point, infinite in real x = x, y - plane
self.y = y
def add(P, Q, p=modulo):
PG = Point(GX Px, GY)Py = P
Z = Point(0 Qx, 0)Qy = Q
# Function to multiply a point by 2
def multiply_by_2(P, p=MODULO):
if P == Z:
return Z
m = gmpy2.f_mod(3 * P.x * P.x * gmpy2.invert(2 * P.y, p), p)
x = gmpy2.f_mod(m * m - 2 * P.x, p)
y = gmpy2.f_mod(m * (P.x - x) - P.y, p)
return Point(x, y)
# Function to add two points
def add_points(P, Q, p=MODULO):
if P == Z:
return Q
elif Q == Z:
return P
elif P.xPx == Q.xQx and (P.yPy != Q.yQy or P.yPy == 0):
return Z
elif P.xPx == Q.xQx:
m = (3 * P.xPx * P.xPx) * gmpy2.invert(2 * P.yPy, p) % p
else:
m = (Q.yQy - P.yPy) * gmpy2.invert(Q.xQx - P.xPx, p) % p
x = (m * m - P.xPx - Q.xQx) % p
y = (m * (P.xPx - x) - P.yPy) % p
return Point(x, y)
# Function to calculate Y-coordinate from X-coordinate
def x_to_ymul2(XP, y_parity, p=MODULOmodulo):
YPx, Py = gmpy2.mpz(3)P
tmpif P = gmpy2.mpz(1)= Z:
return Z
while Y > 0:m = gmpy2.f_mod(3 * Px * Px * gmpy2.invert(2 * Py, p), p)
if Y % 2x == 1: gmpy2.f_mod(m * m - 2 * Px, p)
tmpy = gmpy2.f_mod(tmpm * X(Px - x) - Py, p)
Y >>= 1return (x, y)
X = gmpy2.f_mod(X * X, p)
def mulk(k, P=PG, p=modulo):
Xif k = gmpy2.f_mod(tmp + 7, p)= 0:
return Z
Yelif k = gmpy2.f_div(gmpy2.add(p,= 1), 4):
tmp = gmpy2.mpz(1) return P
elif k % 2 == 0:
while Y >nbsp; 0: return mulk(k // 2, mul2(P, p), p)
if Y % 2 == 1else:
tmp = gmpy2.f_modreturn add(tmp * XP, mulk((k - 1) // 2, mul2(P, p), p), p)
Y >>= 1
X = gmpy2.f_moddef X2Y(X * X, y_parity, p=modulo):
X_cubed = gmpy2.powmod(X, 3, p)
YX_squared = tmpgmpy2.powmod(X, 2, p)
tmp = gmpy2.f_mod(X_cubed + 7, p)
if Y % 2 != y_parity:gmpy2.powmod(tmp, gmpy2.f_div(gmpy2.add(p, 1), 4), p)
if y_parity == 1:
Y = gmpy2.f_mod(-Y, p)
return Y
# Function to compute a table of pointsdef comparator(A, Ak, B, Bk, core_number, random_seed):
def compute_point_table():
points = [PG]
for k in range(255):
points.append(multiply_by_2(points[k]))
return points
POINTS_TABLE = compute_point_table()
# Global event to signal all processes to stop
STOP_EVENT = multiprocessing.Event()
# Function to check and compare points for potential solutions
def check(P, Pindex, DP_rarity, A, Ak, B, Bk):
modulo_val = P.x % DP_rarity
if modulo_val == 0:
A.append(gmpy2.mpz(P.x))
Ak.append(gmpy2.mpz(Pindex))
return comparator(A, Ak, B, Bk)
else:
return False
# Function to compare two sets of points and find a common point
def comparator(A, Ak, B, Bk):
global STOP_EVENT
result = set(A).intersection(set(B))
if result:
sol_kt = A.index(next(iter(result)))
sol_kw = B.index(next(iter(result)))
HEX = "%064x" % abs(Ak[sol_kt] - Bk[sol_kw])
dec = int(HEX, 16)
ttotal_time = time.ctimetime() - starttime
pid = osprint('\n[+] total time: %.getpid2f sec' % (total_time) # Get the process ID)
core_numbert = pid % cpu_counttime.ctime() # Calculate the CPU core number
total_time = time.timeprint(f"\033[32m[+] PUZZLE SOLVED: {t}, Core: {core_number+1:02} \033[0m") - starttime
print(f"\n\033[32m[+] PUZZLE SOLVEDRandom seed used: {trandom_seed}, total time: {total_time:.2f} sec, Core: {core_number+1:02} \033[0m")
print(f"\033[32m[+] HEXPrivate key (dec) : \033[32m {HEXdec} \033[0m")
dash_line = '-' * 140
with open("KEYFOUNDKEYFOUND.txt", "a") as file:
file.write(f"\n{dash_line}")
file.write("\n\nSOLVED " + t)
file.write(f"\nTotal Time: {total_time:.2f} sec")
file.write(f"\nCore: {core_number+1:02}")
file.write(f"\nRandom seed: {random_seed}")
file.write("\nPrivate Key (decimal): " + str(dec))
file.write("\nPrivate Key (hex): " + HEX)
file.write(f"\n{dash_line}")
"\n-------------------------------------------------------------------------------------------------------------------------------------\n"file.close()
)return True
STOP_EVENT.set() # Set the stop event to signal all processes
# Memoization for point multiplication
ECMULTIPLY_MEMO = {}
# Function to multiply a point by a scalar
def ecmultiply(k, P=PG, p=MODULO):
if k == 0:
return ZERO_POINT
elif k == 1:
return P
elif k % 2 == 0:
if k in ECMULTIPLY_MEMO:
return ECMULTIPLY_MEMO[k]
else:
result = ecmultiply(k // 2, multiply_by_2(P, p), p)
ECMULTIPLY_MEMO[k] = result
return result
else:
return add_points(P, ecmultiply((k - 1) // 2, multiply_by_2(P, p), p))False
# Recursive function to multiply a point by a scalardef check(P, Pindex, DP_rarity, A, Ak, B, Bk, core_number, random_seed):
def mulk(k, P modulo_val =PG, p=MODULO): P[0] % DP_rarity
if kmodulo_val == 0:
return ZERO_POINTA.append(gmpy2.mpz(P[0]))
elif k == 1: Ak.append(gmpy2.mpz(Pindex))
return Pcomparator(A, Ak, B, Bk, core_number, random_seed)
elif k % 2 == 0:
return mulk(k // 2, multiply_by_2(P, p), p)
else:
return add_points(P, mulk((k - 1) // 2, multiply_by_2(P, p), p))False
# Generate a list of powers of two for faster access
def generate_powers_of_two(hop_modulo):
return [gmpy2.mpz(1 << pw) for pw in range(hop_modulo)]
t = time.ctimedef search(thread_id, P, W0, DP_rarity, Nw, Nt, hop_modulo, upper_range_limit, lower_range_limit, result_queue, powers_of_two):
sys pid = os.stdout.writegetpid("\033[01;33m")
sys.stdout.write core_number = pid % cpu_count(f"[+] [Kangaroo]: {t}" + "\n")
sys.stdout.flush() # Random seed Config
constant_prefix = b''
# Configuration for the puzzle prefix_length = len(constant_prefix)
puzzle length = 508
compressed_public_key ending_length = "03f46f41027bbf44fafd6b059091b900dad41e6845b2241dc3254c7cdd3c5a16c6" length - prefix_length
lower_range_limit ending_bytes = 2 ** os.urandom(puzzle - 1ending_length)
upper_range_limit random_seed = (2**puzzle) - 1constant_prefix + ending_bytes
random.seed(random_seed)
kangaroo_power = 6 print(f"[+] [Core]: {core_number+1:02}, [Random seed]: {random_seed}")
t = [gmpy2.mpz(lower_range_limit + gmpy2.mpz(random.randint(0, upper_range_limit - lower_range_limit))) for _ in range(Nt)]
Nt T = Nw = [mulk(2 ** kangaroo_power // puzzleti) * puzzle + 8for ti in t]
DP_rarity dt = 8 * puzzle[gmpy2.mpz(0) for _ in range(Nt)]
hop_modulo = (puzzle // 2) + 8
w = [gmpy2.mpz(random.randint(0, upper_range_limit - lower_range_limit)) for _ in range(Nw)]
# Precompute powers of two W = [add(W0, mulk(wk)) for faster accesswk in w]
powers_of_two dw = generate_powers_of_two[gmpy2.mpz(hop_modulo0) for _ in range(Nw)]
if len(compressed_public_key) Hops, Hops_old == 66: 0, 0
Xt0 = mpztime.time(compressed_public_key[2:66], 16)
Ymemo = x_to_y(X, mpz(compressed_public_key[:2]) - 2){}
else: solution_found = False
print("[error] pubkey len(66/130) invalid!")
while not solution_found:
print for k in range(f"[+] [Puzzle]: {puzzle}"Nt):
print(f"[ Hops +] [Lower range limit]: {lower_range_limit}")= 1
print(f" pw = T[+k][Upper range limit0]: {upper_range_limit}") % hop_modulo
print("[+] [Xcoordinate] if pw not in memo: %064x" % X)
print(" memo[+pw] = powers_of_two[Ycoordinatepw]: %064x" % Y)
print(f"[+] [Expected Hops: 2^{log2(2.2 * sqrt(1 <nbsp; <nbsp; (puzzle-1))):.2f} ({int(2.2 * sqrt(1 <nbsp; <nbsp; (puzzle-1)))}) dt[k]") = memo[pw]
if check(T[k], t[k], DP_rarity, T, t, W, w, core_number, random_seed):
result_queue.put((thread_id, T[k], t[k], W[k], w[k], core_number, random_seed))
W0 solution_found = Point(X, Y)True
starttime = oldtime = time.time() break
t[k] += dt[k]
Hops T[k] = 0add(P[int(pw)], T[k])
if solution_found:
# Worker function for point search break
def search_worker(
Nt, for k in range(Nw, puzzle, kangaroo_power, starttime, lower_range_limit, upper_range_limit):
): Hops += 1
global STOP_EVENT pw = W[k][0] % hop_modulo
pid = os.getpid() if pw not in memo:
core_number memo[pw] = pid % cpu_count()powers_of_two[pw]
#Random seed Config dw[k] = memo[pw]
#constant_prefix = b'' #back to no constant if check(W[k], w[k], DP_rarity, W, w, T, t, core_number, random_seed):
constant_prefix = b'\xbc\x9b\x8cd\xfc\xa1?\xcf' result_queue.put((thread_id, T[k], t[k], W[k], w[k], core_number, random_seed))
prefix_length solution_found = len(constant_prefix)True
length = 8 break
ending_length w[k] += length - prefix_lengthdw[k]
with open W[k] = add("/dev/urandom"P[int(pw)], "rb"W[k]) as urandom_file:
ending_bytes = urandom_file.read(ending_length)if solution_found:
random_bytes = constant_prefix + ending_bytes break
print(f"[+] [Core]: {core_number+1:02}, [Random seed]: {random_bytes}")
random t1 = time.seedtime(random_bytes)
t elapsed_time = [t1 - starttime
mpz(if t1 - t0 > 1 and thread_id == 0:
lower_range_limithops_per_second = (Hops - Hops_old) / (t1 - t0) * cores
+ mpzhours, rem = divmod(random.randint(0elapsed_time, upper_range_limit - lower_range_limit3600))
minutes, seconds = divmod(rem, 60)
for _ in range elapsed_time_str = f"{int(Nthours):02d}:{int(minutes):02d}:{int(seconds):02d}"
] p_2 = f'{log2(Hops*cores):.2f}'
T = [mulk print(ti) for ti in tf'[+] [Hops: 2^{p_2} <-> {hops_per_second:.0f} h/s] [{elapsed_time_str}]', end='\r', flush=True)
dt t0 = [mpz(0) for _ in range(Nt)]t1
w Hops_old = [Hops
mpz(random.randint(0, upper_range_limit - lower_range_limit)) for _ in range(Nw)
print('\r[+] Hops:', Hops* cores)
W = print('[add_points+] Average time to solve: %.2f sec' % (W0, mulk(wktime.time()-starttime) for wk in w]))
dw = [mpz(0) for _ in range(Nw)]
def main():
Hops, Hops_oldresult_queue = 0, 0multiprocessing.Queue()
coresprocesses = cpu_count()[
t0 = time multiprocessing.timeProcess(target=search, args=(i, P, W0, DP_rarity, Nw, Nt, hop_modulo, upper_range_limit, lower_range_limit, result_queue, powers_of_two)) for i in range(cores)
oldtime = time.time()]
starttime = oldtimefor p in processes:
p.start()
while True:
# Wait for k in range(Nt):a result
Hops +result = 1result_queue.get()
pwthread_id, T_k, t_k, W_k, w_k, core_number, random_seed = T[k].x % hop_moduloresult
dt[k] = powers_of_two[pw]
solved = check(T[k], t[k], DP_rarity, T, t, W, w)# Print the successful core and seed
if solvedprint(f"\n[+] Solution found by Core: {core_number+1:02}")
STOP_EVENT.setprint(f"[+] Random seed used: {random_seed}")
break
t[k] = mpz(t[k]) + dt[k] # Use mpz hereTerminate all processes
T[k] = add_points(POINTS_TABLE[pw], T[k])for p in processes:
p.terminate()
for k in range(Nw):
Hops += 1# Configuration for the puzzle
pwcores = W[k].x % hop_modulocpu_count()
dw[k]puzzle = powers_of_two[pw]40
solvedcompressed_public_key = check(W[k], w[k], DP_rarity, W, w, T, t)"03a2efa402fd5268400c77c20e574ba86409ededee7c4020e4b9f0edbee53de0d4"
if solved:kangaroo_power = 3
STOP_EVENT.setlower_range_limit = 2 ** (puzzle - 1)
breakupper_range_limit = (2**puzzle) - 1
w[k] = mpz(w[k]) + dw[k] # Use mpz here
DP_rarity = 1  lt; lt; int(((puzzle - W[k] = add_points(POINTS_TABLE[pw], W[k]2*kangaroo_power)/2 - 2))
hop_modulo = ((puzzle - 1) // 2) + kangaroo_power
if STOP_EVENT.is_set():Nt = Nw = 2**kangaroo_power
break
t1 = time.time()# Precompute powers of two for faster access
elapsed_timepowers_of_two = t1 - starttimegenerate_powers_of_two(hop_modulo)
if t1 - t0 > 1 and core_number == 0:
hops_per_second = print(Hops - Hops_old'[+] [Tame and Wild herds are prepared]') / (t1 - t0) * cores
hours, rem = divmod(elapsed_time, 3600)
minutes, seconds = divmodif len(rem, 60compressed_public_key) == 66:
elapsed_time_strX = f"{intgmpy2.mpz(hours)compressed_public_key[2:02d}:{int(minutes66], 16):02d}:{int(seconds):02d}"
p_2Y = f'{log2X2Y(Hops*cores):X, gmpy2.2f}'mpz(compressed_public_key[:2]) - 2)
print(f'[+] [Hopselse: 2^{p_2} <-> {hops_per_second:.0f} h/s] [{elapsed_time_str}]', end='\r', flush=True)
t0 = t1print("[error] pubkey len(66/130) invalid!")
Hops_old = Hops
W0 = (X,Y)
starttime = oldtime = time.time()
# Main script
if __name__Hops == "__main__": 0
process_count = cpu_count()
print(f"P = [+PG] [Using {process_count} CPU cores for parallel search]:")
for k in range(255):
# Create a pool of worker processesP.append(mul2(P[k]))
pool = Poolprint(process_count'[+] [P-table prepared]')
results = pool.starmap(
search_worker,print(f"[+] [Puzzle: {puzzle}]")
print(f"[+] [Lower range limit: {lower_range_limit}]")
print(f"[+] [Upper range limit: {upper_range_limit}]")
print(f"[+] [Expected Hops: 2^{log2(2.2 * sqrt(1  lt; lt; (puzzle-1))):.2f} ({int(2.2 * sqrt(1  lt; lt; Nt,(puzzle-1)))})]")
Nw,print(f"[+] [Using {cores} CPU cores for parallel search]")
puzzle,
kangaroo_power,if __name__ == '__main__':
starttime,main()
lower_range_limit,
upper_range_limit,
)
]
* process_count,
)
pool.close()
pool.join()
- [Kangaroo]: Mon May 5 10:14:12 2025
- [Puzzle]: 50
- [Lower range limit]: 562949953421312
- [Upper range limit]: 1125899906842623
- [Xcoordinate]: f46f41027bbf44fafd6b059091b900dad41e6845b2241dc3254c7cdd3c5a16c6
- [Ycoordinate]: eb3dfcc04c320b55c529291478550be6072977c0c86603fb2e4f5283631064fb
- [Expected Hops: 2^25.64 (52198446)]
- [Using 12 CPU cores for parallel search]:
- [Core]: 04, [Random seed]: b'\xbc\x9b\x8cd\xfc\xa1?\xcf'
- [Core]: 05, [Random seed]: b'\xbc\x9b\x8cd\xfc\xa1?\xcf'
- [Core]: 08, [Random seed]: b'\xbc\x9b\x8cd\xfc\xa1?\xcf'
- [Core]: 07, [Random seed]: b'\xbc\x9b\x8cd\xfc\xa1?\xcf'
- [Core]: 06, [Random seed]: b'\xbc\x9b\x8cd\xfc\xa1?\xcf'
- [Core]: 09, [Random seed]: b'\xbc\x9b\x8cd\xfc\xa1?\xcf'
- [Core]: 10, [Random seed]: b'\xbc\x9b\x8cd\xfc\xa1?\xcf'
- [Core]: 11, [Random seed]: b'\xbc\x9b\x8cd\xfc\xa1?\xcf'
- [Core]: 12, [Random seed]: b'\xbc\x9b\x8cd\xfc\xa1?\xcf'
- [Core]: 02, [Random seed]: b'\xbc\x9b\x8cd\xfc\xa1?\xcf'
- [Core]: 01, [Random seed]: b'\xbc\x9b\x8cd\xfc\xa1?\xcf'
- [Core]: 03, [Random seed]: b'\xbc\x9b\x8cd\xfc\xa1?\xcf'
- [Hops: 2^24.44 <-> 1982097 h/s] [00:00:10]
- PUZZLE SOLVED: Mon May 5 10:14:22 2025, total time: 10.73 sec, Core: 04
- HEX: 00000000000000000000000000000000000000000000000000022bd43c2e9354