/*

  Authors: Antti Huima <huima@ssh.fi>
           Mika Kojo <mkojo@ssh.fi>
  
  Copyright (C) 1996 SSH Communications Security Oy, Espoo, Finland
  All rights reserved.

  Created: Mon May  6 00:18:19 1996 [huima]

  This file contains generic functions which have to do with
  multiple-precision integers but are not provided by the GMP library.

  TODO:

    remove almost everything from this file and move them to
    sshmath/sshmp.c or equivalent in that directory.

    What stays here?

    Mainly routines that handle random numbers, e.g. use the
    cryptographically strong random number generator. We don't want to
    move it into sshmath, it wouldn't do much there.
  
  */

/*
 * $Id: genmp.c,v 1.34 2000/01/11 15:00:58 mkojo Exp $
 * $Log: genmp.c,v $
 * $EndLog$
 */

#include "sshincludes.h"
#include "sshmp.h"
#include "sieve.h"
#include "sshcrypt.h"
#include "libmonitor.h"
#include "genmp.h"
#include "sshgetput.h"

#define SSH_GENMP_MAX_PRIME        16000
#define SSH_GENMP_MAX_SIEVE_MEMORY 8192

#define SSH_DEBUG_MODULE "SshGenMP"

/* Generate a random integer (using the cryptographically strong random number
   generator). */

void ssh_mp_random_integer(SshInt *ret, unsigned int bits)
{
  unsigned int i;
  SshUInt32 limb;
  
  ssh_mp_set_ui(ret, 0);
  /* Loop 32 bit limbs */
  for (i = 0; i < bits; i += 32)
    {
      /* Construct one limb */
      limb = (((SshUInt32)ssh_random_get_byte() << 24) |
              ((SshUInt32)ssh_random_get_byte() << 16) |
              ((SshUInt32)ssh_random_get_byte() << 8) |
              ((SshUInt32)ssh_random_get_byte() & 0xff));
      /* Shift and add */
      ssh_mp_mul_2exp(ret, ret, 32);
      ssh_mp_add_ui(ret, ret, limb);
    }
  /* Cut unneeded bits off */
  ssh_mp_mod_2exp(ret, ret, bits);
}

/* Generate traditional prime. */

void ssh_mp_random_prime(SshInt *ret, unsigned int bits)
{
  SshInt start, aux;
  SshSieve sieve;
  unsigned int num_primes, p, i;
  SshWord *moduli, *prime_table;
  SshWord difference;

  /* Progress monitoring. */
  unsigned int progress_counter = 0;
  
  /* Initialize the prime search. */
  ssh_mp_init(&start);
  ssh_mp_init(&aux);

  if (bits < 16)
    {
      SshWord temp;
      /* Check from the prime sieve. */
      ssh_sieve_allocate_ui(&sieve, (1 << bits),
                            (1 << bits));

      /* Do not choose 2. */
      num_primes = ssh_sieve_prime_count(&sieve) - 1;
      
      ssh_mp_random_integer(&aux, bits);
      temp = ssh_mp_get_ui(&aux) % num_primes;
      
      for (p = 2; p; p = ssh_sieve_next_prime(p, &sieve), temp--)
        if (temp == 0)
          {
            ssh_mp_set_ui(ret, p);
            break;
          }
      if (temp != 0)
        ssh_fatal("ssh_mp_random_prime: could not find small prime.");

      ssh_mp_clear(&start);
      ssh_mp_clear(&aux);
      return;
    }

  /* Generate the prime sieve, this takes very little time. */
  ssh_sieve_allocate_ui(&sieve, SSH_GENMP_MAX_PRIME,
                        SSH_GENMP_MAX_SIEVE_MEMORY);
  /* Don't count 2. */
  num_primes = ssh_sieve_prime_count(&sieve)-1;

  /* Generate a simply indexed prime table. */
  prime_table = ssh_xmalloc(num_primes * sizeof(SshWord));
  for (p = 2, i = 0; p; p = ssh_sieve_next_prime(p, &sieve), i++)
    prime_table[i] = p;

  /* Allocate moduli table. */
  moduli = ssh_xmalloc(num_primes * sizeof(SshWord));
  
 retry:

  /* Pick a random integer of the appropriate size. */
  ssh_mp_random_integer(&start, bits);

  /* Set the highest bit. */
  ssh_mp_set_ui(&aux, 1);
  ssh_mp_mul_2exp(&aux, &aux, bits - 1);
  ssh_mp_or(&start, &start, &aux);
  /* Set the lowest bit to make it odd. */
  ssh_mp_set_ui(&aux, 1);
  ssh_mp_or(&start, &start, &aux);

  /* Initialize moduli of the small primes with respect to the given
     random number. */
  for (i = 0; i < num_primes; i++)
    moduli[i] = ssh_mp_mod_ui(&start, prime_table[i]);

  /* Look for numbers that are not evenly divisible by any of the small
     primes. */
  for (difference = 0; ; difference += 2)
    {
      unsigned int i;
      
      if (difference > 0x70000000)
        {
          /* Might never happen... */
          goto retry;
        }

      /* Check if it is a multiple of any small prime.  Note that this
         updates the moduli into negative values as difference grows. */
      for (i = 1; i < num_primes; i++)
        {
          while (moduli[i] + difference >= prime_table[i])
            moduli[i] -= prime_table[i];
          if (moduli[i] + difference == 0)
            break;
        }
      if (i < num_primes)
        continue; /* Multiple of a known prime. */

      /* Progress information. */
      ssh_crypto_progress_monitor(SSH_CRYPTO_PRIME_SEARCH,
                                  ++progress_counter);
      
      /* Compute the number in question. */
      ssh_mp_add_ui(ret, &start, difference);

      /* Perform Miller-Rabin strong pseudo primality tests */
      if (ssh_mp_is_probable_prime(ret, 20))
        break; 
    }

  /* Found a (probable) prime.  It is in ret. */

  /* Sanity check: does it still have the high bit set (we might have
     wrapped around)? */
  ssh_mp_div_2exp(&aux, ret, bits - 1);
  if (ssh_mp_get_ui(&aux) != 1)
    {
      goto retry;
    }

  /* Free the small prime moduli; they are no longer needed. */
  ssh_xfree(moduli);
  ssh_xfree(prime_table);
  /* Free the sieve. */
  ssh_sieve_free(&sieve);

  ssh_mp_clear(&start);
  ssh_mp_clear(&aux);
  /* Return value already set in ret. */
}

