def _double_point(self, P: Point) -> Point: # xR = (2 * xP * yP) / (a * xP^2 + yP^2) up_x = 2 * P.x * P.y down_x = self.a * P.x * P.x + P.y * P.y res_x = (up_x * modinv(down_x, self.p)) % self.p # yR = (yP^2 - a * xP * xP) / (2 - a * xP^2 - yP^2) up_y = P.y * P.y - self.a * P.x * P.x down_y = 2 - self.a * P.x * P.x - P.y * P.y res_y = (up_y * modinv(down_y, self.p)) % self.p return Point(res_x, res_y, self)
def _add_point(self, P: Point, Q: Point) -> Point: # xR = (xP * yQ + yP * xQ) / (1 + b * xP * xQ * yP * yQ) up_x = P.x * Q.y + P.y * Q.x down_x = 1 + self.b * P.x * Q.x * P.y * Q.y res_x = (up_x * modinv(down_x, self.p)) % self.p # yR = (yP * yQ - a * xP * xQ) / (1 - b * xP * xQ * yP * yQ) up_y = P.y * Q.y - self.a * P.x * Q.x down_y = 1 - self.b * P.x * Q.x * P.y * Q.y res_y = (up_y * modinv(down_y, self.p)) % self.p return Point(res_x, res_y, self)
def compute_y(self, x: int) -> int: # (bx^2 - 1) * y^2 = ax^2 - 1 right = self.a * x * x - 1 left_scale = (self.b * x * x - 1) % self.p inv_scale = modinv(left_scale, self.p) right = (right * inv_scale) % self.p y = modsqrt(right, self.p) return y
def _double_point(self, P: Point) -> Point: # s = (3 * xP^2 + a) / (2 * yP) # xR = s^2 - 2 * xP # yR = yP + s * (xR - xP) s = (3 * P.x * P.x + self.a) * modinv(2 * P.y, self.p) res_x = (s * s - 2 * P.x) % self.p res_y = (P.y + s * (res_x - P.x)) % self.p return - Point(res_x, res_y, self)
def _double_point(self, P: Point) -> Point: # s = (3 * xP^2 + 2 * a * xP + 1) / (2 * b * yP) # xR = b * s^2 - a - 2 * xP # yR = yP + s * (xR - xP) up = 3 * P.x * P.x + 2 * self.a * P.x + 1 down = 2 * self.b * P.y s = up * modinv(down, self.p) res_x = (self.b * s * s - self.a - 2 * P.x) % self.p res_y = (P.y + s * (res_x - P.x)) % self.p return - Point(res_x, res_y, self)
def _add_point(self, P: Point, Q: Point) -> Point: # s = (yP - yQ) / (xP - xQ) # xR = b * s^2 - a - xP - xQ # yR = yP + s * (xR - xP) delta_x = P.x - Q.x delta_y = P.y - Q.y s = delta_y * modinv(delta_x, self.p) res_x = (self.b * s * s - self.a - P.x - Q.x) % self.p res_y = (P.y + s * (res_x - P.x)) % self.p return - Point(res_x, res_y, self)
def compute_y(self, x: int) -> int: right = (x * x * x + self.a * x * x + x) % self.p inv_b = modinv(self.b, self.p) right = (right * inv_b) % self.p y = modsqrt(right, self.p) return y
def test_big_prime_exist(self): self.assertEqual(modinv(-2**522, BIG_PRIME), 2**520 - 1) self.assertEqual(modinv(2**485, BIG_PRIME), 68719476736) self.assertEqual(modinv(2**555, BIG_PRIME), 2**487)
def test_small_prime_exist(self): self.assertEqual(modinv(-1000, SMALL_PRIME), 42) self.assertEqual(modinv(55, SMALL_PRIME), 30) self.assertEqual(modinv(1000, SMALL_PRIME), 55)