xref: /netbsd-src/external/lgpl3/gmp/dist/demos/factorize.c (revision ce54336801cf28877c3414aa2fcb251dddd543a2)
151c586b8Smrg /* Factoring with Pollard's rho method.
251c586b8Smrg 
3*ce543368Smrg Copyright 1995, 1997-2003, 2005, 2009, 2012, 2015 Free Software
4*ce543368Smrg Foundation, Inc.
551c586b8Smrg 
651c586b8Smrg This program is free software; you can redistribute it and/or modify it under
751c586b8Smrg the terms of the GNU General Public License as published by the Free Software
851c586b8Smrg Foundation; either version 3 of the License, or (at your option) any later
951c586b8Smrg version.
1051c586b8Smrg 
1151c586b8Smrg This program is distributed in the hope that it will be useful, but WITHOUT ANY
1251c586b8Smrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
1351c586b8Smrg PARTICULAR PURPOSE.  See the GNU General Public License for more details.
1451c586b8Smrg 
1551c586b8Smrg You should have received a copy of the GNU General Public License along with
16*ce543368Smrg this program.  If not, see https://www.gnu.org/licenses/.  */
1751c586b8Smrg 
1851c586b8Smrg 
1951c586b8Smrg #include <stdlib.h>
2051c586b8Smrg #include <stdio.h>
2151c586b8Smrg #include <string.h>
22dab47db4Smrg #include <inttypes.h>
2351c586b8Smrg 
2451c586b8Smrg #include "gmp.h"
2551c586b8Smrg 
26dab47db4Smrg static unsigned char primes_diff[] = {
27dab47db4Smrg #define P(a,b,c) a,
28dab47db4Smrg #include "primes.h"
29dab47db4Smrg #undef P
30dab47db4Smrg };
31dab47db4Smrg #define PRIMES_PTAB_ENTRIES (sizeof(primes_diff) / sizeof(primes_diff[0]))
32dab47db4Smrg 
3351c586b8Smrg int flag_verbose = 0;
3451c586b8Smrg 
35dab47db4Smrg /* Prove primality or run probabilistic tests.  */
36dab47db4Smrg int flag_prove_primality = 1;
37dab47db4Smrg 
38dab47db4Smrg /* Number of Miller-Rabin tests to run when not proving primality. */
39dab47db4Smrg #define MR_REPS 25
40dab47db4Smrg 
41dab47db4Smrg struct factors
42dab47db4Smrg {
43dab47db4Smrg   mpz_t         *p;
44dab47db4Smrg   unsigned long *e;
45dab47db4Smrg   long nfactors;
46dab47db4Smrg };
47dab47db4Smrg 
48dab47db4Smrg void factor (mpz_t, struct factors *);
4951c586b8Smrg 
5051c586b8Smrg void
factor_init(struct factors * factors)51dab47db4Smrg factor_init (struct factors *factors)
5251c586b8Smrg {
53dab47db4Smrg   factors->p = malloc (1);
54dab47db4Smrg   factors->e = malloc (1);
55dab47db4Smrg   factors->nfactors = 0;
56dab47db4Smrg }
57dab47db4Smrg 
58dab47db4Smrg void
factor_clear(struct factors * factors)59dab47db4Smrg factor_clear (struct factors *factors)
60dab47db4Smrg {
61dab47db4Smrg   int i;
62dab47db4Smrg 
63dab47db4Smrg   for (i = 0; i < factors->nfactors; i++)
64dab47db4Smrg     mpz_clear (factors->p[i]);
65dab47db4Smrg 
66dab47db4Smrg   free (factors->p);
67dab47db4Smrg   free (factors->e);
68dab47db4Smrg }
69dab47db4Smrg 
70dab47db4Smrg void
factor_insert(struct factors * factors,mpz_t prime)71dab47db4Smrg factor_insert (struct factors *factors, mpz_t prime)
72dab47db4Smrg {
73dab47db4Smrg   long    nfactors  = factors->nfactors;
74dab47db4Smrg   mpz_t         *p  = factors->p;
75dab47db4Smrg   unsigned long *e  = factors->e;
76dab47db4Smrg   long i, j;
77dab47db4Smrg 
78dab47db4Smrg   /* Locate position for insert new or increment e.  */
79dab47db4Smrg   for (i = nfactors - 1; i >= 0; i--)
80dab47db4Smrg     {
81dab47db4Smrg       if (mpz_cmp (p[i], prime) <= 0)
82dab47db4Smrg 	break;
83dab47db4Smrg     }
84dab47db4Smrg 
85dab47db4Smrg   if (i < 0 || mpz_cmp (p[i], prime) != 0)
86dab47db4Smrg     {
87dab47db4Smrg       p = realloc (p, (nfactors + 1) * sizeof p[0]);
88dab47db4Smrg       e = realloc (e, (nfactors + 1) * sizeof e[0]);
89dab47db4Smrg 
90dab47db4Smrg       mpz_init (p[nfactors]);
91dab47db4Smrg       for (j = nfactors - 1; j > i; j--)
92dab47db4Smrg 	{
93dab47db4Smrg 	  mpz_set (p[j + 1], p[j]);
94dab47db4Smrg 	  e[j + 1] = e[j];
95dab47db4Smrg 	}
96dab47db4Smrg       mpz_set (p[i + 1], prime);
97dab47db4Smrg       e[i + 1] = 1;
98dab47db4Smrg 
99dab47db4Smrg       factors->p = p;
100dab47db4Smrg       factors->e = e;
101dab47db4Smrg       factors->nfactors = nfactors + 1;
102dab47db4Smrg     }
103dab47db4Smrg   else
104dab47db4Smrg     {
105dab47db4Smrg       e[i] += 1;
106dab47db4Smrg     }
107dab47db4Smrg }
108dab47db4Smrg 
109dab47db4Smrg void
factor_insert_ui(struct factors * factors,unsigned long prime)110dab47db4Smrg factor_insert_ui (struct factors *factors, unsigned long prime)
111dab47db4Smrg {
112dab47db4Smrg   mpz_t pz;
113dab47db4Smrg 
114dab47db4Smrg   mpz_init_set_ui (pz, prime);
115dab47db4Smrg   factor_insert (factors, pz);
116dab47db4Smrg   mpz_clear (pz);
117dab47db4Smrg }
118dab47db4Smrg 
119dab47db4Smrg 
120dab47db4Smrg void
factor_using_division(mpz_t t,struct factors * factors)121dab47db4Smrg factor_using_division (mpz_t t, struct factors *factors)
122dab47db4Smrg {
123dab47db4Smrg   mpz_t q;
124dab47db4Smrg   unsigned long int p;
125dab47db4Smrg   int i;
12651c586b8Smrg 
12751c586b8Smrg   if (flag_verbose > 0)
12851c586b8Smrg     {
129dab47db4Smrg       printf ("[trial division] ");
13051c586b8Smrg     }
13151c586b8Smrg 
13251c586b8Smrg   mpz_init (q);
13351c586b8Smrg 
134dab47db4Smrg   p = mpz_scan1 (t, 0);
135*ce543368Smrg   mpz_fdiv_q_2exp (t, t, p);
136dab47db4Smrg   while (p)
13751c586b8Smrg     {
138dab47db4Smrg       factor_insert_ui (factors, 2);
139dab47db4Smrg       --p;
14051c586b8Smrg     }
14151c586b8Smrg 
142dab47db4Smrg   p = 3;
143dab47db4Smrg   for (i = 1; i <= PRIMES_PTAB_ENTRIES;)
14451c586b8Smrg     {
145dab47db4Smrg       if (! mpz_divisible_ui_p (t, p))
14651c586b8Smrg 	{
147dab47db4Smrg 	  p += primes_diff[i++];
148dab47db4Smrg 	  if (mpz_cmp_ui (t, p * p) < 0)
14951c586b8Smrg 	    break;
15051c586b8Smrg 	}
15151c586b8Smrg       else
15251c586b8Smrg 	{
153dab47db4Smrg 	  mpz_tdiv_q_ui (t, t, p);
154dab47db4Smrg 	  factor_insert_ui (factors, p);
15551c586b8Smrg 	}
15651c586b8Smrg     }
15751c586b8Smrg 
158dab47db4Smrg   mpz_clear (q);
159dab47db4Smrg }
160dab47db4Smrg 
161dab47db4Smrg static int
mp_millerrabin(mpz_srcptr n,mpz_srcptr nm1,mpz_ptr x,mpz_ptr y,mpz_srcptr q,unsigned long int k)162dab47db4Smrg mp_millerrabin (mpz_srcptr n, mpz_srcptr nm1, mpz_ptr x, mpz_ptr y,
163dab47db4Smrg 		mpz_srcptr q, unsigned long int k)
164dab47db4Smrg {
165dab47db4Smrg   unsigned long int i;
166dab47db4Smrg 
167dab47db4Smrg   mpz_powm (y, x, q, n);
168dab47db4Smrg 
169dab47db4Smrg   if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0)
170dab47db4Smrg     return 1;
171dab47db4Smrg 
172dab47db4Smrg   for (i = 1; i < k; i++)
173dab47db4Smrg     {
174dab47db4Smrg       mpz_powm_ui (y, y, 2, n);
175dab47db4Smrg       if (mpz_cmp (y, nm1) == 0)
176dab47db4Smrg 	return 1;
177dab47db4Smrg       if (mpz_cmp_ui (y, 1) == 0)
178dab47db4Smrg 	return 0;
179dab47db4Smrg     }
180dab47db4Smrg   return 0;
181dab47db4Smrg }
182dab47db4Smrg 
183dab47db4Smrg int
mp_prime_p(mpz_t n)184dab47db4Smrg mp_prime_p (mpz_t n)
185dab47db4Smrg {
186dab47db4Smrg   int k, r, is_prime;
187dab47db4Smrg   mpz_t q, a, nm1, tmp;
188dab47db4Smrg   struct factors factors;
189dab47db4Smrg 
190dab47db4Smrg   if (mpz_cmp_ui (n, 1) <= 0)
191dab47db4Smrg     return 0;
192dab47db4Smrg 
193dab47db4Smrg   /* We have already casted out small primes. */
194dab47db4Smrg   if (mpz_cmp_ui (n, (long) FIRST_OMITTED_PRIME * FIRST_OMITTED_PRIME) < 0)
195dab47db4Smrg     return 1;
196dab47db4Smrg 
197dab47db4Smrg   mpz_inits (q, a, nm1, tmp, NULL);
198dab47db4Smrg 
199dab47db4Smrg   /* Precomputation for Miller-Rabin.  */
200dab47db4Smrg   mpz_sub_ui (nm1, n, 1);
201dab47db4Smrg 
202dab47db4Smrg   /* Find q and k, where q is odd and n = 1 + 2**k * q.  */
203dab47db4Smrg   k = mpz_scan1 (nm1, 0);
204dab47db4Smrg   mpz_tdiv_q_2exp (q, nm1, k);
205dab47db4Smrg 
206dab47db4Smrg   mpz_set_ui (a, 2);
207dab47db4Smrg 
208dab47db4Smrg   /* Perform a Miller-Rabin test, finds most composites quickly.  */
209dab47db4Smrg   if (!mp_millerrabin (n, nm1, a, tmp, q, k))
210dab47db4Smrg     {
211dab47db4Smrg       is_prime = 0;
212dab47db4Smrg       goto ret2;
213dab47db4Smrg     }
214dab47db4Smrg 
215dab47db4Smrg   if (flag_prove_primality)
216dab47db4Smrg     {
217dab47db4Smrg       /* Factor n-1 for Lucas.  */
218dab47db4Smrg       mpz_set (tmp, nm1);
219dab47db4Smrg       factor (tmp, &factors);
220dab47db4Smrg     }
221dab47db4Smrg 
222dab47db4Smrg   /* Loop until Lucas proves our number prime, or Miller-Rabin proves our
223dab47db4Smrg      number composite.  */
224dab47db4Smrg   for (r = 0; r < PRIMES_PTAB_ENTRIES; r++)
225dab47db4Smrg     {
226dab47db4Smrg       int i;
227dab47db4Smrg 
228dab47db4Smrg       if (flag_prove_primality)
229dab47db4Smrg 	{
230dab47db4Smrg 	  is_prime = 1;
231dab47db4Smrg 	  for (i = 0; i < factors.nfactors && is_prime; i++)
232dab47db4Smrg 	    {
233dab47db4Smrg 	      mpz_divexact (tmp, nm1, factors.p[i]);
234dab47db4Smrg 	      mpz_powm (tmp, a, tmp, n);
235dab47db4Smrg 	      is_prime = mpz_cmp_ui (tmp, 1) != 0;
236dab47db4Smrg 	    }
237dab47db4Smrg 	}
238dab47db4Smrg       else
239dab47db4Smrg 	{
240dab47db4Smrg 	  /* After enough Miller-Rabin runs, be content. */
241dab47db4Smrg 	  is_prime = (r == MR_REPS - 1);
242dab47db4Smrg 	}
243dab47db4Smrg 
244dab47db4Smrg       if (is_prime)
245dab47db4Smrg 	goto ret1;
246dab47db4Smrg 
247dab47db4Smrg       mpz_add_ui (a, a, primes_diff[r]);	/* Establish new base.  */
248dab47db4Smrg 
249dab47db4Smrg       if (!mp_millerrabin (n, nm1, a, tmp, q, k))
250dab47db4Smrg 	{
251dab47db4Smrg 	  is_prime = 0;
252dab47db4Smrg 	  goto ret1;
253dab47db4Smrg 	}
254dab47db4Smrg     }
255dab47db4Smrg 
256dab47db4Smrg   fprintf (stderr, "Lucas prime test failure.  This should not happen\n");
257dab47db4Smrg   abort ();
258dab47db4Smrg 
259dab47db4Smrg  ret1:
260dab47db4Smrg   if (flag_prove_primality)
261dab47db4Smrg     factor_clear (&factors);
262dab47db4Smrg  ret2:
263dab47db4Smrg   mpz_clears (q, a, nm1, tmp, NULL);
264dab47db4Smrg 
265dab47db4Smrg   return is_prime;
26651c586b8Smrg }
26751c586b8Smrg 
26851c586b8Smrg void
factor_using_pollard_rho(mpz_t n,unsigned long a,struct factors * factors)269dab47db4Smrg factor_using_pollard_rho (mpz_t n, unsigned long a, struct factors *factors)
27051c586b8Smrg {
271dab47db4Smrg   mpz_t x, z, y, P;
272dab47db4Smrg   mpz_t t, t2;
27351c586b8Smrg   unsigned long long k, l, i;
27451c586b8Smrg 
27551c586b8Smrg   if (flag_verbose > 0)
27651c586b8Smrg     {
27751c586b8Smrg       printf ("[pollard-rho (%lu)] ", a);
27851c586b8Smrg     }
27951c586b8Smrg 
280dab47db4Smrg   mpz_inits (t, t2, NULL);
28151c586b8Smrg   mpz_init_set_si (y, 2);
28251c586b8Smrg   mpz_init_set_si (x, 2);
283dab47db4Smrg   mpz_init_set_si (z, 2);
28451c586b8Smrg   mpz_init_set_ui (P, 1);
28551c586b8Smrg   k = 1;
28651c586b8Smrg   l = 1;
28751c586b8Smrg 
28851c586b8Smrg   while (mpz_cmp_ui (n, 1) != 0)
28951c586b8Smrg     {
29051c586b8Smrg       for (;;)
29151c586b8Smrg 	{
29251c586b8Smrg 	  do
29351c586b8Smrg 	    {
294dab47db4Smrg 	      mpz_mul (t, x, x);
295dab47db4Smrg 	      mpz_mod (x, t, n);
29651c586b8Smrg 	      mpz_add_ui (x, x, a);
29751c586b8Smrg 
298dab47db4Smrg 	      mpz_sub (t, z, x);
299dab47db4Smrg 	      mpz_mul (t2, P, t);
30051c586b8Smrg 	      mpz_mod (P, t2, n);
30151c586b8Smrg 
30251c586b8Smrg 	      if (k % 32 == 1)
30351c586b8Smrg 		{
304dab47db4Smrg 		  mpz_gcd (t, P, n);
305dab47db4Smrg 		  if (mpz_cmp_ui (t, 1) != 0)
30651c586b8Smrg 		    goto factor_found;
30751c586b8Smrg 		  mpz_set (y, x);
30851c586b8Smrg 		}
30951c586b8Smrg 	    }
31051c586b8Smrg 	  while (--k != 0);
31151c586b8Smrg 
312dab47db4Smrg 	  mpz_set (z, x);
31351c586b8Smrg 	  k = l;
31451c586b8Smrg 	  l = 2 * l;
31551c586b8Smrg 	  for (i = 0; i < k; i++)
31651c586b8Smrg 	    {
317dab47db4Smrg 	      mpz_mul (t, x, x);
318dab47db4Smrg 	      mpz_mod (x, t, n);
31951c586b8Smrg 	      mpz_add_ui (x, x, a);
32051c586b8Smrg 	    }
32151c586b8Smrg 	  mpz_set (y, x);
32251c586b8Smrg 	}
32351c586b8Smrg 
32451c586b8Smrg     factor_found:
32551c586b8Smrg       do
32651c586b8Smrg 	{
327dab47db4Smrg 	  mpz_mul (t, y, y);
328dab47db4Smrg 	  mpz_mod (y, t, n);
32951c586b8Smrg 	  mpz_add_ui (y, y, a);
33051c586b8Smrg 
331dab47db4Smrg 	  mpz_sub (t, z, y);
332dab47db4Smrg 	  mpz_gcd (t, t, n);
333dab47db4Smrg 	}
334dab47db4Smrg       while (mpz_cmp_ui (t, 1) == 0);
33551c586b8Smrg 
336dab47db4Smrg       mpz_divexact (n, n, t);	/* divide by t, before t is overwritten */
337dab47db4Smrg 
338dab47db4Smrg       if (!mp_prime_p (t))
33951c586b8Smrg 	{
34051c586b8Smrg 	  if (flag_verbose > 0)
34151c586b8Smrg 	    {
34251c586b8Smrg 	      printf ("[composite factor--restarting pollard-rho] ");
34351c586b8Smrg 	    }
344dab47db4Smrg 	  factor_using_pollard_rho (t, a + 1, factors);
34551c586b8Smrg 	}
34651c586b8Smrg       else
34751c586b8Smrg 	{
348dab47db4Smrg 	  factor_insert (factors, t);
34951c586b8Smrg 	}
35051c586b8Smrg 
351dab47db4Smrg       if (mp_prime_p (n))
352dab47db4Smrg 	{
353dab47db4Smrg 	  factor_insert (factors, n);
354dab47db4Smrg 	  break;
355dab47db4Smrg 	}
356dab47db4Smrg 
357dab47db4Smrg       mpz_mod (x, x, n);
358dab47db4Smrg       mpz_mod (z, z, n);
359dab47db4Smrg       mpz_mod (y, y, n);
360dab47db4Smrg     }
361dab47db4Smrg 
362dab47db4Smrg   mpz_clears (P, t2, t, z, x, y, NULL);
36351c586b8Smrg }
36451c586b8Smrg 
36551c586b8Smrg void
factor(mpz_t t,struct factors * factors)366dab47db4Smrg factor (mpz_t t, struct factors *factors)
36751c586b8Smrg {
368dab47db4Smrg   factor_init (factors);
36951c586b8Smrg 
370dab47db4Smrg   if (mpz_sgn (t) != 0)
371dab47db4Smrg     {
372dab47db4Smrg       factor_using_division (t, factors);
37351c586b8Smrg 
37451c586b8Smrg       if (mpz_cmp_ui (t, 1) != 0)
37551c586b8Smrg 	{
37651c586b8Smrg 	  if (flag_verbose > 0)
37751c586b8Smrg 	    {
37851c586b8Smrg 	      printf ("[is number prime?] ");
37951c586b8Smrg 	    }
380dab47db4Smrg 	  if (mp_prime_p (t))
381dab47db4Smrg 	    factor_insert (factors, t);
38251c586b8Smrg 	  else
383dab47db4Smrg 	    factor_using_pollard_rho (t, 1, factors);
384dab47db4Smrg 	}
38551c586b8Smrg     }
38651c586b8Smrg }
38751c586b8Smrg 
38851c586b8Smrg int
main(int argc,char * argv[])38951c586b8Smrg main (int argc, char *argv[])
39051c586b8Smrg {
39151c586b8Smrg   mpz_t t;
392dab47db4Smrg   int i, j, k;
393dab47db4Smrg   struct factors factors;
39451c586b8Smrg 
395dab47db4Smrg   while (argc > 1)
39651c586b8Smrg     {
397dab47db4Smrg       if (!strcmp (argv[1], "-v"))
39851c586b8Smrg 	flag_verbose = 1;
399dab47db4Smrg       else if (!strcmp (argv[1], "-w"))
400dab47db4Smrg 	flag_prove_primality = 0;
401dab47db4Smrg       else
402dab47db4Smrg 	break;
403dab47db4Smrg 
40451c586b8Smrg       argv++;
40551c586b8Smrg       argc--;
40651c586b8Smrg     }
40751c586b8Smrg 
40851c586b8Smrg   mpz_init (t);
40951c586b8Smrg   if (argc > 1)
41051c586b8Smrg     {
41151c586b8Smrg       for (i = 1; i < argc; i++)
41251c586b8Smrg 	{
41351c586b8Smrg 	  mpz_set_str (t, argv[i], 0);
41451c586b8Smrg 
415dab47db4Smrg 	  gmp_printf ("%Zd:", t);
416dab47db4Smrg 	  factor (t, &factors);
417dab47db4Smrg 
418dab47db4Smrg 	  for (j = 0; j < factors.nfactors; j++)
419dab47db4Smrg 	    for (k = 0; k < factors.e[j]; k++)
420dab47db4Smrg 	      gmp_printf (" %Zd", factors.p[j]);
421dab47db4Smrg 
42251c586b8Smrg 	  puts ("");
423dab47db4Smrg 	  factor_clear (&factors);
42451c586b8Smrg 	}
42551c586b8Smrg     }
42651c586b8Smrg   else
42751c586b8Smrg     {
42851c586b8Smrg       for (;;)
42951c586b8Smrg 	{
43051c586b8Smrg 	  mpz_inp_str (t, stdin, 0);
43151c586b8Smrg 	  if (feof (stdin))
43251c586b8Smrg 	    break;
433dab47db4Smrg 
434dab47db4Smrg 	  gmp_printf ("%Zd:", t);
435dab47db4Smrg 	  factor (t, &factors);
436dab47db4Smrg 
437dab47db4Smrg 	  for (j = 0; j < factors.nfactors; j++)
438dab47db4Smrg 	    for (k = 0; k < factors.e[j]; k++)
439dab47db4Smrg 	      gmp_printf (" %Zd", factors.p[j]);
440dab47db4Smrg 
44151c586b8Smrg 	  puts ("");
442dab47db4Smrg 	  factor_clear (&factors);
44351c586b8Smrg 	}
44451c586b8Smrg     }
44551c586b8Smrg 
44651c586b8Smrg   exit (0);
44751c586b8Smrg }
448