/* Generate a random prime within the [min, max] interval. We observe that
   the process can just choose a random number modulo (max - min) and
   then start from there. If it goes beyond max-1 then it cycles.
   */

void ssh_mp_random_prime_within_interval(SshInt *ret,
                                         SshInt *min, SshInt *max)
{
  SshInt pprime, temp, aux;
  SshSieve sieve;
  SshWord *moduli, *prime_table, difference, max_difference, num_primes, p;
  unsigned int i, bits;

  /* Progress monitoring. */
  unsigned int progress_counter = 0;

  /* Verify the interval. */
  if (ssh_mp_cmp(min, max) >= 0)
    ssh_fatal("ssh_mp_random_prime_within_interval: interval invalid.");

  /* Initialize temps. */
  ssh_mp_init(&pprime);
  ssh_mp_init(&temp);
  ssh_mp_init(&aux);

  /* Allocate a sieve. */
  ssh_sieve_allocate_ui(&sieve, SSH_GENMP_MAX_PRIME,
                        SSH_GENMP_MAX_SIEVE_MEMORY);
  /* Don't count 2. */
  num_primes = ssh_sieve_prime_count(&sieve) - 1;
  
  /* Allocate moduli table. */
  moduli = ssh_xmalloc(num_primes * sizeof(SshWord));
  
  /* Make a table of the primes. */
  prime_table = ssh_xmalloc(num_primes * sizeof(SshWord));
  for (p = 2, i = 0; p; p = ssh_sieve_next_prime(p, &sieve), i++)
    prime_table[i] = p;

retry:

  /* Generate the random number within the interval. */
  ssh_mp_sub(&temp, max, min);
  bits = ssh_mp_get_size(&temp, 2);
  
  /* Generate suitable random number (some additional bits for
     perhaps more uniform distribution, these really shouldn't matter). */
  ssh_mp_random_integer(&aux, bits + 10);
  /* Compute. */
  ssh_mp_mod(&aux, &aux, &temp);
  ssh_mp_add(&pprime, &aux, min);


  /* Fix it as odd. */
  ssh_mp_set_bit(&pprime, 0);
  
  /* Compute the max difference. */
  ssh_mp_sub(&aux, max, &pprime);
  if (ssh_mp_cmp_ui(&aux, 0) < 0)
    goto retry;

  /* Get it. */
  max_difference = ssh_mp_get_ui(&aux);
    
  /* Now we need to set up the moduli table. */
  for (i = 0; i < num_primes; i++)
    moduli[i] = ssh_mp_mod_ui(&pprime, prime_table[i]);
  
  
  /* Look for numbers that are not evenly divisible by any of the small
     primes. */
  for (difference = 0; ; difference += 2)
    {
      unsigned int i;
      
      if (difference > max_difference)
        /* Although we could just wrap around, we currently choose to
           just start from the scratch again. */
        goto retry;

      /* Check if it is a multiple of any small prime.  Note that this
         updates the moduli into negative values as difference grows. */
      for (i = 1; i < num_primes; i++)
        {
          while (moduli[i] + difference >= prime_table[i])
            moduli[i] -= prime_table[i];
          if (moduli[i] + difference == 0)
            break;
        }
      if (i < num_primes)
        continue; /* Multiple of a known prime. */

      /* Progress information. */
      ssh_crypto_progress_monitor(SSH_CRYPTO_PRIME_SEARCH,
                                  ++progress_counter);
      
      /* Compute the number in question. */
      ssh_mp_add_ui(ret, &pprime, difference);

      /* Perform Miller-Rabin strong pseudo primality tests */
      if (ssh_mp_is_probable_prime(ret, 20))
        break; 
    }

  /* Found a (probable) prime.  It is in ret. */

  /* Sanity check, are we in the interval. */
  if (ssh_mp_cmp(ret, min) <= 0 ||
      ssh_mp_cmp(ret, max) >= 0)
    goto retry;

  /* Free the small prime moduli; they are no longer needed. */
  ssh_xfree(moduli);
  ssh_xfree(prime_table);
  /* Free the sieve. */
  ssh_sieve_free(&sieve);

  ssh_mp_clear(&pprime);
  ssh_mp_clear(&aux);
  ssh_mp_clear(&temp);
  /* Return value already set in ret. */
}

/* The P1363 prime generation (from working draft i.e. might change in
   future). */

/* Generate random prime number using explicitly set limits. */

