File: //home/arjun/projects/aigenerator/venv/lib64/python3.12/site-packages/ellipticcurve/math.py
from .point import Point
class Math:
@classmethod
def modularSquareRoot(cls, value, prime):
return pow(value, (prime + 1) // 4, prime)
@classmethod
def multiply(cls, p, n, N, A, P):
"""
Fast way to multily point and scalar in elliptic curves
:param p: First Point to mutiply
:param n: Scalar to mutiply
:param N: Order of the elliptic curve
:param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p)
:param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p)
:return: Point that represents the sum of First and Second Point
"""
return cls._fromJacobian(
cls._jacobianMultiply(cls._toJacobian(p), n, N, A, P), P
)
@classmethod
def add(cls, p, q, A, P):
"""
Fast way to add two points in elliptic curves
:param p: First Point you want to add
:param q: Second Point you want to add
:param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p)
:param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p)
:return: Point that represents the sum of First and Second Point
"""
return cls._fromJacobian(
cls._jacobianAdd(cls._toJacobian(p), cls._toJacobian(q), A, P), P,
)
@classmethod
def inv(cls, x, n):
"""
Extended Euclidean Algorithm. It's the 'division' in elliptic curves
:param x: Divisor
:param n: Mod for division
:return: Value representing the division
"""
if x == 0:
return 0
lm = 1
hm = 0
low = x % n
high = n
while low > 1:
r = high // low
nm = hm - lm * r
nw = high - low * r
high = low
hm = lm
low = nw
lm = nm
return lm % n
@classmethod
def _toJacobian(cls, p):
"""
Convert point to Jacobian coordinates
:param p: First Point you want to add
:return: Point in Jacobian coordinates
"""
return Point(p.x, p.y, 1)
@classmethod
def _fromJacobian(cls, p, P):
"""
Convert point back from Jacobian coordinates
:param p: First Point you want to add
:param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p)
:return: Point in default coordinates
"""
z = cls.inv(p.z, P)
x = (p.x * z ** 2) % P
y = (p.y * z ** 3) % P
return Point(x, y, 0)
@classmethod
def _jacobianDouble(cls, p, A, P):
"""
Double a point in elliptic curves
:param p: Point you want to double
:param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p)
:param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p)
:return: Point that represents the sum of First and Second Point
"""
if p.y == 0:
return Point(0, 0, 0)
ysq = (p.y ** 2) % P
S = (4 * p.x * ysq) % P
M = (3 * p.x ** 2 + A * p.z ** 4) % P
nx = (M**2 - 2 * S) % P
ny = (M * (S - nx) - 8 * ysq ** 2) % P
nz = (2 * p.y * p.z) % P
return Point(nx, ny, nz)
@classmethod
def _jacobianAdd(cls, p, q, A, P):
"""
Add two points in elliptic curves
:param p: First Point you want to add
:param q: Second Point you want to add
:param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p)
:param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p)
:return: Point that represents the sum of First and Second Point
"""
if p.y == 0:
return q
if q.y == 0:
return p
U1 = (p.x * q.z ** 2) % P
U2 = (q.x * p.z ** 2) % P
S1 = (p.y * q.z ** 3) % P
S2 = (q.y * p.z ** 3) % P
if U1 == U2:
if S1 != S2:
return Point(0, 0, 1)
return cls._jacobianDouble(p, A, P)
H = U2 - U1
R = S2 - S1
H2 = (H * H) % P
H3 = (H * H2) % P
U1H2 = (U1 * H2) % P
nx = (R ** 2 - H3 - 2 * U1H2) % P
ny = (R * (U1H2 - nx) - S1 * H3) % P
nz = (H * p.z * q.z) % P
return Point(nx, ny, nz)
@classmethod
def _jacobianMultiply(cls, p, n, N, A, P):
"""
Multily point and scalar in elliptic curves
:param p: First Point to mutiply
:param n: Scalar to mutiply
:param N: Order of the elliptic curve
:param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p)
:param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p)
:return: Point that represents the sum of First and Second Point
"""
if p.y == 0 or n == 0:
return Point(0, 0, 1)
if n == 1:
return p
if n < 0 or n >= N:
return cls._jacobianMultiply(p, n % N, N, A, P)
if (n % 2) == 0:
return cls._jacobianDouble(
cls._jacobianMultiply(p, n // 2, N, A, P), A, P
)
return cls._jacobianAdd(
cls._jacobianDouble(cls._jacobianMultiply(p, n // 2, N, A, P), A, P), p, A, P
)