|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""Functions to create and test prime numbers. |
|
|
|
:undocumented: __package__ |
|
""" |
|
|
|
from Crypto import Random |
|
from Crypto.Math.Numbers import Integer |
|
|
|
from Crypto.Util.py3compat import iter_range |
|
|
|
COMPOSITE = 0 |
|
PROBABLY_PRIME = 1 |
|
|
|
|
|
def miller_rabin_test(candidate, iterations, randfunc=None): |
|
"""Perform a Miller-Rabin primality test on an integer. |
|
|
|
The test is specified in Section C.3.1 of `FIPS PUB 186-4`__. |
|
|
|
:Parameters: |
|
candidate : integer |
|
The number to test for primality. |
|
iterations : integer |
|
The maximum number of iterations to perform before |
|
declaring a candidate a probable prime. |
|
randfunc : callable |
|
An RNG function where bases are taken from. |
|
|
|
:Returns: |
|
``Primality.COMPOSITE`` or ``Primality.PROBABLY_PRIME``. |
|
|
|
.. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf |
|
""" |
|
|
|
if not isinstance(candidate, Integer): |
|
candidate = Integer(candidate) |
|
|
|
if candidate in (1, 2, 3, 5): |
|
return PROBABLY_PRIME |
|
|
|
if candidate.is_even(): |
|
return COMPOSITE |
|
|
|
one = Integer(1) |
|
minus_one = Integer(candidate - 1) |
|
|
|
if randfunc is None: |
|
randfunc = Random.new().read |
|
|
|
|
|
m = Integer(minus_one) |
|
a = 0 |
|
while m.is_even(): |
|
m >>= 1 |
|
a += 1 |
|
|
|
|
|
|
|
|
|
for i in iter_range(iterations): |
|
|
|
|
|
base = 1 |
|
while base in (one, minus_one): |
|
base = Integer.random_range(min_inclusive=2, |
|
max_inclusive=candidate - 2, |
|
randfunc=randfunc) |
|
assert(2 <= base <= candidate - 2) |
|
|
|
|
|
z = pow(base, m, candidate) |
|
if z in (one, minus_one): |
|
continue |
|
|
|
|
|
for j in iter_range(1, a): |
|
z = pow(z, 2, candidate) |
|
if z == minus_one: |
|
break |
|
if z == one: |
|
return COMPOSITE |
|
else: |
|
return COMPOSITE |
|
|
|
|
|
return PROBABLY_PRIME |
|
|
|
|
|
def lucas_test(candidate): |
|
"""Perform a Lucas primality test on an integer. |
|
|
|
The test is specified in Section C.3.3 of `FIPS PUB 186-4`__. |
|
|
|
:Parameters: |
|
candidate : integer |
|
The number to test for primality. |
|
|
|
:Returns: |
|
``Primality.COMPOSITE`` or ``Primality.PROBABLY_PRIME``. |
|
|
|
.. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf |
|
""" |
|
|
|
if not isinstance(candidate, Integer): |
|
candidate = Integer(candidate) |
|
|
|
|
|
if candidate in (1, 2, 3, 5): |
|
return PROBABLY_PRIME |
|
if candidate.is_even() or candidate.is_perfect_square(): |
|
return COMPOSITE |
|
|
|
|
|
def alternate(): |
|
value = 5 |
|
while True: |
|
yield value |
|
if value > 0: |
|
value += 2 |
|
else: |
|
value -= 2 |
|
value = -value |
|
|
|
for D in alternate(): |
|
if candidate in (D, -D): |
|
continue |
|
js = Integer.jacobi_symbol(D, candidate) |
|
if js == 0: |
|
return COMPOSITE |
|
if js == -1: |
|
break |
|
|
|
|
|
|
|
|
|
K = candidate + 1 |
|
|
|
r = K.size_in_bits() - 1 |
|
|
|
|
|
U_i = Integer(1) |
|
V_i = Integer(1) |
|
U_temp = Integer(0) |
|
V_temp = Integer(0) |
|
|
|
for i in iter_range(r - 1, -1, -1): |
|
|
|
|
|
U_temp.set(U_i) |
|
U_temp *= V_i |
|
U_temp %= candidate |
|
|
|
V_temp.set(U_i) |
|
V_temp *= U_i |
|
V_temp *= D |
|
V_temp.multiply_accumulate(V_i, V_i) |
|
if V_temp.is_odd(): |
|
V_temp += candidate |
|
V_temp >>= 1 |
|
V_temp %= candidate |
|
|
|
if K.get_bit(i): |
|
|
|
U_i.set(U_temp) |
|
U_i += V_temp |
|
if U_i.is_odd(): |
|
U_i += candidate |
|
U_i >>= 1 |
|
U_i %= candidate |
|
|
|
V_i.set(V_temp) |
|
V_i.multiply_accumulate(U_temp, D) |
|
if V_i.is_odd(): |
|
V_i += candidate |
|
V_i >>= 1 |
|
V_i %= candidate |
|
else: |
|
U_i.set(U_temp) |
|
V_i.set(V_temp) |
|
|
|
if U_i == 0: |
|
return PROBABLY_PRIME |
|
return COMPOSITE |
|
|
|
|
|
from Crypto.Util.number import sieve_base as _sieve_base_large |
|
|
|
|
|
_sieve_base = set(_sieve_base_large[:100]) |
|
|
|
|
|
def test_probable_prime(candidate, randfunc=None): |
|
"""Test if a number is prime. |
|
|
|
A number is qualified as prime if it passes a certain |
|
number of Miller-Rabin tests (dependent on the size |
|
of the number, but such that probability of a false |
|
positive is less than 10^-30) and a single Lucas test. |
|
|
|
For instance, a 1024-bit candidate will need to pass |
|
4 Miller-Rabin tests. |
|
|
|
:Parameters: |
|
candidate : integer |
|
The number to test for primality. |
|
randfunc : callable |
|
The routine to draw random bytes from to select Miller-Rabin bases. |
|
:Returns: |
|
``PROBABLE_PRIME`` if the number if prime with very high probability. |
|
``COMPOSITE`` if the number is a composite. |
|
For efficiency reasons, ``COMPOSITE`` is also returned for small primes. |
|
""" |
|
|
|
if randfunc is None: |
|
randfunc = Random.new().read |
|
|
|
if not isinstance(candidate, Integer): |
|
candidate = Integer(candidate) |
|
|
|
|
|
if int(candidate) in _sieve_base: |
|
return PROBABLY_PRIME |
|
try: |
|
map(candidate.fail_if_divisible_by, _sieve_base) |
|
except ValueError: |
|
return COMPOSITE |
|
|
|
|
|
|
|
|
|
mr_ranges = ((220, 30), (280, 20), (390, 15), (512, 10), |
|
(620, 7), (740, 6), (890, 5), (1200, 4), |
|
(1700, 3), (3700, 2)) |
|
|
|
bit_size = candidate.size_in_bits() |
|
try: |
|
mr_iterations = list(filter(lambda x: bit_size < x[0], |
|
mr_ranges))[0][1] |
|
except IndexError: |
|
mr_iterations = 1 |
|
|
|
if miller_rabin_test(candidate, mr_iterations, |
|
randfunc=randfunc) == COMPOSITE: |
|
return COMPOSITE |
|
if lucas_test(candidate) == COMPOSITE: |
|
return COMPOSITE |
|
return PROBABLY_PRIME |
|
|
|
|
|
def generate_probable_prime(**kwargs): |
|
"""Generate a random probable prime. |
|
|
|
The prime will not have any specific properties |
|
(e.g. it will not be a *strong* prime). |
|
|
|
Random numbers are evaluated for primality until one |
|
passes all tests, consisting of a certain number of |
|
Miller-Rabin tests with random bases followed by |
|
a single Lucas test. |
|
|
|
The number of Miller-Rabin iterations is chosen such that |
|
the probability that the output number is a non-prime is |
|
less than 1E-30 (roughly 2^{-100}). |
|
|
|
This approach is compliant to `FIPS PUB 186-4`__. |
|
|
|
:Keywords: |
|
exact_bits : integer |
|
The desired size in bits of the probable prime. |
|
It must be at least 160. |
|
randfunc : callable |
|
An RNG function where candidate primes are taken from. |
|
prime_filter : callable |
|
A function that takes an Integer as parameter and returns |
|
True if the number can be passed to further primality tests, |
|
False if it should be immediately discarded. |
|
|
|
:Return: |
|
A probable prime in the range 2^exact_bits > p > 2^(exact_bits-1). |
|
|
|
.. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf |
|
""" |
|
|
|
exact_bits = kwargs.pop("exact_bits", None) |
|
randfunc = kwargs.pop("randfunc", None) |
|
prime_filter = kwargs.pop("prime_filter", lambda x: True) |
|
if kwargs: |
|
raise ValueError("Unknown parameters: " + kwargs.keys()) |
|
|
|
if exact_bits is None: |
|
raise ValueError("Missing exact_bits parameter") |
|
if exact_bits < 160: |
|
raise ValueError("Prime number is not big enough.") |
|
|
|
if randfunc is None: |
|
randfunc = Random.new().read |
|
|
|
result = COMPOSITE |
|
while result == COMPOSITE: |
|
candidate = Integer.random(exact_bits=exact_bits, |
|
randfunc=randfunc) | 1 |
|
if not prime_filter(candidate): |
|
continue |
|
result = test_probable_prime(candidate, randfunc) |
|
return candidate |
|
|
|
|
|
def generate_probable_safe_prime(**kwargs): |
|
"""Generate a random, probable safe prime. |
|
|
|
Note this operation is much slower than generating a simple prime. |
|
|
|
:Keywords: |
|
exact_bits : integer |
|
The desired size in bits of the probable safe prime. |
|
randfunc : callable |
|
An RNG function where candidate primes are taken from. |
|
|
|
:Return: |
|
A probable safe prime in the range |
|
2^exact_bits > p > 2^(exact_bits-1). |
|
""" |
|
|
|
exact_bits = kwargs.pop("exact_bits", None) |
|
randfunc = kwargs.pop("randfunc", None) |
|
if kwargs: |
|
raise ValueError("Unknown parameters: " + kwargs.keys()) |
|
|
|
if randfunc is None: |
|
randfunc = Random.new().read |
|
|
|
result = COMPOSITE |
|
while result == COMPOSITE: |
|
q = generate_probable_prime(exact_bits=exact_bits - 1, randfunc=randfunc) |
|
candidate = q * 2 + 1 |
|
if candidate.size_in_bits() != exact_bits: |
|
continue |
|
result = test_probable_prime(candidate, randfunc=randfunc) |
|
return candidate |
|
|