示例#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
def pollardRho_brent(n):
    from _primefac._arith import gcd
    from _primefac._prime import isprime
    from six.moves import xrange
    from random import randrange

    if isprime(n):
        return n
    g = n
    while g == n:
        y, c, m, g, r, q = randrange(1, n), randrange(1, n), randrange(1, n), 1, 1, 1
        while g == 1:
            x, k = y, 0
            for _ in xrange(r):
                y = (y ** 2 + c) % n
            while k < r and g == 1:
                ys = y
                for _ in xrange(min(m, r - k)):
                    y = (y ** 2 + c) % n
                    q = q * abs(x - y) % n
                g, k = gcd(q, n), k + m
            r *= 2
        if g == n:
            while True:
                ys = (ys ** 2 + c) % n
                g = gcd(abs(x - ys), n)
                if g > 1:
                    break
    return g
示例#3
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
示例#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
示例#5
0
def _isprime(n, tb=(3, 5, 7, 11), eb=(2, ), mrb=()):  # TODO: more streamlining
    from _primefac import _arith
    # tb: trial division basis
    # eb: Euler's test basis
    # mrb: Miller-Rabin basis

    # This test suite's first false positve is unknown but has been shown to
    # be greater than 2**64.
    # Infinitely many are thought to exist.

    if n % 2 == 0 or n < 13 or n == _arith.isqrt(n)**2:
        # Remove evens, squares, and numbers less than 13
        return n in (2, 3, 5, 7, 11)
    if any(n % p == 0 for p in tb):
        return n in tb  # Trial division

    for b in eb:  # Euler's test
        if b >= n:
            continue
        if not pow(b, n - 1, n) == 1:
            return False
        r = n - 1
        while r % 2 == 0:
            r //= 2
        c = pow(b, r, n)
        if c == 1:
            continue
        while c != 1 and c != n - 1:
            c = pow(c, 2, n)
        if c == 1:
            return False

    s, d = pfactor(n)
    if not sprp(n, 2, s, d):
        return False
    if n < 2047:
        return True
    # BPSW has two phases: SPRP with base 2 and SLPRP.
    # We just did the SPRP; now we do the SLPRP:
    if n >= 3825123056546413051:
        d = 5
        while True:
            if _arith.gcd(d, n) > 1:
                p, q = 0, 0
                break
            if _arith.jacobi(d, n) == -1:
                p, q = 1, (1 - d) // 4
                break
            d = -d - 2 * d // abs(d)
        if p == 0:
            return n == d
        s, t = pfactor(n + 2)
        u, v, u2, v2, m = 1, p, 1, p, t // 2
        k = q
        while m > 0:
            u2, v2, q = (u2 * v2) % n, (v2 * v2 - 2 * q) % n, (q * q) % n
            if m % 2 == 1:
                u, v = u2 * v + u * v2, v2 * v + u2 * u * d
                if u % 2 == 1:
                    u += n
                if v % 2 == 1:
                    v += n
                u, v, k = (u // 2) % n, (v // 2) % n, (q * k) % n
            m //= 2
        if (u == 0) or (v == 0):
            return True
        for _ in xrange(1, s):
            v, k = (v * v - 2 * k) % n, (k * k) % n
            if v == 0:
                return True
        return False

    if not mrb:
        if n < 1373653:
            mrb = [3]
        elif n < 25326001:
            mrb = [3, 5]
        elif n < 3215031751:
            mrb = [3, 5, 7]
        elif n < 2152302898747:
            mrb = [3, 5, 7, 11]
        elif n < 3474749660383:
            mrb = [3, 5, 6, 11, 13]
        elif n < 341550071728321:
            # This number is also a false positive for primes(19+1).
            mrb = [3, 5, 7, 11, 13, 17]
        elif n < 3825123056546413051:
            # Also a false positive for primes(31+1).
            mrb = [3, 5, 7, 11, 13, 17, 19, 23]
    # Miller-Rabin
    return all(sprp(n, b, s, d) for b in mrb)
示例#6
0
def primefac(n,
             trial_limit=1000,
             rho_rounds=42000,
             verbose=False,
             methods=(_primefac.pollardRho_brent, _primefac.pollard_pm1,
                      _primefac.williams_pp1, _primefac.ecm, _primefac.mpqs,
                      _primefac.fermat, _primefac.factordb),
             timeout=60):
    from _primefac import isprime, isqrt, primegen
    from random import randrange
    timeout = timeout - 1
    if n < 2:
        return
    if isprime(n):
        yield n
        return

    factors, nroot = [], isqrt(n)
    # Note that we remove factors of 2 whether the user wants to or not.
    for p in primegen():
        if n % p == 0:
            while n % p == 0:
                yield p
                n //= p
            nroot = isqrt(n)
            if isprime(n):
                yield n
                return
        if p > nroot:
            if n != 1:
                yield n
            return
        if p >= trial_limit:
            break
    if isprime(n):
        yield n
        return

    if rho_rounds == "inf":
        factors = [n]
        while len(factors) != 0:
            n = min(factors)
            factors.remove(n)
            f = _primefac.pollardRho_brent(n)
            if isprime(f):
                yield f
            else:
                factors.append(f)
            n //= f
            if isprime(n):
                yield n
            else:
                factors.append(n)
        return

    factors, difficult = [n], []
    while len(factors) != 0:
        rhocount = 0
        n = factors.pop()
        try:
            g = n
            while g == n:
                x, c, g = randrange(1, n), randrange(1, n), 1
                y = x
                while g == 1:
                    if rhocount >= rho_rounds:
                        raise Exception
                    rhocount += 1
                    x = (x**2 + c) % n
                    y = (y**2 + c) % n
                    y = (y**2 + c) % n
                    g = gcd(x - y, n)
            # We now have a nontrivial factor g of n.  If we took too long to get here, we're actually at the except statement.
            if isprime(g):
                yield g
            else:
                factors.append(g)
            n //= g
            if isprime(n):
                yield n
            else:
                factors.append(n)
        except Exception:
            difficult.append(
                n
            )  # Factoring n took too long.  We'll have multifactor chug on it.

    factors = difficult
    while len(factors) != 0:
        n = min(factors)
        factors.remove(n)
        f = multifactor(n, methods=methods, verbose=verbose, timeout=timeout)
        if isprime(f):
            yield f
        else:
            factors.append(f)
        n //= f
        if isprime(n):
            yield n
        else:
            factors.append(n)
def mpqs(n):
    """
    When the bound proves insufficiently large, we throw out all our work and
    start over.
    TODO: When this happens, get more data, but don't trash what we already
          have.
    TODO: Rewrite to get a few more relations before proceeding to the
          linear algebra.
    TODO: When we need to increase the bound, what is the optimal increment?
    """
    from _primefac._arith import ispower, isqrt, ilog, gcd, mod_sqrt, legendre
    from _primefac._arith import modinv
    from _primefac._prime import isprime, nextprime
    from _primefac._util import listprod, mpz
    from six.moves import xrange
    from math import log

    # Special cases: this function poorly handles primes and perfect powers:
    m = ispower(n)
    if m:
        return m
    if isprime(n):
        return n

    root_2n = isqrt(2 * n)
    bound = ilog(n**6, 10)**2  # formula chosen by experiment

    while True:
        try:
            prime, mod_root, log_p, num_prime = [], [], [], 0

            # find a number of small primes for which n is a quadratic residue
            p = 2
            while p < bound or num_prime < 3:
                leg = legendre(n % p, p)
                if leg == 1:
                    prime += [p]
                    # the rhs was [int(mod_sqrt(n, p))].
                    # If we get errors, put it back.
                    mod_root += [mod_sqrt(n, p)]
                    log_p += [log(p, 10)]
                    num_prime += 1
                elif leg == 0:
                    return p
                p = nextprime(p)

            x_max = len(prime) * 60  # size of the sieve

            # maximum value on the sieved range
            m_val = (x_max * root_2n) >> 1
            """
            fudging the threshold down a bit makes it easier to find powers of
            primes as factors as well as partial-partial relationships, but it
            also makes the smoothness check slower. there's a happy medium
            somewhere, depending on how efficient the smoothness check is
            """
            thresh = log(m_val, 10) * 0.735

            # skip small primes. they contribute very little to the log sum
            # and add a lot of unnecessary entries to the table instead, fudge
            # the threshold down a bit, assuming ~1/4 of them pass
            min_prime = mpz(thresh * 3)
            fudge = sum(log_p[i] for i, p in enumerate(prime) if p < min_prime)
            fudge = fudge // 4
            thresh -= fudge

            smooth, used_prime, partial = [], set(), {}
            num_smooth, num_used_prime, num_partial = 0, 0, 0
            num_poly, root_A = 0, isqrt(root_2n // x_max)

            while num_smooth <= num_used_prime:
                # find an integer value A such that:
                # A is =~ sqrt(2*n) // x_max
                # A is a perfect square
                # sqrt(A) is prime, and n is a quadratic residue mod sqrt(A)
                while True:
                    root_A = nextprime(root_A)
                    leg = legendre(n, root_A)
                    if leg == 1:
                        break
                    elif leg == 0:
                        return root_A
                A = root_A**2
                # solve for an adequate B. B*B is a quadratic residue mod n,
                # such that B*B-A*C = n. this is unsolvable if n is not a
                # quadratic residue mod sqrt(A)
                b = mod_sqrt(n, root_A)
                B = (b + (n - b * b) * modinv(b + b, root_A)) % A
                C = (B * B - n) // A  # B*B-A*C = n <=> C = (B*B-n)//A
                num_poly += 1
                # sieve for prime factors
                sums, i = [0.0] * (2 * x_max), 0
                for p in prime:
                    if p < min_prime:
                        i += 1
                        continue
                    logp = log_p[i]
                    g = gcd(A, p)
                    inv_A = modinv(A // g, p // g) * g
                    # modular root of the quadratic
                    a, b, k = (mpz(((mod_root[i] - B) * inv_A) % p),
                               mpz(((p - mod_root[i] - B) * inv_A) % p), 0)
                    while k < x_max:
                        if k + a < x_max:
                            sums[k + a] += logp
                        if k + b < x_max:
                            sums[k + b] += logp
                        if k:
                            sums[k - a + x_max] += logp
                            sums[k - b + x_max] += logp
                        k += p
                    i += 1
                # check for smooths
                i = 0
                for v in sums:
                    if v > thresh:
                        x, vec, sqr = x_max - i if i > x_max else i, set(), []
                        # because B*B-n = A*C
                        # (A*x+B)^2 - n = A*A*x*x+2*A*B*x + B*B - n
                        #               = A*(A*x*x+2*B*x+C)
                        # gives the congruency
                        # (A*x+B)^2 = A*(A*x*x+2*B*x+C) (mod n)
                        # because A is chosen to be square, it doesn't
                        # need to be sieved
                        sieve_val = (A * x + 2 * B) * x + C
                        if sieve_val < 0:
                            vec, sieve_val = {-1}, -sieve_val
                        for p in prime:
                            while sieve_val % p == 0:
                                if p in vec:
                                    """
                                    track perfect sqr facs to avoid sqrting
                                    something huge at the end
                                    """
                                    sqr += [p]
                                vec ^= {p}
                                sieve_val = mpz(sieve_val // p)
                        if sieve_val == 1:  # smooth
                            smooth += [(vec, (sqr, (A * x + B), root_A))]
                            used_prime |= vec
                        elif sieve_val in partial:
                            """
                            combine two partials to make a (xor) smooth that
                            is, every prime factor with an odd power is in our
                            factor base
                            """
                            pair_vec, pair_vals = partial[sieve_val]
                            sqr += list(vec & pair_vec) + [sieve_val]
                            vec ^= pair_vec
                            smooth += [(vec, (sqr + pair_vals[0],
                                              (A * x + B) * pair_vals[1],
                                              root_A * pair_vals[2]))]
                            used_prime |= vec
                            num_partial += 1
                        else:
                            # save partial for later pairing
                            partial[sieve_val] = (vec, (sqr, A * x + B,
                                                        root_A))
                    i += 1
                num_smooth, num_used_prime = len(smooth), len(used_prime)
            used_prime = sorted(list(used_prime))
            # set up bit fields for gaussian elimination
            masks, mask, bitfields = [], 1, [0] * num_used_prime
            for vec, _ in smooth:
                masks += [mask]
                i = 0
                for p in used_prime:
                    if p in vec:
                        bitfields[i] |= mask
                    i += 1
                mask <<= 1
            # row echelon form
            offset = 0
            null_cols = []
            for col in xrange(num_smooth):
                pivot = bitfields[col - offset] & masks[
                    col] == 0  # This occasionally throws IndexErrors.
                # TODO: figure out why it throws errors and fix it.
                for row in xrange(col + 1 - offset, num_used_prime):
                    if bitfields[row] & masks[col]:
                        if pivot:
                            bitfields[col - offset], bitfields[
                                row], pivot = bitfields[row], bitfields[
                                    col - offset], False
                        else:
                            bitfields[row] ^= bitfields[col - offset]
                if pivot:
                    null_cols += [col]
                    offset += 1
            # reduced row echelon form
            for row in xrange(num_used_prime):
                mask = bitfields[row] & -bitfields[row]  # lowest set bit
                for up_row in xrange(row):
                    if bitfields[up_row] & mask:
                        bitfields[up_row] ^= bitfields[row]
            # check for non-trivial congruencies
            # TODO: if none exist, check combinations of null space columns...
            # if _still_ none exist, sieve more values
            for col in null_cols:
                all_vec, (lh, rh, rA) = smooth[col]
                lhs = lh  # sieved values (left hand side)
                rhs = [rh]  # sieved values - n (right hand side)
                rAs = [rA]  # root_As (cofactor of lhs)
                i = 0
                for field in bitfields:
                    if field & masks[col]:
                        vec, (lh, rh, rA) = smooth[i]
                        lhs += list(all_vec & vec) + lh
                        all_vec ^= vec
                        rhs += [rh]
                        rAs += [rA]
                    i += 1
                factor = gcd(listprod(rAs) * listprod(lhs) - listprod(rhs), n)
                if 1 < factor < n:
                    return factor
        except IndexError:
            pass
        bound *= 1.2