/*************************************************
* Random BigInt Generation Source File           *
* (C) 1999-2003 The Botan Project                *
*************************************************/

#include <botan/numthry.h>

namespace Botan {

/*************************************************
* Generate a random integer                      *
*************************************************/
BigInt random_integer(u32bit bits, RNG_Quality level)
   {
   BigInt x;
   x.randomize(bits, level);
   return x;
   }

/*************************************************
* Generate a random integer within given range   *
*************************************************/
BigInt random_integer(const BigInt& min, const BigInt& max, RNG_Quality level)
   {
   BigInt range = max - min;

   if(range <= 0)
      throw Invalid_Argument("random_integer: invalid min/max values");

   return (min + (random_integer(range.bits() + 2, level) % range));
   }

/*************************************************
* Generate a random prime                        *
*************************************************/
BigInt random_prime(u32bit bits, RNG_Quality level, const BigInt& coprime,
                    u32bit equiv, u32bit modulo)
   {
   if(bits <= 48)
      throw Invalid_Argument("random_prime: Can't make a prime of " +
                             to_string(bits) + " bits");

   if(coprime <= 0)
      throw Invalid_Argument("random_prime: coprime must be > 0");
   if(modulo % 2 == 1 || 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");

   while(true)
      {
      BigInt p = random_integer(bits, level);
      p.set_bit(bits - 2);
      p.set_bit(0);

      if(p % modulo != equiv)
         p += (modulo - p % modulo) + equiv;

      const u32bit sieve_size = std::min(bits / 2, PRIME_TABLE_SIZE);
      SecureVector<u32bit> sieve(sieve_size);

      for(u32bit j = 0; j != sieve.size(); j++)
         sieve[j] = p % PRIMES[j];

      u32bit counter = 0;
      while(true)
         {
         if(counter == 4096 || p.bits() > bits)
            break;

         bool passes_sieve = true;
         counter++;
         p += modulo;

         for(u32bit j = 0; j != sieve.size(); j++)
            {
            sieve[j] = (sieve[j] + modulo) % PRIMES[j];
            if(sieve[j] == 0)
               passes_sieve = false;
            }

         if(!passes_sieve || gcd(p - BigInt::one(), coprime) != BigInt::one())
            continue;
         if(passes_mr_tests(p))
            return p;
         }
      }
   }

/*************************************************
* Generate a random safe prime                   *
*************************************************/
BigInt random_safe_prime(u32bit bits, RNG_Quality level)
   {
   if(bits <= 64)
      throw Invalid_Argument("random_safe_prime: Can't make a prime of " +
                             to_string(bits) + " bits");

   BigInt p;
   do
      p = (random_prime(bits - 1, level) << 1) + BigInt::one();
   while(!is_prime(p));
   return p;
   }

}
