예제 #1
0
 def register(self, divisor, isprime=Unknown):
     """
     Register a divisor of the number, if the divisor is a true
     divisor of the number.  The number is divided by the divisor
     as many times as possible.
     """
     for base, index in self.factors:
         if base == divisor:
             if isprime and not self.primality[base]:
                 self.setPrimality(base, isprime)
             break
         common_divisor = gcd.gcd(base, divisor)
         if common_divisor == 1:
             continue
         # common_divisor > 1:
         if common_divisor == divisor:
             if isprime:
                 self.setPrimality(divisor, isprime)
             k, coprime = arith1.vp(base, common_divisor)
             while not gcd.coprime(common_divisor, coprime):
                 # try a smaller factor
                 common_divisor = gcd.gcd(common_divisor, coprime)
                 k, coprime = arith1.vp(base, common_divisor)
             if k:
                 if coprime > 1:
                     self.replace(base, [(common_divisor, k), (coprime, 1)])
                 else:
                     self.replace(base, [(common_divisor, k)])
         else:  # common_divisor properly divides divisor.
             self.register(common_divisor)
             self.register(divisor // common_divisor)
예제 #2
0
파일: util.py 프로젝트: nickspoon/part-ii
 def register(self, divisor, isprime=Unknown):
     """
     Register a divisor of the number, if the divisor is a true
     divisor of the number.  The number is divided by the divisor
     as many times as possible.
     """
     for base, index in self.factors:
         if base == divisor:
             if isprime and not self.primality[base]:
                 self.setPrimality(base, isprime)
             break
         common_divisor = gcd.gcd(base, divisor)
         if common_divisor == 1:
             continue
         # common_divisor > 1:
         if common_divisor == divisor:
             if isprime:
                 self.setPrimality(divisor, isprime)
             k, coprime = arith1.vp(base, common_divisor)
             while not gcd.coprime(common_divisor, coprime):
                 # try a smaller factor
                 common_divisor = gcd.gcd(common_divisor, coprime)
                 k, coprime = arith1.vp(base, common_divisor)
             if k:
                 if coprime > 1:
                     self.replace(base, [(common_divisor, k), (coprime, 1)])
                 else:
                     self.replace(base, [(common_divisor, k)])
         else: # common_divisor properly divides divisor.
             self.register(common_divisor)
             self.register(divisor // common_divisor)
예제 #3
0
def _factor_order(m, u, era=None):
    """
    Return triple (k, q, primes) if m is factored as m = kq,
    where k > 1 and q is a probable prime > u.
    u is expected to be (n^(1/4)+1)^2 for Atkin-Morain ECPP.
    If m is not successfully factored into desired form,
    return (False, False, primes).
    The third component of both cases is a list of primes
    to do trial division.

    Algorithm 27 (Atkin-morain ECPP) Step3
    """
    if era is None:
        v = min(500000, int(log(m)))
        era = factor.mpqs.eratosthenes(v)
    k = 1
    q = m
    for p in era:
        if p > u:
            break
        e, q = arith1.vp(q, p)
        k *= p**e
    if q < u or k == 1:
        return False, False, era
    if not prime.millerRabin(q):
        return False, False, era
    return k, q, era
예제 #4
0
파일: ecpp.py 프로젝트: nickspoon/part-ii
def _factor_order(m, u, era=None):
    """
    Return triple (k, q, primes) if m is factored as m = kq,
    where k > 1 and q is a probable prime > u.
    u is expected to be (n^(1/4)+1)^2 for Atkin-Morain ECPP.
    If m is not successfully factored into desired form,
    return (False, False, primes).
    The third component of both cases is a list of primes
    to do trial division.

    Algorithm 27 (Atkin-morain ECPP) Step3
    """
    if era is None:
        v = min(500000, int(log(m)))
        era = factor.mpqs.eratosthenes(v)
    k = 1
    q = m
    for p in era:
        if p > u:
            break
        e, q = arith1.vp(q, p)
        k *= p ** e
    if q < u or k == 1:
        return False, False, era
    if not prime.millerRabin(q):
        return False, False, era
    return k, q, era
예제 #5
0
def primePowerTest(n):
    """
    This program using Algo. 1.7.5 in Cohen's book judges whether
    n is of the form p**k with prime p or not.
    If it is True, then (p,k) will be returned,
    otherwise (n,0).
    """
    if n & 1:
        q = n
        while True:
            if not prime.primeq(q):
                a = 2
                while prime.spsp(n, a):
                    a += 1
                d = gcd.gcd(pow(a,q,q) - a, q)
                if d == 1 or d == q:
                    return (n, 0)
                q = d
            else:
                p = q
                break
    else:
        p = 2

    k, q = arith1.vp(n, p)
    if q == 1:
        return (p, k)
    else:
        return (n, 0)
예제 #6
0
def dumas(target, p):
    """
    Return True if target is irreducible, False if reducible
    or None if undecidable.

    Dumas's criterion is the following.  Let f = \sum a_i X^i be a
    integer coefficient polynomial with degree n, and p be a prime
    number.  f is irreducible if
    (I) gcd(n, v(a_n) - v(a_0)) == 1
        (where v(m) denotes the number e that p**e divide m but
        p**(e+1) doesn't)
    (II) for any i (0 < i < n), (i, v(a_i)) is above the line connecting
        (0, v(a_0)) and (n, v(a_n)).
    This criterion includes Eisenstein's case.
    """
    segments = dict((d, arith1.vp(c, p=p)[0]) for (d, c) in target)
    # (I)
    degree = target.degree()
    if abs(gcd.gcd(degree, segments[degree] - segments[0])) != 1:
        return None
    # (II)
    #(segments[degree] - segments[0]) / degree * x + segment[0] < segments[x]
    slope = segments[degree] - segments[0]
    if all(slope * x <= degree * (v - segments[0])
           for x, v in segments.iteritems()):
        return True
    # the criterion doesn't work
    return None
예제 #7
0
파일: misc.py 프로젝트: nickspoon/part-ii
def primePowerTest(n):
    """
    This program using Algo. 1.7.5 in Cohen's book judges whether
    n is of the form p**k with prime p or not.
    If it is True, then (p,k) will be returned,
    otherwise (n,0).
    """
    if n % 2 == 1:
        q = n
        while True:
            if not prime.primeq(q):
                a = 2
                while prime.spsp(n, a):
                    a += 1
                d = gcd.gcd(pow(a,q,q) - a, q)
                if d == 1 or d == q:
                    return (n, 0)
                else:
                    q = d
            else:
                p = q
                break
    else:
        p = 2

    k, q = arith1.vp(n, p)
    if q == 1:
        return (p, k)
    else:
        return (n, 0)
예제 #8
0
 def _flexible_pow(self, element, index):
     """
     powering by using flexible base method.
     (Algorithm 1.2.4.1 & 1.2.4.2 of Cohen's book)
     size is selected by average analystic optimization
     """
     log_n = int(math.log(index, 2))
     # Find the proper window size
     size = 1
     pow_size = 1
     while log_n > (size + 1) * (size + 2) * pow_size:
         pow_size <<= 1
         size += 1
     pow_size <<= 1
     # Compute win_lst, sqr_lst
     b, n = arith1.vp(index, 2)
     win_lst, sqr_lst = [], [b]
     while True:
         m, r = divmod(n, pow_size)
         win_lst.append(r)
         if not (m):
             break
         b, n = arith1.vp(m, 2)
         sqr_lst.append(b + size)
     e = len(win_lst) - 1
     f = e
     # Precomputation
     sqrs = element
     pre_table = [element]
     pow_size >>= 1
     for i in range(pow_size - 1):
         sqrs = self.square(sqrs)
         pre_table.append(self.mul(pre_table[-1], sqrs))
     # Main Loop
     while f >= 0:
         if f == e:
             sol = pre_table[(win_lst[f] - 1) >> 1]
         else:
             sol = self.mul(sol, pre_table[(win_lst[f] - 1) >> 1])
         for i in range(sqr_lst[f]):
             sol = self.square(sol)
         f -= 1
     return sol
예제 #9
0
 def _two_pow_ary_pow(self, element, index):
     """
     powering by using left-right 2^size ary method.('size' is the proper integer)
     (Algorithm 1.2.4 of Cohen's book)
     size is selected by average analystic optimization
     """
     # Find the proper size
     log_n = int(math.log(index, 2))
     size = 1
     pow_size = 1
     while log_n > (size + 1) * (size + 2) * pow_size:
         pow_size <<= 1
         size += 1
     # Compute win_lst, sqr_lst
     pow_size <<= 1
     s, m = arith1.vp(index, 2)
     win_lst, sqr_lst = [], [s]
     while m > pow_size:
         m, b = divmod(m, pow_size)
         win_lst.append(b)
         s, m = arith1.vp(m, 2)
         sqr_lst.append(s + size)
     win_lst.append(m)
     e = len(win_lst) - 1
     f = e
     # Precomputation
     sqr = self.square(element)
     pre_table = [element]
     pow_size = (pow_size // 2) - 1
     for i in range(pow_size):
         pre_table.append(self.mul(pre_table[-1], sqr))
     # Main Loop
     while f >= 0:
         if f == e:
             sol = pre_table[(win_lst[f] - 1) >> 1]
         else:
             sol = self.mul(sol, pre_table[(win_lst[f] - 1) >> 1])
         for i in range(sqr_lst[f]):
             sol = self.square(sol)
         f -= 1
     return sol
예제 #10
0
파일: prime.py 프로젝트: nickspoon/part-ii
def millerRabin(n, times=20):
    """
    Miller-Rabin pseudo-primality test.  Optional second argument
    times (default to 20) is the number of repetition.  The error
    probability is at most 4**(-times).
    """
    s, t = arith1.vp(n - 1, 2)
    for _ in range(times):
        b = bigrandom.randrange(2, n-1)
        if not spsp(n, b, s, t):
            return False
    return True
예제 #11
0
def millerRabin(n, times=20):
    """
    Miller-Rabin pseudo-primality test.  Optional second argument
    times (default to 20) is the number of repetition.  The error
    probability is at most 4**(-times).
    """
    s, t = arith1.vp(n - 1, 2)
    for _ in range(times):
        b = bigrandom.randrange(2, n - 1)
        if not spsp(n, b, s, t):
            return False
    return True
예제 #12
0
def smallSpsp(n, s=None, t=None):
    """
    4 spsp tests are sufficient to determine whether an integer less
    than 10**12 is prime or not.  Optional third and fourth argument
    s and t are the numbers such that n - 1 = 2**s * t and t is odd.
    """
    if s is None or t is None:
        s, t = arith1.vp(n - 1, 2)
    for p in (2, 13, 23, 1662803):
        if not spsp(n, p, s, t):
            return False
    return True
예제 #13
0
파일: prime.py 프로젝트: nickspoon/part-ii
def _factor(n, bound=0):
    """
    Trial division factorization for a natural number.
    Optional second argument is a search bound of primes.
    If the bound is given and less than the sqaure root of n,
    result is not proved to be a prime factorization.
    """
    factors = []
    if not (n % 2):
        v2, n = arith1.vp(n, 2)
        factors.append((2, v2))
    m = _calc_bound(n, bound)
    p = 3
    while p <= m:
        if not (n % p):
            v, n = arith1.vp(n, p)
            factors.append((p, v))
            m = _calc_bound(n, bound)
        p += 2
    if n > 1:
        factors.append((n, 1))
    return factors
예제 #14
0
def miller_rabin(n, times=20):
    """
    Miller-Rabin pseudo-primality test.
    The error probability is at most 4**(-times).

    Optional second argument times (default to 20) is the number of
    repetition.  The testee 'n' is required to be much bigger than
    'times'.
    """
    nminus1 = n - 1
    s, t = arith1.vp(nminus1, 2)
    randrange = bigrandom.randrange
    return all(spsp(n, randrange(i + 2, nminus1), s, t) for i in range(times))
예제 #15
0
def _factor(n, bound=0):
    """
    Trial division factorization for a natural number.
    Optional second argument is a search bound of primes.
    If the bound is given and less than the sqaure root of n,
    result is not proved to be a prime factorization.
    """
    factors = []
    if not (n & 1):
        v2, n = arith1.vp(n, 2)
        factors.append((2, v2))
    m = _calc_bound(n, bound)
    p = 3
    while p <= m:
        if not (n % p):
            v, n = arith1.vp(n, p)
            factors.append((p, v))
            m = _calc_bound(n, bound)
        p += 2
    if n > 1:
        factors.append((n, 1))
    return factors
예제 #16
0
파일: prime.py 프로젝트: nickspoon/part-ii
def apr(n):
    """
    apr is the main function for Adleman-Pomerance-Rumery primality test.
    Assuming n has no prime factors less than 32.
    Assuming n is spsp for several bases.
    """
    L = Status()

    rb = arith1.floorsqrt(n) + 1
    el = TestPrime()
    while el.et <= rb:
        el = el.next()

    plist = el.t.factors.keys()
    plist.remove(2)
    L.yet(2)
    for p in plist:
        if pow(n, p-1, p*p) != 1:
            L.done(p)
        else:
            L.yet(p)
    qlist = el.et.factors.keys()
    qlist.remove(2)
    J = JacobiSum()
    for q in qlist:
        for p in plist:
            if (q-1) % p != 0:
                continue
            if not L.subodd(p, q, n, J):
                return False
        k = arith1.vp(q-1, 2)[0]
        if k == 1:
            if not L.sub2(q, n):
                return False
        elif k == 2:
            if not L.sub4(q, n, J):
                return False
        else:
            if not L.sub8(q, k, n, J):
                return False
    for p in L.yet_keys():
        if not L.subrest(p, n, el.et, J):
            return False
    r = int(n)
    for _ in bigrange.range(1, el.t.integer):
        r = (r*n) % el.et.integer
        if n % r == 0 and r != 1 and r != n:
            _log.info("%s divides %s.\n" %(r, n))
            return False
    return True
예제 #17
0
def apr(n):
    """
    apr is the main function for Adleman-Pomerance-Rumery primality test.
    Assuming n has no prime factors less than 32.
    Assuming n is spsp for several bases.
    """
    L = Status()

    rb = arith1.floorsqrt(n) + 1
    el = TestPrime()
    while el.et <= rb:
        el = next(el)

    plist = list(el.t.factors.keys())
    plist.remove(2)
    L.yet(2)
    for p in plist:
        if pow(n, p - 1, p * p) != 1:
            L.done(p)
        else:
            L.yet(p)
    qlist = list(el.et.factors.keys())
    qlist.remove(2)
    J = JacobiSum()
    for q in qlist:
        for p in plist:
            if (q - 1) % p != 0:
                continue
            if not L.subodd(p, q, n, J):
                return False
        k = arith1.vp(q - 1, 2)[0]
        if k == 1:
            if not L.sub2(q, n):
                return False
        elif k == 2:
            if not L.sub4(q, n, J):
                return False
        else:
            if not L.sub8(q, k, n, J):
                return False
    for p in L.yet_keys():
        if not L.subrest(p, n, el.et, J):
            return False
    r = int(n)
    for _ in bigrange.range(1, el.t.integer):
        r = (r * n) % el.et.integer
        if n % r == 0 and r != 1 and r != n:
            _log.info("%s divides %s.\n" % (r, n))
            return False
    return True
예제 #18
0
파일: quad.py 프로젝트: nickspoon/part-ii
def kronecker(a, b):
    """
    Compute the Kronecker symbol (a/b) using algo 1.4.10 in Cohen's book.
    """
    tab2 = (0, 1, 0, -1, 0, -1, 0, 1)
    if b == 0:
        if abs(a) != 1:
            return 0
        if abs(a) == 1:
            return 1
    if a % 2 == 0 and b % 2 == 0:
        return 0

    v, b = arith1.vp(b, 2)
    if v % 2 == 0:
        k = 1
    else:
        k = tab2[a & 7]
    if b < 0:
        b = -b
        if a < 0:
            k = -k
    while a:
        v, a = arith1.vp(a, 2)
        if v % 2 == 1:
            k *= tab2[b & 7]
        if a & b & 2:
            # both a and b are 3 mod 4
            k = -k
        r = abs(a)
        a = b % r
        b = r
    if b > 1:
        # a and be are not coprime
        return 0
    return k
예제 #19
0
def kronecker(a, b):
    """
    Compute the Kronecker symbol (a/b) using algo 1.4.10 in Cohen's book.
    """
    tab2 = (0, 1, 0, -1, 0, -1, 0, 1)
    if b == 0:
        if abs(a) != 1:
            return 0
        if abs(a) == 1:
            return 1
    if a & 1 == 0 and b & 1 == 0:
        return 0

    v, b = arith1.vp(b, 2)
    if v & 1 == 0:
        k = 1
    else:
        k = tab2[a & 7]
    if b < 0:
        b = -b
        if a < 0:
            k = -k
    while a:
        v, a = arith1.vp(a, 2)
        if v & 1:
            k *= tab2[b & 7]
        if a & b & 2:
            # both a and b are 3 mod 4
            k = -k
        r = abs(a)
        a = b % r
        b = r
    if b > 1:
        # a and be are not coprime
        return 0
    return k
예제 #20
0
파일: prime.py 프로젝트: nickspoon/part-ii
def miller(n):
    """
    Miller's primality test.

    This test is valid under GRH.
    """
    s, t = arith1.vp(n - 1, 2)
    # The O-constant 2 by E.Bach
    ## 2 log(n) = 2 log_2(n)/log_2(e) = 2 log(2) log_2(n)
    ## 2 log(2) <= 1.3862943611198906
    bound = min(n - 2, 13862943611198906 * arith1.log(n) // 10 ** 16) + 1
    _log.info("bound: %d" % bound)
    for b in range(2, bound):
        if not spsp(n, b, s, t):
            return False
    return True
예제 #21
0
def miller(n):
    """
    Miller's primality test.

    This test is valid under GRH.
    """
    s, t = arith1.vp(n - 1, 2)
    # The O-constant 2 by E.Bach
    ## ln(n) = log_2(n)/log_2(e) = ln(2) * log_2(n)
    ## 2 * ln(2) ** 2 <= 0.960906027836404
    bound = min(n - 1, 960906027836404 * (arith1.log(n) + 1)**2 // 10**15 + 1)
    _log.info("bound: %d" % bound)
    for b in range(2, bound):
        if not spsp(n, b, s, t):
            return False
    return True
예제 #22
0
    def generate(self, target, **options):
        """
        Generate squarefree factors of the target number with their
        valuations.  The method may terminate with yielding (1, 1)
        to indicate the factorization is incomplete.

        If a keyword option 'strict' is False (default to True),
        factorization will stop after the first square factor no
        matter whether it is squarefree or not.
        """
        strict = options.get('strict', True)
        options['n'] = target
        primeseq = self._parse_seq(options)
        for p in primeseq:
            if not (target % p):
                e, target = arith1.vp(target, p)
                yield p, e
                if target == 1:
                    break
                elif e > 1 and not strict:
                    yield 1, 1
                    break
                elif trivial_test_ternary(target):
                    # the factor remained is squarefree.
                    yield target, 1
                    break
                q, e = factor_misc.primePowerTest(target)
                if e:
                    yield q, e
                    break
                sqrt = arith1.issquare(target)
                if sqrt:
                    if strict:
                        for q, e in self.factor(sqrt, iterator=primeseq):
                            yield q, 2 * e
                    else:
                        yield sqrt, 2
                    break
            if p ** 3 > target:
                # there are no more square factors of target,
                # thus target is squarefree
                yield target, 1
                break
        else:
            # primeseq is exhausted but target has not been proven prime
            yield 1, 1
예제 #23
0
    def generate(self, target, **options):
        """
        Generate squarefree factors of the target number with their
        valuations.  The method may terminate with yielding (1, 1)
        to indicate the factorization is incomplete.

        If a keyword option 'strict' is False (default to True),
        factorization will stop after the first square factor no
        matter whether it is squarefree or not.
        """
        strict = options.get('strict', True)
        options['n'] = target
        primeseq = self._parse_seq(options)
        for p in primeseq:
            if not (target % p):
                e, target = arith1.vp(target, p)
                yield p, e
                if target == 1:
                    break
                elif e > 1 and not strict:
                    yield 1, 1
                    break
                elif trivial_test_ternary(target):
                    # the factor remained is squarefree.
                    yield target, 1
                    break
                q, e = factor_misc.primePowerTest(target)
                if e:
                    yield q, e
                    break
                sqrt = arith1.issquare(target)
                if sqrt:
                    if strict:
                        for q, e in self.factor(sqrt, iterator=primeseq):
                            yield q, 2 * e
                    else:
                        yield sqrt, 2
                    break
            if p ** 3 > target:
                # there are no more square factors of target,
                # thus target is squarefree
                yield target, 1
                break
        else:
            # primeseq is exhausted but target has not been proven prime
            yield 1, 1
예제 #24
0
 def generate(self, target, **options):
     """
     Generate prime factors of the target number with their
     valuations.  The method may terminate with yielding (1, 1)
     to indicate the factorization is incomplete.
     """
     primeseq = self._parse_seq(options)
     for p in primeseq:
         if not (target % p):
             e, target = arith1.vp(target // p, p, 1)
             yield p, e
         if p ** 2 > target:
             # there are no more factors of target, thus target is a prime
             yield target, 1
             break
     else:
         # primeseq is exhausted but target has not been proven prime
         yield 1, 1
예제 #25
0
 def generate(self, target, **options):
     """
     Generate prime factors of the target number with their
     valuations.  The method may terminate with yielding (1, 1)
     to indicate the factorization is incomplete.
     """
     primeseq = self._parse_seq(options)
     for p in primeseq:
         if not (target % p):
             e, target = arith1.vp(target // p, p, 1)
             yield p, e
         if p**2 > target:
             # there are no more factors of target, thus target is a prime
             yield target, 1
             break
     else:
         # primeseq is exhausted but target has not been proven prime
         yield 1, 1
예제 #26
0
파일: prime.py 프로젝트: nickspoon/part-ii
def spsp(n, base, s=None, t=None):
    """
    Strong Pseudo-Prime test.  Optional third and fourth argument
    s and t are the numbers such that n-1 = 2**s * t and t is odd.
    """
    if not s or not t:
        s, t = arith1.vp(n-1, 2)
    z = pow(base, t, n)
    if z != 1 and z != n-1:
        j = 0
        while j < s:
            j += 1
            z = pow(z, 2, n)
            if z == n-1:
                break
        else:
            return False
    return True
예제 #27
0
def spsp(n, base, s=None, t=None):
    """
    Strong Pseudo-Prime test.  Optional third and fourth argument
    s and t are the numbers such that n-1 = 2**s * t and t is odd.
    """
    if s is None or t is None:
        s, t = arith1.vp(n - 1, 2)
    z = pow(base, t, n)
    if z != 1 and z != n - 1:
        j = 0
        while j < s:
            j += 1
            z = pow(z, 2, n)
            if z == n - 1:
                break
        else:
            return False
    return True
예제 #28
0
    def general_lift(self):
        """
        Continue lifting.
            f == a1*a2*...*ar (mod p*q)
        Update ai's, bi's, ui's, yi's and zi's.
        Then, update q with p*q.
        """
        j = arith1.vp(self.q, self.p)[0]
        if len(self.dis) > j:
            mini_target = self.dis[j]
        else:
            mini_target = the_zero

        self.ais[-2], self.ais[-1] = self.ais[-1], self.ais[0]
        self.bis[-2], self.bis[-1] = self.bis[-1], self.bis[0]
        aj, bj = [], []
        for i in range(self.r - 1):
            yi, zi = self.yis[i], self.zis[i]
            dividend = self.ais[-2][i] * yi + self.bis[-2][i] * zi - self.uis[i]
            v_j = dividend.scalar_exact_division(self.p)
            if j == 2:
                self.uis[i] = mini_target - v_j - yi * zi
            else:
                self.uis[i] = mini_target - v_j - (yi * zi).scalar_mul(
                    self.p**(j - 2))
            self.yis[i], self.zis[i] = self._solve_yz(i)
            aj.append(self.ais[-1][i] + self.zis[i].scalar_mul(self.q))
            bj.append(self.bis[-1][i] + self.yis[i].scalar_mul(self.q))
            self._assertEqualModulo(self.f,
                                    arith1.product(aj) * bj[i],
                                    self.q * self.p, (i, j))
            mini_target = self.yis[i]
        aj.append(bj[-1])
        self.q *= self.p

        for i in range(self.r - 1):
            self._assertEqualModulo(self.f,
                                    arith1.product(aj[:i + 1]) * bj[i], self.q,
                                    "f != a%d * b%d" % (i, i))
            self._assertEqualModulo(self.gis[i], aj[i], self.p)
        self._assertEqualModulo(self.f, arith1.product(aj), self.q)

        self.ais[0] = tuple(aj)
        self.bis[0] = tuple(bj)
예제 #29
0
 def _ones_and_zero_pows(self, element, index):
     """
     powering by 'ones' window method.
     """
     # Compute win_lst, sqr_lst
     b, n = arith1.vp(index, 2)
     win_lst, sqr_lst = [], [b]
     maxa = 1
     while True:
         ones = 0
         while n & 1:
             n >>= 1
             ones += 1
         win_lst.append(ones)
         if maxa < ones:
             maxa = ones
         if n == 0:
             break
         zeros = 0
         while not (n & 1):
             n >>= 1
             zeros += 1
         sqr_lst.append(zeros + win_lst[-1])
     e = len(win_lst) - 1
     f = e
     # Precomputation
     sqrs = element
     pre_table = [element]
     for i in range(maxa - 1):
         sqrs = self.square(sqrs)
         pre_table.append(self.mul(pre_table[-1], sqrs))
     # Main Loop
     while f >= 0:
         if f == e:
             sol = pre_table[win_lst[f] - 1]
         else:
             sol = self.mul(sol, pre_table[win_lst[f] - 1])
         for i in range(sqr_lst[f]):
             sol = self.square(sol)
         f -= 1
     return sol
예제 #30
0
    def TonelliShanks(self, element):
        """ Return square root of element if exist.
        assume that characteristic have to be more than three.
        """
        if self.char == 2:
            return self.sqrt(element)  # should be error

        if self.Legendre(element) == -1:
            raise ValueError("There is no solution")

        # symbol and code reference from Cohen, CCANT 1.5.1
        (e, q) = arith1.vp(card(self) - 1, 2)

        a = element
        n = self.createElement(self.char + 1)
        while self.Legendre(n) != -1:
            n = self.createElement(
                bigrandom.randrange(self.char + 1,
                                    card(self)))  # field maybe large
        y = z = n**q
        r = e
        x = a**((q - 1) // 2)
        b = a * (x**2)
        x = a * x
        while True:
            if b == self.one:
                return x
            m = 1
            while m < r:
                if b**(2**m) == self.one:
                    break
                m = m + 1
            if m == r:
                break
            t = y**(2**(r - m - 1))
            y = t**2
            r = m
            x = x * t
            b = b * y
        raise ValueError("There is no solution")
예제 #31
0
파일: prime.py 프로젝트: nickspoon/part-ii
 def subrest(self, p, n, et, J, ub=200):
     if p == 2:
         q = 5
         while q < 2*ub + 5:
             q += 2
             if not _isprime(q) or et % q == 0:
                 continue
             if n % q == 0:
                 _log.info("%s divides %s.\n" % (q, n))
                 return False
             k = arith1.vp(q-1, 2)[0]
             if k == 1:
                 if n % 4 == 1 and not self.sub2(q, n):
                     return False
             elif k == 2:
                 if not self.sub4(q, n, J):
                     return False
             else:
                 if not self.sub8(q, k, n, J):
                     return False
             if self.isDone(p):
                 return True
         else:
             raise ImplementLimit("limit")
     else:
         step = p*2
         q = 1
         while q < step*ub + 1:
             q += step
             if not _isprime(q) or et % q == 0:
                 continue
             if n % q == 0:
                 _log.info("%s divides %s.\n" % (q, n))
                 return False
             if not self.subodd(p, q, n, J):
                 return False
             if self.isDone(p):
                 return True
         else:
             raise ImplementLimit("limit")
예제 #32
0
 def subrest(self, p, n, et, J, ub=200):
     if p == 2:
         q = 5
         while q < 2 * ub + 5:
             q += 2
             if not _isprime(q) or et % q == 0:
                 continue
             if n % q == 0:
                 _log.info("%s divides %s.\n" % (q, n))
                 return False
             k = arith1.vp(q - 1, 2)[0]
             if k == 1:
                 if n & 3 == 1 and not self.sub2(q, n):
                     return False
             elif k == 2:
                 if not self.sub4(q, n, J):
                     return False
             else:
                 if not self.sub8(q, k, n, J):
                     return False
             if self.isDone(p):
                 return True
         else:
             raise ImplementLimit("limit")
     else:
         step = p * 2
         q = 1
         while q < step * ub + 1:
             q += step
             if not _isprime(q) or et % q == 0:
                 continue
             if n % q == 0:
                 _log.info("%s divides %s.\n" % (q, n))
                 return False
             if not self.subodd(p, q, n, J):
                 return False
             if self.isDone(p):
                 return True
         else:
             raise ImplementLimit("limit")
예제 #33
0
파일: hensel.py 프로젝트: nickspoon/part-ii
    def general_lift(self):
        """
        Continue lifting.
            f == a1*a2*...*ar (mod p*q)
        Update ai's, bi's, ui's, yi's and zi's.
        Then, update q with p*q.
        """
        j = arith1.vp(self.q, self.p)[0]
        if len(self.dis) > j:
            mini_target = self.dis[j]
        else:
            mini_target = the_zero

        self.ais[-2], self.ais[-1] = self.ais[-1], self.ais[0]
        self.bis[-2], self.bis[-1] = self.bis[-1], self.bis[0]
        aj, bj = [], []
        for i in xrange(self.r - 1):
            yi, zi = self.yis[i], self.zis[i]
            dividend = self.ais[-2][i]*yi + self.bis[-2][i]*zi - self.uis[i]
            v_j = dividend.scalar_exact_division(self.p)
            if j == 2:
                self.uis[i] = mini_target - v_j - yi*zi
            else:
                self.uis[i] = mini_target - v_j - (yi*zi).scalar_mul(self.p**(j - 2))
            self.yis[i], self.zis[i] = self._solve_yz(i)
            aj.append(self.ais[-1][i] + self.zis[i].scalar_mul(self.q))
            bj.append(self.bis[-1][i] + self.yis[i].scalar_mul(self.q))
            self._assertEqualModulo(self.f, arith1.product(aj)*bj[i], self.q*self.p, (i, j))
            mini_target = self.yis[i]
        aj.append(bj[-1])
        self.q *= self.p

        for i in range(self.r - 1):
            self._assertEqualModulo(self.f, arith1.product(aj[:i+1])*bj[i], self.q, "f != a%d * b%d" % (i, i))
            self._assertEqualModulo(self.gis[i], aj[i], self.p)
        self._assertEqualModulo(self.f, arith1.product(aj), self.q)

        self.ais[0] = tuple(aj)
        self.bis[0] = tuple(bj)
예제 #34
0
def spsp(n, base, s=None, t=None):
    """
    Strong PSeudo-Prime test.
    A composite can pass this test with probability at most 1/4.

    Optional third and fourth argument s and t are the numbers such
    that n-1 = 2**s * t and t is odd.
    """
    nminus1 = n - 1
    if s is None or t is None:
        s, t = arith1.vp(nminus1, 2)
    z = pow(base, t, n)
    if z != 1 and z != nminus1:
        j = 0
        while j < s:
            j += 1
            z = pow(z, 2, n)
            if z == nminus1:
                break
        else:
            return False
    return True
예제 #35
0
    def TonelliShanks(self, element):
        """ Return square root of element if exist.
        assume that characteristic have to be more than three.
        """
        if  self.char == 2:
            return self.sqrt(element) # should be error

        if self.Legendre(element) == -1:
            raise ValueError("There is no solution")

        # symbol and code reference from Cohen, CCANT 1.5.1
        (e, q) = arith1.vp(card(self)-1, 2)

        a = element
        n = self.createElement(self.char+1)
        while self.Legendre(n) != -1:
            n = self.random_element(2, card(self)) # field maybe large
        y = z = n ** q
        r = e
        x = a ** ((q-1) // 2)
        b = a * (x ** 2)
        x = a * x
        while True:
            if b == self.one:
                return x
            m = 1
            while m < r:
                if b ** (2 ** m) == self.one:
                    break
                m = m+1
            if m == r:
                break
            t = y ** (2 ** (r-m-1))
            y = t ** 2
            r = m
            x = x * t
            b = b * y
        raise ValueError("There is no solution")
예제 #36
0
def _prepare_squarefactors(disc):
    """
    Return a list of square factors of disc (=discriminant).

    PRECOND: d is integer
    """
    squarefactors = []
    if disc < 0:
        fund_disc, absd = -1, -disc
    else:
        fund_disc, absd = 1, disc
    v2, absd = arith1.vp(absd, 2)
    if squarefree.trivial_test_ternary(absd):
        fund_disc *= absd
    else:
        for p, e in factor_misc.FactoredInteger(absd):
            if e > 1:
                squareness, oddity = divmod(e, 2)
                squarefactors.append((p, squareness))
                if oddity:
                    fund_disc *= p
            else:
                fund_disc *= p
    if fund_disc & 3 == 1:
        if v2 & 1:
            squareness, oddity = divmod(v2, 2)
            squarefactors.append((2, squareness))
            if oddity:
                fund_disc *= 2
        else:
            squarefactors.append((2, v2 >> 1))
    else: # fund_disc & 3 == 3
        assert v2 >= 2
        fund_disc *= 4
        if v2 > 2:
            squarefactors.append((2, (v2 - 2) >> 1))
    return squarefactors
예제 #37
0
파일: round2.py 프로젝트: nickspoon/part-ii
def _prepare_squarefactors(disc):
    """
    Return a list of square factors of disc (=discriminant).

    PRECOND: d is integer
    """
    squarefactors = []
    if disc < 0:
        fund_disc, absd = -1, -disc
    else:
        fund_disc, absd = 1, disc
    v2, absd = arith1.vp(absd, 2)
    if squarefree.trivial_test_ternary(absd):
        fund_disc *= absd
    else:
        for p, e in factor_misc.FactoredInteger(absd):
            if e > 1:
                squareness, oddity = divmod(e, 2)
                squarefactors.append((p, squareness))
                if oddity:
                    fund_disc *= p
            else:
                fund_disc *= p
    if fund_disc % 4 == 1:
        if v2 % 2:
            squareness, oddity = divmod(v2, 2)
            squarefactors.append((2, squareness))
            if oddity:
                fund_disc *= 2
        else:
            squarefactors.append((2, v2 // 2))
    else: # fund_disc % 4 == 3
        assert v2 >= 2
        fund_disc *= 4
        if v2 > 2:
            squarefactors.append((2, (v2 - 2) // 2))
    return squarefactors
예제 #38
0
 def testVp(self):
     self.assertEqual((3, 1), arith1.vp(8, 2))
     self.assertEqual((0, 10), arith1.vp(10, 3))
     self.assertEqual((1, 10), arith1.vp(10, 3, 1))
     self.assertEqual((3, 10), arith1.vp(270, 3))
예제 #39
0
파일: mpqs.py 프로젝트: nickspoon/part-ii
def mpqs(n, s=0, f=0, m=0):
    """
    This is main function of MPQS.
    Arguments are (composite_number, sieve_range, factorbase_size, multiplier)
    You must input composite_number at least.
    """
    T = time.time()
    M = MPQS(n, s, f, m)
    _log.info("Sieve range is [ %d , %d ] , Factorbase size = %d , Max Factorbase %d" % (M.move_range[0], M.move_range[-1], len(M.FB), M.maxFB))
    M.get_vector()
    N = M.number // M.multiplier
    V = Elimination(M.smooth)
    A = V.gaussian()
    _log.info("Found %d linerly dependent relations" % len(A))
    answerX_Y = []
    N_prime_factors = []
    N_factors = []
    output = []
    for i in A:
        B = V.history[i].keys()
        X = 1
        Y = 1
        for j in B:
            X *= M.smooth[j][1][0]
            Y *= M.smooth[j][1][1]
            Y = Y % M.number
        X = sqrt_modn(X, M.number)
        if X != Y:
            answerX_Y.append(X-Y)
    NN = 1
    for k in answerX_Y:
        factor = gcd.gcd(k, N)
        if factor not in N_factors and factor != 1 and factor != N \
               and factor not in N_prime_factors:
            if prime.primeq(factor):
                NN = NN*factor
                N_prime_factors.append(factor)
            else:
                N_factors.append(factor)

    _log.info("Total time = %f sec" % (time.time() - T))

    if NN == N:
        _log.debug("Factored completely!")
        N_prime_factors.sort()
        for p in N_prime_factors:
            N = N // p
            i = arith1.vp(N, p, 1)[0]
            output.append((p, i))
        return output
    elif NN != 1:
        f = N // NN
        if prime.primeq(f):
            N_prime_factors.append(f)
            _log.debug("Factored completely !")
            N_prime_factors.sort()
            for p in N_prime_factors:
                N = N // p
                i = arith1.vp(N, p, 1)[0]
                output.append((p, i))
            return output

    for F in N_factors:
        for FF in N_factors:
            if F != FF:
                Q = gcd.gcd(F, FF)
                if prime.primeq(Q) and Q not in N_prime_factors:
                    N_prime_factors.append(Q)
                    NN = NN*Q

    N_prime_factors.sort()
    for P in N_prime_factors:
        i, N = arith1.vp(N, P)
        output.append((P, i))

    if  N == 1:
        _log.debug("Factored completely!! ")
        return output

    for F in N_factors:
        g = gcd.gcd(N, F)
        if prime.primeq(g):
            N_prime_factors.append(g)
            N = N // g
            i = arith1.vp(N, g, 1)[0]
            output.append((g, i))
    if N == 1:
        _log.debug("Factored completely !! ")
        return output
    elif prime.primeq(N):
        output.append((N, 1))
        _log.debug("Factored completely!!! ")
        return output
    else:
        N_factors.sort()
        _log.error("Sorry, not factored completely")
        return output, N_factors