# =================================================================== # # Copyright (c) 2014, Legrandin # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # =================================================================== """Functions to create and test prime numbers. :undocumented: __package__ """ from Cryptodome import Random from Cryptodome.Math.Numbers import Integer from Cryptodome.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 # Step 1 and 2 m = Integer(minus_one) a = 0 while m.is_even(): m >>= 1 a += 1 # Skip step 3 # Step 4 for i in iter_range(iterations): # Step 4.1-2 base = 1 while base in (one, minus_one): base = Integer.random_range(min_inclusive=2, max_inclusive=candidate - 2) assert(2 <= base <= candidate - 2) # Step 4.3-4.4 z = pow(base, m, candidate) if z in (one, minus_one): continue # Step 4.5 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 # Step 5 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) # Step 1 if candidate in (1, 2, 3, 5): return PROBABLY_PRIME if candidate.is_even() or candidate.is_perfect_square(): return COMPOSITE # Step 2 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 # Found D. P=1 and Q=(1-D)/4 (note that Q is guaranteed to be an integer) # Step 3 # This is \delta(n) = n - jacobi(D/n) K = candidate + 1 # Step 4 r = K.size_in_bits() - 1 # Step 5 # U_1=1 and V_1=P U_i = Integer(1) V_i = Integer(1) U_temp = Integer(0) V_temp = Integer(0) # Step 6 for i in iter_range(r - 1, -1, -1): # Square # U_temp = U_i * V_i % candidate U_temp.set(U_i) U_temp *= V_i U_temp %= candidate # V_temp = (((V_i ** 2 + (U_i ** 2 * D)) * K) >> 1) % 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 # Multiply if K.get_bit(i): # U_i = (((U_temp + V_temp) * K) >> 1) % candidate 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 = (((V_temp + U_temp * D) * K) >> 1) % 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) # Step 7 if U_i == 0: return PROBABLY_PRIME return COMPOSITE from Cryptodome.Util.number import sieve_base as _sieve_base_large ## The optimal number of small primes to use for the sieve ## is probably dependent on the platform and the candidate size _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) # First, check trial division by the smallest primes if int(candidate) in _sieve_base: return PROBABLY_PRIME try: map(candidate.fail_if_divisible_by, _sieve_base) except ValueError: return COMPOSITE # These are the number of Miller-Rabin iterations s.t. p(k, t) < 1E-30, # with p(k, t) being the probability that a randomly chosen k-bit number # is composite but still survives t MR iterations. 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