Path: blob/master/attacks/factorization/complex_multiplication.py
2589 views
import logging1import os2import sys3from math import gcd45from sage.all import EllipticCurve6from sage.all import Zmod7from sage.all import hilbert_class_polynomial89path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(os.path.abspath(__file__)))))10if sys.path[1] != path:11sys.path.insert(1, path)1213from shared.polynomial import polynomial_inverse14from shared.polynomial import polynomial_xgcd151617def factorize(N, D):18"""19Recovers the prime factors from a modulus using Cheng's elliptic curve complex multiplication method.20More information: Sedlacek V. et al., "I want to break square-free: The 4p - 1 factorization method and its RSA backdoor viability"21:param N: the modulus22:param D: the discriminant to use to generate the Hilbert polynomial23:return: a tuple containing the prime factors24"""25assert D % 8 == 3, "D should be square-free"2627zmodn = Zmod(N)28pr = zmodn["x"]2930H = pr(hilbert_class_polynomial(-D))31Q = pr.quotient(H)32j = Q.gen()3334try:35k = j * polynomial_inverse((1728 - j).lift(), H)36except ArithmeticError as err:37# If some polynomial was not invertible during XGCD calculation, we can factor n.38p = gcd(int(err.args[1].lc()), N)39return int(p), int(N // p)4041E = EllipticCurve(Q, [3 * k, 2 * k])42while True:43x = zmodn.random_element()4445logging.debug(f"Calculating division polynomial of Q{x}...")46z = E.division_polynomial(N, x=Q(x))4748try:49d, _, _ = polynomial_xgcd(z.lift(), H)50except ArithmeticError as err:51# If some polynomial was not invertible during XGCD calculation, we can factor n.52p = gcd(int(err.args[1].lc()), N)53return int(p), int(N // p)5455p = gcd(int(d), N)56if 1 < p < N:57return int(p), int(N // p)585960