void ssh_mp_random_prime_within_limits(SshInt *ret,
                                       int min_bits, int max_bits)
{
  SshInt pprime, temp;
  SshSieve sieve;
  SshWord *moduli, *prime_table, difference, num_primes, p;
  unsigned int i, len;
  Boolean divisible;

  /* Progress monitoring. */
  unsigned int progress_counter = 0;
  
  /* Verify that limits are in correct order. */
  if (min_bits >= max_bits)
    {
      /* Assume we still want random prime so get it but use more bits
         rather than less. */
      
      min_bits = max_bits;
      max_bits = min_bits + 2;
    }

  ssh_mp_init(&pprime);
  ssh_mp_init(&temp);

  /* Allocate a sieve. */
  ssh_sieve_allocate_ui(&sieve, SSH_GENMP_MAX_PRIME,
                        SSH_GENMP_MAX_SIEVE_MEMORY);
  /* Don't count 2. */
  num_primes = ssh_sieve_prime_count(&sieve) - 1;
  
  /* Allocate moduli table. */
  moduli = ssh_xmalloc(num_primes * sizeof(SshWord));
  
  /* Make a table of the primes. */
  prime_table = ssh_xmalloc(num_primes * sizeof(SshWord));
  for (p = 2, i = 0; p; p = ssh_sieve_next_prime(p, &sieve), i++)
    prime_table[i] = p;
  
retry:
  
  /* Get a random integer within limits. (Should not be too difficult,
     could be done also by setting the highest bit, but that approach was
     taken in the above code so doing this differently). */
  do {
    ssh_mp_random_integer(&pprime, max_bits);
    len = ssh_mp_get_size(&pprime, 2);
  } while (len < min_bits);

  /* If even the make it odd. */
  if ((ssh_mp_get_ui(&pprime) & 0x1) == 0)
    ssh_mp_add_ui(&pprime, &pprime, 1);

  /* Initialize moduli of the small primes with respect to the given
     random number. */
  for (i = 0; i < num_primes; i++)
    moduli[i] = ssh_mp_mod_ui(&pprime, prime_table[i]);

  /* Look for numbers that are not evenly divisible by any of the small
     primes. */
  difference = 0;
  
  while (1)
    {
      /* Set the divisible flag. */
      divisible = FALSE;

      /* In now and them add the difference to the probable prime. */
      if (difference > 1000)
        {
          ssh_mp_add_ui(&pprime, &pprime, difference);
          difference = 0;

          len = ssh_mp_get_size(&pprime, 2);
          if (len > max_bits)
            {
              ssh_mp_set_ui(&temp, 1);
              ssh_mp_mul_2exp(&temp, &temp, max_bits);
              ssh_mp_sub(&pprime, &pprime, &temp);
              
              ssh_mp_div_2exp(&temp, &temp, max_bits - min_bits);
              ssh_mp_add(&pprime, &pprime, &temp);
              ssh_mp_sub_ui(&pprime, &pprime, 1);

              /* Check that the probable prime is odd. */
              if ((ssh_mp_get_ui(&pprime) & 0x1) == 0)
                ssh_mp_add_ui(&pprime, &pprime, 1);

              /* Compute again the moduli table. */
              for (i = 0; i < num_primes; i++)
                moduli[i] = ssh_mp_mod_ui(&pprime, prime_table[i]);
            }
        }
              
      /* Check if it is a multiple of any small prime. */
      for (i = 0; i < num_primes; i++)
        {
          /* Check for this round. */
          if (moduli[i] == 0)
            divisible = TRUE;
          /* Compute for the next round. */
          moduli[i] += 2;
          if (moduli[i] >= prime_table[i])
            moduli[i] -= prime_table[i];
        }

      /* Add the difference by 2. */
      difference += 2;
      
      /* Multiple of known prime. */
      if (divisible)
        continue; 

      /* Acknowledge application. */
      ssh_crypto_progress_monitor(SSH_CRYPTO_PRIME_SEARCH,
                                  ++progress_counter);
      
      /* Set to ret and check if gone over the max limit. */
      ssh_mp_add_ui(&pprime, &pprime, difference);
      difference = 0;

      /* Check the length. */
      len = ssh_mp_get_size(&pprime, 2);
      if (len > max_bits)
        {
          /* compute: pprime - 2^max_bits + 2^min_bits - 1 */
          ssh_mp_set_ui(&temp, 1);
          ssh_mp_mul_2exp(&temp, &temp, max_bits);
          ssh_mp_sub(&pprime, &pprime, &temp);
          ssh_mp_set_ui(&temp, 1);
          ssh_mp_mul_2exp(&temp, &temp, min_bits);
          ssh_mp_add(&pprime, &pprime, &temp);
          ssh_mp_sub_ui(&pprime, &pprime, 1);
          
          /* Check that the probable prime is odd. */
          if ((ssh_mp_get_ui(&pprime) & 0x1) == 0)
            ssh_mp_add_ui(&pprime, &pprime, 1);
          
          /* Compute again the moduli table. */
          for (i = 0; i < num_primes; i++)
            moduli[i] = ssh_mp_mod_ui(&pprime, prime_table[i]);
          continue;
        }
      
      /* Compute the number in question. */
      ssh_mp_set(ret, &pprime);

      /* Perform Miller-Rabin strong pseudo primality tests */
      if (ssh_mp_is_probable_prime(ret, 15))
        break; 
    }

  /* Found a (probable) prime.  It is in ret. */

  /* Sanity check. */
  len = ssh_mp_get_size(ret, 2);
  if (len < min_bits || len > max_bits)
    goto retry;

  /* Free the small prime moduli; they are no longer needed. */
  ssh_xfree(moduli);
  ssh_xfree(prime_table);
  ssh_sieve_free(&sieve);
  
  ssh_mp_clear(&pprime);
  ssh_mp_clear(&temp);
  /* Return value already set in ret. */  
}

/* Generate random prime number using explicitly set limits and
   a congruence condition. ret = a (mod r). This operation is
   rather slow. */

