def quadratic_sieve(n, bound=1024, sieve=1000000):
    """
    quadratic sieve to find a factor of an integer
    """
    if n % 2 == 0:
        return 2
    if isprime(n):
        return n
    if ispower(n):
        return ispower(n)

    memo = defaultdict(list)
    for a0 in range(isqrt(n) + 1, isqrt(2 * n), sieve):
        # primes where n is a quadratic residue
        p_list = [p for p in primes(bound) if 0 < pow(n, (p - 1) // 2, p) < p - 1]

        # sieving for b smooth numbers
        v_list = [a * a - n for a in range(a0, a0 + sieve)]
        for p in p_list:
            r = mod_sqrt(n, p)
            for i in range((r - a0) % p, sieve, p):
                while v_list[i] % p == 0:
                    v_list[i] //= p
            for i in range((p - r - a0) % p, sieve, p):
                while v_list[i] % p == 0:
                    v_list[i] //= p

        # factoring and checking
        for ai, r in enumerate(v_list):
            if r != 1 and not issquare(r):
                continue

            # factor all b smooth numbers
            ai += a0
            b2 = ai * ai - n
            v = 0
            for i, p in enumerate(p_list):
                while b2 % p == 0:
                    b2 //= p
                    v ^= 1 << i
                if b2 == 1:
                    break

            # if b2 is square, use fermat's method
            if not v:
                return ai - isqrt(ai * ai - n)

            # compare against sieved congruent a values
            for aj in memo[v]:
                x = ai * aj - n
                y = isqrt((ai * ai - n) * (aj * aj - n))
                if 1 < gcd(y - x, n) < n:
                    return gcd(y - x, n)

            memo[v].append(ai)

        # increase bound size
        bound *= 2
Esempio n. 2
0
def fermat_sieve(n):
    """
    returns factor of N using fermat sieve method
    """
    if n <= 1:
        return 1
    if n % 2 == 0:
        return 2
    if isprime(n):
        return n

    def prime_powers():
        # iterates through increasingly smaller powers of primes
        # modeled after powers of highly composite numbers
        # also finds squares mod p to simply check if square
        perc = 1.0
        for p in primegen():
            p = p**(max(1, ilog(ilog(n, p), p)))
            yield p, frozenset(i * i % p for i in range(p // 2 + 1))

    def worker(a, b2, astep, i):
        # finishes off steps if it deems it low enough
        # otherwise it finds more squares via quadratic residue
        double = astep + astep
        square = astep * astep
        m, s = modulus[i]
        if astep * m + a >= aend:
            while a < aend:
                b = isqrt(b2)
                if b * b == b2:
                    return a - b, a + b
                else:
                    b2 += double * a + square
                    a += astep
        else:
            for _ in range(m):
                if b2 % m in s:
                    ret = worker(a, b2, astep * m, i + 1)
                    if ret is not None:
                        return ret
                b2 += double * a + square
                a += astep

    # prime power iterator, saved powers, start and end
    ps = prime_powers()
    modulus = defaultdict(lambda: next(ps))
    astart = isqrt(n)
    aend = isqrt(n + n)

    # call to helper function
    while True:
        ret = worker(astart, astart * astart - n, 1, 0)
        if ret is not None:
            return ret
        astart, aend = aend, 2 * aend
def quadratic_factor(n, bound=None):
    """
    return factor of n using congruence of squares
    looks for two congruent b^2s using a dictionary of bitsets
    """
    if n <= 1:
        return 1
    if isprime(n):
        return n
    if ispower(n):
        return ispower(n)

    # heuristic optimization of bound
    if bound is None:
        bound = max(int(10 ** (log(n, 10) / 4)), 3)

    # look for b^2s by iterating a above the sqrt of n
    p_list = list(primes(bound))
    memo = defaultdict(list)
    for ai in count(isqrt(n) + 1):
        vi = 0
        b2 = ai * ai - n

        # odd powers bitset of the factorization of b2 using trial division
        for i, p in enumerate(p_list):
            while b2 % p == 0:
                b2 //= p
                vi ^= 1 << i
            if b2 == 1:
                break
        else:
            # not b-smooth
            if not issquare(b2):
                continue

        # if b2 is square, use fermat's method
        if not vi:
            return ai - isqrt(ai * ai - n)

        # compare against sieved congruent a values
        for aj in memo[vi]:
            x = ai * aj - n
            y = isqrt((ai * ai - n) * (aj * aj - n))
            # pow(x, 2, n) == pow(y, 2, n)
            if 1 < gcd(y - x, n) < n:
                return gcd(y - x, n)

        # add the current a to the memo
        memo[vi].append(ai)
def william_pp1(n):
    """
    williams p+1 algorithm for finding factors of a number
    """
    if n == 0:
        return 0
    if n == 1:
        return 1
    if n % 2 == 0:
        return 2
    if isprime(n):
        return n

    nsqrt = isqrt(n)
    if nsqrt * nsqrt == n:
        return nsqrt

    for v in count(1):
        for p in primegen():
            e = ilog(nsqrt, p)
            if e == 0:
                break
            for _ in range(e):
                v = mlucas(v, p, n)

            g = gcd(v - 2, n)
            if g == n:
                break
            if 1 < g:
                return g
Esempio n. 5
0
def pollard_pm2(n, lo=2, hi=4):
    p_gen = primegen()
    p_lo = list()
    p_hi = list()
    p_next = next(p_gen)

    while p_next < lo:
        p_lo.append(p_next)
        p_next = next(p_gen)

    am1 = 2
    nsqrt = isqrt(n)
    while True:
        a = am1
        for p in p_lo:
            a = pow(a, p, n)
        d = gcd(a - 1, n)
        if 1 < d < n:
            return d
        am1 = a

        while p_next < hi:
            p_hi.append(p_next)
            p_next = next(p_gen)

        for p in p_hi:
            a = pow(a, p, n)

        d = gcd(a - 1, n)
        if 1 < d < n:
            return d

        lo, hi = hi, hi * 2
        p_lo, p_hi = p_hi, list()
Esempio n. 6
0
def fermat(n):
    """
    return factor of n using fermat method
    """
    if n <= 1:
        return 1
    if n % 2 == 0:
        return 2

    a = isqrt(n)
    b2 = a * a - n
    while not issquare(b2):
        b2 += 2 * a + 1
        a += 1

    b = isqrt(b2)
    return a - b, a + b
def trial_division(n):
    """
    returns the lowest prime that divides n
    """
    for p in primes(isqrt(n)):
        if n % p == 0:
            return p
    return n
Esempio n. 8
0
def isPrime(n):
    """
    Returns True if n is prime, false otherwise

    n: positive integer
    """
    for num in range(2, isqrt(n) + 1):
        if(n % num == 0):
            return False
    return True
def euler(n):
    """
    uses euler's method to factor n
    """
    for b in range(1, n):
        a2 = n - b * b
        if issquare(a2):
            a = isqrt(a2)
            break
    else:
        return

    for d in range(b + 1, n):
        c2 = n - d * d
        if issquare(c2):
            c = isqrt(c2)
            break
    if a == d:
        return

    A, B, C, D = a - c, a + c, d - b, d + b
    k, h, i, m = gcd(A, C) // 2, gcd(B, D) // 2, gcd(A, D) // 2, gcd(B, C) // 2

    return (k * k + h * h), (i * i + m * m)
Esempio n. 10
0
def primeFactorize(n, list=[]):
    """
    Gives the prime factors of n
    
    n: integer > 0
    returns: list of integers
    """
    if(isPrime(n)):
        list.append(n)
        return list
    for num in range(2, 1 + isqrt(n)):#2 - ceil(n)
        if(n % num == 0):
            list + primeFactorize(int(n/num), list)
            list + primeFactorize(num, list)

    return list
Esempio n. 11
0
 def worker(a, b2, astep, i):
     # finishes off steps if it deems it low enough
     # otherwise it finds more squares via quadratic residue
     double = astep + astep
     square = astep * astep
     m, s = modulus[i]
     if astep * m + a >= aend:
         while a < aend:
             b = isqrt(b2)
             if b * b == b2:
                 return a - b, a + b
             else:
                 b2 += double * a + square
                 a += astep
     else:
         for _ in range(m):
             if b2 % m in s:
                 ret = worker(a, b2, astep * m, i + 1)
                 if ret is not None:
                     return ret
             b2 += double * a + square
             a += astep
def quadratic_sieve2(n, bound=100000):
    global c_list, v_list
    p_list = list(primes(bound))
    ai = isqrt(n)
    b2 = ai * ai - n

    def vectorize(b2):
        v = 0
        for i, p in enumerate(p_list):
            while b2 % p == 0:
                b2 //= p
                v ^= 1 << i
            if b2 == 1:
                return v

    a_list = list()
    v_list = list()
    b_list = list()
    c_list = [0] * len(p_list)

    # sieving
    for i in range(len(p_list) + 1):
        # find b that is smooth
        vi = None
        while vi is None:
            b2 += 2 * ai + 1
            ai += 1
            vi = vectorize(b2)

        # check fermat simple case
        if not vi:
            print("fermat")
            return ai - isqrt(b2)

        # add to lists
        a_list.append(ai)
        b_list.append(b2)
        v_list.append(vi)

        # add column
        v = vi
        c = 0
        for _ in range(len(p_list)):
            c_list[c] *= 2
            if v % 2:
                c_list[c] += 1
            v //= 2
            c += 1

    # attempt at gauss
    c_copy = c_list[:]
    marks = set(range(len(v_list)))
    for col_j, bits_j in enumerate(c_copy):
        if not bits_j:
            continue
        row_i = 0
        bit_i = 1
        while not bits_j & bit_i:
            row_i += 1
            bit_i *= 2

        marks.discard(row_i)
        for col_k in range(len(c_copy)):
            if col_k == col_j:
                continue
            if bit_i & c_copy[col_k]:
                c_copy[col_k] ^= bits_j

    # find lone rows
    v_copy = list()
    for i in range(len(v_list)):
        v = 0
        for c in range(len(c_copy)):
            v *= 2
            if c_copy[c] % 2:
                v += 1
            c_copy[c] //= 2
        v_copy.append(v)

    # find dependences
    for m in marks:
        j_list = [m]
        row_j = v_copy[m]
        bit_j = 1
        # could be dictionary
        for i in range(row_j.bit_length()):
            if bit_j & row_j:
                j_list.append(v_copy.index(bit_j))
            bit_j *= 2

        # calculate x and y
        x = y = 1
        for j in j_list:
            x = x * a_list[-j - 1] % n
            y = y * b_list[-j - 1]
        y = iroot(y, len(j_list))

        # check if valid
        if 1 < gcd(y - x, n) < n:
            print(len(j_list))
            return gcd(y - x, n)
Esempio n. 13
0
def quadratic_sieve(n, bound=1024, sieve=1000000):
    """
    quadratic sieve to find a factor of an integer
    """

    if n % 2 == 0:
        return 2
    if isprime(n):
        return n
    if ispower(n):
        return ispower(n)

    # primes where n is a quadratic residue - 0 would mean divisable ...
    p_list = [p for p in primes(bound) if pow(n, (p - 1) // 2, p) != p - 1]
    pi = len(p_list)

    rows = list()
    a_list = list()
    b_list = list()

    for a0 in range(isqrt(n) + 1, isqrt(2 * n), sieve):

        # sieving for b smooth numbers
        v_list = [a * a - n for a in range(a0, a0 + sieve)]
        for p in p_list:
            r = mod_sqrt(n, p)
            for i in range((r - a0) % p, sieve, p):
                while v_list[i] % p == 0:
                    v_list[i] //= p
            for i in range((p - r - a0) % p, sieve, p):
                while v_list[i] % p == 0:
                    v_list[i] //= p

        # factoring and checking
        for ai, r in enumerate(v_list):
            if r != 1 and not issquare(r):
                continue

            # factor all b smooth numbers
            ai += a0
            b2 = ai * ai - n
            v = 0
            factors = Counter()
            for i, p in enumerate(p_list):
                power = 0
                while b2 % p == 0:
                    b2 //= p
                    power += 1
                if power:
                    factors[p] = power
                    if power % 2:
                        v |= 1 << i
                if b2 == 1:
                    break

            # if b2 is square, use fermat's method
            if not v:
                print("fermat")
                return ai - isqrt(ai * ai - n)

            rows.append(v)
            a_list.append(ai)
            b_list.append(factors)

        # look for 3+ that combine
        print(len(rows))
        cols = [
            sum(1 << i for i, x in enumerate(rows) if (1 << j) & x)
            for j in range(pi)
        ]
        marks = set(range(len(a_list)))

        # gaussian elimination
        for j, col in enumerate(cols):
            if not col:
                continue
            mask = 1
            i = 0
            while not mask & col:
                mask *= 2
                i += 1
            marks.remove(i)
            for k, col2 in enumerate(cols):
                if j == k:
                    continue
                elif mask & col2:
                    cols[k] ^= col

        # find matches
        rows2 = [
            sum(1 << i for i, x in enumerate(reversed(cols)) if (1 << j) & x)
            for j in range(len(a_list))
        ]
        for mark in marks:
            r_list = [mark]
            mask = 1
            row = rows2[mark]
            for _ in range(pi):
                if mask & row:
                    r_list.append(rows2.index(mask))
                mask *= 2

            # combine with 0s?
            x = y = 1
            sq = Counter()
            for r in r_list:
                x = x * a_list[r] % n
                sq += b_list[r]
            for k, v in sq.items():
                y = y * pow(k, v // 2, n) % n
            f = gcd(y - x, n)

            if 1 < f < n:
                return f
Esempio n. 14
0
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?

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

    root_n, root_2n = isqrt(n), 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]
                    mod_root += [
                        mod_sqrt(n, p)
                    ]  # the rhs was [int(mod_sqrt(n, p))].  If we get errors, put it back.
                    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

            m_val = (x_max * root_2n) >> 1  # maximum value on the sieved range

            # 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 = thresh * 3
            fudge = sum(log_p[i]
                        for i, p in enumerate(prime) if p < min_prime) // 4
            thresh -= fudge

            smooth, used_prime, partial = [], set(), {}
            num_smooth, num_used_prime, num_partial, num_poly, root_A = (
                0,
                0,
                0,
                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]
                    inv_A = modinv(A, p)
                    # modular root of the quadratic
                    a, b, k = (
                        (((mod_root[i] - B) * inv_A) % p),
                        (((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
                        # val = sieve_val = (A*x + 2*B)*x + C
                        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:
                                    sqr += [
                                        p
                                    ]  # track perfect sqr facs to avoid sqrting something huge at the end
                                vec ^= {p}
                                sieve_val = sieve_val // p
                        if sieve_val == 1:  # smooth
                            smooth.append((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.extend(vec & pair_vec)
                            sqr.append(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:
                            partial[sieve_val] = (
                                vec,
                                (sqr, A * x + B, root_A),
                            )  # save partial for later pairing
                    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, vals 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 range(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 range(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 range(num_used_prime):
                mask = bitfields[row] & -bitfields[row]  # lowest set bit
                for up_row in range(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.extend(all_vec & vec)
                        lhs.extend(lh)
                        all_vec ^= vec
                        rhs.append(rh)
                        ras.append(ra)
                    i += 1
                f = gcd(
                    reduce(mul, ras) * reduce(mul, lhs) - reduce(mul, rhs), n)
                if 1 < f < n:
                    return f

        except IndexError:
            pass

        bound *= 1.2