FactHacks |
RSA factorization in the real world |
|
Fermat's factorization methodFermat's factorization method factors N into p and q very quickly if p and q share half of their leading bits, i.e., if the gap between p and q is below the square root of p. It becomes much slower if p and q share significantly fewer bits.One can save time in RSA decryption by choosing, e.g., p and q very close to 2^512. Fermat's factorization method shows that this is unsafe if "very close" means, e.g., between 2^512-2^256 and 2^512+2^256. Fermat's factorization method is also a first step towards understanding the quadratic sieve. Lattice techniques show that it's always unsafe to choose p very close to 2^512, even if q is chosen randomly. How it worksSage code:
def fermatfactor(N):
if N <= 0: return [N]
if is_even(N): return [2,N/2]
a = ceil(sqrt(N))
while not is_square(a^2-N):
a = a + 1
b = sqrt(a^2-N)
return [a - b,a + b]
Examples:
sage: print fermatfactor(91)
[7, 13]
sage: print fermatfactor(1009) # this one is prime
[1, 1009]
sage: print fermatfactor(6557)
[79, 83]
sage: N = 115792089237316195423570985008721211221144628262713908746538761285902758367353
sage: print fermatfactor(N)
[340282366920938463463374607431817146293, 340282366920938463463374607431817146421]
sage: N = 115792089237316195448679392282006640413199890130332179010243714077028592474181
sage: print fermatfactor(N)
[340282366920938463463374607431817146293, 340282366920938463537161584701547790417]
In the last example,
q was chosen as the next prime after p+2^66+974892437589,
and both p and q were very close to 2^128.
In the previous example,
q was chosen as the next prime after p;
this would happen if the RSA implementor generated both p and q
from the same sequential search.
Speed degenerates rapidly when p and q share fewer than half their leading bits:
sage: p = next_prime(2^512 + randrange(2^264))
sage: q = next_prime(p + 2^264 + randrange(2^262))
sage: time f = fermatfactor(p * q)
Time: CPU 0.18 s, Wall: 0.17 s
sage: p = next_prime(2^512 + randrange(2^265))
sage: q = next_prime(p + 2^265 + randrange(2^263))
sage: time f = fermatfactor(p * q)
Time: CPU 0.37 s, Wall: 0.37 s
sage: p = next_prime(2^512 + randrange(2^266))
sage: q = next_prime(p + 2^266 + randrange(2^264))
sage: time f = fermatfactor(p * q)
Time: CPU 0.91 s, Wall: 0.91 s
sage: p = next_prime(2^512 + randrange(2^267))
sage: q = next_prime(p + 2^267 + randrange(2^265))
sage: time f = fermatfactor(p * q)
Time: CPU 4.64 s, Wall: 4.67 s
sage: p = next_prime(2^512 + randrange(2^268))
sage: q = next_prime(p + 2^268 + randrange(2^266))
sage: time f = fermatfactor(p * q)
Time: CPU 18.53 s, Wall: 18.57 s
sage: p = next_prime(2^512 + randrange(2^269))
sage: q = next_prime(p + 2^269 + randrange(2^267))
sage: time f = fermatfactor(p * q)
Time: CPU 50.85 s, Wall: 50.94 s
Version: This is version 2012.12.28 of the fermat.html web page. |