def pollard_pm1(n, B1=100, B2=1000): from _primefac._arith import ispower, gcd, ilog from _primefac._prime import isprime, primegen import six if isprime(n): return n m = ispower(n) if m: return m while True: pg = primegen() q = 2 # TODO: what about other initial values of q? p = six.next(pg) while p <= B1: q, p = pow(q, p ** ilog(B1, p), n), six.next(pg) g = gcd(q - 1, n) if 1 < g < n: return g while p <= B2: q, p = pow(q, p, n), six.next(pg) g = gcd(q - 1, n) if 1 < g < n: return g # These bounds failed. Increase and try again. B1 *= 10 B2 *= 10
def ecm(n, B1=10, B2=20): """ TODO: Determine the best defaults for B1 and B2 and the best way to increment them and iters "Modern" ECM using Montgomery curves and an algorithm analogous to the two-phase variant of Pollard's p-1 method TODO: We currently compute the prime lists from the sieve as we need them, but this means that we recompute them at every iteration. While it would not be particularly efficient memory-wise, we might be able to increase time-efficiency by computing the primes we need ahead of time (say once at the beginning and then once each time we increase the bounds) and saving them in lists, and then iterate the inner while loops over those lists. """ from _primefac._arith import ispower, gcd, ilog from _primefac._prime import isprime, primegen from six.moves import xrange from random import randrange import six if isprime(n): return n m = ispower(n) if m: return m iters = 1 while True: for _ in xrange(iters): seed = randrange(6, n) u, v = (seed**2 - 5) % n, 4 * seed % n p = pow(u, 3, n) Q, C = (pow(v - u, 3, n) * (3 * u + v) % n, 4 * p * v % n), (p, pow(v, 3, n)) pg = primegen() p = six.next(pg) while p <= B1: Q, p = _ecmul(p**ilog(B1, p), Q, C, n), six.next(pg) g = gcd(Q[1], n) if 1 < g < n: return g while p <= B2: """ "There is a simple coding trick that can speed up the second stage. Instead of multiplying each prime times Q, we iterate over i from B1 + 1 to B2, adding 2Q at each step; when i is prime, the current Q can be accumulated into the running solution. Again, we defer the calculation of the greatest common divisor until the end of the iteration." TODO: Implement this trick and compare performance. """ Q = _ecmul(p, Q, C, n) g *= Q[1] g %= n p = six.next(pg) g = gcd(g, n) if 1 < g < n: return g # This seed failed. Try again with a new one. # These bounds failed. Increase and try again. B1 *= 3 B2 *= 3 iters *= 2
def ispower(n): for p in _prime.primegen(): r = introot(n, p) if r is None: continue if r**p == n: return r if r == 1: return 0
def williams_pp1(n): from _primefac._arith import ispower, ilog, isqrt, gcd from _primefac._prime import isprime, primegen from six.moves import xrange import itertools if isprime(n): return n m = ispower(n) if m: return m for v in itertools.count(1): for p in primegen(): e = ilog(isqrt(n), p) if e == 0: break for _ in xrange(e): v = mlucas(v, p, n) g = gcd(v - 2, n) if 1 < g < n: return g if g == n: break