|
1 | 1 | from random import randint |
2 | | -try: |
3 | | - import sympy.ntheory |
4 | | -except ImportError: |
5 | | - sympy = None |
6 | 2 |
|
7 | 3 |
|
8 | 4 | class Factorization: |
9 | | - @staticmethod |
10 | | - def find_small_multiplier_lopatin(what): |
11 | | - """Finds the small multiplier by using Lopatin's method""" |
12 | | - g = 0 |
13 | | - for i in range(3): |
14 | | - q = (randint(0, 127) & 15) + 17 |
15 | | - x = randint(0, 1000000000) + 1 |
16 | | - y = x |
17 | | - lim = 1 << (i + 18) |
18 | | - for j in range(1, lim): |
19 | | - a, b, c = x, x, q |
20 | | - while b != 0: |
21 | | - if (b & 1) != 0: |
22 | | - c += a |
23 | | - if c >= what: |
24 | | - c -= what |
25 | | - a += a |
26 | | - if a >= what: |
27 | | - a -= what |
28 | | - b >>= 1 |
29 | | - |
30 | | - x = c |
31 | | - z = y - x if x < y else x - y |
32 | | - g = Factorization.gcd(z, what) |
33 | | - if g != 1: |
| 5 | + @classmethod |
| 6 | + def factorize(cls, pq): |
| 7 | + if pq % 2 == 0: |
| 8 | + return 2, pq // 2 |
| 9 | + |
| 10 | + y, c, m = randint(1, pq - 1), randint(1, pq - 1), randint(1, pq - 1) |
| 11 | + g = r = q = 1 |
| 12 | + x = ys = 0 |
| 13 | + |
| 14 | + while g == 1: |
| 15 | + x = y |
| 16 | + for i in range(r): |
| 17 | + y = (pow(y, 2, pq) + c) % pq |
| 18 | + |
| 19 | + k = 0 |
| 20 | + while k < r and g == 1: |
| 21 | + ys = y |
| 22 | + for i in range(min(m, r - k)): |
| 23 | + y = (pow(y, 2, pq) + c) % pq |
| 24 | + q = q * (abs(x - y)) % pq |
| 25 | + |
| 26 | + g = cls.gcd(q, pq) |
| 27 | + k += m |
| 28 | + |
| 29 | + r *= 2 |
| 30 | + |
| 31 | + if g == pq: |
| 32 | + while True: |
| 33 | + ys = (pow(ys, 2, pq) + c) % pq |
| 34 | + g = cls.gcd(abs(x - ys), pq) |
| 35 | + if g > 1: |
34 | 36 | break |
35 | 37 |
|
36 | | - if (j & (j - 1)) == 0: |
37 | | - y = x |
38 | | - |
39 | | - if g > 1: |
40 | | - break |
41 | | - |
42 | | - p = what // g |
43 | | - return min(p, g) |
| 38 | + return g, pq // g |
44 | 39 |
|
45 | 40 | @staticmethod |
46 | 41 | def gcd(a, b): |
47 | | - """Calculates the greatest common divisor""" |
48 | | - while a != 0 and b != 0: |
49 | | - while b & 1 == 0: |
50 | | - b >>= 1 |
| 42 | + while b: |
| 43 | + a, b = b, a % b |
51 | 44 |
|
52 | | - while a & 1 == 0: |
53 | | - a >>= 1 |
54 | | - |
55 | | - if a > b: |
56 | | - a -= b |
57 | | - else: |
58 | | - b -= a |
59 | | - |
60 | | - return a if b == 0 else b |
61 | | - |
62 | | - @staticmethod |
63 | | - def factorize(pq): |
64 | | - """Factorizes the given number and returns both |
65 | | - the divisor and the number divided by the divisor |
66 | | - """ |
67 | | - if sympy: |
68 | | - return tuple(sympy.ntheory.factorint(pq).keys()) |
69 | | - else: |
70 | | - divisor = Factorization.find_small_multiplier_lopatin(pq) |
71 | | - return divisor, pq // divisor |
| 45 | + return a |
0 commit comments