diff options
Diffstat (limited to 'src/lib/math/numbertheory/make_prm.cpp')
-rw-r--r-- | src/lib/math/numbertheory/make_prm.cpp | 90 |
1 files changed, 59 insertions, 31 deletions
diff --git a/src/lib/math/numbertheory/make_prm.cpp b/src/lib/math/numbertheory/make_prm.cpp index f06f1978e..419252ed6 100644 --- a/src/lib/math/numbertheory/make_prm.cpp +++ b/src/lib/math/numbertheory/make_prm.cpp @@ -16,20 +16,22 @@ namespace Botan { */ BigInt random_prime(RandomNumberGenerator& rng, size_t bits, const BigInt& coprime, - size_t equiv, size_t modulo) + size_t equiv, size_t modulo, + size_t prob) { - if(coprime <= 0) + if(coprime.is_negative()) { - throw Invalid_Argument("random_prime: coprime must be > 0"); + throw Invalid_Argument("random_prime: coprime must be >= 0"); } - if(modulo % 2 == 1 || modulo == 0) + if(modulo == 0) { throw Invalid_Argument("random_prime: Invalid modulo value"); } - if(equiv >= modulo || equiv % 2 == 0) - { - throw Invalid_Argument("random_prime: equiv must be < modulo, and odd"); - } + + equiv %= modulo; + + if(equiv == 0) + throw Invalid_Argument("random_prime Invalid value for equiv/modulo"); // Handle small values: if(bits <= 1) @@ -50,6 +52,9 @@ BigInt random_prime(RandomNumberGenerator& rng, return ((rng.next_byte() % 2) ? 11 : 13); } + secure_vector<uint16_t> sieve(PRIME_TABLE_SIZE); + const size_t MAX_ATTEMPTS = 32*1024; + while(true) { BigInt p(rng, bits); @@ -59,21 +64,18 @@ BigInt random_prime(RandomNumberGenerator& rng, p.set_bit(bits - 2); p.set_bit(0); - if(p % modulo != equiv) - p += (modulo - p % modulo) + equiv; + // Force p to be equal to equiv mod modulo + p += (modulo - (p % modulo)) + equiv; - const size_t sieve_size = std::min(bits / 2, PRIME_TABLE_SIZE); - secure_vector<uint16_t> sieve(sieve_size); - - for(size_t j = 0; j != sieve.size(); ++j) - sieve[j] = static_cast<uint16_t>(p % PRIMES[j]); + for(size_t i = 0; i != sieve.size(); ++i) + sieve[i] = static_cast<uint16_t>(p % PRIMES[i]); size_t counter = 0; while(true) { ++counter; - if(counter >= 4096) + if(counter > MAX_ATTEMPTS) { break; // don't try forever, choose a new starting point } @@ -84,26 +86,39 @@ BigInt random_prime(RandomNumberGenerator& rng, break; bool passes_sieve = true; - for(size_t j = 0; j != sieve.size(); ++j) + for(size_t i = 0; i != sieve.size(); ++i) { - sieve[j] = (sieve[j] + modulo) % PRIMES[j]; - if(sieve[j] == 0) - { + sieve[i] = (sieve[i] + modulo) % PRIMES[i]; + + /* + In this case, p is a multiple of PRIMES[i] + */ + if(sieve[i] == 0) + passes_sieve = false; + + /* + In this case, 2*p+1 will be a multiple of PRIMES[i] + + So if generating a safe prime, we want to avoid this value + because 2*p+1 will not be useful. Since the check is cheap to + do and doesn't seem to affect the overall distribution of the + generated primes overmuch it's used in all cases. + + See "Safe Prime Generation with a Combined Sieve" M. Wiener + https://eprint.iacr.org/2003/186.pdf + */ + if(sieve[i] == PRIMES[i] / 2) passes_sieve = false; - break; - } } if(!passes_sieve) continue; - if(gcd(p - 1, coprime) != 1) + if(coprime > 0 && gcd(p - 1, coprime) != 1) continue; - if(is_prime(p, rng, 128, true)) - { + if(is_prime(p, rng, prob, true)) return p; - } } } } @@ -117,12 +132,25 @@ BigInt random_safe_prime(RandomNumberGenerator& rng, size_t bits) throw Invalid_Argument("random_safe_prime: Can't make a prime of " + std::to_string(bits) + " bits"); - BigInt p; - do - p = (random_prime(rng, bits - 1) << 1) + 1; - while(!is_prime(p, rng, 128, true)); + BigInt q, p; + for(;;) + { + /* + Generate q == 2 (mod 3) + + Otherwise [q == 1 (mod 3) case], 2*q+1 == 3 (mod 3) and not prime. + */ + q = random_prime(rng, bits - 1, 1, 2, 3, 8); + p = (q << 1) + 1; - return p; + if(is_prime(p, rng, 128, true)) + { + // We did only a weak check before, go back and verify q before returning + if(is_prime(q, rng, 128, true)) + return p; + } + + } } } |