Post
Topic
Board Bitcoin Discussion
Merits 1 from 1 user
Re: Bitcoin puzzle transaction ~32 BTC prize to who solves it
by
nomachine
on 19/09/2023, 14:33:04 UTC
⭐ Merited by digaran (1)

Can you please explain in details for us noobs how this works and what we need to change when searching for our desired keys?
Also what do you mean by solving 65 without needing a public key, do you search for address or something?

Do you happen to have a python code for it, even if it's slow. Or isn't it better to ask ai to convert the code into python? Is that even possible?


Edit:

Here is a working script which divides 2 points by start/end range and then subtracts the results of division from each other.
No external module/ library needed, just run the script.

Code:
# Define the EllipticCurve class
class EllipticCurve:
    def __init__(self, a, b, p):
        self.a = a
        self.b = b
        self.p = p

    def contains(self, point):
        x, y = point.x, point.y
        return (y * y) % self.p == (x * x * x + self.a * x + self.b) % self.p

    def __str__(self):
        return f"y^2 = x^3 + {self.a}x + {self.b} mod {self.p}"

# Define the Point class
class Point:
    def __init__(self, x, y, curve):
        self.x = x
        self.y = y
        self.curve = curve

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y and self.curve == other.curve

    def __ne__(self, other):
        return not self == other

    def __add__(self, other):
        if self.curve != other.curve:
            raise ValueError("Cannot add points on different curves")

        # Case when one point is zero
        if self == Point.infinity(self.curve):
            return other
        if other == Point.infinity(self.curve):
            return self

        if self.x == other.x and self.y != other.y:
            return Point.infinity(self.curve)

        p = self.curve.p
        s = 0
        if self == other:
            s = ((3 * self.x * self.x + self.curve.a) * pow(2 * self.y, -1, p)) % p
        else:
            s = ((other.y - self.y) * pow(other.x - self.x, -1, p)) % p

        x = (s * s - self.x - other.x) % p
        y = (s * (self.x - x) - self.y) % p

        return Point(x, y, self.curve)

    def __sub__(self, other):
        if self.curve != other.curve:
            raise ValueError("Cannot subtract points on different curves")

        # Case when one point is zero
        if self == Point.infinity(self.curve):
            return other
        if other == Point.infinity(self.curve):
            return self

        return self + Point(other.x, (-other.y) % self.curve.p, self.curve)

    def __mul__(self, n):
        if not isinstance(n, int):
            raise ValueError("Multiplication is defined for integers only")

        n = n % (self.curve.p - 1)
        res = Point.infinity(self.curve)
        addend = self

        while n:
            if n & 1:
                res += addend

            addend += addend
            n >>= 1

        return res

    def __str__(self):
        return f"({self.x}, {self.y}) on {self.curve}"

    @staticmethod
    def from_hex(s, curve):
        if len(s) == 66 and s.startswith("02") or s.startswith("03"):
            compressed = True
        elif len(s) == 130 and s.startswith("04"):
            compressed = False
        else:
            raise ValueError("Hex string is not a valid compressed or uncompressed point")

        if compressed:
            is_odd = s.startswith("03")
            x = int(s[2:], 16)

            # Calculate y-coordinate from x and parity bit
            y_square = (x * x * x + curve.a * x + curve.b) % curve.p
            y = pow(y_square, (curve.p + 1) // 4, curve.p)
            if is_odd != (y & 1):
                y = -y % curve.p

            return Point(x, y, curve)
        else:
            s_bytes = bytes.fromhex(s)
            uncompressed = s_bytes[0] == 4
            if not uncompressed:
                raise ValueError("Only uncompressed or compressed points are supported")

            num_bytes = len(s_bytes) // 2
            x_bytes = s_bytes[1 : num_bytes + 1]
            y_bytes = s_bytes[num_bytes + 1 :]

            x = int.from_bytes(x_bytes, byteorder="big")
            y = int.from_bytes(y_bytes, byteorder="big")

            return Point(x, y, curve)

    def to_hex(self, compressed=True):
        if self.x is None and self.y is None:
            return "00"
        elif compressed:
            prefix = "03" if self.y & 1 else "02"
            return prefix + hex(self.x)[2:].zfill(64)
        else:
            x_hex = hex(self.x)[2:].zfill(64)
            y_hex = hex(self.y)[2:].zfill(64)
            return "04" + x_hex + y_hex

    @staticmethod
    def infinity(curve):
        return Point(None, None, curve)

# Define the ec_mul function
def ec_mul(point, scalar, base_point):
    result = Point.infinity(point.curve)
    addend = point

    while scalar:
        if scalar & 1:
            result += addend

        addend += addend
        scalar >>= 1

    return result

# Define the ec_operations function
def ec_operations(start_range, end_range, target_1, target_2, curve):
    # Define parameters for secp256k1 curve
    n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
    G = Point(
        0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
        0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,
        curve
    )

    # Open the files for writing
    with open("target1_division_results.txt", "a") as file1, \
            open("target2_division_results.txt", "a") as file2, \
            open("subtract_results.txt", "a") as file3:

        for i in range(start_range, end_range + 1):
            try:
                # Compute the inverse of i modulo n
                i_inv = pow(i, n-2, n)

                # Divide the targets by i modulo n
                result_1 = ec_mul(target_1, i_inv, G)
                result_2 = ec_mul(target_2, i_inv, G)

                # Subtract the results
                sub_result = result_2 - result_1

                # Write the results to separate files
                file1.write(f"{result_1.to_hex()}\n")
                file2.write(f"{result_2.to_hex()}\n")
                file3.write(f"Subtracting results for {i}:\n")
                file3.write(f"Target 1 / {i}: {result_1.to_hex()}\n")
                file3.write(f"Target 2 / {i}: {result_2.to_hex()}\n")
                file3.write(f"Subtraction: {sub_result.to_hex()}\n")
                file3.write("="*50 + "\n")

                print(f"Completed calculation for divisor {i}")
            except ZeroDivisionError:
                print(f"Error: division by zero for {i}")

    print("Calculation completed. Results saved in separate files.")

if __name__ == "__main__":
    # Set the targets and range for the operations
    curve = EllipticCurve(0, 7, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
    target_1 = Point.from_hex("0230210C23B1A047BC9BDBB13448E67DEDDC108946DE6DE639BCC75D47C0216B1B", curve)
    target_2 = Point.from_hex("02F6B787195159544330085C6014DBA627FF5B14F3203FF05D12482F76261F4FC3", curve)
    start_range = 2
    end_range = 200

    ec_operations(start_range, end_range, target_1, target_2, curve)

Note that on previous page there is one similar script but operating over scalar not points.
Also the credit for the division by a range part goes to @mcdouglasx, the rest goes to anyone here helping and of course the biggest idiot AI made by mankind ( all of them are for now ) aka deep.ai chatbot.

As a test sample I have used puzzle 65 in target1 and target 2 is an offset after subtracting the following scalar from puzzle 65.
0x0000000000000000000000000000000000000000000000020000000000000000

The script is really slow because I had problem using multiprocessing  in the code, so I decided to remove it, it also first calculates everything and then writes them to the files, since I'm not a coder, I don't know whether doing that requires more RAM or not.

Feel free to optimize, improve and add other functions/operations as you see fit and please do share.
Thanks.



Code:
import gmpy2 as mpz
from gmpy2 import powmod

# Define the EllipticCurve class
class EllipticCurve:
    def __init__(self, a, b, p):
        self.a = mpz.mpz(a)
        self.b = mpz.mpz(b)
        self.p = mpz.mpz(p)

    def contains(self, point):
        x, y = point.x, point.y
        return (y * y) % self.p == (x * x * x + self.a * x + self.b) % self.p

    def __str__(self):
        return f"y^2 = x^3 + {self.a}x + {self.b} mod {self.p}"

# Define the Point class
class Point:
    def __init__(self, x, y, curve):
        self.x = mpz.mpz(x)
        self.y = mpz.mpz(y)
        self.curve = curve

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y and self.curve == other.curve

    def __ne__(self, other):
        return not self == other

    def __add__(self, other):
        if self.curve != other.curve:
            raise ValueError("Cannot add points on different curves")

        # Case when one point is zero
        if self == Point.infinity(self.curve):
            return other
        if other == Point.infinity(self.curve):
            return self

        if self.x == other.x and self.y != other.y:
            return Point.infinity(self.curve)

        p = self.curve.p
        s = 0
        if self == other:
            s = ((3 * self.x * self.x + self.curve.a) * pow(2 * self.y, -1, p)) % p
        else:
            s = ((other.y - self.y) * pow(other.x - self.x, -1, p)) % p

        x = (s * s - self.x - other.x) % p
        y = (s * (self.x - x) - self.y) % p

        return Point(x, y, self.curve)

    def __sub__(self, other):
        if self.curve != other.curve:
            raise ValueError("Cannot subtract points on different curves")

        # Case when one point is zero
        if self == Point.infinity(self.curve):
            return other
        if other == Point.infinity(self.curve):
            return self

        return self + Point(other.x, (-other.y) % self.curve.p, self.curve)

    def __mul__(self, n):
        if not isinstance(n, int):
            raise ValueError("Multiplication is defined for integers only")

        n = n % (self.curve.p - 1)
        res = Point.infinity(self.curve)
        addend = self

        while n:
            if n & 1:
                res += addend

            addend += addend
            n >>= 1

        return res

    def __str__(self):
        return f"({self.x}, {self.y}) on {self.curve}"

    @staticmethod
    def from_hex(s, curve):
        if len(s) == 66 and s.startswith("02") or s.startswith("03"):
            compressed = True
        elif len(s) == 130 and s.startswith("04"):
            compressed = False
        else:
            raise ValueError("Hex string is not a valid compressed or uncompressed point")

        if compressed:
            is_odd = s.startswith("03")
            x = mpz.mpz(s[2:], 16)

            # Calculate y-coordinate from x and parity bit
            y_square = (x * x * x + curve.a * x + curve.b) % curve.p
            y = powmod(y_square, (curve.p + 1) // 4, curve.p)
            if is_odd != (y & 1):
                y = -y % curve.p

            return Point(x, y, curve)
        else:
            s_bytes = bytes.fromhex(s)
            uncompressed = s_bytes[0] == 4
            if not uncompressed:
                raise ValueError("Only uncompressed or compressed points are supported")

            num_bytes = len(s_bytes) // 2
            x_bytes = s_bytes[1 : num_bytes + 1]
            y_bytes = s_bytes[num_bytes + 1 :]

            x = mpz.mpz(int.from_bytes(x_bytes, byteorder="big"))
            y = mpz.mpz(int.from_bytes(y_bytes, byteorder="big"))

            return Point(x, y, curve)

    def to_hex(self, compressed=True):
        if self.x is None and self.y is None:
            return "00"
        elif compressed:
            prefix = "03" if self.y & 1 else "02"
            return prefix + hex(self.x)[2:].zfill(64)
        else:
            x_hex = hex(self.x)[2:].zfill(64)
            y_hex = hex(self.y)[2:].zfill(64)
            return "04" + x_hex + y_hex

    @staticmethod
    def infinity(curve):
        return Point(-1, -1, curve)

# Define the ec_mul function
def ec_mul(point, scalar, base_point):
    result = Point.infinity(point.curve)
    addend = point

    while scalar:
        if scalar & 1:
            result += addend

        addend += addend
        scalar >>= 1

    return result

# Define the ec_operations function
def ec_operations(start_range, end_range, target_1, target_2, curve):
    # Define parameters for secp256k1 curve
    n = mpz.mpz("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141")
    G = Point(
        mpz.mpz("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),
        mpz.mpz("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"),
        curve
    )

    # Open the files for writing
    with open("target1_division_results.txt", "a") as file1, \
            open("target2_division_results.txt", "a") as file2, \
            open("subtract_results.txt", "a") as file3:

        for i in range(start_range, end_range + 1):
            try:
                # Compute the inverse of i modulo n
                i_inv = powmod(i, n-2, n)

                # Divide the targets by i modulo n
                result_1 = ec_mul(target_1, i_inv, G)
                result_2 = ec_mul(target_2, i_inv, G)

                # Subtract the results
                sub_result = result_2 - result_1

                # Write the results to separate files
                file1.write(f"{result_1.to_hex()}\n")
                file2.write(f"{result_2.to_hex()}\n")
                file3.write(f"Subtracting results for {i}:\n")
                file3.write(f"Target 1 / {i}: {result_1.to_hex()}\n")
                file3.write(f"Target 2 / {i}: {result_2.to_hex()}\n")
                file3.write(f"Subtraction: {sub_result.to_hex()}\n")
                file3.write("="*50 + "\n")

                print(f"Completed calculation for divisor {i}")
            except ZeroDivisionError:
                print(f"Error: division by zero for {i}")

    print("Calculation completed. Results saved in separate files.")

if __name__ == "__main__":
    # Set the targets and range for the operations
    curve = EllipticCurve(
        mpz.mpz(0),
        mpz.mpz(7),
        mpz.mpz("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F")
    )
    target_1 = Point.from_hex("0230210C23B1A047BC9BDBB13448E67DEDDC108946DE6DE639BCC75D47C0216B1B", curve)
    target_2 = Point.from_hex("02F6B787195159544330085C6014DBA627FF5B14F3203FF05D12482F76261F4FC3", curve)
    start_range = 2
    end_range = 200

    ec_operations(start_range, end_range, target_1, target_2, curve)


The first thing I do is install gmpy2 in everything where large numbers are used.
gmpy2 is a highly optimized library for arbitrary-precision arithmetic. It is written in C and provides low-level access to the GMP (GNU Multiple Precision) library, which is known for its efficiency in handling large integers.