import sys
import os
import time
import random
import hashlib
import gmpy2
from gmpy2 import mpz
from functools import lru_cache
import multiprocessing
from multiprocessing import Pool, cpu_count
os.system("cls")
# Constants
MODULO = gmpy2.mpz(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
ORDER = gmpy2.mpz(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141)
GX = gmpy2.mpz(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798)
GY = gmpy2.mpz(0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8)
# Define Point class
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
PG = Point(GX, GY)
ZERO_POINT = Point(0, 0)
# Function to multiply a point by 2
def multiply_by_2(P, p=MODULO):
c = gmpy2.f_mod(3 * P.x * P.x * gmpy2.powmod(2 * P.y, -1, p), p)
R = Point()
R.x = gmpy2.f_mod(c * c - 2 * P.x, p)
R.y = gmpy2.f_mod(c * (P.x - R.x) - P.y, p)
return R
# Function to add two points
def add_points(P, Q, p=MODULO):
dx = Q.x - P.x
dy = Q.y - P.y
c = gmpy2.f_mod(dy * gmpy2.invert(dx, p), p)
R = Point()
R.x = gmpy2.f_mod(c * c - P.x - Q.x, p)
R.y = gmpy2.f_mod(c * (P.x - R.x) - P.y, p)
return R
# Function to calculate Y-coordinate from X-coordinate
@lru_cache(maxsize=None)
def x_to_y(X, y_parity, p=MODULO):
Y = gmpy2.mpz(3)
tmp = gmpy2.mpz(1)
while Y > 0:
if Y % 2 == 1:
tmp = gmpy2.f_mod(tmp * X, p)
Y >>= 1
X = gmpy2.f_mod(X * X, p)
X = gmpy2.f_mod(tmp + 7, p)
Y = gmpy2.f_div(gmpy2.add(p, 1), 4)
tmp = gmpy2.mpz(1)
while Y > 0:
if Y % 2 == 1:
tmp = gmpy2.f_mod(tmp * X, p)
Y >>= 1
X = gmpy2.f_mod(X * X, p)
Y = tmp
if Y % 2 != y_parity:
Y = gmpy2.f_mod(-Y, p)
return Y
# Function to compute a table of points
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):
check = gmpy2.f_mod(P.x, DP_rarity)
if check == 0:
message = f"\r[+] [Pindex]: {mpz(Pindex)}"
messages = []
messages.append(message)
output = "\033[01;33m" + ''.join(messages) + "\r"
sys.stdout.write(output)
sys.stdout.flush()
A.append(mpz(P.x))
Ak.append(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)))
difference = Ak[sol_kt] - Bk[sol_kw]
HEX = "%064x" % difference
t = time.ctime()
pid = os.getpid() # Get the process ID
core_number = pid % cpu_count() # Calculate the CPU core number
total_time = time.time() - starttime
print(f"\033[32m[+] PUZZLE SOLVED: {t}, total time: {total_time:.2f} sec, Core: {core_number+1:02} \033[0m")
print(f"\033[32m[+] WIF: \033[32m {HEX} \033[0m")
with open("KEYFOUNDKEYFOUND.txt", "a") as file:
file.write("\n\nSOLVED " + t)
file.write(f"\nTotal Time: {total_time:.2f} sec")
file.write("\nPrivate Key (decimal): " + str(difference))
file.write("\nPrivate Key (hex): " + HEX)
file.write(
"\n-------------------------------------------------------------------------------------------------------------------------------------\n"
)
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))
# Recursive function to multiply a point by a scalar
def mulk(k, P=PG, p=MODULO):
if k == 0:
return ZERO_POINT
elif k == 1:
return P
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))
# Generate a list of powers of two for faster access
@lru_cache(maxsize=None)
def generate_powers_of_two(hop_modulo):
return [mpz(1 << pw) for pw in range(hop_modulo)]
t = time.ctime()
sys.stdout.write("\033[01;33m")
sys.stdout.write(f"[+] [Kangaroo]: {t}" + "\n")
sys.stdout.flush()
# Configuration for the puzzle
puzzle = 70
compressed_public_key = "0290e6900a58d33393bc1097b5aed31f2e4e7cbd3e5466af958665bc0121248483" # Puzzle 70
lower_range_limit = 2 ** (puzzle - 1)
upper_range_limit = (2 ** puzzle) - 1
kangaroo_power = puzzle/ 8
Nt = Nw = (2 ** kangaroo_power/ puzzle) * puzzle + 8
DP_rarity = 8 * puzzle
hop_modulo = (puzzle/ 2) + 8
# Precompute powers of two for faster access
powers_of_two = generate_powers_of_two(hop_modulo)
T, t, dt = [], [], []
W, w, dw = [], [], []
if len(compressed_public_key) == 66:
X = mpz(compressed_public_key[2:66], 16)
Y = x_to_y(X, mpz(compressed_public_key[:2]) - 2)
else:
print("[error] pubkey len(66/130) invalid!")
print(f"[+] [Puzzle]: {puzzle}")
print(f"[+] [Lower range limit]: {lower_range_limit}")
print(f"[+] [Upper range limit]: {upper_range_limit}")
print("[+] [Xcoordinate]: %064x" % X)
print("[+] [Ycoordinate]: %064x" % Y)
W0 = Point(X, Y)
starttime = oldtime = time.time()
Hops = 0
# Worker function for point search
def search_worker(
Nt, Nw, puzzle, kangaroo_power, starttime, lower_range_limit, upper_range_limit
):
global STOP_EVENT
pid = os.getpid()
core_number = pid % cpu_count()
#Random seed Config
#constant_prefix = b'' #back to no constant
#constant_prefix = b'\xbc\x9b\x8cd\xfc\xa1?\xcf' #Puzzle 50 seed - 10-18s
constant_prefix = b'\xbc\x9b\x8cd'
prefix_length = len(constant_prefix)
length = 8
ending_length = length - prefix_length
ending_bytes = os.urandom(ending_length)
random_bytes = constant_prefix + ending_bytes
print(f"[+] [Core]: {core_number+1:02}, [Random seed]: {random_bytes}")
random.seed(random_bytes)
t = [
mpz(
lower_range_limit
+ mpz(random.randint(0, upper_range_limit - lower_range_limit))
)
for _ in range(Nt)
]
T = [mulk(ti) for ti in t]
dt = [mpz(0) for _ in range(Nt)]
w = [
mpz(random.randint(0, upper_range_limit - lower_range_limit)) for _ in range(Nt)
]
W = [add_points(W0, mulk(wk)) for wk in w]
dw = [mpz(0) for _ in range(Nw)]
Hops, Hops_old = 0, 0
oldtime = time.time()
starttime = oldtime
while True:
for k in range(Nt):
Hops += 1
pw = T[k].x % hop_modulo
dt[k] = powers_of_two[pw]
solved = check(T[k], t[k], DP_rarity, T, t, W, w)
if solved:
STOP_EVENT.set()
break
t[k] = mpz(t[k]) + dt[k] # Use mpz here
T[k] = add_points(POINTS_TABLE[pw], T[k])
for k in range(Nw):
Hops += 1
pw = W[k].x % hop_modulo
dw[k] = powers_of_two[pw]
solved = check(W[k], w[k], DP_rarity, W, w, T, t)
if solved:
STOP_EVENT.set()
break
w[k] = mpz(w[k]) + dw[k] # Use mpz here
W[k] = add_points(POINTS_TABLE[pw], W[k])
if STOP_EVENT.is_set():
break
# Main script
if __name__ == "__main__":
process_count = 2
print(f"[+] [Using {process_count} CPU cores for parallel search]:")
# Create a pool of worker processes
pool = Pool(process_count)
results = pool.starmap(
search_worker,
[
(
Nt,
Nw,
puzzle,
kangaroo_power,
starttime,
lower_range_limit,
upper_range_limit,
)
]
* process_count,
)
pool.close()
pool.join()
Try this, it works for me on windows.