123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- # ===================================================================
- #
- # Copyright (c) 2014, Legrandin <helderijs@gmail.com>
- # 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,
- randfunc=randfunc)
- 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
|