Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jvdsn
GitHub Repository: jvdsn/crypto-attacks
Path: blob/master/attacks/factorization/complex_multiplication.py
2589 views
1
import logging
2
import os
3
import sys
4
from math import gcd
5
6
from sage.all import EllipticCurve
7
from sage.all import Zmod
8
from sage.all import hilbert_class_polynomial
9
10
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(os.path.abspath(__file__)))))
11
if sys.path[1] != path:
12
sys.path.insert(1, path)
13
14
from shared.polynomial import polynomial_inverse
15
from shared.polynomial import polynomial_xgcd
16
17
18
def factorize(N, D):
19
"""
20
Recovers the prime factors from a modulus using Cheng's elliptic curve complex multiplication method.
21
More information: Sedlacek V. et al., "I want to break square-free: The 4p - 1 factorization method and its RSA backdoor viability"
22
:param N: the modulus
23
:param D: the discriminant to use to generate the Hilbert polynomial
24
:return: a tuple containing the prime factors
25
"""
26
assert D % 8 == 3, "D should be square-free"
27
28
zmodn = Zmod(N)
29
pr = zmodn["x"]
30
31
H = pr(hilbert_class_polynomial(-D))
32
Q = pr.quotient(H)
33
j = Q.gen()
34
35
try:
36
k = j * polynomial_inverse((1728 - j).lift(), H)
37
except ArithmeticError as err:
38
# If some polynomial was not invertible during XGCD calculation, we can factor n.
39
p = gcd(int(err.args[1].lc()), N)
40
return int(p), int(N // p)
41
42
E = EllipticCurve(Q, [3 * k, 2 * k])
43
while True:
44
x = zmodn.random_element()
45
46
logging.debug(f"Calculating division polynomial of Q{x}...")
47
z = E.division_polynomial(N, x=Q(x))
48
49
try:
50
d, _, _ = polynomial_xgcd(z.lift(), H)
51
except ArithmeticError as err:
52
# If some polynomial was not invertible during XGCD calculation, we can factor n.
53
p = gcd(int(err.args[1].lc()), N)
54
return int(p), int(N // p)
55
56
p = gcd(int(d), N)
57
if 1 < p < N:
58
return int(p), int(N // p)
59
60