#!/usr/bin/python3 # -*- coding: utf-8 -*- # Prime Number Sieve # https://www.nostarch.com/crackingcodes/ (BSD Licensed) import math, random from typing import List def isPrimeTrialDiv(num: int) -> bool: # Returns True if num is a prime number, otherwise False. # Uses the trial division algorithm for testing primality. # All numbers less than 2 are not prime: if num < 2: return False # Is num divisible by any number up to the square root of num? for i in range(2, int(math.sqrt(num)) + 1): if num % i == 0: return False return True def primeSieve(sieveSize: int) -> List[int]: # Returns a list of prime numbers calculated using # the Sieve of Eratosthenes algorithm. sieve = [True] * sieveSize # Zero and one are not prime numbers. sieve[0] = False sieve[1] = False # Create the sieve: for i in range(2, int(math.sqrt(sieveSize)) + 1): pointer = i * 2 while pointer < sieveSize: sieve[pointer] = False pointer += i # Compile the list of primes: primes = [] for i in range(sieveSize): if sieve[i] == True: primes.append(i) return primes def rabinMiller(num: int) -> bool: # Returns True if num is a prime number. if num % 2 == 0 or num < 2: # Rabin-Miller doesn't work on even integers. return False if num == 3: return True s = num - 1 t = 0 while s % 2 == 0: # Keep halving s until it is odd (and use t # to count how many times we halve s): s = s // 2 t += 1 # Try to falsify num's primality 5 times. for trials in range(5): a = random.randrange(2, num - 1) v = pow(a, s, num) # (This test does not apply if v is 1.) if v != 1: i = 0 while v != (num - 1): if i == t - 1: return False else: i = i + 1 v = (v**2) % num return True # Most of the time we can quickly determine if num is not prime # by dividing by the first few dozen prime numbers. This is quicker # than rabinMiller(), but does not detect all composites. LOW_PRIMES = primeSieve(100) def isPrime(num: int) -> bool: # Return True if num is a prime number. This function does a quicker # prime number check before calling rabinMiller(). if num < 2: # 0, 1, and negative numbers are not prime. return False # See if any of the low prime numbers can divide num: for prime in LOW_PRIMES: if num == prime: return True if num % prime == 0: return False # If all else fails, call rabinMiller() to determine if num is a prime: return rabinMiller(num) def generateLargePrime(keysize: int = 1024) -> int: # Return a random prime number that is keysize bits in size: while True: num = random.randrange(2 ** (keysize - 1), 2 ** (keysize)) if isPrime(num): return num