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