Source code for hal.maths.nt.primes

# -*- coding: utf-8 -*-

"""Primes functions """

import random

LOW_PRIMES = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
              59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
              103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163,
              167, 173, 179, 181, 191, 193, 197, 199,
              211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271,
              277, 281, 283, 293, 307, 311, 313, 317,
              331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397,
              401, 409, 419, 421, 431, 433, 439, 443,
              449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521,
              523, 541, 547, 557, 563, 569, 571, 577,
              587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647,
              653, 659, 661, 673, 677, 683, 691, 701,
              709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787,
              797, 809, 811, 821, 823, 827, 829, 839,
              853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929,
              937, 941, 947, 953, 967, 971, 977, 983,
              991, 997]  # primes until 1000


[docs]class Integer: """Big int std python won't recognize""" def __init__(self, string): self.to_int = int(string) self.to_string = string
[docs] def is_naive_prime(self): """Checks if prime in very naive way :return: True iff prime """ if self.to_int < 2: return False elif self.to_int % 2 == 0: return False return self.to_int in LOW_PRIMES
[docs] def is_probably_prime(self): """Tests with miller-rabin :return: True iff prime """ if self.is_naive_prime(): return True # check if multiple pf low primes for prime in LOW_PRIMES: if self.to_int % prime == 0: return False # if all else fails, call rabin to determine if to_int is prime return self.test_miller_rabin(5)
[docs] def test_miller_rabin(self, precision): """Tests prime with miller-rabin algorithm :param precision: number of rounds to perform :return: True iff probably prime """ if not self.is_naive_prime(): # true -> probably prime # false -> composite s = self.to_int - 1 # write n = d * 2^s, d odd t = 0 while s % 2 == 0: s /= 2 t += 1 # let a = random in the range 2, n-1 # v = a^d mod n # if v = +-1 mod n: # repeat this s-1 times: # v = v^2 mod n # if v = 1 -> composite # -> prime for _ in range(precision): a = random.randrange(2, self.to_int - 1) v = pow(int(a), int(s), self.to_int) if v != 1: i = 0 while v != (self.to_int - 1): if i == t - 1: return False else: i += 1 v = (v ** 2) % self.to_int return True return True
[docs]def get_prime(bits): """Creates (probable) prime number of given size :param bits: size of number to generate :return: prime number of given size """ while True: num = random.randrange(2 ** (bits - 1), 2 ** bits) if Integer(str(num)).is_probably_prime(): return num
[docs]def blum_blum_shub(seed, amount, prime0, prime1): """Creates pseudo-number generator :param seed: seeder :param amount: amount of number to generate :param prime0: one prime number :param prime1: the second prime number :return: pseudo-number generator """ if amount == 0: return [] assert (prime0 % 4 == 3 and prime1 % 4 == 3) # primes must be congruent 3 mod 4 mod = prime0 * prime1 rand = [seed] for _ in range(amount - 1): last_num = rand[len(rand) - 1] next_num = (last_num * last_num) % mod rand.append(next_num) return rand