void ssh_mp_random_prime_with_congruence(SshInt *ret,
                                         int min_bits, int max_bits,
                                         SshInt *r, SshInt *a)
{
  SshInt pprime, temp, w, r2;
  unsigned int len;

  unsigned int progress_counter = 0;
  
  /* Verify that limits are in correct order. */
  if (min_bits >= max_bits)
    {
      /* Assume we still want random prime so get it but use more bits
         rather than less. */
      
      min_bits = max_bits;
      max_bits = min_bits + 2;
    }

  ssh_mp_init(&pprime);
  ssh_mp_init(&temp);
  ssh_mp_init(&w);
  ssh_mp_init(&r2);
  
retry:
  
  /* Get a random integer within limits. (Should not be too difficult,
     could be done also by setting the highest bit, but that approach was
     taken in the above code so doing this differently). */
  do {
    ssh_mp_random_integer(&pprime, max_bits);
    len = ssh_mp_get_size(&pprime, 2);
  } while (len < min_bits);

  ssh_mp_mul_ui(&r2, r, 2);
  ssh_mp_mod(&w, &pprime, &r2);

  ssh_mp_add(&pprime, &pprime, &r2);
  ssh_mp_add(&pprime, &pprime, a);
  ssh_mp_sub(&pprime, &pprime, &w);
  
  /* If even the make it odd. */
  if ((ssh_mp_get_ui(&pprime) & 0x1) == 0)
    ssh_mp_add(&pprime, &pprime, r);

  while (1)
    {
      ssh_mp_add(&pprime, &pprime, &r2);
      
      /* Check the length. */
      len = ssh_mp_get_size(&pprime, 2);
      if (len > max_bits)
        {
          /* compute: pprime - 2^max_bits + 2^min_bits - 1 */
          ssh_mp_set_ui(&temp, 1);
          ssh_mp_mul_2exp(&temp, &temp, max_bits);
          ssh_mp_sub(&pprime, &pprime, &temp);
          ssh_mp_set_ui(&temp, 1);
          ssh_mp_mul_2exp(&temp, &temp, min_bits);
          ssh_mp_add(&pprime, &pprime, &temp);
          ssh_mp_sub_ui(&pprime, &pprime, 1);
          
          /* Check that the probable prime is odd. */
          if ((ssh_mp_get_ui(&pprime) & 0x1) == 0)
            ssh_mp_add_ui(&pprime, &pprime, 1);

          ssh_mp_mod(&w, &pprime, &r2);
          
          ssh_mp_add(&pprime, &pprime, &r2);
          ssh_mp_add(&pprime, &pprime, a);
          ssh_mp_sub(&pprime, &pprime, &w);
          continue;
        }

      ssh_crypto_progress_monitor(SSH_CRYPTO_PRIME_SEARCH,
                                  ++progress_counter);
      
      /* Check for primality. */
      
      /* Compute the number in question. */
      ssh_mp_set(ret, &pprime);

      /* Perform Miller-Rabin strong pseudo primality tests */
      if (ssh_mp_is_probable_prime(ret, 15))
        break;
    }

  /* Sanity check. */
  len = ssh_mp_get_size(ret, 2);
  if (len < min_bits || len > max_bits)
    {
      goto retry;
    }
  ssh_mp_clear(&pprime);
  ssh_mp_clear(&temp);
  ssh_mp_clear(&w);
  ssh_mp_clear(&r2);
  /* Return value already set in ret. */  
}

/* Generate strong random primes P1363 style. Where prime 'prime' satisfies
   prime = 1 (mod r), prime = -1 (mod s), r = 1 (mod t) and r, s, t are all
   large primes. Also 'div' = r. */

void ssh_mp_strong_p1363_random_prime(SshInt *prime, SshInt *div, 
                                      int big_bits, int small_bits)
{
  SshInt t, r, s, u, v, a, temp;
  unsigned int lt_bits, lr_bits, ls_bits;

  if (small_bits < 160 || big_bits < 320)
    ssh_fatal("error: discrete log might be too easy with primes (%d, %d).\n",
              big_bits, small_bits);

  if (small_bits > big_bits)
    big_bits = small_bits + 10;
  
  /* Assume that small_bits > 160. */
  lr_bits = small_bits;
  lt_bits = lr_bits - 10;
  ls_bits = small_bits;
  
  /* Initialize integers. */
  ssh_mp_init(&t);
  ssh_mp_init(&r);
  ssh_mp_init(&s);
  ssh_mp_init(&u);
  ssh_mp_init(&v);
  ssh_mp_init(&a);
  ssh_mp_init(&temp);

  ssh_mp_set_ui(&temp, 1);
  
  ssh_mp_random_prime_within_limits(&t, lt_bits - 1, lt_bits);
  ssh_mp_random_prime_with_congruence(&r, lr_bits - 1, lr_bits, &t, &temp);
  ssh_mp_random_prime_within_limits(&s, ls_bits - 1, ls_bits);

  /* Invert s (mod r) and r (mod s). */
  ssh_mp_mod_invert(&u, &s, &r);
  ssh_mp_mod_invert(&v, &r, &s);

  /* Compute a = su - rv (mod rs) */
  ssh_mp_mul(&a, &s, &u);
  ssh_mp_mul(&temp, &r, &v);
  ssh_mp_sub(&a, &a, &temp);

  ssh_mp_mul(&temp, &r, &s);
  ssh_mp_mod(&a, &a, &temp);

  ssh_mp_random_prime_with_congruence(prime, big_bits - 1, big_bits, &temp,
                                      &a);

  ssh_mp_set(div, &r);
  
  /* Free integers. */
  ssh_mp_clear(&t);
  ssh_mp_clear(&r);
  ssh_mp_clear(&s);
  ssh_mp_clear(&u);
  ssh_mp_clear(&v);
  ssh_mp_clear(&a);
  ssh_mp_clear(&temp);
}

/* Generate a strong random prime. That is, p = q * c + 1, where p and q are
   prime and c > 1.

   Here we use the idea that given random 2^n-1 < x < 2^n, we can compute
   y = x (mod 2q), and then p = x - y + 1 + 2tq. Given this method the
   probability that we get values that are not in the correct range is
   reasonably small. 
   
   */

