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 cornacchiamodify(d, p): """ Algorithm 26 (Modified cornacchia) Input : p be a prime and d be an integer such that d < 0 and d > -4p with d = 0, 1 (mod 4) Output : the solution of u^2 -d * v^2 = 4p. """ q = 4 * p if (d >= 0) or (d <= -q): raise ValueError("invalid input") if p == 2: b = arith1.issquare(d + 8) if b: return (b, 1) else: raise ValueError("no solution") if arith1.legendre(d, p) == -1: raise ValueError("no solution") x0 = arith1.modsqrt(d, p) if (x0 - d) & 1: x0 = p - x0 a = 2 * p b = x0 l = arith1.floorsqrt(q) while b > l: a, b = b, a % b c, r = divmod(q - b * b, -d) if r: raise ValueError("no solution") t = arith1.issquare(c) if t: return (b, t) else: raise ValueError("no solution")
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 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 _ecpp_find_disc(n, era=None): """ Return (disc, m, k, q, era) where: - disc: appropriate discriminant for ecpp - m: one of possible orders for disc - k: smooth part of m - q: rough part of m which is greater than (n^(1/4) + 1)^2 - era: list of small primes """ up = (arith1.floorpowerroot(n, 4) + 1) ** 2 for disc in disc_gen(n): legendre = arith1.legendre(disc, n) if legendre == 0: return False elif legendre == -1: continue # legendre == 1: try: u, v = cornacchiamodify(disc, n) except ValueError: continue for m in (f(n, u, v) for f in orders.get(disc, default_orders)): k, q, era = _factor_order(m, up, era) if k: return disc, m, k, q, era else: # no usable discriminat found return False
def cornacchiamodify(d, p): """ Algorithm 26 (Modified cornacchia) Input : p be a prime and d be an integer such that d < 0 and d > -4p with d = 0, 1 (mod 4) Output : the solution of u^2 -d * v^2 = 4p. """ q = 4 * p if (d >= 0) or (d <= -q): raise ValueError("invalid input") if p == 2: b = arith1.issquare(d + 8) if b: return (b, 1) else: raise ValueError("no solution") if arith1.legendre(d, p) == -1: raise ValueError("no solution") x0 = arith1.modsqrt(d, p) if (x0 - d) % 2 != 0: x0 = p - x0 a = 2 * p b = x0 l = arith1.floorsqrt(q) while b > l: a, b = b, a % b c, r = divmod(q - b * b, -d) if r: raise ValueError("no solution") t = arith1.issquare(c) if t: return (b, t) else: raise ValueError("no solution")
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 _ecpp_find_disc(n, era=None): """ Return (disc, m, k, q, era) where: - disc: appropriate discriminant for ecpp - m: one of possible orders for disc - k: smooth part of m - q: rough part of m which is greater than (n^(1/4) + 1)^2 - era: list of small primes """ up = (arith1.floorpowerroot(n, 4) + 1)**2 for disc in disc_gen(n): legendre = arith1.legendre(disc, n) if legendre == 0: return False elif legendre == -1: continue # legendre == 1: try: u, v = cornacchiamodify(disc, n) except ValueError: continue for m in (f(n, u, v) for f in orders.get(disc, default_orders)): k, q, era = _factor_order(m, up, era) if k: return disc, m, k, q, era else: # no usable discriminat found return False
def cornacchia(d, p): """ Return the solution of x^2 + d * y^2 = p . p be a prime and d be an integer such that 0 < d < p. """ if (d <= 0) or (d >= p): raise ValueError("invalid input") k = arith1.legendre(-d, p) if k == -1: raise ValueError("no solution") x0 = arith1.modsqrt(-d, p) if x0 < (p / 2): x0 = p - x0 a = p b = x0 l = arith1.floorsqrt(p) while b > l: a, b = b, a % b c, r = divmod(p - b * b, d) if r: raise ValueError("no solution") t = arith1.issquare(c) if t == 0: raise ValueError("no solution") else: return (b, t)
def Legendre(self, element): """ Return generalize Legendre Symbol for FinitePrimeField. """ if not element: return 0 if element.n == 1 or element.m == 2: return 1 # trivial return arith1.legendre(element.n, element.m)
def __init__(self, n, sieverange, factorbase): self.number = n self.sqrt_n = int(math.sqrt(n)) for i in [2,3,5,7,11,17,19]: if n % i == 0: raise ValueError("This number is divided by %d" % i) self.digit = arith1.log(self.number, 10) + 1 self.Srange = sieverange self.FBN = factorbase self.move_range = range(self.sqrt_n-self.Srange, self.sqrt_n+self.Srange+1) i = 0 k = 0 factor_base = [-1] FB_log = [0] while True: ii = primes_table[i] if arith1.legendre(self.number, ii) == 1: factor_base.append(ii) FB_log.append(primes_log_table[i]) k += 1 i += 1 if k == self.FBN: break else: i += 1 self.FB = factor_base self.FB_log = FB_log self.maxFB = factor_base[-1] N_sqrt_list = [] for i in self.FB: if i != 2 and i != -1: e = int(math.log(2*self.Srange, i)) N_sqrt_modp = sqroot_power(self.number, i, e) N_sqrt_list.append(N_sqrt_modp) self.solution = N_sqrt_list #This is square roots of N on Z/pZ, p in factor base. poly_table = [] log_poly = [] minus_val = [] for j in self.move_range: jj = (j**2)-self.number if jj < 0: jj = -jj minus_val.append(j-self.sqrt_n+self.Srange) elif jj == 0: jj = 1 lj = int((math.log(jj)*30)*0.97) # 0.97 is an erroe poly_table.append(jj) log_poly.append(lj) self.poly_table = poly_table # This is Q(x) value , x in [-M+sqrt_n,M+sqrt_n]. self.log_poly = log_poly # This is log(Q(x)) value. self.minus_check = minus_val # This is "x" that Q(x) is minus value.
def choose_point(self): """ Choose point on E_{a,b}(Z_n) Algorithm 27 (Atkin-morain ECPP) Step5 """ n, f = self.modulus, self.f x = bigrandom.randrange(n) Q = f(x) while arith1.legendre(Q, n) == -1: x = bigrandom.randrange(n) Q = f(x) y = arith1.modsqrt(Q, n) return [intresidue.IntegerResidueClass(t, n) for t in (x, y)]
def make_poly(self): """ Make coefficients of f(x)= ax^2+b*x+c """ T = time.time() if self.d_list == []: d = int(math.sqrt((math.sqrt(self.number)/(math.sqrt(2)*self.Srange)))) if d%2 == 0: if (d+1)%4 == 1: #case d=0 mod4 d += 3 else: d += 1 #case d=2 mod4 elif d%4 == 1: #case d=1 mod4 d += 2 #case d=3 mod4 else: d = self.d_list[-1] while d in self.d_list or not prime.primeq(d) or \ arith1.legendre(self.number,d) != 1 or d in self.FB: d += 4 a = d**2 h_0 = pow(self.number, (d-3)//4, d) h_1 = (h_0*self.number) % d h_2 = ((arith1.inverse(2,d)*h_0*(self.number - h_1**2))/d) % d b = (h_1 + h_2*d) % a if b%2 == 0: b = b - a self.d_list.append(d) self.a_list.append(a) self.b_list.append(b) # Get solution of F(x) = 0 (mod p^i) solution = [] i = 0 for s in self.Nsqrt: k = 0 p_solution = [] ppow = 1 while k < len(s): ppow *= self.FB[i+2] a_inverse = arith1.inverse(2*self.a_list[-1], ppow) x_1 = ((-b + s[k][0])*a_inverse) % ppow x_2 = ((-b + s[k][1])*a_inverse) % ppow p_solution.append([x_1, x_2]) k += 1 i += 1 solution.append(p_solution) self.solution = solution self.coefficienttime += time.time() - T
def prime_mod8(n): """ This is table for choosing multiplier which makes N to have factorbase(2,3,5,7,11,13) """ primes = eratosthenes(n) PrimeList = {1:[], 3:[], 5:[], 7:[]} LegendreList = {1:[], 3:[], 5:[], 7:[]} sp = [2, 3, 5, 7, 11, 13] for p in primes: if p not in sp: leg = [arith1.legendre(p, q) for q in sp[1:]] if leg not in PrimeList[p % 8]: LegendreList[p % 8].append(leg) PrimeList[p % 8].append([p, leg]) return [PrimeList[1], PrimeList[3], PrimeList[5], PrimeList[7]]
def _cmm_find_disc(p, absbound=DEFAULT_ABS_BOUND): """ Input : a prime number p (>=3) Output : (disc, g, u, v) where: - disc: discriminant appropriate for CM method - g: quasi primitive element of p - u, v: a solution of u**2 + disc * v**2 = 4*p """ for disc in disc_gen(absbound): if arith1.legendre(disc, p) == 1: try: u, v = cornacchiamodify(disc, p) g = quasi_primitive(p, disc == -3) return disc, g, u, v except ValueError: continue raise ValueError("no discriminant found")
def e2_Fp(x, p): """ p is prime f = x[0] + x[1]*t + x[2]*t**2 """ c, b, a = [_x % p for _x in x] if a == 0: return [e1_ZnZ([c, b], p)] if p == 2: solutions = [] if x[0] % 2 == 0: solutions.append(0) if (x[0] + x[1] + x[2]) % 2 == 0: solutions.append(1) if len(solutions) == 1: return solutions * 2 return solutions d = b**2 - 4*a*c if arith1.legendre(d, p) == -1: return [] sqrtd = arith1.modsqrt(d, p) a = arith1.inverse(2*a, p) return [((-b+sqrtd)*a)%p, ((-b-sqrtd)*a)%p]
def e2_Fp(x, p): """ p is prime f = x[0] + x[1]*t + x[2]*t**2 """ c, b, a = [_x % p for _x in x] if a == 0: return [e1_ZnZ([c, b], p)] if p == 2: solutions = [] if x[0] & 1 == 0: solutions.append(0) if (x[0] + x[1] + x[2]) & 1 == 0: solutions.append(1) if len(solutions) == 1: return solutions * 2 return solutions d = b**2 - 4 * a * c if arith1.legendre(d, p) == -1: return [] sqrtd = arith1.modsqrt(d, p) a = arith1.inverse(2 * a, p) return [((-b + sqrtd) * a) % p, ((-b - sqrtd) * a) % p]
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 __init__(self, n, sieverange=0, factorbase=0, multiplier=0): self.number = n _log.info("The number is %d MPQS starting" % n) if prime.primeq(self.number): raise ValueError("This number is Prime Number") for i in [2,3,5,7,11,13]: if n % i == 0: raise ValueError("This number is divided by %d" % i) self.sievingtime = 0 self.coefficienttime = 0 self.d_list = [] self.a_list = [] self.b_list = [] #Decide prameters for each digits self.digit = arith1.log(self.number, 10) + 1 if sieverange != 0: self.Srange = sieverange if factorbase != 0: self.FBN = factorbase elif self.digit < 9: self.FBN = parameters_for_mpqs[0][1] else: self.FBN = parameters_for_mpqs[self.digit-9][1] elif factorbase != 0: self.FBN = factorbase if self.digit < 9: self.Srange = parameters_for_mpqs[0][0] else: self.Srange = parameters_for_mpqs[self.digit-9][0] elif self.digit < 9: self.Srange = parameters_for_mpqs[0][0] self.FBN = parameters_for_mpqs[0][1] elif self.digit > 53: self.Srange = parameters_for_mpqs[44][0] self.FBN = parameters_for_mpqs[44][1] else: self.Srange = parameters_for_mpqs[self.digit-9][0] self.FBN = parameters_for_mpqs[self.digit-9][1] self.move_range = range(-self.Srange, self.Srange+1) # Decide k such that k*n = 1 (mod4) and k*n has many factor base if multiplier == 0: self.sqrt_state = [] for i in [3,5,7,11,13]: s = arith1.legendre(self.number, i) self.sqrt_state.append(s) index8 = (self.number % 8) // 2 j = 0 while self.sqrt_state != prime_8[index8][j][1]: j += 1 k = prime_8[index8][j][0] else: if n % 4 == 1: k = 1 else: if multiplier == 1: raise ValueError("This number is 3 mod 4 ") else: k = multiplier self.number = k*self.number self.multiplier = k _log.info("%d - digits Number" % self.digit) _log.info("Multiplier is %d" % self.multiplier) # Table of (log p) , p in FB i = 0 k = 0 factor_base = [-1] FB_log = [0] while k < self.FBN: ii = primes_table[i] if arith1.legendre(self.number,ii) == 1: factor_base.append(ii) FB_log.append(primes_log_table[i]) k += 1 i += 1 self.FB = factor_base self.FB_log = FB_log self.maxFB = factor_base[-1] # Solve x^2 = n (mod p^e) N_sqrt_list = [] for i in self.FB: if i != 2 and i != -1: e = int(math.log(2*self.Srange, i)) N_sqrt_modp = sqroot_power(self.number, i, e) N_sqrt_list.append(N_sqrt_modp) self.Nsqrt = N_sqrt_list
def testLegendre(self): self.assertEqual(1, arith1.legendre(4, 13)) self.assertEqual(1, arith1.legendre(396685310, 2**31 - 1)) self.assertEqual(-1, arith1.legendre(2, 11**1293)) self.assertEqual(1, arith1.legendre(1, 3)) self.assertEqual(0, arith1.legendre(13 * (2**107 - 1), 2**107 - 1))