xref: /netbsd-src/external/lgpl3/gmp/dist/demos/factorize.c (revision ce54336801cf28877c3414aa2fcb251dddd543a2)
1 /* Factoring with Pollard's rho method.
2 
3 Copyright 1995, 1997-2003, 2005, 2009, 2012, 2015 Free Software
4 Foundation, Inc.
5 
6 This program is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free Software
8 Foundation; either version 3 of the License, or (at your option) any later
9 version.
10 
11 This program is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License along with
16 this program.  If not, see https://www.gnu.org/licenses/.  */
17 
18 
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <inttypes.h>
23 
24 #include "gmp.h"
25 
26 static unsigned char primes_diff[] = {
27 #define P(a,b,c) a,
28 #include "primes.h"
29 #undef P
30 };
31 #define PRIMES_PTAB_ENTRIES (sizeof(primes_diff) / sizeof(primes_diff[0]))
32 
33 int flag_verbose = 0;
34 
35 /* Prove primality or run probabilistic tests.  */
36 int flag_prove_primality = 1;
37 
38 /* Number of Miller-Rabin tests to run when not proving primality. */
39 #define MR_REPS 25
40 
41 struct factors
42 {
43   mpz_t         *p;
44   unsigned long *e;
45   long nfactors;
46 };
47 
48 void factor (mpz_t, struct factors *);
49 
50 void
factor_init(struct factors * factors)51 factor_init (struct factors *factors)
52 {
53   factors->p = malloc (1);
54   factors->e = malloc (1);
55   factors->nfactors = 0;
56 }
57 
58 void
factor_clear(struct factors * factors)59 factor_clear (struct factors *factors)
60 {
61   int i;
62 
63   for (i = 0; i < factors->nfactors; i++)
64     mpz_clear (factors->p[i]);
65 
66   free (factors->p);
67   free (factors->e);
68 }
69 
70 void
factor_insert(struct factors * factors,mpz_t prime)71 factor_insert (struct factors *factors, mpz_t prime)
72 {
73   long    nfactors  = factors->nfactors;
74   mpz_t         *p  = factors->p;
75   unsigned long *e  = factors->e;
76   long i, j;
77 
78   /* Locate position for insert new or increment e.  */
79   for (i = nfactors - 1; i >= 0; i--)
80     {
81       if (mpz_cmp (p[i], prime) <= 0)
82 	break;
83     }
84 
85   if (i < 0 || mpz_cmp (p[i], prime) != 0)
86     {
87       p = realloc (p, (nfactors + 1) * sizeof p[0]);
88       e = realloc (e, (nfactors + 1) * sizeof e[0]);
89 
90       mpz_init (p[nfactors]);
91       for (j = nfactors - 1; j > i; j--)
92 	{
93 	  mpz_set (p[j + 1], p[j]);
94 	  e[j + 1] = e[j];
95 	}
96       mpz_set (p[i + 1], prime);
97       e[i + 1] = 1;
98 
99       factors->p = p;
100       factors->e = e;
101       factors->nfactors = nfactors + 1;
102     }
103   else
104     {
105       e[i] += 1;
106     }
107 }
108 
109 void
factor_insert_ui(struct factors * factors,unsigned long prime)110 factor_insert_ui (struct factors *factors, unsigned long prime)
111 {
112   mpz_t pz;
113 
114   mpz_init_set_ui (pz, prime);
115   factor_insert (factors, pz);
116   mpz_clear (pz);
117 }
118 
119 
120 void
factor_using_division(mpz_t t,struct factors * factors)121 factor_using_division (mpz_t t, struct factors *factors)
122 {
123   mpz_t q;
124   unsigned long int p;
125   int i;
126 
127   if (flag_verbose > 0)
128     {
129       printf ("[trial division] ");
130     }
131 
132   mpz_init (q);
133 
134   p = mpz_scan1 (t, 0);
135   mpz_fdiv_q_2exp (t, t, p);
136   while (p)
137     {
138       factor_insert_ui (factors, 2);
139       --p;
140     }
141 
142   p = 3;
143   for (i = 1; i <= PRIMES_PTAB_ENTRIES;)
144     {
145       if (! mpz_divisible_ui_p (t, p))
146 	{
147 	  p += primes_diff[i++];
148 	  if (mpz_cmp_ui (t, p * p) < 0)
149 	    break;
150 	}
151       else
152 	{
153 	  mpz_tdiv_q_ui (t, t, p);
154 	  factor_insert_ui (factors, p);
155 	}
156     }
157 
158   mpz_clear (q);
159 }
160 
161 static int
mp_millerrabin(mpz_srcptr n,mpz_srcptr nm1,mpz_ptr x,mpz_ptr y,mpz_srcptr q,unsigned long int k)162 mp_millerrabin (mpz_srcptr n, mpz_srcptr nm1, mpz_ptr x, mpz_ptr y,
163 		mpz_srcptr q, unsigned long int k)
164 {
165   unsigned long int i;
166 
167   mpz_powm (y, x, q, n);
168 
169   if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0)
170     return 1;
171 
172   for (i = 1; i < k; i++)
173     {
174       mpz_powm_ui (y, y, 2, n);
175       if (mpz_cmp (y, nm1) == 0)
176 	return 1;
177       if (mpz_cmp_ui (y, 1) == 0)
178 	return 0;
179     }
180   return 0;
181 }
182 
183 int
mp_prime_p(mpz_t n)184 mp_prime_p (mpz_t n)
185 {
186   int k, r, is_prime;
187   mpz_t q, a, nm1, tmp;
188   struct factors factors;
189 
190   if (mpz_cmp_ui (n, 1) <= 0)
191     return 0;
192 
193   /* We have already casted out small primes. */
194   if (mpz_cmp_ui (n, (long) FIRST_OMITTED_PRIME * FIRST_OMITTED_PRIME) < 0)
195     return 1;
196 
197   mpz_inits (q, a, nm1, tmp, NULL);
198 
199   /* Precomputation for Miller-Rabin.  */
200   mpz_sub_ui (nm1, n, 1);
201 
202   /* Find q and k, where q is odd and n = 1 + 2**k * q.  */
203   k = mpz_scan1 (nm1, 0);
204   mpz_tdiv_q_2exp (q, nm1, k);
205 
206   mpz_set_ui (a, 2);
207 
208   /* Perform a Miller-Rabin test, finds most composites quickly.  */
209   if (!mp_millerrabin (n, nm1, a, tmp, q, k))
210     {
211       is_prime = 0;
212       goto ret2;
213     }
214 
215   if (flag_prove_primality)
216     {
217       /* Factor n-1 for Lucas.  */
218       mpz_set (tmp, nm1);
219       factor (tmp, &factors);
220     }
221 
222   /* Loop until Lucas proves our number prime, or Miller-Rabin proves our
223      number composite.  */
224   for (r = 0; r < PRIMES_PTAB_ENTRIES; r++)
225     {
226       int i;
227 
228       if (flag_prove_primality)
229 	{
230 	  is_prime = 1;
231 	  for (i = 0; i < factors.nfactors && is_prime; i++)
232 	    {
233 	      mpz_divexact (tmp, nm1, factors.p[i]);
234 	      mpz_powm (tmp, a, tmp, n);
235 	      is_prime = mpz_cmp_ui (tmp, 1) != 0;
236 	    }
237 	}
238       else
239 	{
240 	  /* After enough Miller-Rabin runs, be content. */
241 	  is_prime = (r == MR_REPS - 1);
242 	}
243 
244       if (is_prime)
245 	goto ret1;
246 
247       mpz_add_ui (a, a, primes_diff[r]);	/* Establish new base.  */
248 
249       if (!mp_millerrabin (n, nm1, a, tmp, q, k))
250 	{
251 	  is_prime = 0;
252 	  goto ret1;
253 	}
254     }
255 
256   fprintf (stderr, "Lucas prime test failure.  This should not happen\n");
257   abort ();
258 
259  ret1:
260   if (flag_prove_primality)
261     factor_clear (&factors);
262  ret2:
263   mpz_clears (q, a, nm1, tmp, NULL);
264 
265   return is_prime;
266 }
267 
268 void
factor_using_pollard_rho(mpz_t n,unsigned long a,struct factors * factors)269 factor_using_pollard_rho (mpz_t n, unsigned long a, struct factors *factors)
270 {
271   mpz_t x, z, y, P;
272   mpz_t t, t2;
273   unsigned long long k, l, i;
274 
275   if (flag_verbose > 0)
276     {
277       printf ("[pollard-rho (%lu)] ", a);
278     }
279 
280   mpz_inits (t, t2, NULL);
281   mpz_init_set_si (y, 2);
282   mpz_init_set_si (x, 2);
283   mpz_init_set_si (z, 2);
284   mpz_init_set_ui (P, 1);
285   k = 1;
286   l = 1;
287 
288   while (mpz_cmp_ui (n, 1) != 0)
289     {
290       for (;;)
291 	{
292 	  do
293 	    {
294 	      mpz_mul (t, x, x);
295 	      mpz_mod (x, t, n);
296 	      mpz_add_ui (x, x, a);
297 
298 	      mpz_sub (t, z, x);
299 	      mpz_mul (t2, P, t);
300 	      mpz_mod (P, t2, n);
301 
302 	      if (k % 32 == 1)
303 		{
304 		  mpz_gcd (t, P, n);
305 		  if (mpz_cmp_ui (t, 1) != 0)
306 		    goto factor_found;
307 		  mpz_set (y, x);
308 		}
309 	    }
310 	  while (--k != 0);
311 
312 	  mpz_set (z, x);
313 	  k = l;
314 	  l = 2 * l;
315 	  for (i = 0; i < k; i++)
316 	    {
317 	      mpz_mul (t, x, x);
318 	      mpz_mod (x, t, n);
319 	      mpz_add_ui (x, x, a);
320 	    }
321 	  mpz_set (y, x);
322 	}
323 
324     factor_found:
325       do
326 	{
327 	  mpz_mul (t, y, y);
328 	  mpz_mod (y, t, n);
329 	  mpz_add_ui (y, y, a);
330 
331 	  mpz_sub (t, z, y);
332 	  mpz_gcd (t, t, n);
333 	}
334       while (mpz_cmp_ui (t, 1) == 0);
335 
336       mpz_divexact (n, n, t);	/* divide by t, before t is overwritten */
337 
338       if (!mp_prime_p (t))
339 	{
340 	  if (flag_verbose > 0)
341 	    {
342 	      printf ("[composite factor--restarting pollard-rho] ");
343 	    }
344 	  factor_using_pollard_rho (t, a + 1, factors);
345 	}
346       else
347 	{
348 	  factor_insert (factors, t);
349 	}
350 
351       if (mp_prime_p (n))
352 	{
353 	  factor_insert (factors, n);
354 	  break;
355 	}
356 
357       mpz_mod (x, x, n);
358       mpz_mod (z, z, n);
359       mpz_mod (y, y, n);
360     }
361 
362   mpz_clears (P, t2, t, z, x, y, NULL);
363 }
364 
365 void
factor(mpz_t t,struct factors * factors)366 factor (mpz_t t, struct factors *factors)
367 {
368   factor_init (factors);
369 
370   if (mpz_sgn (t) != 0)
371     {
372       factor_using_division (t, factors);
373 
374       if (mpz_cmp_ui (t, 1) != 0)
375 	{
376 	  if (flag_verbose > 0)
377 	    {
378 	      printf ("[is number prime?] ");
379 	    }
380 	  if (mp_prime_p (t))
381 	    factor_insert (factors, t);
382 	  else
383 	    factor_using_pollard_rho (t, 1, factors);
384 	}
385     }
386 }
387 
388 int
main(int argc,char * argv[])389 main (int argc, char *argv[])
390 {
391   mpz_t t;
392   int i, j, k;
393   struct factors factors;
394 
395   while (argc > 1)
396     {
397       if (!strcmp (argv[1], "-v"))
398 	flag_verbose = 1;
399       else if (!strcmp (argv[1], "-w"))
400 	flag_prove_primality = 0;
401       else
402 	break;
403 
404       argv++;
405       argc--;
406     }
407 
408   mpz_init (t);
409   if (argc > 1)
410     {
411       for (i = 1; i < argc; i++)
412 	{
413 	  mpz_set_str (t, argv[i], 0);
414 
415 	  gmp_printf ("%Zd:", t);
416 	  factor (t, &factors);
417 
418 	  for (j = 0; j < factors.nfactors; j++)
419 	    for (k = 0; k < factors.e[j]; k++)
420 	      gmp_printf (" %Zd", factors.p[j]);
421 
422 	  puts ("");
423 	  factor_clear (&factors);
424 	}
425     }
426   else
427     {
428       for (;;)
429 	{
430 	  mpz_inp_str (t, stdin, 0);
431 	  if (feof (stdin))
432 	    break;
433 
434 	  gmp_printf ("%Zd:", t);
435 	  factor (t, &factors);
436 
437 	  for (j = 0; j < factors.nfactors; j++)
438 	    for (k = 0; k < factors.e[j]; k++)
439 	      gmp_printf (" %Zd", factors.p[j]);
440 
441 	  puts ("");
442 	  factor_clear (&factors);
443 	}
444     }
445 
446   exit (0);
447 }
448