def _inv(s, a): if len(a) == 1: return Zmod._inv(s, a) a, b = map(int, a) if s.t == 1: u = a * a + b * b u = modinv(u, s.n) return s.element_class(s, a * u, -b * u) elif s.t == 2: u = a * a - a * b + b * b u = modinv(u, s.n) return s.element_class(s, (a - b) * u, (-b) * u)
def SSSA_Attack(F, E, P, Q): """ Solve ECDLP using SSSA(Semaev-Smart-Satoh-Araki) Attack. Args: F: The Base Field E: The Elliptic Curve P: A point on E Q: A point on E Returns: Return x where satisfies Q = xP. """ from .EllipticCurve import EllipticCurve from ecpy.fields import QQ, Zmod from ecpy.utils.util import modinv, is_enable_native, _native A = E.a # lP, lQ, ... is "lifted" P, Q, ... x1, y1 = hensel_lift(E, P) x2, y2 = hensel_lift(E, Q) lF = Zmod(F.p**2) lA = (y2 * y2 - y1 * y1 - (x2 * x2 * x2 - x1 * x1 * x1)) lA = (lA * modinv(x2 - x1, lF.n)) % lF.n lB = (y1 * y1 - x1 * x1 * x1 - A * x1) % lF.n if not is_enable_native: modulo = F.p**2 lE = EllipticCurve(lF, lA, lB) lP = lE(x1, y1) lQ = lE(x2, y2) lU = (F.p - 1) * lP lV = (F.p - 1) * lQ dx1 = ((int(lU.x) - x1) // F.p) % modulo dx2 = int(lU.y) - y1 dy1 = ((int(lV.x) - x2) // F.p) % modulo dy2 = int(lV.y) - y2 m = (dy1 * dx2 * modinv(dx1 * dy2, modulo)) % modulo return m % F.p else: modulo = F.p**2 base = _native.FF(modulo) lE = _native.EC(base, lA, lB) lP = _native.EC_elem(lE, x1, y1) lQ = _native.EC_elem(lE, x2, y2) lU = _native.EC_elem(lE, 0, 1, 0) lV = _native.EC_elem(lE, 0, 1, 0) lE.mul(lU, lP, F.p - 1) lE.mul(lV, lQ, F.p - 1) lUx, lUy, lUz = lU.to_python() lVx, lVy, lVz = lV.to_python() lUx = (lUx * modinv(lUz, modulo)) % modulo lUy = (lUy * modinv(lUz, modulo)) % modulo lVx = (lVx * modinv(lVz, modulo)) % modulo lVy = (lVy * modinv(lVz, modulo)) % modulo dx1 = ((lUx - x1) // F.p) % modulo dx2 = lUy - y1 dy1 = ((lVx - x2) // F.p) % modulo dy2 = lVy - y2 m = (dy1 * dx2 * modinv(dx1 * dy2, modulo)) % modulo return m % F.p
def hensel_lift(curve, P): from six.moves import map """ Calculate Lifted Point using Hensel's Lemma Args: curve: The Elliptic Curve P: A point on curve Returns: The "lifted" Point """ from six.moves import map from ecpy.utils import modinv x, y, _ = map(int, tuple(P)) p = curve.field.p t = (((x * x * x + curve.a * x + curve.b) - y * y) // p) % p t = (t * modinv(2 * y, p)) % p return list(map(int, (x, y + (curve.field.p * t))))
def __modular_square_root(a, m): from ecpy.utils import is_prime, legendre_symbol, modinv if is_prime(m): if legendre_symbol(a, m) == -1: return [] # Tonelli-Shanks Algorithm if m % 4 == 3: r = pow(a, (m + 1) // 4, m) return [r, m - r] s = _find_power_divisor(2, m - 1) q = (m - 1) // 2**s z = 0 while legendre_symbol(z, m) != -1: z = random.randint(1, m) c = pow(z, q, m) r = pow(a, (q + 1) // 2, m) t = pow(a, q, m) l = s while True: if t % m == 1: assert (r ** 2) % m == a return [r, m - r] i = _find_power(2, t, 1, m) power = l - i - 1 if power < 0: power = modinv(2**-power, m) else: power = 2**power b = pow(c, power, m) r = (r * b) % m t = (t * (b**2)) % m c = pow(b, 2, m) l = i if m == 2: return a if m % 4 == 3: r = pow(a, (m + 1) // 4, m) return [r, m - r] if m % 8 == 5: v = pow(2 * a, (m - 5) // 8, m) i = pow(2 * a * v, 2, m) r = a * v * (i - 1) % m return [r, m - r] if m % 8 == 1: e = _find_power_divisor(2, m - 1) q = (m - 1) // 2**e z = 1 while pow(z, 2**(e - 1), m) == 1: x = random.randint(1, m) z = pow(x, q, m) y = z r = e x = pow(a, (q - 1) // 2, m) v = a * x % m w = v * x % m while True: if w == 1: return [v, m - v] k = _find_power(2, w, 1, m) d = pow(y, 2**(r - k - 1), m) y = pow(d, 2, m) r = k v = d * v % m w = w * y % m
def __modular_square_root(a, m): from ecpy.utils import is_prime, legendre_symbol, modinv if is_prime(m): if legendre_symbol(a, m) == -1: return [] # Tonelli-Shanks Algorithm if m % 4 == 3: r = pow(a, (m + 1) // 4, m) return [r, m - r] s = _find_power_divisor(2, m - 1) q = (m - 1) // 2**s z = 0 while legendre_symbol(z, m) != -1: z = random.randint(1, m) c = pow(z, q, m) r = pow(a, (q + 1) // 2, m) t = pow(a, q, m) l = s while True: if t % m == 1: assert (r**2) % m == a return [r, m - r] i = _find_power(2, t, 1, m) power = l - i - 1 if power < 0: power = modinv(2**-power, m) else: power = 2**power b = pow(c, power, m) r = (r * b) % m t = (t * (b**2)) % m c = pow(b, 2, m) l = i if m == 2: return a if m % 4 == 3: r = pow(a, (m + 1) // 4, m) return [r, m - r] if m % 8 == 5: v = pow(2 * a, (m - 5) // 8, m) i = pow(2 * a * v, 2, m) r = a * v * (i - 1) % m return [r, m - r] if m % 8 == 1: e = _find_power_divisor(2, m - 1) q = (m - 1) // 2**e z = 1 while pow(z, 2**(e - 1), m) == 1: x = random.randint(1, m) z = pow(x, q, m) y = z r = e x = pow(a, (q - 1) // 2, m) v = a * x % m w = v * x % m while True: if w == 1: return [v, m - v] k = _find_power(2, w, 1, m) d = pow(y, 2**(r - k - 1), m) y = pow(d, 2, m) r = k v = d * v % m w = w * y % m
def _inv(s, a): return s.element_class(s, modinv(a[0], s.n))