| # Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu> |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """Numerical functions related to primes. |
| |
| Implementation based on the book Algorithm Design by Michael T. Goodrich and |
| Roberto Tamassia, 2002. |
| """ |
| |
| import rsa.common |
| import rsa.randnum |
| |
| __all__ = ['getprime', 'are_relatively_prime'] |
| |
| |
| def gcd(p: int, q: int) -> int: |
| """Returns the greatest common divisor of p and q |
| |
| >>> gcd(48, 180) |
| 12 |
| """ |
| |
| while q != 0: |
| (p, q) = (q, p % q) |
| return p |
| |
| |
| def get_primality_testing_rounds(number: int) -> int: |
| """Returns minimum number of rounds for Miller-Rabing primality testing, |
| based on number bitsize. |
| |
| According to NIST FIPS 186-4, Appendix C, Table C.3, minimum number of |
| rounds of M-R testing, using an error probability of 2 ** (-100), for |
| different p, q bitsizes are: |
| * p, q bitsize: 512; rounds: 7 |
| * p, q bitsize: 1024; rounds: 4 |
| * p, q bitsize: 1536; rounds: 3 |
| See: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf |
| """ |
| |
| # Calculate number bitsize. |
| bitsize = rsa.common.bit_size(number) |
| # Set number of rounds. |
| if bitsize >= 1536: |
| return 3 |
| if bitsize >= 1024: |
| return 4 |
| if bitsize >= 512: |
| return 7 |
| # For smaller bitsizes, set arbitrary number of rounds. |
| return 10 |
| |
| |
| def miller_rabin_primality_testing(n: int, k: int) -> bool: |
| """Calculates whether n is composite (which is always correct) or prime |
| (which theoretically is incorrect with error probability 4**-k), by |
| applying Miller-Rabin primality testing. |
| |
| For reference and implementation example, see: |
| https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test |
| |
| :param n: Integer to be tested for primality. |
| :type n: int |
| :param k: Number of rounds (witnesses) of Miller-Rabin testing. |
| :type k: int |
| :return: False if the number is composite, True if it's probably prime. |
| :rtype: bool |
| """ |
| |
| # prevent potential infinite loop when d = 0 |
| if n < 2: |
| return False |
| |
| # Decompose (n - 1) to write it as (2 ** r) * d |
| # While d is even, divide it by 2 and increase the exponent. |
| d = n - 1 |
| r = 0 |
| |
| while not (d & 1): |
| r += 1 |
| d >>= 1 |
| |
| # Test k witnesses. |
| for _ in range(k): |
| # Generate random integer a, where 2 <= a <= (n - 2) |
| a = rsa.randnum.randint(n - 3) + 1 |
| |
| x = pow(a, d, n) |
| if x == 1 or x == n - 1: |
| continue |
| |
| for _ in range(r - 1): |
| x = pow(x, 2, n) |
| if x == 1: |
| # n is composite. |
| return False |
| if x == n - 1: |
| # Exit inner loop and continue with next witness. |
| break |
| else: |
| # If loop doesn't break, n is composite. |
| return False |
| |
| return True |
| |
| |
| def is_prime(number: int) -> bool: |
| """Returns True if the number is prime, and False otherwise. |
| |
| >>> is_prime(2) |
| True |
| >>> is_prime(42) |
| False |
| >>> is_prime(41) |
| True |
| """ |
| |
| # Check for small numbers. |
| if number < 10: |
| return number in {2, 3, 5, 7} |
| |
| # Check for even numbers. |
| if not (number & 1): |
| return False |
| |
| # Calculate minimum number of rounds. |
| k = get_primality_testing_rounds(number) |
| |
| # Run primality testing with (minimum + 1) rounds. |
| return miller_rabin_primality_testing(number, k + 1) |
| |
| |
| def getprime(nbits: int) -> int: |
| """Returns a prime number that can be stored in 'nbits' bits. |
| |
| >>> p = getprime(128) |
| >>> is_prime(p-1) |
| False |
| >>> is_prime(p) |
| True |
| >>> is_prime(p+1) |
| False |
| |
| >>> from rsa import common |
| >>> common.bit_size(p) == 128 |
| True |
| """ |
| |
| assert nbits > 3 # the loop wil hang on too small numbers |
| |
| while True: |
| integer = rsa.randnum.read_random_odd_int(nbits) |
| |
| # Test for primeness |
| if is_prime(integer): |
| return integer |
| |
| # Retry if not prime |
| |
| |
| def are_relatively_prime(a: int, b: int) -> bool: |
| """Returns True if a and b are relatively prime, and False if they |
| are not. |
| |
| >>> are_relatively_prime(2, 3) |
| True |
| >>> are_relatively_prime(2, 4) |
| False |
| """ |
| |
| d = gcd(a, b) |
| return d == 1 |
| |
| |
| if __name__ == '__main__': |
| print('Running doctests 1000x or until failure') |
| import doctest |
| |
| for count in range(1000): |
| (failures, tests) = doctest.testmod() |
| if failures: |
| break |
| |
| if count % 100 == 0 and count: |
| print('%i times' % count) |
| |
| print('Doctests done') |