Exemplo n.º 1
0
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
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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
Exemplo n.º 4
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