def quasi_primitive(p, disc_is_minus3): """ Return g s.t. 0) 1 < g < p 1) quadratic nonresidue modulo p and 2) cubic nonresidue modulo p if p == 1 mod 3 with p >= 3, a prime. For p, not a prime, condition 1 means the Jacobi symbol (g/p) != -1, and condition 2 means g doesn't have order dividing (p - 1)//3. if disc_is_minus3 is True, cubic nonresidue check becomes stricter so that g**((p-1)//3) must match with one of the primitive third roots of unity. """ third_order = (p - 1) // 3 for g in bigrange.range(2, p): # if g is not quadratic nonresidue, then skipped. legendre_jacobi = arith1.legendre(g, p) if legendre_jacobi != -1: continue # if p != 1 mod 3 or g is cubic nonresidue, it's what we need. if p % 3 != 1: return g cubic_symbol = pow(g, third_order, p) if cubic_symbol != 1: # g is cubic nonresidue. if disc_is_minus3 and pow(cubic_symbol, 3, p) != 1: # stricter check continue return g else: raise ValueError("p is not prime.")
def fqiso(f_q, gfq): """ Return isomorphism function of extended finite fields from f_q to gfq. """ if f_q is gfq: return lambda x: x if card(f_q) != card(gfq): raise TypeError("both fields must have the same cardinality.") # find a root of f_q's defining polynomial in gfq. p = f_q.getCharacteristic() q = card(f_q) for i in bigrange.range(p, q): root = gfq.createElement(i) if not f_q.modulus(root): break # finally, define a function def f_q_to_gfq_iso(f_q_elem): """ Return the image of the isomorphism of the given element. """ if not f_q_elem: return gfq.zero if f_q_elem.rep.degree() == 0: # F_p elements return gfq.createElement(f_q_elem.rep) return f_q_elem.rep(root) return f_q_to_gfq_iso
def gen_QNR(p, d): ''' generating quardratic residue p -- prime ''' # generate random number g g = random.randrange(2, p) # 1. g has to be quadratic nonresidue # 2. repeat if p = 1 (mod 3) and g^((p-1)/3) = 1 (mod p) ''' while jacobi(g, p) != -1 \ or (p % 3 == 1 and pow(g, (p-1)/3, p) == 1): g = random.randrange(2, p) return g ''' #while True: # g = random.randrange(2, p) for g in bigrange.range(2, p): if jacobi(g, p) != -1: continue if p%3 != 1: return g cube = pow(g, (p-1)/3, p) if cube != 1: if d==-3 and pow(cube, 3, p) != 1: continue return g
def full_euler(n, divisors): """ Return True iff n is prime. The method proves the primality of n by the equality phi(n) = n - 1, where phi denotes the Euler totient. It requires a sequence of all prime divisors of n - 1. Brillhart,J. & Selfridge,J.L., Some Factorizations of $2^n\pm 1$ and Related Results, Math.Comp., Vol.21, 87-96, 1967 """ m_order = n - 1 primes = set(divisors) for g in bigrange.range(2, n): if pow(g, m_order, n) != 1: return False if 2 in primes: jacobi = arith1.legendre(g, n) if jacobi == 0: return False elif jacobi == -1: primes.remove(2) satisfied = [ p for p in primes if p > 2 and pow(g, m_order // p, n) != 1 ] if satisfied: primes.difference_update(satisfied) if not primes: return True return True # only when n=2, flow reaches this line
def _parse_seq(self, options): """ Parse 'options' to define trial sequaence. """ if 'start' in options and 'stop' in options: if 'step' in options: trials = bigrange.range(options['start'], options['stop'], options['step']) else: trials = bigrange.range(options['start'], options['stop']) elif 'iterator' in options: trials = options['iterator'] elif 'eratosthenes' in options: trials = prime.generator_eratosthenes(options['eratosthenes']) elif options['n'] < 1000000: trials = prime.generator_eratosthenes(arith1.floorsqrt(options['n'])) else: trials = prime.generator() return trials
def _parse_seq(self, options): """ Parse 'options' to define trial sequaence. """ if 'start' in options and 'stop' in options: if 'step' in options: trials = bigrange.range(options['start'], options['stop'], options['step']) else: trials = bigrange.range(options['start'], options['stop']) elif 'iterator' in options: trials = options['iterator'] elif 'eratosthenes' in options: trials = prime.generator_eratosthenes(options['eratosthenes']) elif options['n'] < 1000000: trials = prime.generator_eratosthenes( arith1.floorsqrt(options['n'])) else: trials = prime.generator() return trials
def primitive_root(p): """ Return a primitive root of p. """ pd = FactoredInteger(p - 1).proper_divisors() for i in bigrange.range(2, p): for d in pd: if pow(i, (p - 1) // d, p) == 1: break else: return i
def primitive_root(p): """ Return a primitive root of p. """ pd = FactoredInteger(p - 1).proper_divisors() for i in bigrange.range(2, p): for d in pd: if pow(i, (p - 1)//d, p) == 1: break else: return i
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
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
def primitive_element(self): """ Return a primitive element of the field, i.e., a generator of the multiplicative group. """ fullorder = card(self) - 1 if self._orderfactor is None: self._orderfactor = factor_misc.FactoredInteger(fullorder) for i in bigrange.range(self.char, card(self)): g = self.createElement(i) for p in self._orderfactor.prime_divisors(): if g ** (fullorder // p) == self.one: break else: return g
def primitive_element(self): """ Return a primitive element of the field, i.e., a generator of the multiplicative group. """ fullorder = card(self) - 1 if self._orderfactor is None: self._orderfactor = factor_misc.FactoredInteger(fullorder) for i in bigrange.range(self.char, card(self)): g = self.createElement(i) for p in self._orderfactor.prime_divisors(): if g**(fullorder // p) == self.one: break else: return g
def next_disc(d, absbound): """ Return fundamental discriminant D, such that D < d. If there is no D with |d| < |D| < absbound, return False """ # -disc % 16 negdisc_mod16 = (3, 4, 7, 8, 11, 15) for negdisc in bigrange.range(-d + 1, absbound): if negdisc % 16 not in negdisc_mod16: continue if negdisc % 2 == 1 and not squarefree.trial_division(negdisc): continue if arith1.issquare(negdisc): continue return -negdisc return False
def next_disc(d, absbound): """ Return fundamental discriminant D, such that D < d. If there is no D with |d| < |D| < absbound, return False """ # -disc % 16 negdisc_mod16 = (3, 4, 7, 8, 11, 15) for negdisc in bigrange.range(-d + 1, absbound): if negdisc & 15 not in negdisc_mod16: continue if negdisc & 1 and not squarefree.trial_division(negdisc): continue if arith1.issquare(negdisc): continue return -negdisc return False
def trialDivision(n, bound=0): """ Trial division primality test for an odd natural number. Optional second argument is a search bound of primes. If the bound is given and less than the sqaure root of n and True is returned, it only means there is no prime factor less than the bound. """ if bound: m = min(bound, arith1.floorsqrt(n)) else: m = arith1.floorsqrt(n) for p in bigrange.range(3, m + 1, 2): if not (n % p): return False return True
def trialDivision(n, bound=0): """ Trial division primality test for an odd natural number. Optional second argument is a search bound of primes. If the bound is given and less than the sqaure root of n and True is returned, it only means there is no prime factor less than the bound. """ if bound: m = min(bound, arith1.floorsqrt(n)) else: m = arith1.floorsqrt(n) for p in bigrange.range(3, m+1, 2): if not (n % p): return False return True
def e3_Fp(x, p): """ p is prime 0 = x[0] + x[1]*t + x[2]*t**2 + x[3]*t**3 """ x.reverse() lc_inv = finitefield.FinitePrimeFieldElement(x[0], p).inverse() coeff = [] for c in x[1:]: coeff.append((c * lc_inv).n) sol = [] for i in bigrange.range(p): if (i**3 + coeff[0]*i**2 + coeff[1]*i + coeff[2]) % p == 0: sol.append(i) break if len(sol) == 0: return sol X = e2_Fp([coeff[1] + (coeff[0] + sol[0])*sol[0], coeff[0] + sol[0], 1], p) if len(X) != 0: sol.extend(X) return sol
def e3_Fp(x, p): """ p is prime 0 = x[0] + x[1]*t + x[2]*t**2 + x[3]*t**3 """ x.reverse() lc_inv = finitefield.FinitePrimeFieldElement(x[0], p).inverse() coeff = [] for c in x[1:]: coeff.append((c * lc_inv).n) sol = [] for i in bigrange.range(p): if (i**3 + coeff[0] * i**2 + coeff[1] * i + coeff[2]) % p == 0: sol.append(i) break if len(sol) == 0: return sol X = e2_Fp([coeff[1] + (coeff[0] + sol[0]) * sol[0], coeff[0] + sol[0], 1], p) if len(X) != 0: sol.extend(X) return sol
def by_primitive_root(n, divisors): """ Return True iff n is prime. The method proves the primality of n by existence of a primitive root. It requires a sequence of all prime divisors of n - 1. Lehmer,D.H., Tests for primality by the converse of Fermat's theorem, Bull.Amer.Math.Soc, Vol.33, pp.327-340, 1927. """ m_order = n - 1 primes = tuple(p for p in divisors if p > 2) for g in bigrange.range(2, n): jacobi = arith1.legendre(g, n) if jacobi == 0: return False elif jacobi == 1: continue if pow(g, m_order, n) != 1: return False if all(pow(g, m_order // p, n) != 1 for p in primes): return True return True # only when n=2, flow reaches this line
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