diff --git a/2/1.py b/2/1.py new file mode 100644 index 0000000..4f19cec --- /dev/null +++ b/2/1.py @@ -0,0 +1,120 @@ +import gmpy2 +from gmpy2 import mpz, is_prime, powmod, invert, random_state, mpz_random +import random + +# Task 1: Generate a random elliptic curve over F_p +def generate_random_curve(p): + p = mpz(p) + rs = random_state(random.randrange(2**32)) + while True: + A = mpz_random(rs, p) + B = mpz_random(rs, p) + # Check that the discriminant is non-zero + discriminant = (4 * powmod(A, 3, p) + 27 * powmod(B, 2, p)) % p + if discriminant != 0: + return A, B + +# Task 2: Find a random point on the elliptic curve over F_p +def find_random_point(A, B, p): + p = mpz(p) + rs = random_state(random.randrange(2**32)) + while True: + x = mpz_random(rs, p) + rhs = (powmod(x, 3, p) + A * x + B) % p + legendre_symbol = gmpy2.legendre(rhs, p) + if legendre_symbol == 1: + # Compute y using the fact that p ≡ 3 mod 4 + y = powmod(rhs, (p + 1) // 4, p) + return x, y + elif legendre_symbol == 0: + # y = 0 is a valid solution + y = mpz(0) + return x, y + # If rhs is not a quadratic residue, try another x + +# Task 3: Compute the inverse (negative) of a given point +def point_negation(P, p): + x, y = P + return x, (-y) % p + +# Task 4: Compute P ⊕ Q, the sum of two points on the elliptic curve +def point_addition(P, Q, A, p): + if P == 'O': + return Q + if Q == 'O': + return P + x1, y1 = P + x2, y2 = Q + if x1 == x2 and (y1 + y2) % p == 0: + # P + (-P) = O + return 'O' + if x1 == x2 and y1 == y2: + # Point doubling + if y1 == 0: + return 'O' + numerator = (3 * powmod(x1, 2, p) + A) % p + denominator = (2 * y1) % p + else: + # P ≠ Q + numerator = (y2 - y1) % p + denominator = (x2 - x1) % p + inv_denominator = invert(denominator, p) + if inv_denominator is None: + return 'O' # Cannot invert denominator; result is point at infinity + lam = (numerator * inv_denominator) % p + x3 = (powmod(lam, 2, p) - x1 - x2) % p + y3 = (lam * (x1 - x3) - y1) % p + return x3, y3 + +# Task 5: Compute nP, the scalar multiplication of a point +def scalar_multiplication(P, n, A, p): + n = mpz(n) + result = 'O' # Start with the point at infinity + addend = P + while n > 0: + if n % 2 == 1: + result = point_addition(result, addend, A, p) + addend = point_addition(addend, addend, A, p) + n = n // 2 + return result + +# Helper function to generate a large prime p ≡ 3 mod 4 +def generate_large_prime(bits): + rs = random_state(random.randrange(2**32)) + while True: + candidate = mpz_random(rs, 2 ** bits) + candidate |= 1 # Ensure it's odd + candidate |= 3 # Ensure p ≡ 3 mod 4 + candidate = gmpy2.next_prime(candidate) + if candidate % 4 == 3 and candidate.bit_length() == bits: + return candidate + +# Example usage of the functions +if __name__ == "__main__": + # Generate a large prime p ≡ 3 mod 4 (approximately 300 bits) + bits = 300 + p = generate_large_prime(bits) + print(f"Generated prime p = {p}") + + # Task 1: Generate random curve coefficients A and B + A, B = generate_random_curve(p) + print(f"Random curve coefficients: A = {A}, B = {B}") + + # Task 2: Find a random point on the curve + P = find_random_point(A, B, p) + print(f"Random point P = {P}") + + # Task 3: Compute the inverse of point P + negative_P = point_negation(P, p) + print(f"Inverse of P: -P = {negative_P}") + + # Task 4: Add two points P and Q on the curve + Q = find_random_point(A, B, p) + print(f"Another random point Q = {Q}") + R = point_addition(P, Q, A, p) + print(f"Sum of P and Q: R = P ⊕ Q = {R}") + + # Task 5: Compute nP for a random scalar n + n = mpz_random(random_state(random.randrange(2**32)), p) + nP = scalar_multiplication(P, n, A, p) + print(f"Scalar multiplication: {n} * P = {nP}") diff --git a/miniprojekt_nr2.pdf b/miniprojekt_nr2.pdf new file mode 100644 index 0000000..4263e08 Binary files /dev/null and b/miniprojekt_nr2.pdf differ