defcalcLam(self, other) -> int: x1, x2, y1, y2 = self.x, other.x, self.y, other.y if x2 == x1 and y2 == y1: # P == Q if y1 == 0: return math.inf return self.frac(3*x1*x1 + self.A, 2*y1) # s = lambda else: # P != Q if x2 == x1: return math.inf return self.frac(y2 - y1, x2 - x1)
defadd(self, other): if self.O: # is the point at infinity # O + P = P return EpPoint(other.x, other.y, self.curve) if other.O: # P + O = P return EpPoint(self.x, self.y, self.curve) s = self.calcLam(other) if s == math.inf: res = copy.deepcopy(self) res.O = True return res x1, x2, y1, y2 = self.x, other.x, self.y, other.y x3 = (s*s - x1 - x2) % self.mod y3 = (s * (x1 - x3) - y1) % self.mod return EpPoint(x3, y3, self.curve)
classEpPoint(EpCurve): def__init__(self, x, y, curve) -> None: super().__init__(curve.A, curve.B, curve.mod) ifnot self.isOnCurve(x, y): raise ValueError(f"Point ({x}, {y}) is not on the curve") self.x = x % self.mod self.y = y % self.mod self.O = False self.curve = curve
def__str__(self) -> str: if self.O: return'O' returnf"({self.x}, {self.y})"
defcalcLam(self, other) -> int: x1, x2, y1, y2 = self.x, other.x, self.y, other.y if x2 == x1 and y2 == y1: if y1 == 0: return math.inf return self.frac(3*x1*x1 + self.A, 2*y1) # s = lambda else: if x2 == x1: return math.inf return self.frac(y2 - y1, x2 - x1)
defadd(self, other): if self.O: return EpPoint(other.x, other.y, self.curve) if other.O: return EpPoint(self.x, self.y, self.curve) s = self.calcLam(other) if s == math.inf: res = copy.deepcopy(self) res.O = True return res x1, x2, y1, y2 = self.x, other.x, self.y, other.y x3 = (s*s - x1 - x2) % self.mod y3 = (s * (x1 - x3) - y1) % self.mod return EpPoint(x3, y3, self.curve)
defmul(self, x): # check only, no performance res = self for i inrange(x - 1): res = res.add(self) return res
defcalcOrder(self) -> int: back = self; cnt = 1
whileTrue: cnt += 1 back = back.add(self) if back.O == 1: return cnt
deflineFunc(self, other, S) -> int: # S is the f_p(S) xp, xq, yp, yq = self.x, other.x, self.y, other.y
if self.calcLam(other) == math.inf: return S.x - xp lam = self.calcLam(other) return self.frac(S.y - yp - lam*(S.x - xp), S.x + xp + xq - lam*lam) defmiller(self, S) -> int: # P, S if self.O: return1 T = self; f = 1 n = bin(self.calcOrder())[3:]
for bit in n: f = f * f * T.lineFunc(T, S) % self.mod T = T.add(T) if bit == '1': f = f * T.lineFunc(self, S) % self.mod T = T.add(self) return f defweil(self, Q, S) -> int: # P, Q, S negS = EpPoint(S.x, -S.y, self.curve) # -S
return self.frac(res1, res2) deftate(self, Q, S) -> int: q = self.mod; l = self.calcOrder() if q % l != 1: raise ValueError('q and l don\'t suuport q == 1 mod l')
tau = self.frac(self.miller(Q.add(S)), self.miller(S)) returnpow(tau, self.frac(q-1, l), q)
curve = EpCurve(30, 34, 631) P = EpPoint(36, 60, curve) # Order 5 Q = EpPoint(121, 387, curve) S = EpPoint(0, 36, curve)
# print('P + Q =', P.add(Q)) # print('P + Q =', P.add(P)) # print('Q + S =', Q.add(S)) # print('P\'s order:', P.calcOrder()) # print('P\'s miller function related to S:', P.miller(S)) # print('P + Q\'s miller function related to S:', P.miller(Q.add(S))) # print('P, Q\'s weil pairing:', P.weil(Q, S))