void ssh_mp_random_strong_prime(SshInt *prime,
                                SshInt *order,
                                int prime_bits, int order_bits)
{
  SshInt aux, aux2, u;
  SshSieve sieve;
  SshWord *table_q, *table_u, *prime_table, p;
  unsigned long i, j, table_count, upto;
  Boolean flag;

  unsigned int progress_counter = 0;
  
  /* Check for bugs. */
  if (prime_bits < order_bits)
    ssh_fatal("ssh_mp_random_strong_prime: "
              "requested prime less than the group order!");
  
  /* Keep the running in place. */
  if (prime_bits - order_bits - 1 > 24)
    upto = 1 << 24;
  else
    upto = 1 << (prime_bits - order_bits - 1);
  
  ssh_mp_init(&aux);
  ssh_mp_init(&aux2);
  ssh_mp_init(&u);

  /* There seems to be no real reason to generate this as a strong prime. */
  ssh_mp_random_prime(order, order_bits);

  /* Generate the sieve again (it was already generated in the random
     prime generation code), but it shouldn't be too slow. */
  ssh_sieve_allocate_ui(&sieve, SSH_GENMP_MAX_PRIME,
                        SSH_GENMP_MAX_SIEVE_MEMORY);
  /* Compute the number of primes. */
  table_count = ssh_sieve_prime_count(&sieve) - 1;

  /* Generate a suitable table of primes. */
  prime_table = ssh_xmalloc(table_count * sizeof(SshWord));
  for (p = 2, i = 0; p; p = ssh_sieve_next_prime(p, &sieve), i++)
    prime_table[i] = p;
  
  /* Reduce group order. Remember the factor 2. */
  table_q = ssh_xmalloc(table_count * sizeof(SshWord) * 2);
  table_u = table_q + table_count;
  for (i = 0; i < table_count; i++)
    {
      table_q[i] =
        (ssh_mp_mod_ui(order, prime_table[i]) * 2) % prime_table[i];
    }

  /* In case we don't find one quickly enough. */
retry:

  /* Generate a random integer large enough. */
  ssh_mp_random_integer(&u, prime_bits);

  /* Set the highest bit on. */
  ssh_mp_set_ui(&aux, 1);
  ssh_mp_mul_2exp(&aux, &aux, prime_bits - 1);
  ssh_mp_or(&u, &u, &aux);
  
  /* Compute the initial value for the prime. */
  ssh_mp_set(&aux, order);
  ssh_mp_mul_2exp(&aux, &aux, 1);
  ssh_mp_mod(&aux2, &u, &aux);
  ssh_mp_sub(&u, &u, &aux2);
  ssh_mp_add_ui(&u, &u, 1);

  /* Now check whether the value is still large enough. */
  if (ssh_mp_get_size(&u, 2) <= prime_bits - 1)
    goto retry;

  /* Now compute the residues of the 'probable prime'. */
  for (j = 0; j < table_count; j++)
    table_u[j] = ssh_mp_mod_ui(&u, prime_table[j]);

  /* Set the 2*q for  later. */
  ssh_mp_mul_2exp(&aux2, order, 1);
  
  /* Loop through until a prime is found. */
  for (i = 0; i < upto; i++)
    {
      unsigned long cur_p, value;

      flag = TRUE;
      for (j = 1; j < table_count; j++)
        {
          cur_p = prime_table[j];
          value = table_u[j];

          /* Check if the result seems to indicate divisible value. */
          if (value >= cur_p)
            value -= cur_p;
          if (value == 0)
            flag = FALSE;
          /* For the next round compute. */
          table_u[j] = value + table_q[j];
        }

      if (flag != TRUE)
        continue;

      /* Acknowledge application that again one possibly good value was
         found. */
      ssh_crypto_progress_monitor(SSH_CRYPTO_PRIME_SEARCH,
                                  ++progress_counter);
      
      /* Compute the proposed prime. */
      ssh_mp_set(prime, &u);
      ssh_mp_mul_ui(&aux, &aux2, i);
      ssh_mp_add(prime, prime, &aux);

      /* Check that the size of the prime is within range. */
      if (ssh_mp_get_size(prime, 2) > prime_bits)
        goto retry;
      
      /* Miller-Rabin */
      if (ssh_mp_is_probable_prime(prime, 20))
        break;
    }

  if (i >= upto)
    goto retry;

  /* Free the moduli tables. */
  ssh_xfree(table_q);
  ssh_xfree(prime_table);
  ssh_sieve_free(&sieve);

  /* Free temporary memory. */
  ssh_mp_clear(&aux);
  ssh_mp_clear(&aux2);
  ssh_mp_clear(&u);
}

/* Method for computing a prime that is resistant against p-1 and p+1
   methods of factoring.

   As suggested by John Krueger at sci.crypt (31 Jul 1997).

   The improvement made over Kruegers method is to compute chinese remainder
   theorem so that

     x =  1 mod q1
     x = -1 mod q2
     x =  1 mod 2

   where 1 <= x < q1*q2*2.
     
   Last conqruence, of course, asserts that we don't need to change q1 and
   q2, i.e. there should be number of form  

     t*(q1*q2*2) + x 

   which is prime for some t. Hopefully t need not be too large.
   
   */

