Telethon/telethon/crypto/factorization.py

70 lines
1.8 KiB
Python
Raw Normal View History

2016-08-28 20:26:06 +03:00
from random import randint
try:
import sympy.ntheory
except ImportError:
sympy = None
2016-08-28 20:26:06 +03:00
2017-05-21 14:59:16 +03:00
class Factorization:
2016-08-28 20:26:06 +03:00
@staticmethod
def find_small_multiplier_lopatin(what):
"""Finds the small multiplier by using Lopatin's method"""
2016-08-28 20:26:06 +03:00
g = 0
for i in range(3):
q = (randint(0, 127) & 15) + 17
x = randint(0, 1000000000) + 1
2016-08-28 20:26:06 +03:00
y = x
lim = 1 << (i + 18)
for j in range(1, lim):
a, b, c = x, x, q
while b != 0:
if (b & 1) != 0:
c += a
if c >= what:
c -= what
a += a
if a >= what:
a -= what
b >>= 1
x = c
z = y - x if x < y else x - y
2017-05-21 14:59:16 +03:00
g = Factorization.gcd(z, what)
2016-08-28 20:26:06 +03:00
if g != 1:
break
if (j & (j - 1)) == 0:
y = x
if g > 1:
break
p = what // g
return min(p, g)
@staticmethod
def gcd(a, b):
"""Calculates the greatest common divisor"""
while a != 0 and b != 0:
while b & 1 == 0:
b >>= 1
while a & 1 == 0:
a >>= 1
if a > b:
a -= b
else:
b -= a
return a if b == 0 else b
2016-08-28 20:26:06 +03:00
@staticmethod
def factorize(pq):
"""Factorizes the given number and returns both the divisor and the number divided by the divisor"""
if sympy:
return tuple(sympy.ntheory.factorint(pq).keys())
else:
divisor = Factorization.find_small_multiplier_lopatin(pq)
return divisor, pq // divisor