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)
def rhomethod(n, **options): """ Find a non-trivial factor of n using Pollard's rho algorithm. The implementation refers the explanation in C.Pomerance's book. """ # verbosity verbose = options.get('verbose', False) if not verbose: _silence() if n <= 3: return 1 g = n while g == n: # x^2 + a is iterated. Starting value x = u. a = bigrandom.randrange(1, n - 2) u = v = bigrandom.randrange(0, n - 1) _log.info("%d %d" % (a, u)) g = gcd.gcd((v**2 + v + a) % n - u, n) while g == 1: u = (u**2 + a) % n v = ((pow(v, 2, n) + a)**2 + a) % n g = gcd.gcd(v - u, n) if not verbose: _verbose() return g
def rhomethod(n, **options): """ Find a non-trivial factor of n using Pollard's rho algorithm. The implementation refers the explanation in C.Pomerance's book. """ # verbosity verbose = options.get('verbose', False) if not verbose: _silence() if n <= 3: return 1 g = n while g == n: a = bigrandom.randrange(1, n-2) u = v = bigrandom.randrange(0, n-1) _log.info("%d %d" % (a, u)) g = gcd.gcd((v**2 + v + a) % n - u, n) while g == 1: u = (u**2 + a) % n v = ((pow(v, 2, n) + a)**2 + a) % n g = gcd.gcd(v - u, n) if not verbose: _verbose() return g
def aks(n): """ AKS ( Cyclotomic Congruence Test ) primality test for a natural number. Input: a natural number n ( n > 1 ). Output: n is prime => return True n is not prime => return False. """ import nzmath.multiplicative as multiplicative if arith1.powerDetection(n)[1] != 1: #Power Detection return False lg = math.log(n, 2) k = int(lg * lg) start = 3 while 1: d = gcd.gcd(start, n) if 1 < d < n: return False x = n % start N = x for i in range(1, k + 1): if N == 1: break N = (N * x) % start if i == k: r = start break start += 1 d = gcd.gcd(r, n) if 1 < d < n: return False if n <= r: return True e = multiplicative.euler(r) #Cyclotomic Conguence e = math.sqrt(e) e = int(e * lg) for b in range(1, e + 1): f = array_poly.ArrayPolyMod([b, 1], n) total = array_poly.ArrayPolyMod([1], n) count = n while count > 0: if count & 1: total = total * f total = _aks_mod(total, r) f = f.power() f = _aks_mod(f, r) count = count >> 1 total_poly = total.coefficients_to_dict() if total_poly != {0: b, n % r: 1}: return False return True
def pmom(n, **options): """ This function tries to find a non-trivial factor of n using Algorithm 8.8.2 (p-1 first stage) of Cohen's book. In case of N = pow(2,i), this program will not terminate. """ # verbosity verbose = options.get('verbose', False) if not verbose: _silence() # initialize x = y = 2 primes = [] if 'B' in options: B = options['B'] else: B = 10000 for q in prime.generator(): primes.append(q) if q > B: if gcd.gcd(x - 1, n) == 1: if not verbose: _verbose() return 1 x = y break q1 = q l = B // q while q1 <= l: q1 *= q x = pow(x, q1, n) if len(primes) >= 20: if gcd.gcd(x - 1, n) == 1: primes, y = [], x else: x = y break for q in primes: q1 = q while q1 <= B: x = pow(x, q, n) g = gcd.gcd(x - 1, n) if g != 1: if not verbose: _verbose() if g == n: return 1 return g q1 *= q
def pmom(n, **options): """ This function tries to find a non-trivial factor of n using Algorithm 8.8.2 (p-1 first stage) of Cohen's book. In case of N = pow(2,i), this program will not terminate. """ # verbosity verbose = options.get('verbose', False) if not verbose: _silence() # initialize x , B = 2 , 10000001 y = x primes = [] for q in prime.generator(): primes.append(q) if q > B: if gcd.gcd(x-1, n) == 1: if not verbose: _verbose() return 1 x = y break q1 = q l = B//q while q1 <= l: q1 *= q x = pow(x, q1, n) if len(primes) >= 20: if gcd.gcd(x-1, n) == 1: primes, y = [], x else: x = y break for q in primes: q1 = q while q1 <= B: x = pow(x, q, n) g = gcd.gcd(x-1, n) if g != 1: if not verbose: _verbose() if g == n: return 1 return g q1 *= q
def sub8(self, q, k, n, J): s = J.get(3, q) J3 = J.get(3, q) m = len(s) sx_z = {1: s} x = 3 step = 2 while m > x: z_4b = Zeta(m) i = x j = 1 while i != 0: z_4b[j] = J3[i] i = (i + x) % m j += 1 z_4b[0] = J3[0] sx_z[x] = z_4b s = pow(sx_z[x], x, n) * s step = 8 - step x += step s = pow(s, n // m, n) r = n % m step = 2 x = 3 while m > x: c = r * x if c > m: s = pow(sx_z[x], c // m, n) * s step = 8 - step x += step r = r & 7 if r == 5 or r == 7: s = J.get(2, q).promote(m) * s s = +(s % n) if s.weight() == 1 and s.mass() == 1: if gcd.gcd(m, s.z.index(1)) == 1 and pow(q, (n - 1) >> 1, n) == n - 1: self.done(2) return True elif s.weight() == 1 and s.mass() == n - 1: if gcd.gcd(m, s.z.index(n - 1)) == 1 and pow(q, (n - 1) >> 1, n) == n - 1: self.done(2) return True return False
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
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)
def change_base_module(self, other_base): """ change base_module to other_base_module (i.e. represent with respect to base_module) """ if self.base == other_base: return self n = self.number_field.degree if isinstance(other_base, list): other_base = matrix.FieldSquareMatrix(n, [vector.Vector(other_base[i]) for i in range(n)]) else: # matrix repr other_base = other_base.copy() tr_base_mat, tr_base_denom = _toIntegerMatrix( other_base.inverse(self.base)) denom = tr_base_denom * self.denominator mat_repr, numer = _toIntegerMatrix( tr_base_mat * self.mat_repr, 2) d = gcd.gcd(denom, numer) if d != 1: denom = ring.exact_division(denom, d) numer = ring.exact_division(numer, d) if numer != 1: mat_repr = numer * mat_repr return self.__class__([mat_repr, denom], self.number_field, other_base)
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)
def to_HNFRepresentation(self): """ Transform self to the corresponding ideal as HNF representation """ int_ring = self.number_field.integer_ring() n = self.number_field.degree polynomial = self.number_field.polynomial k = len(self.generator) # separate coeff and denom for generators and base gen_denom = reduce( gcd.lcm, (self.generator[j].denom for j in range(k)) ) gen_list = [gen_denom * self.generator[j] for j in range(k)] base_int, base_denom = _toIntegerMatrix(int_ring) base_alg = [BasicAlgNumber([base_int[j], 1], polynomial) for j in range(1, n + 1)] repr_mat_list = [] for gen in gen_list: for base in base_alg: new_gen = gen * base repr_mat_list.append( vector.Vector([new_gen.coeff[j] for j in range(n)])) mat_repr = matrix.RingMatrix(n, n * k, repr_mat_list) new_mat_repr, numer = _toIntegerMatrix(mat_repr, 2) denom = gen_denom * base_denom denom_gcd = gcd.gcd(numer, denom) if denom_gcd != 1: denom = ring.exact_division(denom, denom_gcd) numer = ring.exact_division(numer, denom_gcd) if numer != 1: new_mat_repr = numer * new_mat_repr else: new_mat_repr = mat_repr return Ideal([new_mat_repr, denom], self.number_field)
def qs(n, s, f): """ This is main function of QS Arguments are (composite_number, sieve_range, factorbase_size) You must input these 3 arguments. """ a = time.time() Q = QS(n, s, f) _log.info("Sieve range is [ %d , %d ] , Factorbase size = %d , Max Factorbase %d" % (Q.move_range[0], Q.move_range[-1], len(Q.FB), Q.maxFB)) Q.run_sieve() V = Elimination(Q.smooth) A = V.gaussian() _log.info("Found %d linearly dependent relations" % len(A)) answerX_Y = [] N_factors = [] for i in A: B = V.history[i].keys() X = 1 Y = 1 for j in B: X *= Q.smooth[j][1][0] Y *= Q.smooth[j][1][1] Y = Y % Q.number X = sqrt_modn(X, Q.number) answerX_Y.append(X-Y) for k in answerX_Y: if k != 0: factor = gcd.gcd(k, Q.number) if factor not in N_factors and factor != 1 and \ factor != Q.number and prime.primeq(factor) == 1: N_factors.append(factor) N_factors.sort() _log.info("Total time = %f sec" % (time.time()-a)) _log.info(str(N_factors))
def get_random_curve_with_point(cls, curve_type, n, bounds): """ Return the curve with parameter C and a point Q on the curve, according to the curve_type, factorization target n and the bounds for stages. curve_type should be one of the module constants corresponding to parameters: S: Suyama's parameter selection strategy B: Bernstein's [2:1], [16,18,4,2] A1: Asuncion's [2:1], [4,14,1,1] A2: Asuncion's [2:1], [16,174,4,41] A3: Asuncion's [3:1], [9,48,1,2] A4: Asuncion's [3:1], [9,39,1,1] A5: Asuncion's [4:1], [16,84,1,1] N3: Nakamura's [2:1], [28,22,7,3] This is a class method. """ bound = bounds.first if curve_type not in cls._CURVE_TYPES: raise ValueError("Input curve_type is wrong.") if curve_type == SUYAMA: t = n while _gcd.gcd(t, n) != 1: sigma = random.randrange(6, bound + 1) u, v = (sigma**2 - 5) % n, (4 * sigma) % n t = 4 * (u**3) * v d = _arith1.inverse(t, n) curve = cls((((u - v)**3 * (3 * u + v)) * d - 2) % n) start_point = Point(pow(u, 3, n), pow(v, 3, n)) elif curve_type == BERNSTEIN: d = random.randrange(1, bound + 1) start_point = Point(2, 1) curve = cls((4 * d + 2) % n) elif curve_type == ASUNCION1: d = random.randrange(1, bound + 1) start_point = Point(2, 1) curve = cls((d + 1) % n) elif curve_type == ASUNCION2: d = random.randrange(1, bound + 1) start_point = Point(2, 1) curve = cls((4 * d + 41) % n) elif curve_type == ASUNCION3: d = random.randrange(1, bound + 1) start_point = Point(3, 1) curve = cls((d + 2) % n) elif curve_type == ASUNCION4: d = random.randrange(1, bound + 1) start_point = Point(3, 1) curve = cls((d + 1) % n) elif curve_type == ASUNCION5: d = random.randrange(1, bound + 1) start_point = Point(4, 1) curve = cls((d + 1) % n) elif curve_type == NAKAMURA3: d = random.randrange(1, bound + 1) start_point = Point(2, 1) curve = cls((7 * d + 3) % n) return curve, start_point
def sub8(self, q, k, n, J): s = J.get(3, q) J3 = J.get(3, q) m = len(s) sx_z = {1:s} x = 3 step = 2 while m > x: z_4b = Zeta(m) i = x j = 1 while i != 0: z_4b[j] = J3[i] i = (i + x) % m j += 1 z_4b[0] = J3[0] sx_z[x] = z_4b s = pow(sx_z[x], x, n) * s step = 8 - step x += step s = pow(s, n//m, n) r = n % m step = 2 x = 3 while m > x: c = r*x if c > m: s = pow(sx_z[x], c//m, n) * s step = 8 - step x += step r = r % 8 if r == 5 or r == 7: s = J.get(2, q).promote(m) * s s = +(s % n) if s.weight() == 1 and s.mass() == 1: if gcd.gcd(m, s.z.index(1)) == 1 and pow(q, (n-1)//2, n) == n-1: self.done(2) return True elif s.weight() == 1 and s.mass() == n-1: if gcd.gcd(m, s.z.index(n-1)) == 1 and pow(q, (n-1)//2, n) == n-1: self.done(2) return True return False
def ecm(n, curve_type=A1, incs=3, trials=20, **options): """ Find a factor of n with Elliptic Curve Method. An unsuccessful factorization returns 1. There are a few optional arguments. By 'curve_type', the function choose a family of curves. Please use a module constant to specify the curve_type. The second optional argument 'incs' specifies the number of times for changing bounds. The function repeats factorization trials several times changing curves with a fixed bounds. The last optional argument 'trials' can control how quickly move on to the next higher bounds. """ # verbosity verbose = options.get('verbose', False) if verbose: _log.setLevel(logging.DEBUG) _log.debug("verbose") else: _log.setLevel(logging.NOTSET) # trivial checks if _prime.primeq(n): _log.info("%d is prime!" % n) return n if _gcd.gcd(n, 6) != 1: _log.info("%d is not coprime to 6!" % n) if n % 2 == 0: return 2 if n % 3 == 0: return 3 # main loop bounds = Bounds(n) for inc in range(incs): _log.info("bounds increment %d times" % inc) _log.debug("Bounds B1, B2 = %s" % (bounds, )) for trial in range(trials): _log.info("Trial #: %d" % (trial + 1)) curve, point = Curve.get_random_curve_with_point( curve_type, n, bounds) _log.debug("Curve param: %d" % curve.c) g = stage1(n, bounds, curve, point) if 1 < g < n: return g g = stage2(n, bounds, curve, point) if 1 < g < n: return g bounds.increment() _log.info("ECM 2 step test failed!") if not verbose: _log.setLevel(logging.DEBUG) return 1
def ecm(n, curve_type=A1, incs=3, trials=20, **options): """ Find a factor of n with Elliptic Curve Method. An unsuccessful factorization returns 1. There are a few optional arguments. By 'curve_type', the function choose a family of curves. Please use a module constant to specify the curve_type. The second optional argument 'incs' specifies the number of times for changing bounds. The function repeats factorization trials several times changing curves with a fixed bounds. The last optional argument 'trials' can control how quickly move on to the next higher bounds. """ # verbosity verbose = options.get('verbose', False) if verbose: _log.setLevel(logging.DEBUG) _log.debug("verbose") else: _log.setLevel(logging.NOTSET) # trivial checks if _prime.primeq(n): _log.info("%d is prime!" % n) return n if _gcd.gcd(n, 6) != 1: _log.info("%d is not coprime to 6!" % n) if n % 2 == 0: return 2 if n % 3 == 0: return 3 # main loop bounds = Bounds(n) for inc in range(incs): _log.info("bounds increment %d times" % inc) _log.debug("Bounds B1, B2 = %s" % (bounds,)) for trial in range(trials): _log.info("Trial #: %d" % (trial + 1)) curve, point = Curve.get_random_curve_with_point(curve_type, n, bounds) _log.debug("Curve param: %d" % curve.c) g = stage1(n, bounds, curve, point) if 1 < g < n: return g g = stage2(n, bounds, curve, point) if 1 < g < n: return g bounds.increment() _log.info("ECM 2 step test failed!") if not verbose: _log.setLevel(logging.DEBUG) return 1
def twoElementRepresentation(self): # refer to [Poh-Zas] # Algorithm 4.7.10 and Exercise 29 in CCANT """ Reduce the number of generator to only two elements Warning: If self is not a prime ideal, this method is not efficient """ k = len(self.generator) gen_denom = reduce( gcd.lcm, (self.generator[j].denom for j in range(k)) ) gen_list = [gen_denom * self.generator[j] for j in range(k)] int_I = Ideal_with_generator(gen_list) R = 1 norm_I = int_I.norm() l_I = int_I.smallest_rational() if l_I.denominator > 1: raise ValueError, "input an integral ideal" else: l_I = l_I.numerator while True: lmda = [R for i in range(k)] while lmda[0] > 0: alpha = lmda[0] * gen_list[0] for i in range(1, k): alpha += lmda[i] * gen_list[i] if gcd.gcd( norm_I, ring.exact_division( alpha.norm(), norm_I) ) == 1 or gcd.gcd( norm_I, ring.exact_division( (alpha + l_I).norm(), norm_I)) == 1: l_I_ori = BasicAlgNumber( [[l_I] + [0] * (self.number_field.degree - 1), gen_denom], self.number_field.polynomial) alpha_ori = BasicAlgNumber([alpha.coeff, gen_denom], self.number_field.polynomial) return Ideal_with_generator([l_I_ori, alpha_ori]) for j in range(k)[::-1]: if lmda[j] != -R: lmda[j] -= 1 break else: lmda[j] = R R += 1
def twoElementRepresentation(self): # refer to [Poh-Zas] # Algorithm 4.7.10 and Exercise 29 in CCANT """ Reduce the number of generator to only two elements Warning: If self is not a prime ideal, this method is not efficient """ k = len(self.generator) gen_denom = reduce(gcd.lcm, (self.generator[j].denom for j in range(k))) gen_list = [gen_denom * self.generator[j] for j in range(k)] int_I = Ideal_with_generator(gen_list) R = 1 norm_I = int_I.norm() l_I = int_I.smallest_rational() if l_I.denominator > 1: raise ValueError, "input an integral ideal" else: l_I = l_I.numerator while True: lmda = [R for i in range(k)] while lmda[0] > 0: alpha = lmda[0] * gen_list[0] for i in range(1, k): alpha += lmda[i] * gen_list[i] if gcd.gcd(norm_I, ring.exact_division( alpha.norm(), norm_I)) == 1 or gcd.gcd( norm_I, ring.exact_division( (alpha + l_I).norm(), norm_I)) == 1: l_I_ori = BasicAlgNumber( [[l_I] + [0] * (self.number_field.degree - 1), gen_denom], self.number_field.polynomial) alpha_ori = BasicAlgNumber([alpha.coeff, gen_denom], self.number_field.polynomial) return Ideal_with_generator([l_I_ori, alpha_ori]) for j in range(k)[::-1]: if lmda[j] != -R: lmda[j] -= 1 break else: lmda[j] = R R += 1
def _simplify(self): """ simplify self.denominator """ mat_repr, numer = _toIntegerMatrix(self.mat_repr, 2) denom_gcd = gcd.gcd(numer, self.denominator) if denom_gcd != 1: self.denominator = ring.exact_division(self.denominator, denom_gcd) self.mat_repr = Submodule.fromMatrix( ring.exact_division(numer, denom_gcd) * mat_repr)
def get_random_curve_with_point(cls, curve_type, n, bounds): """ Return the curve with parameter C and a point Q on the curve, according to the curve_type, factorization target n and the bounds for stages. curve_type should be one of the module constants corresponding to parameters: S: Suyama's parameter selection strategy B: Bernstein's [2:1], [16,18,4,2] A1: Asuncion's [2:1], [4,14,1,1] A2: Asuncion's [2:1], [16,174,4,41] A3: Asuncion's [3:1], [9,48,1,2] A4: Asuncion's [3:1], [9,39,1,1] A5: Asuncion's [4:1], [16,84,1,1] This is a class method. """ bound = bounds.first if curve_type not in cls._CURVE_TYPES: raise ValueError("Input curve_type is wrong.") if curve_type == SUYAMA: t = n while _gcd.gcd(t, n) != 1: sigma = random.randrange(6, bound + 1) u, v = (sigma**2 - 5) % n, (4*sigma) % n t = 4*(u**3)*v d = _arith1.inverse(t, n) curve = cls((((u - v)**3 * (3*u + v)) * d - 2) % n) start_point = Point(pow(u, 3, n), pow(v, 3, n)) elif curve_type == BERNSTEIN: d = random.randrange(1, bound + 1) start_point = Point(2, 1) curve = cls((4*d + 2) % n) elif curve_type == ASUNCION1: d = random.randrange(1, bound + 1) start_point = Point(2, 1) curve = cls((d + 1) % n) elif curve_type == ASUNCION2: d = random.randrange(1, bound + 1) start_point = Point(2, 1) curve = cls((4*d + 41) % n) elif curve_type == ASUNCION3: d = random.randrange(1, bound + 1) start_point = Point(3, 1) curve = cls((d + 2) % n) elif curve_type == ASUNCION4: d = random.randrange(1, bound + 1) start_point = Point(3, 1) curve = cls((d + 1) % n) elif curve_type == ASUNCION5: d = random.randrange(1, bound + 1) start_point = Point(4, 1) curve = cls((d + 1) % n) return curve, start_point
def bigprimeq(z): """ Giving up rigorous proof of primality, return True for a probable prime. """ if int(z) != z: raise ValueError("non-integer for primeq()") elif z <= 1: return False elif gcd.gcd(z, PRIMONIAL_31) > 1: return (z in PRIMES_LE_31) return millerRabin(z)
def bigprimeq(z): """ Giving up rigorous proof of primality, return True for a probable prime. """ if int(z) != z: raise ValueError("non-integer for primeq()") elif z <= 1: return False elif gcd.gcd(z, 510510) > 1: return (z in (2, 3, 5, 7, 11, 13, 17)) return millerRabin(z)
def _toIntegerMatrix(mat, option=0): """ transform a (including integral) rational matrix to some integral matrix as the following [option] 0: return integral-matrix, denominator (mat = 1/denominator * integral-matrix) 1: return integral-matrix, denominator, numerator (mat = numerator/denominator * reduced-int-matrix) 2: return integral-matrix, numerator (assuming mat is integral) (mat = numerator * numerator-reduced-rational-matrix) """ def getDenominator(ele): """ get the denominator of ele """ if rational.isIntegerObject(ele): return 1 else: # rational return ele.denominator def getNumerator(ele): """ get the numerator of ele """ if rational.isIntegerObject(ele): return ele else: # rational return ele.numerator if isinstance(mat, vector.Vector): mat = mat.toMatrix(True) if option <= 1: denom = mat.reduce( lambda x, y: gcd.lcm(x, getDenominator(y)), 1) new_mat = mat.map( lambda x: getNumerator(x) * ring.exact_division( denom, getDenominator(x))) if option == 0: return Submodule.fromMatrix(new_mat), denom else: new_mat = mat numer = new_mat.reduce( lambda x, y: gcd.gcd(x, getNumerator(y))) if numer != 0: new_mat2 = new_mat.map( lambda x: ring.exact_division(getNumerator(x), numer)) else: new_mat2 = new_mat if option == 1: return Submodule.fromMatrix(new_mat2), denom, numer else: return Submodule.fromMatrix(new_mat2), numer
def stage1(n, bounds, C, Q): """ ECM stage 1 for factoring n. The upper bound for primes to be tested is bounds.first. It uses curve C and starting point Q. """ for p in _prime.generator_eratosthenes(bounds.first): q = p while q < bounds.first: Q = mul(Q, p, C, n) q *= p g = _gcd.gcd(Q.z, n) _log.debug("Stage 1: %d" % g) return g
def stage2(n, bounds, C, Q): """ ECM stage 2 for factoring n. The upper bounds for primes to be tested are stored in bounds. It uses curve C and starting point Q. """ d1 = bounds.first + random.randrange(1, 16) d2 = 0 while _gcd.gcd(d1, d2) != 1: d2 = random.randrange(2, d1//5 + 1) # We want to keep d2 small for i in range(1, bounds.second//d1): if _gcd.gcd(i, d2) != 1: continue for j in range(1, d1//2): if _gcd.gcd(j, d1) == 1: Q = mul(Q, i*d1 + j*d2, C, n) if i*d1 - j*d2 > bounds.first: Q = mul(Q, i*d1 - j*d2, C, n) g = _gcd.gcd(Q.z, n) if 1 < g < n: _log.debug("Stage 2: %d" % g) return g _log.debug("Stage 2: %d" % g) return 1
def stage2(n, bounds, C, Q): """ ECM stage 2 for factoring n. The upper bounds for primes to be tested are stored in bounds. It uses curve C and starting point Q. """ d1 = bounds.first + random.randrange(1, 16) d2 = 0 while _gcd.gcd(d1, d2) != 1: d2 = random.randrange(2, d1 // 5 + 1) # We want to keep d2 small for i in range(1, bounds.second // d1): if _gcd.gcd(i, d2) != 1: continue for j in range(1, d1 // 2): if _gcd.gcd(j, d1) == 1: Q = mul(Q, i * d1 + j * d2, C, n) if i * d1 - j * d2 > bounds.first: Q = mul(Q, i * d1 - j * d2, C, n) g = _gcd.gcd(Q.z, n) if 1 < g < n: _log.debug("Stage 2: %d" % g) return g _log.debug("Stage 2: %d" % g) return 1
def _isprime(n, pdivisors=None): """ Return True iff n is prime. The check is done without APR. Assume that n is very small (less than 10**12) or prime factorization of n - 1 is known (prime divisors are passed to the optional argument pdivisors as a sequence). """ if gcd.gcd(n, PRIMONIAL_31) > 1: return n in PRIMES_LE_31 elif n < 10**12: # 1369 == 37**2 # 1662803 is the only prime base in smallSpsp which has not checked return n < 1369 or n == 1662803 or smallSpsp(n) else: return full_euler(n, pdivisors)
def subodd(self, p, q, n, J): """ Return the sub result for odd key 'p'. If it is True, the status of 'p' is flipped to 'done'. """ s = J.get(1, p, q) Jpq = J.get(1, p, q) m = s.size for x in range(2, m): if x % p == 0: continue sx = Zeta(m) i = x j = 1 while i > 0: sx[j] = Jpq[i] i = (i + x) % m j += 1 sx[0] = Jpq[0] sx = pow(sx, x, n) s = s*sx % n s = pow(s, n//m, n) r = n % m t = 1 for x in range(1, m): if x % p == 0: continue c = (r*x) // m if c: tx = Zeta(m) i = x j = 1 while i > 0: tx[j] = Jpq[i] i = (i + x) % m j += 1 tx[0] = Jpq[0] tx = pow(tx, c, n) t = t*tx % n s = +(t*s % n) if s.weight() == 1 and s.mass() == 1: for i in range(1, m): if gcd.gcd(m, s.z.index(1)) == 1: self.done(p) return True return False
def subodd(self, p, q, n, J): """ Return the sub result for odd key 'p'. If it is True, the status of 'p' is flipped to 'done'. """ s = J.get(1, p, q) Jpq = J.get(1, p, q) m = s.size for x in range(2, m): if x % p == 0: continue sx = Zeta(m) i = x j = 1 while i > 0: sx[j] = Jpq[i] i = (i + x) % m j += 1 sx[0] = Jpq[0] sx = pow(sx, x, n) s = s * sx % n s = pow(s, n // m, n) r = n % m t = 1 for x in range(1, m): if x % p == 0: continue c = (r * x) // m if c: tx = Zeta(m) i = x j = 1 while i > 0: tx[j] = Jpq[i] i = (i + x) % m j += 1 tx[0] = Jpq[0] tx = pow(tx, c, n) t = t * tx % n s = +(t * s % n) if s.weight() == 1 and s.mass() == 1: for i in range(1, m): if gcd.gcd(m, s.z.index(1)) == 1: self.done(p) return True return False
def __init__(self, valuelist, polynomial, precompute=False): if len(polynomial) != len(valuelist[0])+1: raise ValueError self.value = valuelist self.coeff = valuelist[0] self.denom = valuelist[1] self.degree = len(polynomial) - 1 self.polynomial = polynomial self.field = NumberField(self.polynomial) Gcd = gcd.gcd_of_list(self.coeff) GCD = gcd.gcd(Gcd[0], self.denom) if GCD != 1: self.coeff = [i//GCD for i in self.coeff] self.denom = self.denom//GCD if precompute: self.getConj() self.getApprox() self.getCharPoly()
def __init__(self, valuelist, polynomial, precompute=False): if len(polynomial) != len(valuelist[0]) + 1: raise ValueError self.value = valuelist self.coeff = valuelist[0] self.denom = valuelist[1] self.degree = len(polynomial) - 1 self.polynomial = polynomial self.field = NumberField(self.polynomial) Gcd = gcd.gcd_of_list(self.coeff) GCD = gcd.gcd(Gcd[0], self.denom) if GCD != 1: self.coeff = [i // GCD for i in self.coeff] self.denom = self.denom // GCD if precompute: self.getConj() self.getApprox() self.getCharPoly()
def _scalar_mul(self, other): """ return other * self, assuming other is a scalar (i.e. an element of self.number_field) """ # use other is an element of higher or lower degree number field ? #if other.getRing() != self.number_field: # raise NotImplementedError( # "other is not a element of number field") if not isinstance(other, BasicAlgNumber): try: other = other.ch_basic() except: raise NotImplementedError( "other is not an element of a number field") # represent other with respect to self.base other_repr, pseudo_other_denom = _toIntegerMatrix( self.base.inverse(vector.Vector(other.coeff))) other_repr = other_repr[1] # compute mul using self.base's multiplication base_mul = self._base_multiplication() n = self.number_field.degree mat_repr = [] for k in range(1, self.mat_repr.column + 1): mat_repr_ele = vector.Vector([0] * n) for i1 in range(1, n + 1): for i2 in range(1, n + 1): mat_repr_ele += self.mat_repr[ i1, k] * other_repr[i2] * _symmetric_element( i1, i2, base_mul) mat_repr.append(mat_repr_ele) mat_repr, denom, numer = _toIntegerMatrix( matrix.FieldMatrix(n, len(mat_repr), mat_repr), 1) denom = self.denominator * pseudo_other_denom * other.denom * denom gcds = gcd.gcd(denom, numer) if gcds != 1: denom = ring.exact_division(denom, gcds) numer = ring.exact_division(numer, gcds) if numer != 1: mat_repr = numer * mat_repr else: mat_repr = mat_repr return self.__class__([mat_repr, denom], self.number_field, self.base)
def _scalar_mul(self, other): """ return other * self, assuming other is a scalar (i.e. an element of self.number_field) """ # use other is an element of higher or lower degree number field ? #if other.getRing() != self.number_field: # raise NotImplementedError( # "other is not a element of number field") if not isinstance(other, BasicAlgNumber): try: other = other.ch_basic() except: raise NotImplementedError( "other is not an element of a number field") # represent other with respect to self.base other_repr, pseudo_other_denom = _toIntegerMatrix( self.base.inverse(vector.Vector(other.coeff))) other_repr = other_repr[1] # compute mul using self.base's multiplication base_mul = self._base_multiplication() n = self.number_field.degree mat_repr = [] for k in range(1, self.mat_repr.column +1): mat_repr_ele = vector.Vector([0] * n) for i1 in range(1, n + 1): for i2 in range(1, n + 1): mat_repr_ele += self.mat_repr[i1, k] * other_repr[ i2] * _symmetric_element(i1, i2, base_mul) mat_repr.append(mat_repr_ele) mat_repr, denom, numer = _toIntegerMatrix( matrix.FieldMatrix(n, len(mat_repr), mat_repr), 1) denom = self.denominator * pseudo_other_denom * other.denom * denom gcds = gcd.gcd(denom, numer) if gcds != 1: denom = ring.exact_division(denom, gcds) numer = ring.exact_division(numer, gcds) if numer != 1: mat_repr = numer * mat_repr else: mat_repr = mat_repr return self.__class__([mat_repr, denom], self.number_field, self.base)
def mpqsfind(n, s=0, f=0, m=0, verbose=False): """ This is main function of MPQS. Arguments are (composite_number, sieve_range, factorbase_size, multiplier) You must input composite_number at least. """ # verbosity if verbose: _log.setLevel(logging.DEBUG) _log.debug("verbose") else: _log.setLevel(logging.NOTSET) starttime = time.time() M = MPQS(n, s, f, m) _log.info("Sieve range is [%d, %d]" % (M.move_range[0], M.move_range[-1])) _log.info("Factorbase size = %d, Max Factorbase %d" % (len(M.FB), M.maxFB)) M.get_vector() N = M.number // M.multiplier V = Elimination(M.smooth) A = V.gaussian() _log.info("Found %d linearly dependent relations" % len(A)) differences = [] 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 = arith1.floorsqrt(X) % M.number if X != Y: differences.append(X-Y) for diff in differences: divisor = gcd.gcd(diff, N) if 1 < divisor < N: _log.info("Total time = %f sec" % (time.time() - starttime)) return divisor
def primeq(n): """ A convenient function for primatilty test. It uses one of trialDivision, smallSpsp or apr depending on the size of n. """ if int(n) != n: raise ValueError("non-integer for primeq()") if n <= 1: return False if gcd.gcd(n, PRIMONIAL_31) > 1: return n in PRIMES_LE_31 if n < 2000000: return trialDivision(n) if not smallSpsp(n): return False if n < 10**12: return True if not GRH: return apr(n) else: return miller(n)
def primeq(n): """ A convinient function for primatilty test. It uses one of trialDivision, smallSpsp or apr depending on the size of n. """ if int(n) != n: raise ValueError("non-integer for primeq()") if n <= 1: return False if gcd.gcd(n, 510510) > 1: return (n in (2, 3, 5, 7, 11, 13, 17)) if n < 2000000: return trialDivision(n) if not smallSpsp(n): return False if n < 10 ** 12: return True if not GRH: return apr(n) else: return miller(n)
def _kernel_of_qpow(omega, q, p, minpoly, n): """ Return the kernel of q-th powering, which is a linear map over Fp. q is a power of p which exceeds n. (omega_j^q (mod theminpoly) = \sum a_i_j omega_i a_i_j in Fp) """ omega_poly = omega.get_polynomials() denom = omega.denominator theminpoly = minpoly.to_field_polynomial() field_p = finitefield.FinitePrimeField.getInstance(p) zero = field_p.zero qpow = matrix.zeroMatrix(n, n, field_p) # Fp matrix for j in range(n): a_j = [zero] * n omega_poly_j = uniutil.polynomial(enumerate(omega.basis[j]), Z) omega_j_qpow = pow(omega_poly_j, q, minpoly) redundancy = gcd.gcd(omega_j_qpow.content(), denom ** q) omega_j_qpow = omega_j_qpow.coefficients_map(lambda c: c // redundancy) essential = denom ** q // redundancy while omega_j_qpow: i = omega_j_qpow.degree() a_ji = int(omega_j_qpow[i] / (omega_poly[i][i] * essential)) omega_j_qpow -= a_ji * (omega_poly[i] * essential) if omega_j_qpow.degree() < i: a_j[i] = field_p.createElement(a_ji) else: _log.debug("%s / %d" % (str(omega_j_qpow), essential)) _log.debug("j = %d, a_ji = %s" % (j, a_ji)) raise ValueError("omega is not a basis") qpow.setColumn(j + 1, a_j) result = qpow.kernel() if result is None: _log.debug("(_k_q): trivial kernel") return matrix.zeroMatrix(n, 1, field_p) else: return result
def _rational_mul(self, other): """ return other * self, assuming other is a rational element """ if rational.isIntegerObject(other): other_numerator = rational.Integer(other) other_denominator = rational.Integer(1) else: other_numerator = other.numerator other_denominator = other.denominator denom_gcd = gcd.gcd(self.denominator, other_numerator) if denom_gcd != 1: new_denominator = ring.exact_division( self.denominator, denom_gcd) * other_denominator multiply_num = other_numerator.exact_division(denom_gcd) else: new_denominator = self.denominator * other_denominator multiply_num = other_numerator new_module = self.__class__( [self.mat_repr * multiply_num, new_denominator], self.number_field, self.base, self.mat_repr.ishnf) new_module._simplify() return new_module
def inverse(self): """ Return the inverse ideal of self """ # Algorithm 4.8.21 in CCANT field = self.number_field # step 1 (Note that det(T)T^-1=(adjugate matrix of T)) T = Ideal._precompute_for_different(field) d = int(T.determinant()) inv_different = Ideal([T.adjugateMatrix(), 1], field, field.integer_ring()) # step 2 inv_I = self * inv_different # already base is taken for integer_ring inv_I.toHNF() # step 3 inv_mat, denom = _toIntegerMatrix( (inv_I.mat_repr.transpose() * T).inverse(), 0) numer = d * inv_I.denominator gcd_denom = gcd.gcd(denom, numer) if gcd_denom != 1: denom = ring.exact_division(denom, gcd_denom) numer = ring.exact_division(numer, gcd_denom) return Ideal([numer * inv_mat, denom], field, field.integer_ring())
def __mul__(self, other): if isinstance(other, BasicAlgNumber): d = self.denom*other.denom f = zpoly(self.polynomial) g = zpoly(self.coeff) h = zpoly(other.coeff) j = (g * h).pseudo_mod(f) jcoeff = [j[i] for i in range(self.degree)] return BasicAlgNumber([jcoeff, d], self.polynomial) elif isinstance(other, (int, long)): Coeff = [i*other for i in self.coeff] return BasicAlgNumber([Coeff, self.denom], self.polynomial) elif isinstance(other, rational.Rational): GCD = gcd.gcd(other.numerator, self.denom) denom = self.denom * other.denominator mul = other.numerator if GCD != 1: denom //= GCD mul //= GCD Coeff = [self.coeff[j] * mul for j in range(self.degree)] return BasicAlgNumber([Coeff, denom], self.polynomial) else: return NotImplemented
def __mul__(self, other): if isinstance(other, BasicAlgNumber): d = self.denom * other.denom f = zpoly(self.polynomial) g = zpoly(self.coeff) h = zpoly(other.coeff) j = (g * h).pseudo_mod(f) jcoeff = [j[i] for i in range(self.degree)] return BasicAlgNumber([jcoeff, d], self.polynomial) elif isinstance(other, int): Coeff = [i * other for i in self.coeff] return BasicAlgNumber([Coeff, self.denom], self.polynomial) elif isinstance(other, rational.Rational): GCD = gcd.gcd(other.numerator, self.denom) denom = self.denom * other.denominator mul = other.numerator if GCD != 1: denom //= GCD mul //= GCD Coeff = [self.coeff[j] * mul for j in range(self.degree)] return BasicAlgNumber([Coeff, denom], self.polynomial) else: return NotImplemented
def _module_mul(self, other): """ return self * other as the multiplication of modules """ #if self.number_field != other.number_field: # raise NotImplementedError if self.base != other.base: new_self = self.change_base_module(other.base) else: new_self = self.copy() base_mul = other._base_multiplication() n = self.number_field.degree new_mat_repr = [] for k1 in range(1, new_self.mat_repr.column + 1): for k2 in range(1, other.mat_repr.column + 1): new_mat_repr_ele = vector.Vector([0] * n) for i1 in range(1, n + 1): for i2 in range(1, n + 1): new_mat_repr_ele += new_self.mat_repr[ i1, k1] * other.mat_repr[i2, k2 ] * _symmetric_element(i1, i2, base_mul) new_mat_repr.append(new_mat_repr_ele) new_mat_repr, denom, numer = _toIntegerMatrix( matrix.FieldMatrix(n, len(new_mat_repr), new_mat_repr), 1) denom = new_self.denominator * other.denominator * denom gcds = gcd.gcd(denom, numer) if gcds != 1: denom = ring.exact_division(denom, gcds) numer = ring.exact_division(numer, gcds) if numer != 1: mat_repr = numer * new_mat_repr else: mat_repr = new_mat_repr sol = self.__class__( [mat_repr, denom], self.number_field, other.base) sol.toHNF() return sol
def represent_element(self, other): """ represent other as a linear combination with generators of self if other not in self, return False Note that we do not assume self.mat_repr is HNF """ #if other not in self.number_field: # return False theta_repr = (self.base * self.mat_repr) theta_repr.toFieldMatrix() pseudo_vect_repr = theta_repr.inverseImage( vector.Vector(other.coeff)) pseudo_vect_repr = pseudo_vect_repr[1] gcd_self_other = gcd.gcd(self.denominator, other.denom) multiply_numerator = self.denominator // gcd_self_other multiply_denominator = other.denom // gcd_self_other def getNumerator_and_Denominator(ele): """ get the pair of numerator and denominator of ele """ if rational.isIntegerObject(ele): return (ele, 1) else: # rational return (ele.numerator, ele.denominator) list_repr = [] for j in range(1, len(pseudo_vect_repr) + 1): try: numer, denom = getNumerator_and_Denominator( pseudo_vect_repr[j]) list_repr_ele = ring.exact_division( numer * multiply_numerator, denom * multiply_denominator) list_repr.append(list_repr_ele) except ValueError: # division is not exact return False return list_repr
def _module_mul(self, other): """ return self * other as the multiplication of modules """ #if self.number_field != other.number_field: # raise NotImplementedError if self.base != other.base: new_self = self.change_base_module(other.base) else: new_self = self.copy() base_mul = other._base_multiplication() n = self.number_field.degree new_mat_repr = [] for k1 in range(1, new_self.mat_repr.column + 1): for k2 in range(1, other.mat_repr.column + 1): new_mat_repr_ele = vector.Vector([0] * n) for i1 in range(1, n + 1): for i2 in range(1, n + 1): new_mat_repr_ele += new_self.mat_repr[ i1, k1] * other.mat_repr[i2, k2] * _symmetric_element( i1, i2, base_mul) new_mat_repr.append(new_mat_repr_ele) new_mat_repr, denom, numer = _toIntegerMatrix( matrix.FieldMatrix(n, len(new_mat_repr), new_mat_repr), 1) denom = new_self.denominator * other.denominator * denom gcds = gcd.gcd(denom, numer) if gcds != 1: denom = ring.exact_division(denom, gcds) numer = ring.exact_division(numer, gcds) if numer != 1: mat_repr = numer * new_mat_repr else: mat_repr = new_mat_repr sol = self.__class__([mat_repr, denom], self.number_field, other.base) sol.toHNF() return sol
def testGcd(self): self.assertEqual(1, gcd.gcd(1, 2)) self.assertEqual(2, gcd.gcd(2, 4)) self.assertEqual(10, gcd.gcd(0, 10)) self.assertEqual(10, gcd.gcd(10, 0)) self.assertEqual(1, gcd.gcd(13, 21))
def _isprime(n): if gcd.gcd(n, 510510) > 1: return (n in (2, 3, 5, 7, 11, 13, 17)) return smallSpsp(n)
def gcd(self, n, m): """ Return the greatest common divisor of given 2 integers. """ a, b = abs(n), abs(m) return Integer(gcd.gcd(a, b))
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