void ssh_mp_random_safe_prime(SshInt *p,
                              SshInt *q1,
                              SshInt *q2,
                              unsigned int bits)
{
  SshInt t1, t2, t3, y1, y2, y3, m1, m2, m3, q3, qq;
  SshWord *table_v, *table_u, *prime_table, small_prime;
  SshSieve sieve;
  unsigned int table_count, i, j;
  unsigned int upto = (1 << 30);
  Boolean flag;

  unsigned int progress_counter = 0;
  
  /* Initialize a few temporary variables. */
  ssh_mp_init(&t1);
  ssh_mp_init(&t2);
  ssh_mp_init(&t3);
  ssh_mp_init(&m1);
  ssh_mp_init(&m2);
  ssh_mp_init(&m3);
  ssh_mp_init(&y1);
  ssh_mp_init(&y2);
  ssh_mp_init(&y3);
  ssh_mp_init(&qq);
  ssh_mp_init(&q3);

  /* Generate the sieve, but it shouldn't be too slow. */
  ssh_sieve_allocate_ui(&sieve, SSH_GENMP_MAX_PRIME,
                        SSH_GENMP_MAX_SIEVE_MEMORY);
  /* Compute the number of primes. */
  table_count = ssh_sieve_prime_count(&sieve) - 1;

  /* Generate a suitable table of primes. */
  prime_table = ssh_xmalloc(table_count * sizeof(SshWord));
  for (small_prime = 3, i = 0; small_prime;
       small_prime = ssh_sieve_next_prime(small_prime, &sieve), i++)
    prime_table[i] = small_prime;

  /* Allocate tables. */
  table_v = ssh_xmalloc(table_count * sizeof(table_v[0]) * 2);
  table_u = table_v + SSH_MAX_PRIMES_IN_TABLE;
  
  /* Using chinese remainder theorem generate t1 = 1 mod q1, t1 = -1 mod q2.
     Also we'd like to make sure that t1 = 1 mod 2. */

  /* Generate two large primes. */
  ssh_mp_random_prime(q1, (bits/2));
  ssh_mp_random_prime(q2, (bits/2));

  /* Compute modulus. */
  ssh_mp_mul(&m3, q1, q2);
  
  /* q3 = 2, thus q1*q2 mod 2 == 1. */
  if ((ssh_mp_get_ui(&m3) & 0x1) == 0)
    ssh_fatal("ssh_mp_random_safe_prime: prime equals to 2.");

  ssh_mp_mul_ui(&qq, &qq, 2);
  
  ssh_mp_mul_ui(&m1, q2, 2);
  ssh_mp_mul_ui(&m2, q1, 2);
  
  ssh_mp_set_ui(&q3, 2);

  /* Compute inverses. */
  ssh_mp_mod_invert(&y1, &m1, q1);
  ssh_mp_mod_invert(&y2, &m2, q2);
  
  /* Compute first part. */
  ssh_mp_mul(&t1, &m1, &y1);

  /* Compute second part. */
  ssh_mp_mul(&t2, &m2, &y2);
  ssh_mp_sub_ui(&t3, q1, 1);
  ssh_mp_mul(&t2, &t2, &t3);
  ssh_mp_mod(&t2, &t2, &qq);

  /* Combine. */
  ssh_mp_add(&t1, &t1, &t2);
  ssh_mp_add(&t1, &t1, &m3);
  ssh_mp_mod(&t1, &t1, &qq);

  /* We never should have to deal with cases like this. */
  if ((ssh_mp_get_ui(&t1) & 0x1) == 0)
    ssh_fatal("ssh_mp_random_safe_prime: should never be divisible by 2!");
  
  /* Next search for number of form l + t1 which is a prime where
     l = c*qq.

     We can again use small primes to get rid of values that are not
     prime, and then Fermats little theorem etc. */

  /* Following generate a table where

     v[i] = t1 % p[i],
     u[i] = qq % p[i],

     which can be used for quick checks. */

  /* For simplicity we'd like to work only with values > qq. */
  ssh_mp_add(&t1, &t1, &qq);
  
  /* Compute table values. */
  for (i = 0; i < table_count; i++)
    {
      table_v[i] = ssh_mp_mod_ui(&t1, prime_table[i]);
      table_u[i] = ssh_mp_mod_ui(&qq, prime_table[i]);
    }

  /* Search for a prime. */
  for (i = 0; i < upto; i++)
    {
      flag = TRUE;
      for (j = 0; j < table_count; j++)
        {
          /* Check if the result seems to indicate divisible value. */
          if (table_v[j] == 0)
            flag = FALSE;
          /* For the next round compute. */
          table_v[j] += table_u[j];
          if (table_v[j] >= prime_table[j])
            table_v[j] -= prime_table[j];
        }

      if (flag != TRUE)
        continue;

      ssh_crypto_progress_monitor(SSH_CRYPTO_PRIME_SEARCH,
                                  ++progress_counter);

      /* Compute the proposed prime. */
      ssh_mp_mul_ui(p, &qq, i);
      ssh_mp_add(p, p, &t1);
      
      /* Miller-Rabin */
      if (ssh_mp_is_probable_prime(p, 20))
        break;
    }

  /* Free tables. */
  ssh_xfree(table_v);
  ssh_xfree(prime_table);
  ssh_sieve_free(&sieve);

  ssh_mp_clear(&t1);
  ssh_mp_clear(&t2);
  ssh_mp_clear(&t3);
  ssh_mp_clear(&m1);
  ssh_mp_clear(&m2);
  ssh_mp_clear(&m3);
  ssh_mp_clear(&y1);
  ssh_mp_clear(&y2);
  ssh_mp_clear(&y3);
  ssh_mp_clear(&qq);
  ssh_mp_clear(&q3);
}
                              
/* Basic modular enhancements. Due the nature of extended euclids algorithm
   it sometimes returns integers that are negative. For our cases positive
   results are better. */

int ssh_mp_mod_invert(SshInt *op_dest, const SshInt *op_src,
                      const SshInt *modulo)
{
  int status;

  status = ssh_mp_invert(op_dest, op_src, modulo);

  if (ssh_mp_cmp_ui(op_dest, 0) < 0)
    ssh_mp_add(op_dest, op_dest, modulo);
  
  return status;
}

/* Get random number mod 'modulo' */

/* Random number with some sense in getting only a small number of
   bits. This will avoid most of the extra bits. However, we could
   do it in many other ways too. Like we could distribute the random bits
   in reasonably random fashion around the available size. This would
   ensure that cryptographical use would be slightly safer. */
void ssh_mp_mod_random_entropy(SshInt *op, const SshInt *modulo,
                               unsigned int bits)
{
  ssh_mp_random_integer(op, bits);
  ssh_mp_mod(op, op, modulo);
}

/* Just plain _modular_ random number generation. */
void ssh_mp_mod_random(SshInt *op, const SshInt *modulo)
{
  unsigned int bits;
 
  bits = ssh_mp_bit_size(modulo);
  ssh_mp_random_integer(op, bits);
  ssh_mp_mod(op, op, modulo);
}

#if 0

/* Reduced and faster lucas function. Works a quite nicely with Williams p+1
   factoring method. */

void ssh_mp_reduced_lucas(SshInt *op_dest, const SshInt *op_e,
                          const SshInt *op_p,
                          const SshInt *op_n)
{
  SshInt v1, v2;
  char *bittable;
  int bit, scan_bit, maxbit;

  if (ssh_mp_cmp_ui(op_e, 0) == 0)
    {
      ssh_mp_set_ui(op_dest, 2);
      return;
    }
  
  maxbit = ssh_mp_bit_size(op_e);

  bittable = (char *)ssh_xmalloc(maxbit);
  
  bit = 0;
  scan_bit = -1;
  
  while (bit < maxbit)
    {
      scan_bit = ssh_mp_scan1(op_e, bit);
      if (scan_bit >= maxbit)
        break;

      while (bit < scan_bit)
        {
          bittable[bit] = 0;
          bit++;
        }

      bittable[bit] = 1;
      bit++;
    }

  /* Set up */
  ssh_mp_init_set(&v2, op_p);
  ssh_mp_init(&v1);
  ssh_mp_mul(&v1, op_p, op_p);
  ssh_mp_sub_ui(&v1, &v1, 2);
  ssh_mp_mod(&v1, &v1, op_n);

  /* Get the most-significant bit */
  bit--;

  while (bit--)
    {
      if (bittable[bit])
        {
          ssh_mp_mul(&v2, &v2, &v1);
          ssh_mp_sub(&v2, &v2, op_p);
          ssh_mp_mod(&v2, &v2, op_n);

          ssh_mp_mul(&v1, &v1, &v1);
          ssh_mp_sub_ui(&v1, &v1, 2);
          ssh_mp_mod(&v1, &v1, op_n);
        }
      else
        {
          ssh_mp_mul(&v1, &v2, &v1);
          ssh_mp_sub(&v1, &v1, op_p);
          ssh_mp_mod(&v1, &v1, op_n);

          ssh_mp_mul(&v2, &v2, &v2);
          ssh_mp_sub_ui(&v2, &v2, 2);
          ssh_mp_mod(&v2, &v2, op_n);
        }
    }

  /* Free bit table */
  ssh_xfree(bittable);

  ssh_mp_clear(&v1);
  ssh_mp_clear(&v2);

  ssh_mp_set(op_dest, &v2);
}
 
