not a bad working code! Are you thinking on implementing multi threading? I know this is not comparable with GPU but its not bad at all
![Smiley](https://bitcointalk.org/Smileys/default/smiley.gif)
Congrats!
Here you go
import time
import os
import sys
import random
import gmpy2
import multiprocessing
from math import log2, sqrt, log
from multiprocessing import Pool, cpu_count
os.system("cls||clear")
t = time.ctime()
sys.stdout.write(f"\033[?25l")
sys.stdout.write(f"\033[01;33m[+]\033[32m KANGAROO: \033[01;33m{t}\n")
sys.stdout.flush()
modulo = gmpy2.mpz(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
Gx = gmpy2.mpz(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798)
Gy = gmpy2.mpz(0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8)
PG = (Gx, Gy)
Z = (0, 0) # zero-point, infinite in real x, y - plane
def add(P, Q, p=modulo):
Px, Py = P
Qx, Qy = Q
if P == Z:
return Q
elif Q == Z:
return P
elif Px == Qx and (Py != Qy or Py == 0):
return Z
elif Px == Qx:
m = (3 * Px * Px) * gmpy2.invert(2 * Py, p) % p
else:
m = (Qy - Py) * gmpy2.invert(Qx - Px, p) % p
x = (m * m - Px - Qx) % p
y = (m * (Px - x) - Py) % p
return (x, y)
def mul2(P, p=modulo):
Px, Py = P
if P == Z:
return Z
m = gmpy2.f_mod(3 * Px * Px * gmpy2.invert(2 * Py, p), p)
x = gmpy2.f_mod(m * m - 2 * Px, p)
y = gmpy2.f_mod(m * (Px - x) - Py, p)
return (x, y)
def mulk(k, P=PG, p=modulo):
if k == 0:
return Z
elif k == 1:
return P
elif k % 2 == 0:
return mulk(k // 2, mul2(P, p), p)
else:
return add(P, mulk((k - 1) // 2, mul2(P, p), p), p)
def X2Y(X, y_parity, p=modulo):
X_cubed = gmpy2.powmod(X, 3, p)
X_squared = gmpy2.powmod(X, 2, p)
tmp = gmpy2.f_mod(X_cubed + 7, p)
Y = gmpy2.powmod(tmp, gmpy2.f_div(gmpy2.add(p, 1), 4), p)
if y_parity == 1:
Y = gmpy2.f_mod(-Y, p)
return Y
def comparator(A, Ak, B, Bk):
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)
total_time = time.time() - starttime
print('\n[+] total time: %.2f sec' % (total_time))
t = time.ctime()
print(f"\033[32m[+] PUZZLE SOLVED: {t} \033[0m")
print(f"\033[32m[+] Private key (dec) : {dec} \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"\nRandom seed: {seed}")
file.write("\nPrivate Key (decimal): " + str(dec))
file.write("\nPrivate Key (hex): " + HEX)
file.write(f"\n{dash_line}")
file.close()
return True
else:
return False
def check(P, Pindex, DP_rarity, A, Ak, B, Bk):
modulo_val = P[0] % DP_rarity
if modulo_val == 0:
A.append(gmpy2.mpz(P[0]))
Ak.append(gmpy2.mpz(Pindex))
return comparator(A, Ak, B, Bk)
else:
return 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)]
def search(thread_id, P, W0, DP_rarity, Nw, Nt, hop_modulo, upper_range_limit, lower_range_limit, result_queue, powers_of_two):
t = [gmpy2.mpz(lower_range_limit + gmpy2.mpz(random.randint(0, upper_range_limit - lower_range_limit))) for _ in range(Nt)]
T = [mulk(ti) for ti in t]
dt = [gmpy2.mpz(0) for _ in range(Nt)]
w = [gmpy2.mpz(random.randint(0, upper_range_limit - lower_range_limit)) for _ in range(Nw)]
W = [add(W0, mulk(wk)) for wk in w]
dw = [gmpy2.mpz(0) for _ in range(Nw)]
Hops, Hops_old = 0, 0
t0 = time.time()
# Memoization dictionary
memo = {}
solution_found = False # Flag to control the loop
while not solution_found:
for k in range(Nt):
Hops += 1
pw = T[k][0] % hop_modulo
if pw not in memo:
memo[pw] = powers_of_two[pw]
dt[k] = memo[pw]
if check(T[k], t[k], DP_rarity, T, t, W, w):
result_queue.put((thread_id, T[k], t[k], W[k], w[k]))
solution_found = True # Set flag to exit loop
break # Exit the for-loop
t[k] += dt[k]
T[k] = add(P[int(pw)], T[k])
if solution_found: # Break the while-loop if solution is found
break
for k in range(Nw):
Hops += 1
pw = W[k][0] % hop_modulo
if pw not in memo:
memo[pw] = powers_of_two[pw]
dw[k] = memo[pw]
if check(W[k], w[k], DP_rarity, W, w, T, t):
result_queue.put((thread_id, T[k], t[k], W[k], w[k]))
solution_found = True # Set flag to exit loop
break # Exit the for-loop
w[k] += dw[k]
W[k] = add(P[int(pw)], W[k])
if solution_found: # Break the while-loop if solution is found
break
t1 = time.time()
elapsed_time = t1 - starttime
if t1 - t0 > 1 and thread_id == 0:
hops_per_second = (Hops - Hops_old) / (t1 - t0) * cores
hours, rem = divmod(elapsed_time, 3600)
minutes, seconds = divmod(rem, 60)
elapsed_time_str = f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}"
p_2 = f'{log2(Hops*cores):.2f}'
print(f'[+] [Hops: 2^{p_2} <-> {hops_per_second:.0f} h/s] [{elapsed_time_str}]', end='\r', flush=True)
t0 = t1
Hops_old = Hops
print('\r[+] Hops:', Hops* cores)
print('[+] Average time to solve: %.2f sec' % ((time.time()-starttime)))
def main():
result_queue = multiprocessing.Queue()
processes = [
multiprocessing.Process(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)
]
for p in processes:
p.start()
result = result_queue.get()
for p in processes:
p.terminate()
# Configuration for the puzzle
cores = cpu_count()
puzzle = 40
compressed_public_key = "03a2efa402fd5268400c77c20e574ba86409ededee7c4020e4b9f0edbee53de0d4"
kangaroo_power = 3
lower_range_limit = 2 ** (puzzle - 1)
upper_range_limit = (2**puzzle) - 1
DP_rarity = 1 << int(((puzzle - 2*kangaroo_power)/2 - 2))
hop_modulo = ((puzzle - 1) // 2) + kangaroo_power
Nt = Nw = 2**kangaroo_power
# Precompute powers of two for faster access
powers_of_two = generate_powers_of_two(hop_modulo)
T, t, dt = [], [], []
W, w, dw = [], [], []
A, Ak, B, Bk = [], [], [], []
print('[+] [Tame and Wild herds are prepared]')
if len(compressed_public_key) == 66:
X = gmpy2.mpz(compressed_public_key[2:66], 16)
Y = X2Y(X, gmpy2.mpz(compressed_public_key[:2]) - 2)
else:
print("[error] pubkey len(66/130) invalid!")
W0 = (X,Y)
starttime = oldtime = time.time()
Hops = 0
P = [PG]
for k in range(255):
P.append(mul2(P[k]))
print('[+] [P-table prepared]')
print(f"[+] [Using {cores} CPU cores for parallel search]")
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 << (puzzle-1))):.2f} ({int(2.2 * sqrt(1 << (puzzle-1)))})]")
#Random seed Config
seed = os.urandom(9).hex()
print(f"[+] [Random seed: {seed}]")
random.seed(seed)
if __name__ == '__main__':
main()
- KANGAROO: Sat Jun 15 21:22:34 2024
- [Tame and Wild herds are prepared]
- [P-table prepared]
- [Using 12 CPU cores for parallel search]
- [Puzzle: 40]
- [Lower range limit: 549755813888]
- [Upper range limit: 1099511627775]
- [Expected Hops: 2^20.64 (1631201)]
- [Random seed: 0932dc777428d6f3b9]
- [Hops: 2^22.21 <-> 2443414 h/s] [00:00:02]
- total time: 2.18 sec
- PUZZLE SOLVED: Sat Jun 15 21:22:36 2024
- Private key (dec) : 1003651412950
- Hops: 5254560
- Average time to solve: 2.18 sec
But I won't give you false hope that this script can solve anything above 50 soon. It's simply beyond the reach of python's capabilities.
You have to program in C++ yourself if the current scripts do not meet your needs.