Blame demos/factorize.c

Packit 5c3484
/* Factoring with Pollard's rho method.
Packit 5c3484
Packit 5c3484
Copyright 1995, 1997-2003, 2005, 2009, 2012, 2015 Free Software
Packit 5c3484
Foundation, Inc.
Packit 5c3484
Packit 5c3484
This program is free software; you can redistribute it and/or modify it under
Packit 5c3484
the terms of the GNU General Public License as published by the Free Software
Packit 5c3484
Foundation; either version 3 of the License, or (at your option) any later
Packit 5c3484
version.
Packit 5c3484
Packit 5c3484
This program is distributed in the hope that it will be useful, but WITHOUT ANY
Packit 5c3484
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
Packit 5c3484
PARTICULAR PURPOSE.  See the GNU General Public License for more details.
Packit 5c3484
Packit 5c3484
You should have received a copy of the GNU General Public License along with
Packit 5c3484
this program.  If not, see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
Packit 5c3484
#include <stdlib.h>
Packit 5c3484
#include <stdio.h>
Packit 5c3484
#include <string.h>
Packit 5c3484
#include <inttypes.h>
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
Packit 5c3484
static unsigned char primes_diff[] = {
Packit 5c3484
#define P(a,b,c) a,
Packit 5c3484
#include "primes.h"
Packit 5c3484
#undef P
Packit 5c3484
};
Packit 5c3484
#define PRIMES_PTAB_ENTRIES (sizeof(primes_diff) / sizeof(primes_diff[0]))
Packit 5c3484
Packit 5c3484
int flag_verbose = 0;
Packit 5c3484
Packit 5c3484
/* Prove primality or run probabilistic tests.  */
Packit 5c3484
int flag_prove_primality = 1;
Packit 5c3484
Packit 5c3484
/* Number of Miller-Rabin tests to run when not proving primality. */
Packit 5c3484
#define MR_REPS 25
Packit 5c3484
Packit 5c3484
struct factors
Packit 5c3484
{
Packit 5c3484
  mpz_t         *p;
Packit 5c3484
  unsigned long *e;
Packit 5c3484
  long nfactors;
Packit 5c3484
};
Packit 5c3484
Packit 5c3484
void factor (mpz_t, struct factors *);
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
factor_init (struct factors *factors)
Packit 5c3484
{
Packit 5c3484
  factors->p = malloc (1);
Packit 5c3484
  factors->e = malloc (1);
Packit 5c3484
  factors->nfactors = 0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
factor_clear (struct factors *factors)
Packit 5c3484
{
Packit 5c3484
  int i;
Packit 5c3484
Packit 5c3484
  for (i = 0; i < factors->nfactors; i++)
Packit 5c3484
    mpz_clear (factors->p[i]);
Packit 5c3484
Packit 5c3484
  free (factors->p);
Packit 5c3484
  free (factors->e);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
factor_insert (struct factors *factors, mpz_t prime)
Packit 5c3484
{
Packit 5c3484
  long    nfactors  = factors->nfactors;
Packit 5c3484
  mpz_t         *p  = factors->p;
Packit 5c3484
  unsigned long *e  = factors->e;
Packit 5c3484
  long i, j;
Packit 5c3484
Packit 5c3484
  /* Locate position for insert new or increment e.  */
Packit 5c3484
  for (i = nfactors - 1; i >= 0; i--)
Packit 5c3484
    {
Packit 5c3484
      if (mpz_cmp (p[i], prime) <= 0)
Packit 5c3484
	break;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  if (i < 0 || mpz_cmp (p[i], prime) != 0)
Packit 5c3484
    {
Packit 5c3484
      p = realloc (p, (nfactors + 1) * sizeof p[0]);
Packit 5c3484
      e = realloc (e, (nfactors + 1) * sizeof e[0]);
Packit 5c3484
Packit 5c3484
      mpz_init (p[nfactors]);
Packit 5c3484
      for (j = nfactors - 1; j > i; j--)
Packit 5c3484
	{
Packit 5c3484
	  mpz_set (p[j + 1], p[j]);
Packit 5c3484
	  e[j + 1] = e[j];
Packit 5c3484
	}
Packit 5c3484
      mpz_set (p[i + 1], prime);
Packit 5c3484
      e[i + 1] = 1;
Packit 5c3484
Packit 5c3484
      factors->p = p;
Packit 5c3484
      factors->e = e;
Packit 5c3484
      factors->nfactors = nfactors + 1;
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      e[i] += 1;
Packit 5c3484
    }
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
factor_insert_ui (struct factors *factors, unsigned long prime)
Packit 5c3484
{
Packit 5c3484
  mpz_t pz;
Packit 5c3484
Packit 5c3484
  mpz_init_set_ui (pz, prime);
Packit 5c3484
  factor_insert (factors, pz);
Packit 5c3484
  mpz_clear (pz);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
factor_using_division (mpz_t t, struct factors *factors)
Packit 5c3484
{
Packit 5c3484
  mpz_t q;
Packit 5c3484
  unsigned long int p;
Packit 5c3484
  int i;
Packit 5c3484
Packit 5c3484
  if (flag_verbose > 0)
Packit 5c3484
    {
Packit 5c3484
      printf ("[trial division] ");
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_init (q);
Packit 5c3484
Packit 5c3484
  p = mpz_scan1 (t, 0);
Packit 5c3484
  mpz_fdiv_q_2exp (t, t, p);
Packit 5c3484
  while (p)
Packit 5c3484
    {
Packit 5c3484
      factor_insert_ui (factors, 2);
Packit 5c3484
      --p;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  p = 3;
Packit 5c3484
  for (i = 1; i <= PRIMES_PTAB_ENTRIES;)
Packit 5c3484
    {
Packit 5c3484
      if (! mpz_divisible_ui_p (t, p))
Packit 5c3484
	{
Packit 5c3484
	  p += primes_diff[i++];
Packit 5c3484
	  if (mpz_cmp_ui (t, p * p) < 0)
Packit 5c3484
	    break;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  mpz_tdiv_q_ui (t, t, p);
Packit 5c3484
	  factor_insert_ui (factors, p);
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_clear (q);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
mp_millerrabin (mpz_srcptr n, mpz_srcptr nm1, mpz_ptr x, mpz_ptr y,
Packit 5c3484
		mpz_srcptr q, unsigned long int k)
Packit 5c3484
{
Packit 5c3484
  unsigned long int i;
Packit 5c3484
Packit 5c3484
  mpz_powm (y, x, q, n);
Packit 5c3484
Packit 5c3484
  if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0)
Packit 5c3484
    return 1;
Packit 5c3484
Packit 5c3484
  for (i = 1; i < k; i++)
Packit 5c3484
    {
Packit 5c3484
      mpz_powm_ui (y, y, 2, n);
Packit 5c3484
      if (mpz_cmp (y, nm1) == 0)
Packit 5c3484
	return 1;
Packit 5c3484
      if (mpz_cmp_ui (y, 1) == 0)
Packit 5c3484
	return 0;
Packit 5c3484
    }
Packit 5c3484
  return 0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
mp_prime_p (mpz_t n)
Packit 5c3484
{
Packit 5c3484
  int k, r, is_prime;
Packit 5c3484
  mpz_t q, a, nm1, tmp;
Packit 5c3484
  struct factors factors;
Packit 5c3484
Packit 5c3484
  if (mpz_cmp_ui (n, 1) <= 0)
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  /* We have already casted out small primes. */
Packit 5c3484
  if (mpz_cmp_ui (n, (long) FIRST_OMITTED_PRIME * FIRST_OMITTED_PRIME) < 0)
Packit 5c3484
    return 1;
Packit 5c3484
Packit 5c3484
  mpz_inits (q, a, nm1, tmp, NULL);
Packit 5c3484
Packit 5c3484
  /* Precomputation for Miller-Rabin.  */
Packit 5c3484
  mpz_sub_ui (nm1, n, 1);
Packit 5c3484
Packit 5c3484
  /* Find q and k, where q is odd and n = 1 + 2**k * q.  */
Packit 5c3484
  k = mpz_scan1 (nm1, 0);
Packit 5c3484
  mpz_tdiv_q_2exp (q, nm1, k);
Packit 5c3484
Packit 5c3484
  mpz_set_ui (a, 2);
Packit 5c3484
Packit 5c3484
  /* Perform a Miller-Rabin test, finds most composites quickly.  */
Packit 5c3484
  if (!mp_millerrabin (n, nm1, a, tmp, q, k))
Packit 5c3484
    {
Packit 5c3484
      is_prime = 0;
Packit 5c3484
      goto ret2;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  if (flag_prove_primality)
Packit 5c3484
    {
Packit 5c3484
      /* Factor n-1 for Lucas.  */
Packit 5c3484
      mpz_set (tmp, nm1);
Packit 5c3484
      factor (tmp, &factors);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  /* Loop until Lucas proves our number prime, or Miller-Rabin proves our
Packit 5c3484
     number composite.  */
Packit 5c3484
  for (r = 0; r < PRIMES_PTAB_ENTRIES; r++)
Packit 5c3484
    {
Packit 5c3484
      int i;
Packit 5c3484
Packit 5c3484
      if (flag_prove_primality)
Packit 5c3484
	{
Packit 5c3484
	  is_prime = 1;
Packit 5c3484
	  for (i = 0; i < factors.nfactors && is_prime; i++)
Packit 5c3484
	    {
Packit 5c3484
	      mpz_divexact (tmp, nm1, factors.p[i]);
Packit 5c3484
	      mpz_powm (tmp, a, tmp, n);
Packit 5c3484
	      is_prime = mpz_cmp_ui (tmp, 1) != 0;
Packit 5c3484
	    }
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  /* After enough Miller-Rabin runs, be content. */
Packit 5c3484
	  is_prime = (r == MR_REPS - 1);
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      if (is_prime)
Packit 5c3484
	goto ret1;
Packit 5c3484
Packit 5c3484
      mpz_add_ui (a, a, primes_diff[r]);	/* Establish new base.  */
Packit 5c3484
Packit 5c3484
      if (!mp_millerrabin (n, nm1, a, tmp, q, k))
Packit 5c3484
	{
Packit 5c3484
	  is_prime = 0;
Packit 5c3484
	  goto ret1;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  fprintf (stderr, "Lucas prime test failure.  This should not happen\n");
Packit 5c3484
  abort ();
Packit 5c3484
Packit 5c3484
 ret1:
Packit 5c3484
  if (flag_prove_primality)
Packit 5c3484
    factor_clear (&factors);
Packit 5c3484
 ret2:
Packit 5c3484
  mpz_clears (q, a, nm1, tmp, NULL);
Packit 5c3484
Packit 5c3484
  return is_prime;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
factor_using_pollard_rho (mpz_t n, unsigned long a, struct factors *factors)
Packit 5c3484
{
Packit 5c3484
  mpz_t x, z, y, P;
Packit 5c3484
  mpz_t t, t2;
Packit 5c3484
  unsigned long long k, l, i;
Packit 5c3484
Packit 5c3484
  if (flag_verbose > 0)
Packit 5c3484
    {
Packit 5c3484
      printf ("[pollard-rho (%lu)] ", a);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_inits (t, t2, NULL);
Packit 5c3484
  mpz_init_set_si (y, 2);
Packit 5c3484
  mpz_init_set_si (x, 2);
Packit 5c3484
  mpz_init_set_si (z, 2);
Packit 5c3484
  mpz_init_set_ui (P, 1);
Packit 5c3484
  k = 1;
Packit 5c3484
  l = 1;
Packit 5c3484
Packit 5c3484
  while (mpz_cmp_ui (n, 1) != 0)
Packit 5c3484
    {
Packit 5c3484
      for (;;)
Packit 5c3484
	{
Packit 5c3484
	  do
Packit 5c3484
	    {
Packit 5c3484
	      mpz_mul (t, x, x);
Packit 5c3484
	      mpz_mod (x, t, n);
Packit 5c3484
	      mpz_add_ui (x, x, a);
Packit 5c3484
Packit 5c3484
	      mpz_sub (t, z, x);
Packit 5c3484
	      mpz_mul (t2, P, t);
Packit 5c3484
	      mpz_mod (P, t2, n);
Packit 5c3484
Packit 5c3484
	      if (k % 32 == 1)
Packit 5c3484
		{
Packit 5c3484
		  mpz_gcd (t, P, n);
Packit 5c3484
		  if (mpz_cmp_ui (t, 1) != 0)
Packit 5c3484
		    goto factor_found;
Packit 5c3484
		  mpz_set (y, x);
Packit 5c3484
		}
Packit 5c3484
	    }
Packit 5c3484
	  while (--k != 0);
Packit 5c3484
Packit 5c3484
	  mpz_set (z, x);
Packit 5c3484
	  k = l;
Packit 5c3484
	  l = 2 * l;
Packit 5c3484
	  for (i = 0; i < k; i++)
Packit 5c3484
	    {
Packit 5c3484
	      mpz_mul (t, x, x);
Packit 5c3484
	      mpz_mod (x, t, n);
Packit 5c3484
	      mpz_add_ui (x, x, a);
Packit 5c3484
	    }
Packit 5c3484
	  mpz_set (y, x);
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
    factor_found:
Packit 5c3484
      do
Packit 5c3484
	{
Packit 5c3484
	  mpz_mul (t, y, y);
Packit 5c3484
	  mpz_mod (y, t, n);
Packit 5c3484
	  mpz_add_ui (y, y, a);
Packit 5c3484
Packit 5c3484
	  mpz_sub (t, z, y);
Packit 5c3484
	  mpz_gcd (t, t, n);
Packit 5c3484
	}
Packit 5c3484
      while (mpz_cmp_ui (t, 1) == 0);
Packit 5c3484
Packit 5c3484
      mpz_divexact (n, n, t);	/* divide by t, before t is overwritten */
Packit 5c3484
Packit 5c3484
      if (!mp_prime_p (t))
Packit 5c3484
	{
Packit 5c3484
	  if (flag_verbose > 0)
Packit 5c3484
	    {
Packit 5c3484
	      printf ("[composite factor--restarting pollard-rho] ");
Packit 5c3484
	    }
Packit 5c3484
	  factor_using_pollard_rho (t, a + 1, factors);
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  factor_insert (factors, t);
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      if (mp_prime_p (n))
Packit 5c3484
	{
Packit 5c3484
	  factor_insert (factors, n);
Packit 5c3484
	  break;
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      mpz_mod (x, x, n);
Packit 5c3484
      mpz_mod (z, z, n);
Packit 5c3484
      mpz_mod (y, y, n);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_clears (P, t2, t, z, x, y, NULL);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
factor (mpz_t t, struct factors *factors)
Packit 5c3484
{
Packit 5c3484
  factor_init (factors);
Packit 5c3484
Packit 5c3484
  if (mpz_sgn (t) != 0)
Packit 5c3484
    {
Packit 5c3484
      factor_using_division (t, factors);
Packit 5c3484
Packit 5c3484
      if (mpz_cmp_ui (t, 1) != 0)
Packit 5c3484
	{
Packit 5c3484
	  if (flag_verbose > 0)
Packit 5c3484
	    {
Packit 5c3484
	      printf ("[is number prime?] ");
Packit 5c3484
	    }
Packit 5c3484
	  if (mp_prime_p (t))
Packit 5c3484
	    factor_insert (factors, t);
Packit 5c3484
	  else
Packit 5c3484
	    factor_using_pollard_rho (t, 1, factors);
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
main (int argc, char *argv[])
Packit 5c3484
{
Packit 5c3484
  mpz_t t;
Packit 5c3484
  int i, j, k;
Packit 5c3484
  struct factors factors;
Packit 5c3484
Packit 5c3484
  while (argc > 1)
Packit 5c3484
    {
Packit 5c3484
      if (!strcmp (argv[1], "-v"))
Packit 5c3484
	flag_verbose = 1;
Packit 5c3484
      else if (!strcmp (argv[1], "-w"))
Packit 5c3484
	flag_prove_primality = 0;
Packit 5c3484
      else
Packit 5c3484
	break;
Packit 5c3484
Packit 5c3484
      argv++;
Packit 5c3484
      argc--;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_init (t);
Packit 5c3484
  if (argc > 1)
Packit 5c3484
    {
Packit 5c3484
      for (i = 1; i < argc; i++)
Packit 5c3484
	{
Packit 5c3484
	  mpz_set_str (t, argv[i], 0);
Packit 5c3484
Packit 5c3484
	  gmp_printf ("%Zd:", t);
Packit 5c3484
	  factor (t, &factors);
Packit 5c3484
Packit 5c3484
	  for (j = 0; j < factors.nfactors; j++)
Packit 5c3484
	    for (k = 0; k < factors.e[j]; k++)
Packit 5c3484
	      gmp_printf (" %Zd", factors.p[j]);
Packit 5c3484
Packit 5c3484
	  puts ("");
Packit 5c3484
	  factor_clear (&factors);
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      for (;;)
Packit 5c3484
	{
Packit 5c3484
	  mpz_inp_str (t, stdin, 0);
Packit 5c3484
	  if (feof (stdin))
Packit 5c3484
	    break;
Packit 5c3484
Packit 5c3484
	  gmp_printf ("%Zd:", t);
Packit 5c3484
	  factor (t, &factors);
Packit 5c3484
Packit 5c3484
	  for (j = 0; j < factors.nfactors; j++)
Packit 5c3484
	    for (k = 0; k < factors.e[j]; k++)
Packit 5c3484
	      gmp_printf (" %Zd", factors.p[j]);
Packit 5c3484
Packit 5c3484
	  puts ("");
Packit 5c3484
	  factor_clear (&factors);
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  exit (0);
Packit 5c3484
}