/* Generating lucas sequences. */

void ssh_mp_lucas(SshInt *op_dest, const SshInt *op_src1,
                  const SshInt *op_src2,
                  const SshInt *k, const SshInt *modulo)
{
  SshInt u, v, inv2, t, t1, t2, t3, a;
  int bits, scan_bits, last_bit = 0, maxbits;
  unsigned char *bit_table;
  
  /* Initialize temporary variables. */
  ssh_mp_init_set_ui(&u, 1);
  ssh_mp_init_set(&v, op_src1);

  ssh_mp_init(&t);
  ssh_mp_init(&t1);
  ssh_mp_init(&t2);
  ssh_mp_init(&t3);
  ssh_mp_init_set_ui(&inv2, 2);
  ssh_mp_mod_invert(&inv2, &inv2, modulo);
  ssh_mp_init(&a);

  /* Compute a = op_src1*op_src1 - 4*op_src2 */
  ssh_mp_mul(&a, op_src1, op_src1);
  ssh_mp_mul_ui(&t, op_src2, 4);
  ssh_mp_sub(&a, &a, &t);
  ssh_mp_mod(&a, &a, modulo);
  
  /* Get the maximum bit count */
  maxbits = ssh_mp_bit_size(k);
  bits = 0;
  scan_bits = -1;

  /* Allocate for reverse bits */
  bit_table = (unsigned char *)ssh_xmalloc(maxbits);
  
  /* Get the reverse order */
  while (bits < maxbits)
    {
      scan_bits = ssh_mp_scan1(k, bits);
      if (scan_bits >= maxbits)
        break;
      
      while (bits < scan_bits)
        {
          bit_table[bits] = 0;
          bits++;
        }
          
      bit_table[bits] = 1;
      last_bit = bits;
      
      bits++;
    }

  bits = last_bit;
  
  while (bits)
    {
      bits--;
      /* Compute (u, v) = (uv (mod p), (v^2 + a)/2 (mod p)) */
      ssh_mp_mul(&t1, &u, &v);
      
      ssh_mp_mul(&t2, &v, &v);
      ssh_mp_mul(&t3, &u, &u);
      ssh_mp_mul(&t3, &t3, &a);
      ssh_mp_add(&t2, &t2, &t3);
      ssh_mp_mul(&t2, &t2, &inv2);
      
      ssh_mp_mod(&v, &t2, modulo);
      ssh_mp_mod(&u, &t1, modulo);
      
      if (bit_table[bits])
        {
          ssh_mp_mul(&t1, op_src1, &u);
          ssh_mp_add(&t1, &t1, &v);
          ssh_mp_mul(&t1, &t1, &inv2);

          ssh_mp_mul(&t2, op_src1, &v);
          ssh_mp_mul(&t3, &a, &u);
          ssh_mp_add(&t2, &t2, &t3);
          ssh_mp_mul(&t2, &t2, &inv2);

          ssh_mp_mod(&u, &t1, modulo);
          ssh_mp_mod(&v, &t2, modulo);
        }
    }

  ssh_mp_set(op_dest, &v);

  /* Free allocated memory */
  ssh_xfree(bit_table);
  
  ssh_mp_clear(&t);
  ssh_mp_clear(&u);
  ssh_mp_clear(&v);
  ssh_mp_clear(&t1);
  ssh_mp_clear(&t2);
  ssh_mp_clear(&t3);
  ssh_mp_clear(&a);
  ssh_mp_clear(&inv2);
  
}

/* Modular square roots, with lucas sequence. Works fine, and is quite
   fast. If possible select the modulus so that you can use the special
   cases. */

