Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jvdsn
GitHub Repository: jvdsn/crypto-attacks
Path: blob/master/attacks/factorization/roca.py
2589 views
1
import logging
2
import os
3
import sys
4
from math import log2
5
6
from sage.all import Zmod
7
from sage.all import factor
8
9
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(os.path.abspath(__file__)))))
10
if sys.path[1] != path:
11
sys.path.insert(1, path)
12
13
from shared.small_roots import howgrave_graham
14
15
16
def _prime_power_divisors(M):
17
divisors = []
18
for p, e in factor(M):
19
for i in range(1, e + 1):
20
divisors.append(p ** i)
21
22
divisors.sort()
23
return divisors
24
25
26
# Algorithm 2.
27
def compute_max_M_(M, ord_):
28
for p in _prime_power_divisors(M):
29
ordp = Zmod(p)(65537).multiplicative_order()
30
if ord_ % ordp != 0:
31
M //= p
32
33
return M
34
35
36
# Section 2.7.2.
37
def _greedy_find_M_(n, M):
38
ord = Zmod(M)(65537).multiplicative_order()
39
while True:
40
best_r = 0
41
best_ord_ = ord
42
best_M_ = M
43
for p in _prime_power_divisors(ord):
44
ord_ = ord // p
45
M_ = compute_max_M_(M, ord_)
46
r = (log2(ord) - log2(ord_)) / (log2(M) - log2(M_))
47
if r > best_r:
48
best_r = r
49
best_ord_ = ord_
50
best_M_ = M_
51
52
if log2(best_M_) < log2(n) / 4:
53
return M
54
55
ord = best_ord_
56
M = best_M_
57
58
59
def factorize(N, M, m, t, g=65537):
60
"""
61
Recovers the prime factors from a modulus using the ROCA method.
62
More information: Nemec M. et al., "The Return of Coppersmith’s Attack: Practical Factorization of Widely Used RSA Moduli"
63
:param N: the modulus
64
:param M: the primorial used to generate the primes
65
:param m: the m parameter for Coppersmith's method
66
:param t: the t parameter for Coppersmith's method
67
:param g: the generator value (default: 65537)
68
:return: a tuple containing the prime factors, or None if the factors were not found
69
"""
70
logging.info("Generating M'...")
71
M_ = _greedy_find_M_(N, M)
72
zmodm_ = Zmod(M_)
73
g = zmodm_(g)
74
c_ = zmodm_(N).log(g)
75
ord_ = g.multiplicative_order()
76
77
x = Zmod(N)["x"].gen()
78
X = int(2 * N ** 0.5 // M_)
79
logging.info("Starting exhaustive a' search...")
80
for a_ in range(c_ // 2, (c_ + ord_) // 2 + 1):
81
f = M_ * x + int(g ** a_)
82
for k_, in howgrave_graham.modular_univariate(f, N, m, t, X):
83
p = int(f(k_))
84
if N % p == 0:
85
return p, N // p
86
87
return None
88
89