CyberSecurityRumble | dlog

import os


class AffinePoint:

    def __init__(self, curve, x, y):
        self.curve = curve
        self.x = x
        self.y = y

    def __add__(self, other):
        return self.curve.add(self, other)

    def __iadd__(self, other):
        return self.__add__(other)

    def __rmul__(self, scalar):
        return self.curve.mul(self, scalar)

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

    def copy(self):
        return AffinePoint(self.curve, self.x, self.y)

    def __eq__(self, other):
        if not isinstance(other, AffinePoint):
            raise ValueError("Can't compare Point to {}".format(type(other)))
        return self.curve == other.curve and self.x == other.x and self.y == other.y


class EllipticCurve:
    
    def __init__(self, a, b, p):
        """
        Define curve by short weierstrass form y**2 = x**3 + ax + b mod p
        """
        self.a = a
        self.b = b
        self.mod = p
        self.poif = AffinePoint(self, "infinity", "infinity")

    def inv_val(self, val):
        """
        Get the inverse of a given field element in the curve's prime field.
        """
        return pow(val, self.mod - 2, self.mod)


    def invert(self, point):
        """
        Invert a point.
        """
        return AffinePoint(self, point.x, (-1 * point.y) % self.mod)

    def mul(self, point, scalar):
        """
        Do scalar multiplication Q = dP using double and add.
        """
        return self.double_and_add(point, scalar)

    def double_and_add(self, point, scalar):
        """
        Do scalar multiplication Q = dP using double and add.
        As here: https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Double-and-add
        """
        if scalar < 1:
            raise ValueError("Scalar must be >= 1")
        result = None
        tmp = point.copy()

        while scalar:
            if scalar & 1:
                if result is None:
                    result = tmp
                else:
                    result = self.add(result, tmp)
            scalar >>= 1
            tmp = self.add(tmp, tmp)

        return result

    def add(self, P, Q):
        """
        Sum of the points P and Q.
        Rules: https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication
        """
        # Cases with POIF
        if P == self.poif:
            result = Q
        elif Q == self.poif:
            result = P
        elif Q == self.invert(P):
            result = self.poif
        else:  # without POIF
            if P == Q:
                slope = (3 * P.x ** 2 + self.a) * self.inv_val(2 * P.y)
            else:
                slope = (Q.y - P.y) * self.inv_val(Q.x - P.x)
            x = (slope ** 2 - P.x - Q.x) % self.mod
            y = (slope * (P.x - x) - P.y) % self.mod
            result = AffinePoint(self, x, y)

        return result

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


a = 0
b = 7
p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f

secp256k1 = EllipticCurve(a, b, p)

print("gif point to nom nom:")
x = input("x: ")
y = input("y: ")

if len(x) > 78 or len(y) > 78:
    print("values too large!")
    exit(0)

G = AffinePoint(
        secp256k1,
        int(x), int(y)
)

secret = int.from_bytes(os.urandom(32), "big")

print("Have curve point: ")
print(secret * G)

user_secret = int(input("now gif secret: "))

if secret == user_secret:
    print("Congratzzzzz!")
    print(open("/opt/flag.txt").read())
else:
    print("Nein!")

自前で楕円曲線を実装していたらInvalidCurveAttackを疑って良い

今回は a = 0なので y^2 = x^3のかたちの singular curveを作る

from ptrlib import Socket
from Crypto.Util.number import inverse

p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f

sock = Socket("chal.cybersecurityrumble.de", 31782)
sock.sendlineafter("x: ", "1")
sock.sendlineafter("y: ", "1")
Q = list(map(int, sock.recvregex(r"Point\(([0-9]+),([0-9]+)\)")))

Fp = 1 * inverse(1, p) % p
Fq = Q[0] * inverse(Q[1], p)  %p

d = Fq  *inverse(Fp, p) % p
sock.sendlineafter("now gif secret: ", str(d))

print(sock.recv())