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 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 testRange(self): for i in range(10000): start = random.randrange(-5000, 1)**3 stop = random.randrange(1, 5000)**3 step = random.randrange(1, 200) d = bigrandom.randrange(start, stop, step) self.assertEqual(0, (d - start) % step) self.assertTrue(start <= d < stop) d = bigrandom.randrange(start**2, -stop**2, -step) self.assertEqual(0, (d - start**2) % step) self.assertTrue(start**2 >= d > -stop**2)
def _random_irriducible(char, degree): """ Return randomly chosen irreducible polynomial of self.degree. """ cardinality = char ** degree basefield = FinitePrimeField.getInstance(char) seed = bigrandom.randrange(1, char) + cardinality cand = uniutil.FiniteFieldPolynomial(enumerate(arith1.expand(seed, cardinality)), coeffring=basefield) while cand.degree() < degree or not cand.isirreducible(): seed = bigrandom.randrange(1, cardinality) + cardinality cand = uniutil.FiniteFieldPolynomial(enumerate(arith1.expand(seed, cardinality)), coeffring=basefield) _log.debug(cand.order.format(cand)) return cand
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 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 _primitive_polynomial(char, degree): """ Return a primitive polynomial of self.degree. REF: Lidl & Niederreiter, Introduction to finite fields and their applications. """ cardinality = char**degree basefield = FinitePrimeField.getInstance(char) const = basefield.primitive_element() if degree & 1: const = -const cand = uniutil.polynomial({0: const, degree: basefield.one}, basefield) maxorder = factor_misc.FactoredInteger((cardinality - 1) // (char - 1)) var = uniutil.polynomial({1: basefield.one}, basefield) while not (cand.isirreducible() and all( pow(var, int(maxorder) // p, cand).degree() > 0 for p in maxorder.prime_divisors())): # randomly modify the polynomial deg = bigrandom.randrange(1, degree) coeff = basefield.random_element(1, char) cand += uniutil.polynomial({deg: coeff}, basefield) _log.debug(cand.order.format(cand)) return cand
def _random_irriducible(char, degree): """ Return randomly chosen irreducible polynomial of self.degree. """ cardinality = char**degree basefield = FinitePrimeField.getInstance(char) seed = bigrandom.randrange(1, char) + cardinality cand = uniutil.FiniteFieldPolynomial(enumerate( arith1.expand(seed, cardinality)), coeffring=basefield) while cand.degree() < degree or not cand.isirreducible(): seed = bigrandom.randrange(1, cardinality) + cardinality cand = uniutil.FiniteFieldPolynomial(enumerate( arith1.expand(seed, cardinality)), coeffring=basefield) _log.debug(cand.order.format(cand)) return cand
def __init__(self, characteristic, n_or_modulus): """ FiniteExtendedField(p, n_or_modulus) creates a finite field. characteristic must be prime. n_or_modulus can be: 1) an integer greater than 1, or 2) a polynomial in a polynomial ring of F_p with degree greater than 1. """ FiniteField.__init__(self, characteristic) self.basefield = FinitePrimeField.getInstance(self.char) if isinstance(n_or_modulus, int): if n_or_modulus <= 1: raise ValueError("degree of extension must be > 1.") self.degree = n_or_modulus # randomly chosen irreducible polynomial top = FinitePrimeFieldPolynomial({self.degree: 1}, coeffring=self.basefield) seed = bigrandom.randrange(1, self.char) cand = FinitePrimeFieldPolynomial(enumerate( arith1.expand(seed, self.char)), coeffring=self.basefield) + top while cand.degree() < self.degree or not cand.isirreducible(): seed = bigrandom.randrange(1, self.char**self.degree) cand = FinitePrimeFieldPolynomial( enumerate(arith1.expand(seed, self.char)), coeffring=self.basefield) + top self.modulus = cand elif isinstance(n_or_modulus, FinitePrimeFieldPolynomial): if isinstance(n_or_modulus.getCoefficientRing(), FinitePrimeField): if n_or_modulus.degree() > 1 and n_or_modulus.isirreducible(): self.degree = n_or_modulus.degree() self.modulus = n_or_modulus else: raise ValueError( "modulus must be of degree greater than 1.") else: raise TypeError("modulus must be F_p polynomial.") else: raise TypeError("degree or modulus must be supplied.") self.registerModuleAction(rational.theIntegerRing, self._int_mul) self.registerModuleAction(FinitePrimeField.getInstance(self.char), self._fp_mul)
def testUniform(self): trial_times = 100000 error_range = 0.03 dist = {} for i in range(5, 100, 10): dist[i] = 0 for i in range(trial_times): rnd = bigrandom.randrange(5, 100, 10) dist[rnd] += 1 for i in range(5, 100, 10): self.assertTrue(abs(0.1 - dist[i]/float(trial_times)) < error_range) dist = {} for i in range(trial_times): rnd = bigrandom.randrange(-1, 255) dist[rnd] = dist.get(rnd, 0) + 1 distkeys = dist.keys() distkeys.sort() self.assertEqual(distkeys, range(-1, 255))
def rand_probable_prime(minimum, maximum, times=20): """ Return a random probable prime in range(minimum, maximum) """ p = next_probable_prime(bigrandom.randrange(minimum, maximum), times) if p < maximum: return p # in very rare case or n is too small case, # search continues from the lower bound. return next_probable_prime(minimum, times)
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
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
def randomele(disc, unit): """ Return a reduced random form with the given discriminant and the given unit. Also random element is not unit. """ limit = int(math.sqrt(-disc / 3)) while True: a = bigrandom.randrange(1, limit + 1) ind = 0 while ind < 2 * a: b = bigrandom.randrange(a) if bigrandom.randrange(2): b = -b tp = disc - b**2 if tp % (-4 * a) == 0: c = tp // (-4 * a) if gcd.gcd_of_list([a, b, c])[0] != 1: continue red = reducePDF((a, b, c)) if red != unit: return ReducedQuadraticForm(red, unit) ind += 1
def randomele(disc, unit): """ Return a reduced random form with the given discriminant and the given unit. Also random element is not unit. """ limit = int(math.sqrt(-disc / 3)) while True: a = bigrandom.randrange(1, limit + 1) ind = 0 while ind < 2*a: b = bigrandom.randrange(a) if bigrandom.randrange(2): b = -b tp = disc - b**2 if tp % (-4 * a) == 0: c = tp // (-4 * a) if gcd.gcd_of_list([a, b, c])[0] != 1: continue red = reducePDF((a, b, c)) if red != unit: return ReducedQuadraticForm(red, unit) ind += 1
def root_Fp(g, p, flag=True): """ Return a root over F_p of nonzero polynomial g. p must be prime. If flag = False, return a root randomly """ if isinstance(g, list): if not isinstance(g[0], tuple): g = zip(range(len(g)), g) Fp = finitefield.FinitePrimeField(p) g = uniutil.FinitePrimeFieldPolynomial(g, Fp) h = uniutil.FinitePrimeFieldPolynomial({1: -1, p: 1}, Fp) g = g.gcd(h) deg_g = g.degree() if g[0] == 0: deg_g = deg_g - 1 g = g.shift_degree_to(deg_g) while True: if deg_g == 0: return None if deg_g == 1: return (-g[0] / g[1]).toInteger() elif deg_g == 2: d = g[1] * g[1] - 4 * g[0] e = arith1.modsqrt(d.toInteger(), p) return ((-g[1] - e) / (2 * g[2])).toInteger() deg_h = 0 x = uniutil.FinitePrimeFieldPolynomial({0: -1, (p - 1) >> 1: 1}, Fp) if flag: a = 0 while deg_h == 0 or deg_h == deg_g: b = uniutil.FinitePrimeFieldPolynomial({0: -a, 1: 1}, Fp) v = g(b) h = x.gcd(v) a = a + 1 deg_h = h.degree() b = uniutil.FinitePrimeFieldPolynomial({0: a - 1, 1: 1}, Fp) else: while deg_h == 0 or deg_h == deg_g: a = bigrandom.randrange(p) b = uniutil.FinitePrimeFieldPolynomial({0: -a, 1: 1}, Fp) v = g(b) h = x.gcd(v) deg_h = h.degree() b = uniutil.FinitePrimeFieldPolynomial({0: a, 1: 1}, Fp) g = h(b) deg_g = deg_h
def root_Fp(g, p, flag=True): """ Return a root over F_p of nonzero polynomial g. p must be prime. If flag = False, return a root randomly """ if isinstance(g, list): if not isinstance(g[0], tuple): g = zip(range(len(g)), g) Fp = finitefield.FinitePrimeField(p) g = uniutil.FinitePrimeFieldPolynomial(g, Fp) h = uniutil.FinitePrimeFieldPolynomial({1:-1, p:1}, Fp) g = g.gcd(h) deg_g = g.degree() if g[0] == 0: deg_g = deg_g - 1 g = g.shift_degree_to(deg_g) while True: if deg_g == 0: return None if deg_g == 1: return (-g[0]/g[1]).toInteger() elif deg_g == 2: d = g[1]*g[1] - 4*g[0] e = arith1.modsqrt(d.toInteger(), p) return ((-g[1]-e)/(2*g[2])).toInteger() deg_h = 0 x = uniutil.FinitePrimeFieldPolynomial({0:-1, (p-1)//2:1}, Fp) if flag: a = 0 while deg_h == 0 or deg_h == deg_g: b = uniutil.FinitePrimeFieldPolynomial({0:-a, 1:1}, Fp) v = g(b) h = x.gcd(v) a = a + 1 deg_h = h.degree() b = uniutil.FinitePrimeFieldPolynomial({0:a-1, 1:1}, Fp) else: while deg_h == 0 or deg_h == deg_g: a = bigrandom.randrange(p) b = uniutil.FinitePrimeFieldPolynomial({0:-a, 1:1}, Fp) v = g(b) h = x.gcd(v) deg_h = h.degree() b = uniutil.FinitePrimeFieldPolynomial({0:a, 1:1}, Fp) g = h(b) deg_g = deg_h
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")
def randPrime(n): """ Return a random n-digits prime """ if n <= 0: raise ValueError("input number must be natural number") if n == 1: return bigrandom.map_choice(lambda i: (2, 3, 5, 7)[i], 4) p = bigrandom.randrange(10**(n-1)+1, 10**n, 2) while not primeq(p): p += 2 if p < 10**n: return p # in very rare case or n is too small case, # search continues from the lower bound. p = 10**(n-1) + 1 while not primeq(p): p += 2 return p
def randPrime(n): """ Return a random n-digits prime """ if n <= 0: raise ValueError("input number must be natural number") if n == 1: return bigrandom.map_choice(lambda i: (2, 3, 5, 7)[i], 4) p = bigrandom.randrange(10**(n - 1) + 1, 10**n, 2) while not primeq(p): p += 2 if p < 10**n: return p # in very rare case or n is too small case, # search continues from the lower bound. p = 10**(n - 1) + 1 while not primeq(p): p += 2 return p
def _primitive_polynomial(char, degree): """ Return a primitive polynomial of self.degree. REF: Lidl & Niederreiter, Introduction to finite fields and their applications. """ cardinality = char ** degree basefield = FinitePrimeField.getInstance(char) const = basefield.primitive_element() if degree % 2: const = -const cand = uniutil.polynomial({0:const, degree:basefield.one}, basefield) maxorder = factor_misc.FactoredInteger((cardinality - 1) // (char - 1)) var = uniutil.polynomial({1:basefield.one}, basefield) while not (cand.isirreducible() and all(pow(var, int(maxorder) // p, cand).degree() > 0 for p in maxorder.prime_divisors())): # randomly modify the polynomial deg = bigrandom.randrange(1, degree) coeff = basefield.random_element(1, char) cand += uniutil.polynomial({deg:coeff}, basefield) _log.debug(cand.order.format(cand)) return cand
def random_element(self, *args): """ Return a randomly chosen element og the field. """ return self.createElement(bigrandom.randrange(*args))
def random_nbit(n): return bigrandom.randrange(2**(n - 1), 2**n)
def random_nbit(n): return bigrandom.randrange(2**(n-1), 2**n)
def testHugeRange(self): self.assertTrue(2 <= bigrandom.randrange(2, 10**500) < 10**500)
def random_element(self, *args): """ Return a randomly chosen element og the field. """ return self.createElement(bigrandom.randrange(*args))