blob: 91e645591eefea411f6d3f8535c54eba4630cc62 [file] [log] [blame]
Austin Schuhbb1338c2024-06-15 19:31:16 -07001/* Factoring with Pollard's rho method.
2
3Copyright 1995, 1997-2003, 2005, 2009, 2012, 2015 Free Software
4Foundation, Inc.
5
6This program is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free Software
8Foundation; either version 3 of the License, or (at your option) any later
9version.
10
11This program is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License along with
16this 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
26static 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
33int flag_verbose = 0;
34
35/* Prove primality or run probabilistic tests. */
36int flag_prove_primality = 1;
37
38/* Number of Miller-Rabin tests to run when not proving primality. */
39#define MR_REPS 25
40
41struct factors
42{
43 mpz_t *p;
44 unsigned long *e;
45 long nfactors;
46};
47
48void factor (mpz_t, struct factors *);
49
50void
51factor_init (struct factors *factors)
52{
53 factors->p = malloc (1);
54 factors->e = malloc (1);
55 factors->nfactors = 0;
56}
57
58void
59factor_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
70void
71factor_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
109void
110factor_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
120void
121factor_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
161static int
162mp_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
183int
184mp_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
268void
269factor_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
365void
366factor (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
388int
389main (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}