int ssh_mp_mod_sqrt(SshInt *op_dest, const SshInt *op_src,
                    const SshInt *modulo)
{
  SshInt t, t1, t2, inv2;

  /* Fast check for 0, which would otherwise confuse the system
     quite a bit. */
  if (ssh_mp_cmp_ui(op_src, 0) == 0)
    {
      ssh_mp_set_ui(op_dest, 0);
      return 1;
    }
  
  /* There is no square root if this is true. */
  if (ssh_mp_legendre(op_src, modulo) == -1)
    {
      ssh_mp_set_ui(op_dest, 0);
      return 0;
    }

  /* Initialize temporary variables. */
  ssh_mp_init(&t);
  ssh_mp_init(&t1);
  ssh_mp_init(&t2);
  ssh_mp_init_set_ui(&inv2, 2);

  /* Test the special cases first */
  
  /* if congruence modulo = 3 (mod 4) holds */
  ssh_mp_mod_ui2(&t, modulo, 4);
  if (ssh_mp_cmp_ui(&t, 3) == 0)
    {
      ssh_mp_sub_ui(&t, modulo, 3);
      ssh_mp_div_2exp(&t, &t, 2);
      ssh_mp_add_ui(&t, &t, 1);
      ssh_mp_powm(op_dest, op_src, &t, modulo);
      goto end;
    }

  /* if congruence modulo = 5 (mod 8) holds */
  ssh_mp_mod_ui2(&t, modulo, 8);
  if (ssh_mp_cmp_ui(&t, 5) == 0)
    {
      ssh_mp_sub_ui(&t, modulo, 5);
      ssh_mp_div_2exp(&t, &t, 3);
      
      ssh_mp_mul_ui(&t1, op_src, 2);
      ssh_mp_powm(&t2, &t1, &t, modulo);

      ssh_mp_mul(&t, &t2, &t2);
      ssh_mp_mul(&t, &t, op_src);
      ssh_mp_mul_ui(&t, &t, 2);
      ssh_mp_mod(&t, &t, modulo);

      ssh_mp_sub_ui(&t, &t, 1);
      ssh_mp_mul(&t, &t, &t2);
      ssh_mp_mul(&t, &t, op_src);
      ssh_mp_mod(op_dest, &t, modulo);

      goto end;
    }
  
  /* Modulo = 1 (mod 4). */

  /* Find t^2 - 4(op_src) such that it has not square root (mod modulo) */
  ssh_mp_mul_ui(&t, op_src, 4);
  ssh_mp_set_ui(&t1, 1);

  while (ssh_mp_cmp(&t1, modulo) <= 0)
    {
      ssh_mp_mul(&t2, &t1, &t1);
      ssh_mp_sub(&t2, &t2, &t);
      ssh_mp_mod(&t2, &t2, modulo);

      if (ssh_mp_legendre(&t2, modulo) == -1)
        break;

      ssh_mp_add_ui(&t1, &t1, 1);
    }
  
  /* Compute the square root with lucas sequence... */
  ssh_mp_add_ui(&t2, modulo, 1);
  ssh_mp_div_ui(&t2, &t2, 2);
  ssh_mp_lucas(op_dest, &t1, op_src, &t2, modulo);

  /* ...multiply with the inverse of 2 */
  ssh_mp_mod_invert(&inv2, &inv2, modulo);
  ssh_mp_mul(op_dest, op_dest, &inv2);
  ssh_mp_mod(op_dest, op_dest, modulo);
  
end:

  /* Clear temporary variables */
  ssh_mp_clear(&t);
  ssh_mp_clear(&t1);
  ssh_mp_clear(&t2);

  ssh_mp_clear(&inv2);

  return 1;
}

#endif

#if 0
/* Check the Menezes, Okamoto and Vanstone elliptic curve reduction attack
   possibility. */

Boolean ssh_mp_mov_condition(const SshInt *op_b, const SshInt *op_q,
                             const SshInt *op_r)
{
  SshInt t, i;
  Boolean mov_condition = FALSE;
  
  /* Initialize temporary variables. */
  ssh_mp_init_set_ui(&t, 1);
  
  ssh_mp_init_set(&i, op_b);

  /* Iterate the mov condition */
  while (ssh_mp_cmp_ui(&i, 0) != 0)
    {
      ssh_mp_mul(&t, &t, op_q);
      ssh_mp_mod(&t, &t, op_r);
      if (ssh_mp_cmp_ui(&t, 1) == 0)
        {
          mov_condition = TRUE;
          break;
        }

      ssh_mp_sub_ui(&i, &i, 1);
    }

  /* Clear temporary variables. */
  ssh_mp_clear(&t);
  ssh_mp_clear(&i);

  return mov_condition;
}

#endif

/* Check whether op_src is of order op_ord (mod modulo). Not used and not
   tested. */

int ssh_mp_is_order(const SshInt *op_ord, const SshInt *op_src,
                    const SshInt *modulo)
{
  SshInt t, t1;
  SshSieve sieve;
  SshWord p;
  int is_order = 1;
  
  /* Initialize t and t1 */
  ssh_mp_init(&t);
  ssh_mp_init(&t1);
  
  ssh_mp_powm(&t, op_src, op_ord, modulo);
  if (ssh_mp_cmp_ui(&t, 1) != 0)
    {
      is_order = 0;
      goto end;
    }

  ssh_sieve_allocate_ui(&sieve, SSH_GENMP_MAX_PRIME,
                        SSH_GENMP_MAX_SIEVE_MEMORY);
  
  /* Trial division factoring algorithm... this shouldn't need better (?) */
  ssh_mp_set(&t, op_ord);
  for (p = 2; p; p = ssh_sieve_next_prime(p, &sieve))
    {
      /* Check whether op_src is divisible by a prime... */
      if (ssh_mp_mod_ui(&t, p) == 0)
        {
          /* This really isn't necessary but speeds up possibly a bit. */
          do
            {
              ssh_mp_div_ui(&t, &t, p);
            }
          while (ssh_mp_mod_ui(&t1, p) == 0);
            
          ssh_mp_powm_expui(&t, op_src, p, modulo);
          if (ssh_mp_cmp_ui(&t, 1) == 0)
            {
              is_order = 0;
              break;
            }
        }
    }
  ssh_sieve_free(&sieve);
  
end:
  
  ssh_mp_clear(&t);
  ssh_mp_clear(&t1);
  
  /* Could be of the order of op_ord */
  return is_order;
}

/* Find a random generator of order 'order' modulo 'modulo'. */

Boolean ssh_mp_random_generator(SshInt *g, SshInt *order, SshInt *modulo)
{
  SshInt aux, t;
  int bits;

  ssh_mp_init(&aux);
  ssh_mp_init(&t);

  ssh_mp_sub_ui(&aux, modulo, 1);
  ssh_mp_mod(&t, &aux, order);

  if (ssh_mp_cmp_ui(&t, 0) != 0)
    {
      ssh_mp_clear(&aux);
      ssh_mp_clear(&t);
      return FALSE;
    }

  ssh_mp_div_q(&t, &aux, order);
  bits = ssh_mp_get_size(modulo, 2);
  
  while (1)
    {
      ssh_mp_random_integer(g, bits);
      ssh_mp_mod(g, g, modulo);
      ssh_mp_powm(g, g, &t, modulo);

      if (ssh_mp_cmp_ui(g, 1) != 0)
        break;
    }

  /* Check. */
  ssh_mp_powm(&aux, g, order, modulo);
  if (ssh_mp_cmp_ui(&aux, 1) != 0)
    {
      ssh_mp_clear(&aux);
      ssh_mp_clear(&t);
      return FALSE;
    }

  ssh_mp_clear(&aux);
  ssh_mp_clear(&t);

  return TRUE;
}

/* genmp.c */

