You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
5.0 KiB

  1. # Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # https://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Numerical functions related to primes.
  15. Implementation based on the book Algorithm Design by Michael T. Goodrich and
  16. Roberto Tamassia, 2002.
  17. """
  18. import rsa.common
  19. import rsa.randnum
  20. __all__ = ['getprime', 'are_relatively_prime']
  21. def gcd(p: int, q: int) -> int:
  22. """Returns the greatest common divisor of p and q
  23. >>> gcd(48, 180)
  24. 12
  25. """
  26. while q != 0:
  27. (p, q) = (q, p % q)
  28. return p
  29. def get_primality_testing_rounds(number: int) -> int:
  30. """Returns minimum number of rounds for Miller-Rabing primality testing,
  31. based on number bitsize.
  32. According to NIST FIPS 186-4, Appendix C, Table C.3, minimum number of
  33. rounds of M-R testing, using an error probability of 2 ** (-100), for
  34. different p, q bitsizes are:
  35. * p, q bitsize: 512; rounds: 7
  36. * p, q bitsize: 1024; rounds: 4
  37. * p, q bitsize: 1536; rounds: 3
  38. See: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
  39. """
  40. # Calculate number bitsize.
  41. bitsize = rsa.common.bit_size(number)
  42. # Set number of rounds.
  43. if bitsize >= 1536:
  44. return 3
  45. if bitsize >= 1024:
  46. return 4
  47. if bitsize >= 512:
  48. return 7
  49. # For smaller bitsizes, set arbitrary number of rounds.
  50. return 10
  51. def miller_rabin_primality_testing(n: int, k: int) -> bool:
  52. """Calculates whether n is composite (which is always correct) or prime
  53. (which theoretically is incorrect with error probability 4**-k), by
  54. applying Miller-Rabin primality testing.
  55. For reference and implementation example, see:
  56. https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
  57. :param n: Integer to be tested for primality.
  58. :type n: int
  59. :param k: Number of rounds (witnesses) of Miller-Rabin testing.
  60. :type k: int
  61. :return: False if the number is composite, True if it's probably prime.
  62. :rtype: bool
  63. """
  64. # prevent potential infinite loop when d = 0
  65. if n < 2:
  66. return False
  67. # Decompose (n - 1) to write it as (2 ** r) * d
  68. # While d is even, divide it by 2 and increase the exponent.
  69. d = n - 1
  70. r = 0
  71. while not (d & 1):
  72. r += 1
  73. d >>= 1
  74. # Test k witnesses.
  75. for _ in range(k):
  76. # Generate random integer a, where 2 <= a <= (n - 2)
  77. a = rsa.randnum.randint(n - 3) + 1
  78. x = pow(a, d, n)
  79. if x == 1 or x == n - 1:
  80. continue
  81. for _ in range(r - 1):
  82. x = pow(x, 2, n)
  83. if x == 1:
  84. # n is composite.
  85. return False
  86. if x == n - 1:
  87. # Exit inner loop and continue with next witness.
  88. break
  89. else:
  90. # If loop doesn't break, n is composite.
  91. return False
  92. return True
  93. def is_prime(number: int) -> bool:
  94. """Returns True if the number is prime, and False otherwise.
  95. >>> is_prime(2)
  96. True
  97. >>> is_prime(42)
  98. False
  99. >>> is_prime(41)
  100. True
  101. """
  102. # Check for small numbers.
  103. if number < 10:
  104. return number in {2, 3, 5, 7}
  105. # Check for even numbers.
  106. if not (number & 1):
  107. return False
  108. # Calculate minimum number of rounds.
  109. k = get_primality_testing_rounds(number)
  110. # Run primality testing with (minimum + 1) rounds.
  111. return miller_rabin_primality_testing(number, k + 1)
  112. def getprime(nbits: int) -> int:
  113. """Returns a prime number that can be stored in 'nbits' bits.
  114. >>> p = getprime(128)
  115. >>> is_prime(p-1)
  116. False
  117. >>> is_prime(p)
  118. True
  119. >>> is_prime(p+1)
  120. False
  121. >>> from rsa import common
  122. >>> common.bit_size(p) == 128
  123. True
  124. """
  125. assert nbits > 3 # the loop wil hang on too small numbers
  126. while True:
  127. integer = rsa.randnum.read_random_odd_int(nbits)
  128. # Test for primeness
  129. if is_prime(integer):
  130. return integer
  131. # Retry if not prime
  132. def are_relatively_prime(a: int, b: int) -> bool:
  133. """Returns True if a and b are relatively prime, and False if they
  134. are not.
  135. >>> are_relatively_prime(2, 3)
  136. True
  137. >>> are_relatively_prime(2, 4)
  138. False
  139. """
  140. d = gcd(a, b)
  141. return d == 1
  142. if __name__ == '__main__':
  143. print('Running doctests 1000x or until failure')
  144. import doctest
  145. for count in range(1000):
  146. (failures, tests) = doctest.testmod()
  147. if failures:
  148. break
  149. if count % 100 == 0 and count:
  150. print('%i times' % count)
  151. print('Doctests done')