from hashlib importsha256defsha256d(string):if notisinstance(string, bytes):
string=string.encode()returnsha256(sha256(string).digest()).hexdigest()definv_mod(b, p):if b < 0 or p <=b:
b= b %p
c , d=b, p
uc, vc, ud, vd, temp= 1, 0, 0, 1, 0while c !=0:
temp=c
q, c, d= d // c, d %c, temp
uc, vc, ud, vd= ud - q * uc, vd - q *vc, uc, vcassert d == 1
if ud >0:returnudelse:return ud +pdefleftmost_bit(x):assert x >0
result= 1
while result <=x:
result= 2 *resultreturn result // 2
print(inv_mod(2, 23))print(3*inv_mod(1, 23) % 23)defshow_points(p, a, b):return [(x, y) for x in range(p) for y in range(p) if (y*y - (x*x*x + a*x + b)) % p ==0]print(show_points(p=29, a=4, b=20))defdouble(x, y, p, a, b):
l= ((3 * x * x + a) * inv_mod(2 * y, p)) %p
x3= (l * l - 2 * x) %p
y3= (l * (x - x3) - y) %preturnx3, y3print(double(1, 4, p=5, a=2, b=3))defadd(x1, y1, x2, y2, p, a, b):if x1 == x2 and y1 ==y2:returndouble(x1, y1, p, a, b)
l= ((y2 - y1) * inv_mod(x2 - x1, p)) %p
x3= (l * l - x1 -x2) %p
y3= (l * (x1 - x3) - y1) %preturnx3, y3print(add(1, 4, 3, 1, p=5, a=2, b=3))defget_bits(n):
bits=[]while n !=0:
bits.append(n& 1)
n>> 1
returnbitsclassCurveFp(object):def __init__(self, p, a, b):"""y^2 = x^3 + a*x + b (mod p)."""self.p=p
self.a=a
self.b=bdefcontains_point(self, x, y):return (y * y - (x * x * x + self.a * x + self.b)) % self.p ==0defshow_all_points(self):return [(x, y) for x in range(self.p) for y in range(self.p) if(y* y - (x * x * x + self.a * x + self.b)) % self.p ==0]def __repr__(self):return "Curve(p={0:d}, a={1:d}, b={2:d})".format(self.p, self.a, self.b)classPoint(object):def __init__(self, curve, x, y, order=None):
self.curve=curve
self.x=x
self.y=y
self.order=order#self.curve is allowed to be None only for INFINITY:
ifself.curve:assertself.curve.contains_point(x, y)iforder:assert self * order ==INFINITYdef __eq__(self, other):"""Is this point equals to another"""
if self.curve ==other.curve \and self.x ==other.x \and self.y ==other.y:returnTrueelse:returnFalsedef __add__(self, other):"""Add one point to another point."""
if other ==INFINITY:returnselfif self ==INFINITY:returnotherassert self.curve ==other.curveif self.x ==other.x:if (self.y + other.y) % self.curve.p ==0:returnINFINITYelse:returnself.double()
p=self.curve.p
l= ((other.y - self.y) *\
inv_mod(other.x- self.x, p)) %p
x3= (l * l - self.x - other.x) %p
y3= (l * (self.x - x3) - self.y) %preturnPoint(self.curve, x3, y3)def __mul__(self, other):
e=otherifself.order:
e= e %self.orderif e ==0:returnINFINITYif self ==INFINITY:returnINFINITY
e3= 3 *e
negative_self= Point(self.curve, self.x, -self.y, self.order)
i= leftmost_bit(e3) // 2result=selfwhile i > 1:
result=result.double()if (e3 & i) != 0 and (e & i) ==0:
result= result +selfif (e3 & i) == 0 and (e & i) !=0:
result= result +negative_self
i= i // 2
returnresultdef __rmul__(self, other):"""Multiply a point by an integer."""
return self *otherdef __repr__(self):if self ==INFINITY:return "infinity"
return "({0},{1})".format(self.x, self.y)defdouble(self):"""the double point."""
if self ==INFINITY:returnINFINITY
p=self.curve.p
a=self.curve.a
l= ((3 * self.x * self.x + a) *\
inv_mod(2 * self.y, p)) %p
x3= (l * l - 2 * self.x) %p
y3= (l * (self.x - x3) - self.y) %preturnPoint(self.curve, x3, y3)definvert(self):return Point(self.curve, self.x, -self.y %self.curve.p)
INFINITY=Point(None, None, None)
p, a, b= 29, 4, 20curve=CurveFp(p, a, b)
p0= Point(curve, 3, 1)print(p0*2)print(p0*20)