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 _lucas_test_sequence(n, a, b): """ Return x_0, x_1, x_m, x_{m+1} of Lucas sequence of parameter a, b, where m = (n - (a**2 - 4*b / n)) // 2. """ d = a**2 - 4*b if (d >= 0 and arith1.floorsqrt(d) ** 2 == d) \ or not(gcd.coprime(n, 2*a*b*d)): raise ValueError("Choose another parameters.") x_0 = 2 inv_b = arith1.inverse(b, n) x_1 = ((a ** 2) * inv_b - 2) % n # Chain functions def even_step(u): """ 'double' u. """ return (u**2 - x_0) % n def odd_step(u, v): """ 'add' u and v. """ return (u*v - x_1) % n m = (n - arith1.legendre(d, n)) // 2 x_m, x_mplus1 = Lucas_chain(m, even_step, odd_step, x_0, x_1) return x_0, x_1, x_m, x_mplus1
def _lucas_test_sequence(n, a, b): """ Return x_0, x_1, x_m, x_{m+1} of Lucas sequence of parameter a, b, where m = (n - (a**2 - 4*b / n)) // 2. """ d = a**2 - 4 * b if (d >= 0 and arith1.issquare(d) or not (gcd.coprime(n, 2 * a * b * d))): raise ValueError("Choose another parameters.") x_0 = 2 inv_b = arith1.inverse(b, n) x_1 = ((a**2) * inv_b - 2) % n # Chain functions def even_step(u): """ 'double' u. """ return (u**2 - x_0) % n def odd_step(u, v): """ 'add' u and v. """ return (u * v - x_1) % n m = (n - arith1.legendre(d, n)) // 2 x_m, x_mplus1 = _lucas_chain(m, even_step, odd_step, x_0, x_1) return x_0, x_1, x_m, x_mplus1
def next_probable_prime(n, times=20): """ Return the smallest probable prime bigger than the given integer. n ought to be greater than, say, 1000. There is no penalty to use prime.nextPrime(n) for n less than 10**12. This implementation uses miller_rabin to determine the pseudoprimality, and 'times' parameter can be specified. """ n += (1 + (n & 1)) # make n be odd. while not gcd.coprime(n, 510510) or not miller_rabin(n, times): n += 2 return n
def embedding(f_q1, f_q2): """ Return embedding homomorphism function from f_q1 to f_q2, where q1 = p ** k1, q2 = p ** k2 and k1 divides k2. """ if card(f_q1) == card(f_q2): return fqiso(f_q1, f_q2) # search multiplicative generators of both fields and relate them. # 0. initialize basic variables p = f_q2.getCharacteristic() q1, q2 = card(f_q1), card(f_q2) q1_mult_order, q2_mult_order = q1 - 1, q2 - 1 # 1. find a multiplicative generator of f_q2 for i in bigrange.range(p, q2): f_q2_gen = f_q2.createElement(i) if f_q2.order(f_q2_gen) == q2_mult_order: break f_q2_subgen = f_q2_gen**((q2 - 1) // (q1 - 1)) # 2.1 minimal polynomial of g = f_q2_gen ** ((q2 - 1) // (q1 - 1)) # minpoly = (X - g)(X - g**p)...(X - g**(p**(k1 - 1))) q, gpow = 1, f_q2_subgen linear_factors = [] while q < q2: linear_factors.append(univar.BasicPolynomial({0: gpow, 1: f_q2.one})) # finally, raise power (Frobenius map). q *= p gpow **= p minpoly = arith1.product(linear_factors) # 2.2 minpoly has f_q2 coefficints but they are indeed f_p elements minpoly = univar.BasicPolynomial([(d, c.rep[0]) for (d, c) in minpoly]) # 3. find a multiplicative generator of f_q1 for i in bigrange.range(p, q1): f_q1_gen = f_q1.createElement(i) if f_q1.order(f_q1_gen) == q1_mult_order: break # 4. find f_q1_gen ** c of a root of minpoly and let it f_q1_gen for c in bigrange.range(1, q1): if gcd.coprime(c, q1_mult_order): if not minpoly(f_q1_gen**c): break f_q1_gen = f_q1_gen**c # 5. solve DLP: # x_1 = f_q1_gen ** t # (Here uses "brute force" method) x_1 = f_q1.createElement(p) gpow = f_q1_gen for i in bigrange.range(1, q): if gpow == x_1: image_of_x_1 = f_q2_subgen**i break gpow *= f_q1_gen # finally, define a function def f_q1_to_f_q2_homo(f_q1_elem): """ Return the image of the isomorphism of the given element. """ if not f_q1_elem: return f_q2.zero if f_q1_elem.rep.degree() == 0: # F_p elements return f_q2.createElement(f_q1_elem.rep) return f_q1_elem.rep(image_of_x_1) return f_q1_to_f_q2_homo