Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set Miller-Rabin rounds based on bitsize #58

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
40 changes: 32 additions & 8 deletions rsa/prime.py
Expand Up @@ -20,6 +20,7 @@
Roberto Tamassia, 2002.
"""

import rsa.common
import rsa.randnum

__all__ = ['getprime', 'are_relatively_prime']
Expand All @@ -37,6 +38,32 @@ def gcd(p, q):
return p


def get_primality_testing_rounds(number):
"""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, k):
"""Calculates whether n is composite (which is always correct) or prime
(which theoretically is incorrect with error probability 4**-k), by
Expand Down Expand Up @@ -109,14 +136,11 @@ def is_prime(number):
if not (number & 1):
return False

# 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
return miller_rabin_primality_testing(number, 7)
# 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):
Expand Down
14 changes: 14 additions & 0 deletions tests/test_prime.py
Expand Up @@ -74,3 +74,17 @@ def fake_randint(maxvalue):
self.assertEqual([], randints)
finally:
rsa.randnum.randint = orig_randint

def test_get_primality_testing_rounds(self):
"""Test round calculation for primality testing."""

self.assertEquals(rsa.prime.get_primality_testing_rounds(1 << 63), 10)
self.assertEquals(rsa.prime.get_primality_testing_rounds(1 << 127), 10)
self.assertEquals(rsa.prime.get_primality_testing_rounds(1 << 255), 10)
self.assertEquals(rsa.prime.get_primality_testing_rounds(1 << 511), 7)
self.assertEquals(rsa.prime.get_primality_testing_rounds(1 << 767), 7)
self.assertEquals(rsa.prime.get_primality_testing_rounds(1 << 1023), 4)
self.assertEquals(rsa.prime.get_primality_testing_rounds(1 << 1279), 4)
self.assertEquals(rsa.prime.get_primality_testing_rounds(1 << 1535), 3)
self.assertEquals(rsa.prime.get_primality_testing_rounds(1 << 2047), 3)
self.assertEquals(rsa.prime.get_primality_testing_rounds(1 << 4095), 3)