16ae1554aSColin Percival /* 26ae1554aSColin Percival * Copyright (c) 1989, 1993 36ae1554aSColin Percival * The Regents of the University of California. All rights reserved. 46ae1554aSColin Percival * 56ae1554aSColin Percival * This code is derived from software contributed to Berkeley by 66ae1554aSColin Percival * Landon Curt Noll. 76ae1554aSColin Percival * 86ae1554aSColin Percival * Redistribution and use in source and binary forms, with or without 96ae1554aSColin Percival * modification, are permitted provided that the following conditions 106ae1554aSColin Percival * are met: 116ae1554aSColin Percival * 1. Redistributions of source code must retain the above copyright 126ae1554aSColin Percival * notice, this list of conditions and the following disclaimer. 136ae1554aSColin Percival * 2. Redistributions in binary form must reproduce the above copyright 146ae1554aSColin Percival * notice, this list of conditions and the following disclaimer in the 156ae1554aSColin Percival * documentation and/or other materials provided with the distribution. 166ae1554aSColin Percival * 3. Neither the name of the University nor the names of its contributors 176ae1554aSColin Percival * may be used to endorse or promote products derived from this software 186ae1554aSColin Percival * without specific prior written permission. 196ae1554aSColin Percival * 206ae1554aSColin Percival * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 216ae1554aSColin Percival * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 226ae1554aSColin Percival * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 236ae1554aSColin Percival * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 246ae1554aSColin Percival * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 256ae1554aSColin Percival * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 266ae1554aSColin Percival * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 276ae1554aSColin Percival * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 286ae1554aSColin Percival * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 296ae1554aSColin Percival * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 306ae1554aSColin Percival * SUCH DAMAGE. 316ae1554aSColin Percival */ 326ae1554aSColin Percival 336ae1554aSColin Percival #ifndef lint 346ae1554aSColin Percival #include <sys/cdefs.h> 356ae1554aSColin Percival #ifdef __COPYRIGHT 366ae1554aSColin Percival __COPYRIGHT("@(#) Copyright (c) 1989, 1993\ 376ae1554aSColin Percival The Regents of the University of California. All rights reserved."); 386ae1554aSColin Percival #endif 396ae1554aSColin Percival #ifdef __SCCSID 406ae1554aSColin Percival __SCCSID("@(#)factor.c 8.4 (Berkeley) 5/4/95"); 416ae1554aSColin Percival #endif 426ae1554aSColin Percival #ifdef __RCSID 436ae1554aSColin Percival __RCSID("$NetBSD: factor.c,v 1.19 2009/08/12 05:54:31 dholland Exp $"); 446ae1554aSColin Percival #endif 456ae1554aSColin Percival #ifdef __FBSDID 466ae1554aSColin Percival __FBSDID("$FreeBSD$"); 476ae1554aSColin Percival #endif 486ae1554aSColin Percival #endif /* not lint */ 496ae1554aSColin Percival 506ae1554aSColin Percival /* 516ae1554aSColin Percival * factor - factor a number into primes 526ae1554aSColin Percival * 536ae1554aSColin Percival * By: Landon Curt Noll chongo@toad.com, ...!{sun,tolsoft}!hoptoad!chongo 546ae1554aSColin Percival * 556ae1554aSColin Percival * chongo <for a good prime call: 391581 * 2^216193 - 1> /\oo/\ 566ae1554aSColin Percival * 576ae1554aSColin Percival * usage: 586ae1554aSColin Percival * factor [-h] [number] ... 596ae1554aSColin Percival * 606ae1554aSColin Percival * The form of the output is: 616ae1554aSColin Percival * 626ae1554aSColin Percival * number: factor1 factor1 factor2 factor3 factor3 factor3 ... 636ae1554aSColin Percival * 646ae1554aSColin Percival * where factor1 <= factor2 <= factor3 <= ... 656ae1554aSColin Percival * 666ae1554aSColin Percival * If no args are given, the list of numbers are read from stdin. 676ae1554aSColin Percival */ 686ae1554aSColin Percival 696ae1554aSColin Percival #include <ctype.h> 706ae1554aSColin Percival #include <err.h> 716ae1554aSColin Percival #include <errno.h> 726ae1554aSColin Percival #include <inttypes.h> 736ae1554aSColin Percival #include <limits.h> 7452647325SGarance A Drosehn #include <stdbool.h> 756ae1554aSColin Percival #include <stdio.h> 766ae1554aSColin Percival #include <stdlib.h> 776ae1554aSColin Percival #include <unistd.h> 786ae1554aSColin Percival 796ae1554aSColin Percival #include "primes.h" 806ae1554aSColin Percival 816ae1554aSColin Percival #ifdef HAVE_OPENSSL 826ae1554aSColin Percival 836ae1554aSColin Percival #include <openssl/bn.h> 846ae1554aSColin Percival 85*dcf5d560SEnji Cooper #if OPENSSL_VERSION_NUMBER < 0x30000000L 86*dcf5d560SEnji Cooper static inline int 87*dcf5d560SEnji Cooper BN_check_prime(BN *p, BN_CTX *ctx, BN_GENCB *cb) 88*dcf5d560SEnji Cooper { 89*dcf5d560SEnji Cooper const int nchecks = 5; 90*dcf5d560SEnji Cooper 91*dcf5d560SEnji Cooper return BN_is_prime_ex(val, nchecks, ctx, cb); 92*dcf5d560SEnji Cooper } 93*dcf5d560SEnji Cooper #endif 946ae1554aSColin Percival 956ae1554aSColin Percival static void pollard_pminus1(BIGNUM *); /* print factors for big numbers */ 966ae1554aSColin Percival 976ae1554aSColin Percival #else 986ae1554aSColin Percival 996ae1554aSColin Percival typedef ubig BIGNUM; 1006ae1554aSColin Percival typedef u_long BN_ULONG; 1016ae1554aSColin Percival 1026ae1554aSColin Percival #define BN_CTX int 1036ae1554aSColin Percival #define BN_CTX_new() NULL 1046ae1554aSColin Percival #define BN_new() ((BIGNUM *)calloc(sizeof(BIGNUM), 1)) 1056ae1554aSColin Percival #define BN_is_zero(v) (*(v) == 0) 1066ae1554aSColin Percival #define BN_is_one(v) (*(v) == 1) 1076ae1554aSColin Percival #define BN_mod_word(a, b) (*(a) % (b)) 1086ae1554aSColin Percival 10952647325SGarance A Drosehn static int BN_dec2bn(BIGNUM **, const char *); 11052647325SGarance A Drosehn static int BN_hex2bn(BIGNUM **, const char *); 1116ae1554aSColin Percival static BN_ULONG BN_div_word(BIGNUM *, BN_ULONG); 1126ae1554aSColin Percival static void BN_print_fp(FILE *, const BIGNUM *); 1136ae1554aSColin Percival 1146ae1554aSColin Percival #endif 1156ae1554aSColin Percival 1166ae1554aSColin Percival static void BN_print_dec_fp(FILE *, const BIGNUM *); 11752647325SGarance A Drosehn static void convert_str2bn(BIGNUM **, char *); 11852647325SGarance A Drosehn static bool is_hex_str(char *); 1196ae1554aSColin Percival static void pr_fact(BIGNUM *); /* print factors of a value */ 1206ae1554aSColin Percival static void pr_print(BIGNUM *); /* print a prime */ 1216ae1554aSColin Percival static void usage(void); 1226ae1554aSColin Percival 1236ae1554aSColin Percival static BN_CTX *ctx; /* just use a global context */ 1246ae1554aSColin Percival static int hflag; 1256ae1554aSColin Percival 1266ae1554aSColin Percival int 1276ae1554aSColin Percival main(int argc, char *argv[]) 1286ae1554aSColin Percival { 1296ae1554aSColin Percival BIGNUM *val; 1306ae1554aSColin Percival int ch; 1316ae1554aSColin Percival char *p, buf[LINE_MAX]; /* > max number of digits. */ 1326ae1554aSColin Percival 1336ae1554aSColin Percival ctx = BN_CTX_new(); 1346ae1554aSColin Percival val = BN_new(); 1356ae1554aSColin Percival if (val == NULL) 1366ae1554aSColin Percival errx(1, "can't initialise bignum"); 1376ae1554aSColin Percival 1386ae1554aSColin Percival while ((ch = getopt(argc, argv, "h")) != -1) 1396ae1554aSColin Percival switch (ch) { 1406ae1554aSColin Percival case 'h': 1416ae1554aSColin Percival hflag++; 1426ae1554aSColin Percival break; 1436ae1554aSColin Percival case '?': 1446ae1554aSColin Percival default: 1456ae1554aSColin Percival usage(); 1466ae1554aSColin Percival } 1476ae1554aSColin Percival argc -= optind; 1486ae1554aSColin Percival argv += optind; 1496ae1554aSColin Percival 1506ae1554aSColin Percival /* No args supplied, read numbers from stdin. */ 1516ae1554aSColin Percival if (argc == 0) 1526ae1554aSColin Percival for (;;) { 1536ae1554aSColin Percival if (fgets(buf, sizeof(buf), stdin) == NULL) { 1546ae1554aSColin Percival if (ferror(stdin)) 1556ae1554aSColin Percival err(1, "stdin"); 1566ae1554aSColin Percival exit (0); 1576ae1554aSColin Percival } 1586ae1554aSColin Percival for (p = buf; isblank(*p); ++p); 1596ae1554aSColin Percival if (*p == '\n' || *p == '\0') 1606ae1554aSColin Percival continue; 16152647325SGarance A Drosehn convert_str2bn(&val, p); 1626ae1554aSColin Percival pr_fact(val); 1636ae1554aSColin Percival } 1646ae1554aSColin Percival /* Factor the arguments. */ 1656ae1554aSColin Percival else 16652647325SGarance A Drosehn for (p = *argv; p != NULL; p = *++argv) { 16752647325SGarance A Drosehn convert_str2bn(&val, p); 1686ae1554aSColin Percival pr_fact(val); 1696ae1554aSColin Percival } 1706ae1554aSColin Percival exit(0); 1716ae1554aSColin Percival } 1726ae1554aSColin Percival 1736ae1554aSColin Percival /* 1746ae1554aSColin Percival * pr_fact - print the factors of a number 1756ae1554aSColin Percival * 1766ae1554aSColin Percival * Print the factors of the number, from the lowest to the highest. 1776ae1554aSColin Percival * A factor will be printed multiple times if it divides the value 1786ae1554aSColin Percival * multiple times. 1796ae1554aSColin Percival * 1806ae1554aSColin Percival * Factors are printed with leading tabs. 1816ae1554aSColin Percival */ 1826ae1554aSColin Percival static void 1836ae1554aSColin Percival pr_fact(BIGNUM *val) 1846ae1554aSColin Percival { 1856ae1554aSColin Percival const ubig *fact; /* The factor found. */ 1866ae1554aSColin Percival 1876ae1554aSColin Percival /* Firewall - catch 0 and 1. */ 1886ae1554aSColin Percival if (BN_is_zero(val)) /* Historical practice; 0 just exits. */ 1896ae1554aSColin Percival exit(0); 1906ae1554aSColin Percival if (BN_is_one(val)) { 1916ae1554aSColin Percival printf("1: 1\n"); 1926ae1554aSColin Percival return; 1936ae1554aSColin Percival } 1946ae1554aSColin Percival 1956ae1554aSColin Percival /* Factor value. */ 1966ae1554aSColin Percival 1976ae1554aSColin Percival if (hflag) { 1986ae1554aSColin Percival fputs("0x", stdout); 1996ae1554aSColin Percival BN_print_fp(stdout, val); 2006ae1554aSColin Percival } else 2016ae1554aSColin Percival BN_print_dec_fp(stdout, val); 2026ae1554aSColin Percival putchar(':'); 2036ae1554aSColin Percival for (fact = &prime[0]; !BN_is_one(val); ++fact) { 2046ae1554aSColin Percival /* Look for the smallest factor. */ 2056ae1554aSColin Percival do { 2066ae1554aSColin Percival if (BN_mod_word(val, (BN_ULONG)*fact) == 0) 2076ae1554aSColin Percival break; 2086ae1554aSColin Percival } while (++fact <= pr_limit); 2096ae1554aSColin Percival 2106ae1554aSColin Percival /* Watch for primes larger than the table. */ 2116ae1554aSColin Percival if (fact > pr_limit) { 2126ae1554aSColin Percival #ifdef HAVE_OPENSSL 2136ae1554aSColin Percival BIGNUM *bnfact; 2146ae1554aSColin Percival 2156ae1554aSColin Percival bnfact = BN_new(); 2166ae1554aSColin Percival BN_set_word(bnfact, *(fact - 1)); 2176ae1554aSColin Percival if (!BN_sqr(bnfact, bnfact, ctx)) 2186ae1554aSColin Percival errx(1, "error in BN_sqr()"); 2196ae1554aSColin Percival if (BN_cmp(bnfact, val) > 0 || 220537cd766SEnji Cooper BN_check_prime(val, NULL, NULL) == 1) 2216ae1554aSColin Percival pr_print(val); 2226ae1554aSColin Percival else 2236ae1554aSColin Percival pollard_pminus1(val); 2246ae1554aSColin Percival #else 2256ae1554aSColin Percival pr_print(val); 2266ae1554aSColin Percival #endif 2276ae1554aSColin Percival break; 2286ae1554aSColin Percival } 2296ae1554aSColin Percival 2306ae1554aSColin Percival /* Divide factor out until none are left. */ 2316ae1554aSColin Percival do { 2326ae1554aSColin Percival printf(hflag ? " 0x%" PRIx64 "" : " %" PRIu64 "", *fact); 2336ae1554aSColin Percival BN_div_word(val, (BN_ULONG)*fact); 2346ae1554aSColin Percival } while (BN_mod_word(val, (BN_ULONG)*fact) == 0); 2356ae1554aSColin Percival 2366ae1554aSColin Percival /* Let the user know we're doing something. */ 2376ae1554aSColin Percival fflush(stdout); 2386ae1554aSColin Percival } 2396ae1554aSColin Percival putchar('\n'); 2406ae1554aSColin Percival } 2416ae1554aSColin Percival 2426ae1554aSColin Percival static void 2436ae1554aSColin Percival pr_print(BIGNUM *val) 2446ae1554aSColin Percival { 2456ae1554aSColin Percival if (hflag) { 2466ae1554aSColin Percival fputs(" 0x", stdout); 2476ae1554aSColin Percival BN_print_fp(stdout, val); 2486ae1554aSColin Percival } else { 2496ae1554aSColin Percival putchar(' '); 2506ae1554aSColin Percival BN_print_dec_fp(stdout, val); 2516ae1554aSColin Percival } 2526ae1554aSColin Percival } 2536ae1554aSColin Percival 2546ae1554aSColin Percival static void 2556ae1554aSColin Percival usage(void) 2566ae1554aSColin Percival { 2576ae1554aSColin Percival fprintf(stderr, "usage: factor [-h] [value ...]\n"); 2586ae1554aSColin Percival exit(1); 2596ae1554aSColin Percival } 2606ae1554aSColin Percival 2616ae1554aSColin Percival #ifdef HAVE_OPENSSL 2626ae1554aSColin Percival 2636ae1554aSColin Percival /* pollard p-1, algorithm from Jim Gillogly, May 2000 */ 2646ae1554aSColin Percival static void 2656ae1554aSColin Percival pollard_pminus1(BIGNUM *val) 2666ae1554aSColin Percival { 2676ae1554aSColin Percival BIGNUM *base, *rbase, *num, *i, *x; 2686ae1554aSColin Percival 2696ae1554aSColin Percival base = BN_new(); 2706ae1554aSColin Percival rbase = BN_new(); 2716ae1554aSColin Percival num = BN_new(); 2726ae1554aSColin Percival i = BN_new(); 2736ae1554aSColin Percival x = BN_new(); 2746ae1554aSColin Percival 2756ae1554aSColin Percival BN_set_word(rbase, 1); 2766ae1554aSColin Percival newbase: 2776ae1554aSColin Percival if (!BN_add_word(rbase, 1)) 2786ae1554aSColin Percival errx(1, "error in BN_add_word()"); 2796ae1554aSColin Percival BN_set_word(i, 2); 2806ae1554aSColin Percival BN_copy(base, rbase); 2816ae1554aSColin Percival 2826ae1554aSColin Percival for (;;) { 2836ae1554aSColin Percival BN_mod_exp(base, base, i, val, ctx); 2846ae1554aSColin Percival if (BN_is_one(base)) 2856ae1554aSColin Percival goto newbase; 2866ae1554aSColin Percival 2876ae1554aSColin Percival BN_copy(x, base); 2886ae1554aSColin Percival BN_sub_word(x, 1); 2896ae1554aSColin Percival if (!BN_gcd(x, x, val, ctx)) 2906ae1554aSColin Percival errx(1, "error in BN_gcd()"); 2916ae1554aSColin Percival 2926ae1554aSColin Percival if (!BN_is_one(x)) { 293537cd766SEnji Cooper if (BN_check_prime(x, NULL, NULL) == 1) 2946ae1554aSColin Percival pr_print(x); 2956ae1554aSColin Percival else 2966ae1554aSColin Percival pollard_pminus1(x); 2976ae1554aSColin Percival fflush(stdout); 2986ae1554aSColin Percival 2996ae1554aSColin Percival BN_div(num, NULL, val, x, ctx); 3006ae1554aSColin Percival if (BN_is_one(num)) 3016ae1554aSColin Percival return; 302*dcf5d560SEnji Cooper if (BN_check_prime(num, NULL, NULL) == 1) { 3036ae1554aSColin Percival pr_print(num); 3046ae1554aSColin Percival fflush(stdout); 3056ae1554aSColin Percival return; 3066ae1554aSColin Percival } 3076ae1554aSColin Percival BN_copy(val, num); 3086ae1554aSColin Percival } 3096ae1554aSColin Percival if (!BN_add_word(i, 1)) 3106ae1554aSColin Percival errx(1, "error in BN_add_word()"); 3116ae1554aSColin Percival } 3126ae1554aSColin Percival } 3136ae1554aSColin Percival 3146ae1554aSColin Percival /* 3156ae1554aSColin Percival * Sigh.. No _decimal_ output to file functions in BN. 3166ae1554aSColin Percival */ 3176ae1554aSColin Percival static void 3186ae1554aSColin Percival BN_print_dec_fp(FILE *fp, const BIGNUM *num) 3196ae1554aSColin Percival { 3206ae1554aSColin Percival char *buf; 3216ae1554aSColin Percival 3226ae1554aSColin Percival buf = BN_bn2dec(num); 3236ae1554aSColin Percival if (buf == NULL) 3246ae1554aSColin Percival return; /* XXX do anything here? */ 3256ae1554aSColin Percival fprintf(fp, "%s", buf); 3266ae1554aSColin Percival free(buf); 3276ae1554aSColin Percival } 3286ae1554aSColin Percival 3296ae1554aSColin Percival #else 3306ae1554aSColin Percival 3316ae1554aSColin Percival static void 3326ae1554aSColin Percival BN_print_fp(FILE *fp, const BIGNUM *num) 3336ae1554aSColin Percival { 3346ae1554aSColin Percival fprintf(fp, "%lx", (unsigned long)*num); 3356ae1554aSColin Percival } 3366ae1554aSColin Percival 3376ae1554aSColin Percival static void 3386ae1554aSColin Percival BN_print_dec_fp(FILE *fp, const BIGNUM *num) 3396ae1554aSColin Percival { 3406ae1554aSColin Percival fprintf(fp, "%lu", (unsigned long)*num); 3416ae1554aSColin Percival } 3426ae1554aSColin Percival 3436ae1554aSColin Percival static int 3446ae1554aSColin Percival BN_dec2bn(BIGNUM **a, const char *str) 3456ae1554aSColin Percival { 3466ae1554aSColin Percival char *p; 3476ae1554aSColin Percival 3486ae1554aSColin Percival errno = 0; 3496ae1554aSColin Percival **a = strtoul(str, &p, 10); 35052647325SGarance A Drosehn return (errno == 0 ? 1 : 0); /* OpenSSL returns 0 on error! */ 3516ae1554aSColin Percival } 3526ae1554aSColin Percival 3536ae1554aSColin Percival static int 3546ae1554aSColin Percival BN_hex2bn(BIGNUM **a, const char *str) 3556ae1554aSColin Percival { 3566ae1554aSColin Percival char *p; 3576ae1554aSColin Percival 3586ae1554aSColin Percival errno = 0; 3596ae1554aSColin Percival **a = strtoul(str, &p, 16); 36052647325SGarance A Drosehn return (errno == 0 ? 1 : 0); /* OpenSSL returns 0 on error! */ 3616ae1554aSColin Percival } 3626ae1554aSColin Percival 3636ae1554aSColin Percival static BN_ULONG 3646ae1554aSColin Percival BN_div_word(BIGNUM *a, BN_ULONG b) 3656ae1554aSColin Percival { 3666ae1554aSColin Percival BN_ULONG mod; 3676ae1554aSColin Percival 3686ae1554aSColin Percival mod = *a % b; 3696ae1554aSColin Percival *a /= b; 3706ae1554aSColin Percival return mod; 3716ae1554aSColin Percival } 3726ae1554aSColin Percival 3736ae1554aSColin Percival #endif 37452647325SGarance A Drosehn 37552647325SGarance A Drosehn /* 37652647325SGarance A Drosehn * Scan the string from left-to-right to see if the longest substring 37752647325SGarance A Drosehn * is a valid hexadecimal number. 37852647325SGarance A Drosehn */ 37952647325SGarance A Drosehn static bool 38052647325SGarance A Drosehn is_hex_str(char *str) 38152647325SGarance A Drosehn { 38252647325SGarance A Drosehn char c, *p; 38352647325SGarance A Drosehn bool saw_hex = false; 38452647325SGarance A Drosehn 38552647325SGarance A Drosehn for (p = str; *p; p++) { 38652647325SGarance A Drosehn if (isdigit(*p)) 38752647325SGarance A Drosehn continue; 38852647325SGarance A Drosehn c = tolower(*p); 38952647325SGarance A Drosehn if (c >= 'a' && c <= 'f') { 39052647325SGarance A Drosehn saw_hex = true; 39152647325SGarance A Drosehn continue; 39252647325SGarance A Drosehn } 39352647325SGarance A Drosehn break; /* Not a hexadecimal digit. */ 39452647325SGarance A Drosehn } 39552647325SGarance A Drosehn return saw_hex; 39652647325SGarance A Drosehn } 39752647325SGarance A Drosehn 39852647325SGarance A Drosehn /* Convert string pointed to by *str to a bignum. */ 39952647325SGarance A Drosehn static void 40052647325SGarance A Drosehn convert_str2bn(BIGNUM **val, char *p) 40152647325SGarance A Drosehn { 40252647325SGarance A Drosehn int n = 0; 40352647325SGarance A Drosehn 40452647325SGarance A Drosehn if (*p == '+') p++; 40552647325SGarance A Drosehn if (*p == '-') 40652647325SGarance A Drosehn errx(1, "negative numbers aren't permitted."); 40752647325SGarance A Drosehn if (*p == '0') { 40852647325SGarance A Drosehn p++; 40952647325SGarance A Drosehn if (*p == 'x' || *p == 'X') 41052647325SGarance A Drosehn n = BN_hex2bn(val, ++p); 41152647325SGarance A Drosehn } else { 41252647325SGarance A Drosehn n = is_hex_str(p) ? BN_hex2bn(val, p) : BN_dec2bn(val, p); 41352647325SGarance A Drosehn } 41452647325SGarance A Drosehn if (n == 0) 41552647325SGarance A Drosehn errx(1, "%s: illegal numeric format.", p); 41652647325SGarance A Drosehn } 417