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