|
2 | 2 | # Code taken from https://facthacks.cr.yp.to/facthacks.sage
|
3 | 3 | # FactHacks is joint work by Daniel J. Bernstein, Nadia Heninger, and Tanja Lange.
|
4 | 4 |
|
5 |
| -from gmpy2 import gcd, isqrt, is_prime, next_prime |
| 5 | +from gmpy2 import gcd, isqrt, is_prime, next_prime, is_power |
6 | 6 | import itertools
|
7 |
| - |
8 |
| - |
9 |
| -def prebuilt_params(bits): |
10 |
| - """ |
11 |
| - Bounds estimation |
12 |
| - borrowed from msieve/mpqs.c |
13 |
| - """ |
14 |
| - if bits <= 64: |
15 |
| - return [100, 40, 1 * 65536] |
16 |
| - if bits <= 128: |
17 |
| - return [450, 40, 1 * 65536] |
18 |
| - if bits <= 183: |
19 |
| - return [2000, 40, 1 * 65536] |
20 |
| - if bits <= 200: |
21 |
| - return [3000, 50, 1 * 65536] |
22 |
| - if bits <= 212: |
23 |
| - return [5400, 50, 3 * 65536] |
24 |
| - if bits <= 233: |
25 |
| - return [10000, 100, 3 * 65536] |
26 |
| - if bits <= 249: |
27 |
| - return [27000, 100, 3 * 65536] |
28 |
| - if bits <= 266: |
29 |
| - return [50000, 100, 3 * 65536] |
30 |
| - if bits <= 283: |
31 |
| - return [55000, 80, 3 * 65536] |
32 |
| - if bits <= 298: |
33 |
| - return [60000, 80, 9 * 65536] |
34 |
| - if bits <= 315: |
35 |
| - return [80000, 150, 9 * 65536] |
36 |
| - if bits <= 332: |
37 |
| - return [100000, 150, 9 * 65536] |
38 |
| - if bits <= 348: |
39 |
| - return [140000, 150, 9 * 65536] |
40 |
| - if bits <= 363: |
41 |
| - return [210000, 150, 13 * 65536] |
42 |
| - if bits <= 379: |
43 |
| - return [300000, 150, 17 * 65536] |
44 |
| - if bits <= 395: |
45 |
| - return [400000, 150, 21 * 65536] |
46 |
| - if bits <= 415: |
47 |
| - return [500000, 150, 25 * 65536] # beyond this point you're crazy |
48 |
| - if bits <= 440: |
49 |
| - return [700000, 150, 33 * 65536] |
50 |
| - if bits <= 465: |
51 |
| - return [900000, 150, 50 * 65536] |
52 |
| - if bits <= 490: |
53 |
| - return [1100000, 150, 75 * 65536] |
54 |
| - if bits <= 512: |
55 |
| - return [1300000, 150, 100 * 65536] |
56 |
| - return [1300000, 150, 100 * 65536] |
57 |
| - |
58 |
| - |
59 |
| -def trial_division_minus_even_powers(n,P): |
60 |
| - a = [] |
61 |
| - r = n |
62 |
| - pw = 0 |
63 |
| - if r & 1 == 0: |
64 |
| - while r & 1 == 0: |
| 7 | +import sys |
| 8 | + |
| 9 | + |
| 10 | +def trial_division_minus_even_powers(n, P): |
| 11 | + a, r, pw = [], n, 0 |
| 12 | + while (r & 1) == 0: |
| 13 | + pw += 1 |
| 14 | + r >>= 1 |
| 15 | + if (pw & 1 == 1): a.append(2) |
| 16 | + for i in range(1, len(P)): |
| 17 | + pw, p = 0, P[i] |
| 18 | + while (r % p) == 0: |
65 | 19 | pw += 1
|
66 |
| - r >>= 1 |
67 |
| - if pw & 1 != 0: |
68 |
| - if 2 not in a: |
69 |
| - a.append(2) |
70 |
| - l=len(P) |
71 |
| - i=0 |
72 |
| - while (i < l) and (P[i] <= n): |
73 |
| - if r % P[i] == 0: |
74 |
| - pw = 0 |
75 |
| - while r % P[i] == 0: |
76 |
| - pw += 1 |
77 |
| - r //= P[i] |
78 |
| - if pw & 1 != 0: |
79 |
| - if P[i] not in a: |
80 |
| - a.append(P[i]) |
81 |
| - else: |
82 |
| - i += 1 |
83 |
| - return [a,r,n] |
| 20 | + r //= p |
| 21 | + if (pw & 1 == 1): a.append(p) |
| 22 | + return a, r, n |
84 | 23 |
|
85 | 24 |
|
86 | 25 | def minifactor(x, P):
|
87 |
| - if not is_prime(x) and not is_square(x): |
88 |
| - p = trial_division_minus_even_powers(x, P) |
89 |
| - if p[1] == 1: # if 1 x is B-smooth |
90 |
| - return p |
91 |
| - |
92 |
| - |
93 |
| -def QS(N,differences,y): |
94 |
| - i2N = isqrt(N) |
95 |
| - X = [int(a * a - N) for a in range(i2N + 1, i2N + differences)] |
96 |
| - P = list(primes(2, y)) |
97 |
| - F = list(filter(None, map(minifactor, X, itertools.repeat(P, len(X))))) |
98 |
| - |
99 |
| - M = matrix(GF(2), len(F), len(P), lambda i, j:P[j] in F[i][0]) |
100 |
| - for K in M.left_kernel().basis(): |
101 |
| - I = [f for f, k in zip(F, K) if k == 1] |
102 |
| - x = product([int(isqrt(f[2] + N)) for f in I]) |
103 |
| - y = isqrt(product([f[2] for f in I])) |
104 |
| - g0, g1 = gcd(N, x - y), gcd(N, x + y) |
105 |
| - if N > g0 > 1 or N > g1 > 1: |
106 |
| - return g0, g1 |
107 |
| - |
| 26 | + p = trial_division_minus_even_powers(x, P) |
| 27 | + if p[1] == 1: return p # if 1 then x is b-smooth |
| 28 | + |
| 29 | + |
| 30 | +def eulercriterion(N, p): |
| 31 | + return pow(N, (p - 1) >> 1, p) |
| 32 | + |
| 33 | + |
| 34 | +def QS(N, B1): |
| 35 | + sys.stderr.write("max prime: %d\n" % B1) |
| 36 | + P = [p for p in list(primes(2, B1)) if eulercriterion(N, p) == 1] |
| 37 | + i2n, B2, X, offset, lp = isqrt(N), 65536, [], 0, len(P) |
| 38 | + while True: |
| 39 | + S = i2n + offset |
| 40 | + sys.stderr.write("Relations matix: [cols: %d x rows: %d]\n" % (lp, offset + B2)) |
| 41 | + X += [int(a * a - N) for a in range(S + 1, S + B2)] |
| 42 | + X = list(filter(lambda x:not is_power(x) and not is_prime(x), X)) |
| 43 | + F = list(filter(None, map(minifactor, X, itertools.repeat(P, len(X))))) |
| 44 | + M = matrix(GF(2), len(F), lp, lambda i, j:P[j] in F[i][0]) |
| 45 | + sys.stderr.write("performing linear algebra:\n") |
| 46 | + for K in M.left_kernel().basis(): |
| 47 | + I = [f for f, k in zip(F, K) if k == 1] |
| 48 | + if len(I) > 0: |
| 49 | + sys.stderr.write("On Vector basis, taking square roots x and y.\n") |
| 50 | + x = product([isqrt(f[2] + N) for f in I]) |
| 51 | + y = isqrt(product([f[2] for f in I])) |
| 52 | + g0, g1 = int(gcd(N, x - y)), int(gcd(N, x + y)) |
| 53 | + if N > g0 > 1: return g0, N // g0 |
| 54 | + if N > g1 > 1: return g1, N // g1 |
| 55 | + offset += B2 |
108 | 56 |
|
109 | 57 | if __name__ == "__main__":
|
110 | 58 | N = int(sys.argv[1])
|
111 |
| - y ,_ ,diff = prebuilt_params(N.bit_length()) |
112 |
| - r = QS(N, diff * 10, y * 10) |
113 |
| - if r != None: |
114 |
| - print("%d, %d" % r) |
115 |
| - |
| 59 | + B1 = int(exp(sqrt(log(N) * log(log(N)))) ** (1 / sqrt(2))) |
| 60 | + print(QS(N, B1)) |
0 commit comments