160 lines
4.1 KiB
Python
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
|