factor.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /* $NetBSD: factor.c,v 1.15 2004/02/08 11:47:36 jsm Exp $ */
  2. /*
  3. * Copyright (c) 1989, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * This code is derived from software contributed to Berkeley by
  7. * Landon Curt Noll.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * 3. Neither the name of the University nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. #include <sys/cdefs.h>
  34. #ifndef lint
  35. __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
  36. The Regents of the University of California. All rights reserved.\n");
  37. #endif /* not lint */
  38. #ifndef lint
  39. #if 0
  40. static char sccsid[] = "@(#)factor.c 8.4 (Berkeley) 5/4/95";
  41. #else
  42. __RCSID("$NetBSD: factor.c,v 1.15 2004/02/08 11:47:36 jsm Exp $");
  43. #endif
  44. #endif /* not lint */
  45. /*
  46. * factor - factor a number into primes
  47. *
  48. * By: Landon Curt Noll chongo@toad.com, ...!{sun,tolsoft}!hoptoad!chongo
  49. *
  50. * chongo <for a good prime call: 391581 * 2^216193 - 1> /\oo/\
  51. *
  52. * usage:
  53. * factor [number] ...
  54. *
  55. * The form of the output is:
  56. *
  57. * number: factor1 factor1 factor2 factor3 factor3 factor3 ...
  58. *
  59. * where factor1 < factor2 < factor3 < ...
  60. *
  61. * If no args are given, the list of numbers are read from stdin.
  62. */
  63. #include <ctype.h>
  64. #include <err.h>
  65. #include <errno.h>
  66. #include <limits.h>
  67. #include <stdio.h>
  68. #include <stdlib.h>
  69. #include <unistd.h>
  70. #ifdef HAVE_OPENSSL
  71. #include <openssl/bn.h>
  72. #else
  73. typedef long BIGNUM;
  74. typedef u_long BN_ULONG;
  75. int BN_dec2bn(BIGNUM **a, const char *str);
  76. #define BN_new() ((BIGNUM *)calloc(sizeof(BIGNUM), 1))
  77. #define BN_is_zero(v) (*(v) == 0)
  78. #define BN_is_one(v) (*(v) == 1)
  79. #define BN_new() ((BIGNUM *)calloc(sizeof(BIGNUM), 1))
  80. #define BN_is_zero(v) (*(v) == 0)
  81. #define BN_is_one(v) (*(v) == 1)
  82. #define BN_mod_word(a, b) (*(a) % (b))
  83. #endif
  84. #include "primes.h"
  85. /*
  86. * prime[i] is the (i-1)th prime.
  87. *
  88. * We are able to sieve 2^32-1 because this byte table yields all primes
  89. * up to 65537 and 65537^2 > 2^32-1.
  90. */
  91. extern const ubig prime[];
  92. extern const ubig *pr_limit; /* largest prime in the prime array */
  93. #define PRIME_CHECKS 5
  94. #ifdef HAVE_OPENSSL
  95. BN_CTX *ctx; /* just use a global context */
  96. #endif
  97. int main(int, char *[]);
  98. void pr_fact(BIGNUM *); /* print factors of a value */
  99. void BN_print_dec_fp(FILE *, const BIGNUM *);
  100. void usage(void) __attribute__((__noreturn__));
  101. #ifdef HAVE_OPENSSL
  102. void pollard_pminus1(BIGNUM *); /* print factors for big numbers */
  103. #else
  104. char *BN_bn2dec(const BIGNUM *);
  105. BN_ULONG BN_div_word(BIGNUM *, BN_ULONG);
  106. #endif
  107. #ifndef HAVE_OPENSSL
  108. int
  109. BN_dec2bn(BIGNUM **a, const char *str)
  110. {
  111. char *p;
  112. errno = 0;
  113. **a = strtoul(str, &p, 10);
  114. if (errno)
  115. err(1, "%s", str);
  116. return (*p == '\n' || *p == '\0');
  117. }
  118. #endif
  119. int
  120. main(int argc, char *argv[])
  121. {
  122. BIGNUM *val;
  123. int ch;
  124. char *p, buf[LINE_MAX]; /* > max number of digits. */
  125. #ifdef HAVE_OPENSSL
  126. ctx = BN_CTX_new();
  127. #endif
  128. val = BN_new();
  129. if (val == NULL)
  130. errx(1, "can't initialise bignum");
  131. /* Revoke setgid privileges */
  132. setregid(getgid(), getgid());
  133. while ((ch = getopt(argc, argv, "")) != -1)
  134. switch (ch) {
  135. case '?':
  136. default:
  137. usage();
  138. }
  139. argc -= optind;
  140. argv += optind;
  141. /* No args supplied, read numbers from stdin. */
  142. if (argc == 0)
  143. for (;;) {
  144. if (fgets(buf, sizeof(buf), stdin) == NULL) {
  145. if (ferror(stdin))
  146. err(1, "stdin");
  147. exit (0);
  148. }
  149. for (p = buf; isblank(*p); ++p);
  150. if (*p == '\n' || *p == '\0')
  151. continue;
  152. if (*p == '-')
  153. errx(1, "negative numbers aren't permitted.");
  154. if (BN_dec2bn(&val, buf) == 0)
  155. errx(1, "%s: illegal numeric format.", argv[0]);
  156. pr_fact(val);
  157. }
  158. /* Factor the arguments. */
  159. else
  160. for (; *argv != NULL; ++argv) {
  161. if (argv[0][0] == '-')
  162. errx(1, "negative numbers aren't permitted.");
  163. if (BN_dec2bn(&val, argv[0]) == 0)
  164. errx(1, "%s: illegal numeric format.", argv[0]);
  165. pr_fact(val);
  166. }
  167. exit(0);
  168. }
  169. /*
  170. * pr_fact - print the factors of a number
  171. *
  172. * If the number is 0 or 1, then print the number and return.
  173. * If the number is < 0, print -1, negate the number and continue
  174. * processing.
  175. *
  176. * Print the factors of the number, from the lowest to the highest.
  177. * A factor will be printed numtiple times if it divides the value
  178. * multiple times.
  179. *
  180. * Factors are printed with leading tabs.
  181. */
  182. void
  183. pr_fact(BIGNUM *val)
  184. {
  185. const ubig *fact; /* The factor found. */
  186. /* Firewall - catch 0 and 1. */
  187. if (BN_is_zero(val)) /* Historical practice; 0 just exits. */
  188. exit(0);
  189. if (BN_is_one(val)) {
  190. printf("1: 1\n");
  191. return;
  192. }
  193. /* Factor value. */
  194. BN_print_dec_fp(stdout, val);
  195. putchar(':');
  196. for (fact = &prime[0]; !BN_is_one(val); ++fact) {
  197. /* Look for the smallest factor. */
  198. do {
  199. if (BN_mod_word(val, (BN_ULONG)*fact) == 0)
  200. break;
  201. } while (++fact <= pr_limit);
  202. /* Watch for primes larger than the table. */
  203. if (fact > pr_limit) {
  204. #ifdef HAVE_OPENSSL
  205. BIGNUM *bnfact;
  206. bnfact = BN_new();
  207. BN_set_word(bnfact, *(fact - 1));
  208. BN_sqr(bnfact, bnfact, ctx);
  209. if (BN_cmp(bnfact, val) > 0
  210. || BN_is_prime(val, PRIME_CHECKS, NULL, NULL,
  211. NULL) == 1) {
  212. putchar(' ');
  213. BN_print_dec_fp(stdout, val);
  214. } else
  215. pollard_pminus1(val);
  216. #else
  217. printf(" %s", BN_bn2dec(val));
  218. #endif
  219. break;
  220. }
  221. /* Divide factor out until none are left. */
  222. do {
  223. printf(" %lu", *fact);
  224. BN_div_word(val, (BN_ULONG)*fact);
  225. } while (BN_mod_word(val, (BN_ULONG)*fact) == 0);
  226. /* Let the user know we're doing something. */
  227. fflush(stdout);
  228. }
  229. putchar('\n');
  230. }
  231. /*
  232. * Sigh.. No _decimal_ output to file functions in BN.
  233. */
  234. void
  235. BN_print_dec_fp(FILE *fp, const BIGNUM *num)
  236. {
  237. char *buf;
  238. buf = BN_bn2dec(num);
  239. if (buf == NULL)
  240. return; /* XXX do anything here? */
  241. fprintf(fp, buf);
  242. free(buf);
  243. }
  244. void
  245. usage(void)
  246. {
  247. fprintf(stderr, "usage: factor [value ...]\n");
  248. exit (0);
  249. }
  250. #ifdef HAVE_OPENSSL
  251. /* pollard p-1, algorithm from Jim Gillogly, May 2000 */
  252. void
  253. pollard_pminus1(BIGNUM *val)
  254. {
  255. BIGNUM *base, *rbase, *num, *i, *x;
  256. base = BN_new();
  257. rbase = BN_new();
  258. num = BN_new();
  259. i = BN_new();
  260. x = BN_new();
  261. BN_set_word(rbase, 1);
  262. newbase:
  263. BN_add_word(rbase, 1);
  264. BN_set_word(i, 2);
  265. BN_copy(base, rbase);
  266. for (;;) {
  267. BN_mod_exp(base, base, i, val, ctx);
  268. if (BN_is_one(base))
  269. goto newbase;
  270. BN_copy(x, base);
  271. BN_sub_word(x, 1);
  272. BN_gcd(x, x, val, ctx);
  273. if (!BN_is_one(x)) {
  274. if (BN_is_prime(x, PRIME_CHECKS, NULL, NULL,
  275. NULL) == 1) {
  276. putchar(' ');
  277. BN_print_dec_fp(stdout, x);
  278. } else
  279. pollard_pminus1(x);
  280. fflush(stdout);
  281. BN_div(num, NULL, val, x, ctx);
  282. if (BN_is_one(num))
  283. return;
  284. if (BN_is_prime(num, PRIME_CHECKS, NULL, NULL,
  285. NULL) == 1) {
  286. putchar(' ');
  287. BN_print_dec_fp(stdout, num);
  288. fflush(stdout);
  289. return;
  290. }
  291. BN_copy(val, num);
  292. }
  293. BN_add_word(i, 1);
  294. }
  295. }
  296. #else
  297. char *
  298. BN_bn2dec(const BIGNUM *val)
  299. {
  300. char *buf;
  301. buf = malloc(100);
  302. if (!buf)
  303. return buf;
  304. snprintf(buf, 100, "%ld", (long)*val);
  305. return buf;
  306. }
  307. BN_ULONG
  308. BN_div_word(BIGNUM *a, BN_ULONG b)
  309. {
  310. BN_ULONG mod;
  311. mod = *a % b;
  312. *a /= b;
  313. return mod;
  314. }
  315. #endif