cryptotools/Cryptotools/Groups/curve.py

160 lines
4.1 KiB
Python

#!/usr/bin/env python3
from Cryptotools.Groups.elliptic import Point
import numpy as np
from math import sqrt
class Curve:
# Curve
WEIERSTRASS = 0
MONTGOMERY = 1
def __init__(self, a, b, t):
self._a = a
self._b = b
if t not in (Curve.WEIERSTRASS, Curve.MONTGOMERY):
raise Exception(f"The type of the curve is not recognized")
self._type = t
self._xtmp = np.linspace(-5, 5, 500).tolist()
self._x = list()
self._y = list()
self._yn = list()
self._points = list()
self._pointsSym = list()
def f(self, x):
if self._type == Curve.WEIERSTRASS:
y = pow(x, 3) + (self._a * x) + self._b
if self._type == Curve.MONTGOMERY:
y = pow(x, 3) + (3 * pow(x, 2)) + x
if y > 0:
return sqrt(y)
return None
def generatePoints(self):
for x in self._xtmp:
y = self.f(x)
if y is None:
continue
self._x.append(x)
self._y.append(y)
self._yn.append(-y)
self._points.append(Point(
x,
y
))
self._pointsSym.append(Point(
x,
-y
))
@property
def x(self):
return self._x
@property
def y(self):
return self._y
@property
def yn(self):
return self._yn
def getPoints(self):
return self._points
def getPointsSym(self):
return self._pointsSym
def add(self, P, Q) -> Point:
"""
This function operathe addition operation on two points P and Q
Args:
P (Object): The first Point on the curve
Q (Object): The second Point on the curve
Returns:
Return the Point object R
"""
## Check if P or Q are infinity
if (P.x, P.y) == (0, 0) and (Q.x, Q.y) == (0, 0):
return Point(0, 0)
elif (P.x, P.y) == (0, 0):
return Point(Q.x, Q.y)
elif (Q.x, Q.y) == (0, 0):
return Point(P.x, P.y)
# point doubling
if P.x == Q.x:
# Infinity
if P.y != Q.y or Q.y == 0:
return Point(0, 0)
# Point doubling
try:
inv = pow(2 * P.y, -1); # It's working with the inverse modular, WHY ???
m = ((3 * pow(P.x, 2)) + self._a) * inv
except ValueError:
return Point(0, 0)
else:
try:
inv = pow(Q.x - P.x, -1)
m = (Q.y - P.y) * inv
except ValueError:
# May call this Exception: base is not invertible for the given modulus
# I return an Infinity point until I fixed that
return Point(0, 0)
xr = (pow(m, 2) - P.x - Q.x)
yr = (m * (P.x - xr)) - P.y
return Point(xr, yr)
def scalar(self, P, n) -> Point:
"""
This function compute a Scalar Multiplication of P, n time. This algorithm is also known as Double and Add.
Args:
P (point): the Point to multiplication
n (Integer): multiplicate n time P
Returns:
Return the result of the Scalar multiplication
"""
binary = bin(n)[2:]
binary = binary[::-1] # We need to reverse the binary
nP = Point(0, 0)
Rtmp = P
for b in binary:
if b == '1':
nP = self.add(nP, Rtmp)
Rtmp = self.add(Rtmp, Rtmp) # Double P
return nP
def find_reverse(self, P):
"""
This function return the reverse of the Point P
Args:
P (Point): Point object to find
Returns:
Return the object Pr, which is the reverse point of P
"""
Pr = None
for p in self._pointsSym:
if P.x == p.x and -P.y == p.y:
Pr = Point(p.x, p.y)
break
return Pr