xref: /netbsd-src/games/factor/factor.c (revision 5d858a7a6bfdfd8bb9502c1da4d4e634ccdb050f)
1*5d858a7aSchristos /*	$NetBSD: factor.c,v 1.38 2020/10/12 13:54:51 christos Exp $	*/
261f28255Scgd /*
342fb1b9dScgd  * Copyright (c) 1989, 1993
442fb1b9dScgd  *	The Regents of the University of California.  All rights reserved.
561f28255Scgd  *
661f28255Scgd  * This code is derived from software contributed to Berkeley by
761f28255Scgd  * Landon Curt Noll.
861f28255Scgd  *
961f28255Scgd  * Redistribution and use in source and binary forms, with or without
1061f28255Scgd  * modification, are permitted provided that the following conditions
1161f28255Scgd  * are met:
1261f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1461f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1561f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1661f28255Scgd  *    documentation and/or other materials provided with the distribution.
17e5aeb4eaSagc  * 3. Neither the name of the University nor the names of its contributors
1861f28255Scgd  *    may be used to endorse or promote products derived from this software
1961f28255Scgd  *    without specific prior written permission.
2061f28255Scgd  *
2161f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2261f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2361f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2461f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2561f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2661f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2761f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2861f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2961f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3061f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3161f28255Scgd  * SUCH DAMAGE.
3261f28255Scgd  */
3361f28255Scgd 
3461f28255Scgd #ifndef lint
355e85fe34Schristos #include <sys/cdefs.h>
365e85fe34Schristos #ifdef __COPYRIGHT
372fe2731dSlukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993\
382fe2731dSlukem 	The Regents of the University of California.  All rights reserved.");
395e85fe34Schristos #endif
405e85fe34Schristos #ifdef __SCCSID
415e85fe34Schristos __SCCSID("@(#)factor.c	8.4 (Berkeley) 5/4/95");
425e85fe34Schristos #endif
435e85fe34Schristos #ifdef __RCSID
44*5d858a7aSchristos __RCSID("$NetBSD: factor.c,v 1.38 2020/10/12 13:54:51 christos Exp $");
455e85fe34Schristos #endif
465e85fe34Schristos #ifdef __FBSDID
475e85fe34Schristos __FBSDID("$FreeBSD: head/usr.bin/factor/factor.c 356666 2020-01-12 20:25:11Z gad $");
4842fb1b9dScgd #endif
4961f28255Scgd #endif /* not lint */
5061f28255Scgd 
5161f28255Scgd /*
5261f28255Scgd  * factor - factor a number into primes
5361f28255Scgd  *
545e85fe34Schristos  * By: Landon Curt Noll   chongo@toad.com,   ...!{sun,tolsoft}!hoptoad!chongo
555e85fe34Schristos  *
565e85fe34Schristos  *   chongo <for a good prime call: 391581 * 2^216193 - 1> /\oo/\
5761f28255Scgd  *
5861f28255Scgd  * usage:
595e85fe34Schristos  *	factor [-hx] [number] ...
6061f28255Scgd  *
615e85fe34Schristos  * The form of the output is:
6261f28255Scgd  *
6361f28255Scgd  *	number: factor1 factor1 factor2 factor3 factor3 factor3 ...
6461f28255Scgd  *
651a815e1fSrillig  * where factor1 <= factor2 <= factor3 <= ...
6661f28255Scgd  *
67f345b5cbSrin  * If the -h flag is specified, the output is in "human-readable" format.
68f345b5cbSrin  * Duplicate factors are printed in the form of x^n.
69f345b5cbSrin  *
705e85fe34Schristos  * If the -x flag is specified numbers are printed in hex.
715e85fe34Schristos  *
72f345b5cbSrin  * If no number args are given, the list of numbers are read from stdin.
7361f28255Scgd  */
7461f28255Scgd 
7561f28255Scgd #include <ctype.h>
76a311a773Ssimonb #include <err.h>
7742fb1b9dScgd #include <errno.h>
785e85fe34Schristos #include <inttypes.h>
7942fb1b9dScgd #include <limits.h>
805e85fe34Schristos #include <stdbool.h>
8142fb1b9dScgd #include <stdio.h>
8242fb1b9dScgd #include <stdlib.h>
8334cd8f5bStls #include <unistd.h>
845e85fe34Schristos 
855e85fe34Schristos #include "primes.h"
8642fb1b9dScgd 
8769757aeeSitojun #ifdef HAVE_OPENSSL
885e85fe34Schristos 
89a311a773Ssimonb #include <openssl/bn.h>
905e85fe34Schristos 
915e85fe34Schristos #define	PRIME_CHECKS	5
925e85fe34Schristos 
93f1aebb0cSchristos /* print factors for big numbers */
94f1aebb0cSchristos static void	pollard_pminus1(BIGNUM *, int, int);
955e85fe34Schristos 
9669757aeeSitojun #else
975e85fe34Schristos 
9869757aeeSitojun typedef long	BIGNUM;
9969757aeeSitojun typedef u_long	BN_ULONG;
1005e85fe34Schristos 
1015e85fe34Schristos #define BN_CTX			int
1025e85fe34Schristos #define BN_CTX_new()		NULL
103c5aeb8a7Schristos #define BN_new()		calloc(sizeof(BIGNUM), 1)
104c5aeb8a7Schristos #define BN_free(a)		free(a)
105c5aeb8a7Schristos 
106c5aeb8a7Schristos #define BN_copy(a, b)		*(a) = *(b)
107c5aeb8a7Schristos #define BN_cmp(a, b)		(*(a) - *(b))
108aab04f50Ssimonb #define BN_is_zero(v)		(*(v) == 0)
109aab04f50Ssimonb #define BN_is_one(v)		(*(v) == 1)
11069757aeeSitojun #define BN_mod_word(a, b)	(*(a) % (b))
111a311a773Ssimonb 
112c5aeb8a7Schristos static BIGNUM  *BN_dup(const BIGNUM *);
1135e85fe34Schristos static int	BN_dec2bn(BIGNUM **, const char *);
1145e85fe34Schristos static int	BN_hex2bn(BIGNUM **, const char *);
115e0ba63feSdholland static BN_ULONG BN_div_word(BIGNUM *, BN_ULONG);
1165e85fe34Schristos static void	BN_print_fp(FILE *, const BIGNUM *);
1175e85fe34Schristos 
11869757aeeSitojun #endif
11961f28255Scgd 
1205e85fe34Schristos static void	BN_print_dec_fp(FILE *, const BIGNUM *);
1215e85fe34Schristos static void	convert_str2bn(BIGNUM **, char *);
1225e85fe34Schristos static void	pr_fact(BIGNUM *, int, int);	/* print factors of a value */
123f1aebb0cSchristos static void	pr_print(BIGNUM *, int, int);	/* print a prime */
1247f481043Stnn static void	usage(void) __dead;
125aab04f50Ssimonb 
1265e85fe34Schristos static BN_CTX	*ctx;			/* just use a global context */
127aab04f50Ssimonb 
12842fb1b9dScgd int
main(int argc,char * argv[])129a311a773Ssimonb main(int argc, char *argv[])
13061f28255Scgd {
131a311a773Ssimonb 	BIGNUM *val;
1325e85fe34Schristos 	int ch, hflag, xflag;
133a311a773Ssimonb 	char *p, buf[LINE_MAX];		/* > max number of digits. */
134a311a773Ssimonb 
1355e85fe34Schristos 	hflag = xflag = 0;
136da942834Ssimonb 	ctx = BN_CTX_new();
137a311a773Ssimonb 	val = BN_new();
138a311a773Ssimonb 	if (val == NULL)
139a311a773Ssimonb 		errx(1, "can't initialise bignum");
14061f28255Scgd 
1415e85fe34Schristos 	while ((ch = getopt(argc, argv, "hx")) != -1)
14242fb1b9dScgd 		switch (ch) {
143f345b5cbSrin 		case 'h':
1445e85fe34Schristos 			hflag++;
1455e85fe34Schristos 			break;
1465e85fe34Schristos 		case 'x':
1475e85fe34Schristos 			xflag++;
148f345b5cbSrin 			break;
14942fb1b9dScgd 		case '?':
15042fb1b9dScgd 		default:
15142fb1b9dScgd 			usage();
15261f28255Scgd 		}
15342fb1b9dScgd 	argc -= optind;
15442fb1b9dScgd 	argv += optind;
15561f28255Scgd 
15642fb1b9dScgd 	/* No args supplied, read numbers from stdin. */
15742fb1b9dScgd 	if (argc == 0)
15842fb1b9dScgd 		for (;;) {
15942fb1b9dScgd 			if (fgets(buf, sizeof(buf), stdin) == NULL) {
16042fb1b9dScgd 				if (ferror(stdin))
16142fb1b9dScgd 					err(1, "stdin");
16242fb1b9dScgd 				exit (0);
16361f28255Scgd 			}
16450eb6aadStnozaki 			for (p = buf; isblank((unsigned char)*p); ++p);
16542fb1b9dScgd 			if (*p == '\n' || *p == '\0')
16642fb1b9dScgd 				continue;
1675e85fe34Schristos 			convert_str2bn(&val, p);
1685e85fe34Schristos 			pr_fact(val, hflag, xflag);
16961f28255Scgd 		}
17042fb1b9dScgd 	/* Factor the arguments. */
17142fb1b9dScgd 	else
1725e85fe34Schristos 		for (p = *argv; p != NULL; p = *++argv) {
1735e85fe34Schristos 			convert_str2bn(&val, p);
1745e85fe34Schristos 			pr_fact(val, hflag, xflag);
17561f28255Scgd 		}
17661f28255Scgd 	exit(0);
17761f28255Scgd }
17861f28255Scgd 
1790540874bSchristos static void
pr_exp(int i,int xflag)1800540874bSchristos pr_exp(int i, int xflag)
1810540874bSchristos {
1820540874bSchristos 	printf(xflag && i > 9 ? "^0x%x" : "^%d", i);
1830540874bSchristos }
1840540874bSchristos 
1850540874bSchristos static void
pr_uint64(uint64_t i,int xflag)1860540874bSchristos pr_uint64(uint64_t i, int xflag)
1870540874bSchristos {
1880540874bSchristos 	printf(xflag ? " 0x%" PRIx64 : " %" PRIu64, i);
1890540874bSchristos }
1900540874bSchristos 
19161f28255Scgd /*
19261f28255Scgd  * pr_fact - print the factors of a number
19361f28255Scgd  *
19461f28255Scgd  * Print the factors of the number, from the lowest to the highest.
1955e85fe34Schristos  * A factor will be printed multiple times if it divides the value
1965e85fe34Schristos  * multiple times.
197f345b5cbSrin  *
198f345b5cbSrin  * If hflag is specified, duplicate factors are printed in "human-
199f345b5cbSrin  * readable" form of x^n.
20061f28255Scgd  *
2015e85fe34Schristos  * If the xflag is specified, numbers will be printed in hex.
2025e85fe34Schristos  *
20361f28255Scgd  * Factors are printed with leading tabs.
20461f28255Scgd  */
205e0ba63feSdholland static void
pr_fact(BIGNUM * val,int hflag,int xflag)2065e85fe34Schristos pr_fact(BIGNUM *val, int hflag, int xflag)
20761f28255Scgd {
208f345b5cbSrin 	int i;
2095e85fe34Schristos 	const uint64_t *fact;	/* The factor found. */
21061f28255Scgd 
21142fb1b9dScgd 	/* Firewall - catch 0 and 1. */
2125e85fe34Schristos 	if (BN_is_zero(val))	/* Historical practice; 0 just exits. */
2135e85fe34Schristos 		exit(0);
2145e85fe34Schristos 	if (BN_is_one(val)) {
2155e85fe34Schristos 		printf("1: 1\n");
2165e85fe34Schristos 		return;
2175e85fe34Schristos 	}
21861f28255Scgd 
21942fb1b9dScgd 	/* Factor value. */
220a311a773Ssimonb 
2215e85fe34Schristos 	if (xflag) {
2225e85fe34Schristos 		fputs("0x", stdout);
2235e85fe34Schristos 		BN_print_fp(stdout, val);
2245e85fe34Schristos 	} else
225a311a773Ssimonb 		BN_print_dec_fp(stdout, val);
226a311a773Ssimonb 	putchar(':');
227*5d858a7aSchristos 	fflush(stdout);
228a311a773Ssimonb 	for (fact = &prime[0]; !BN_is_one(val); ++fact) {
22942fb1b9dScgd 		/* Look for the smallest factor. */
2305e85fe34Schristos 		do {
231a311a773Ssimonb 			if (BN_mod_word(val, (BN_ULONG)*fact) == 0)
23261f28255Scgd 				break;
2335e85fe34Schristos 		} while (++fact <= pr_limit);
23461f28255Scgd 
23542fb1b9dScgd 		/* Watch for primes larger than the table. */
23661f28255Scgd 		if (fact > pr_limit) {
23769757aeeSitojun #ifdef HAVE_OPENSSL
238da942834Ssimonb 			BIGNUM *bnfact;
239da942834Ssimonb 
240da942834Ssimonb 			bnfact = BN_new();
2415e85fe34Schristos 			BN_set_word(bnfact, *(fact - 1));
2425e85fe34Schristos 			if (!BN_sqr(bnfact, bnfact, ctx))
2435e85fe34Schristos 				errx(1, "error in BN_sqr()");
2445e85fe34Schristos 			if (BN_cmp(bnfact, val) > 0 ||
2455e85fe34Schristos 			    BN_is_prime_ex(val, PRIME_CHECKS, NULL, NULL) == 1)
246f1aebb0cSchristos 				pr_print(val, hflag, xflag);
2475e85fe34Schristos 			else
248f1aebb0cSchristos 				pollard_pminus1(val, hflag, xflag);
24969757aeeSitojun #else
250f1aebb0cSchristos 			pr_print(val, hflag, xflag);
25169757aeeSitojun #endif
252f1aebb0cSchristos 			pr_print(NULL, hflag, xflag);
25342fb1b9dScgd 			break;
25461f28255Scgd 		}
25561f28255Scgd 
25642fb1b9dScgd 		/* Divide factor out until none are left. */
257f345b5cbSrin 		i = 0;
25861f28255Scgd 		do {
259f345b5cbSrin 			i++;
260f345b5cbSrin 			if (!hflag)
2610540874bSchristos 				pr_uint64(*fact, xflag);
262a311a773Ssimonb 			BN_div_word(val, (BN_ULONG)*fact);
263a311a773Ssimonb 		} while (BN_mod_word(val, (BN_ULONG)*fact) == 0);
26442fb1b9dScgd 
265f345b5cbSrin 		if (hflag) {
2660540874bSchristos 			pr_uint64(*fact, xflag);
267f345b5cbSrin 			if (i > 1)
2680540874bSchristos 				pr_exp(i, xflag);
269f345b5cbSrin 		}
270f345b5cbSrin 
27142fb1b9dScgd 		/* Let the user know we're doing something. */
272a311a773Ssimonb 		fflush(stdout);
27361f28255Scgd 	}
274a311a773Ssimonb 	putchar('\n');
275a311a773Ssimonb }
276a311a773Ssimonb 
2775e85fe34Schristos static void
pr_print(BIGNUM * val,int hflag,int xflag)278f1aebb0cSchristos pr_print(BIGNUM *val, int hflag, int xflag)
2795e85fe34Schristos {
280c5aeb8a7Schristos 	static BIGNUM *sval;
281c5aeb8a7Schristos 	static int ex = 1;
282f1aebb0cSchristos 	BIGNUM *pval;
283f1aebb0cSchristos 
284f1aebb0cSchristos 	if (hflag) {
285c5aeb8a7Schristos 		if (sval == NULL) {
286c5aeb8a7Schristos 			sval = BN_dup(val);
287c5aeb8a7Schristos 			return;
288c5aeb8a7Schristos 		}
289c5aeb8a7Schristos 
290c5aeb8a7Schristos 		if (val != NULL && BN_cmp(val, sval) == 0) {
291c5aeb8a7Schristos 			ex++;
292c5aeb8a7Schristos 			return;
293c5aeb8a7Schristos 		}
294f1aebb0cSchristos 		pval = sval;
295f1aebb0cSchristos 	} else if (val == NULL) {
296f1aebb0cSchristos 		return;
297f1aebb0cSchristos 	} else {
298f1aebb0cSchristos 		pval = val;
299f1aebb0cSchristos 	}
300c5aeb8a7Schristos 
3015e85fe34Schristos 	if (xflag) {
3025e85fe34Schristos 		fputs(" 0x", stdout);
303f1aebb0cSchristos 		BN_print_fp(stdout, pval);
3045e85fe34Schristos 	} else {
3055e85fe34Schristos 		putchar(' ');
306f1aebb0cSchristos 		BN_print_dec_fp(stdout, pval);
3075e85fe34Schristos 	}
308f1aebb0cSchristos 
309f1aebb0cSchristos 	if (hflag) {
310c5aeb8a7Schristos 		if (ex > 1)
3110540874bSchristos 			pr_exp(ex, xflag);
312c5aeb8a7Schristos 
313c5aeb8a7Schristos 		if (val != NULL) {
314c5aeb8a7Schristos 			BN_copy(sval, val);
315c5aeb8a7Schristos 		} else {
316c5aeb8a7Schristos 			BN_free(sval);
317c5aeb8a7Schristos 			sval = NULL;
318c5aeb8a7Schristos 		}
319c5aeb8a7Schristos 		ex = 1;
3205e85fe34Schristos 	}
321f1aebb0cSchristos }
3225e85fe34Schristos 
3235e85fe34Schristos static void
usage(void)3245e85fe34Schristos usage(void)
3255e85fe34Schristos {
3260540874bSchristos 	fprintf(stderr, "Usage: %s [-hx] [value ...]\n", getprogname());
3275e85fe34Schristos 	exit(1);
3285e85fe34Schristos }
3295e85fe34Schristos 
3305e85fe34Schristos #ifdef HAVE_OPENSSL
3315e85fe34Schristos 
3325e85fe34Schristos /* pollard p-1, algorithm from Jim Gillogly, May 2000 */
3335e85fe34Schristos static void
pollard_pminus1(BIGNUM * val,int hflag,int xflag)334f1aebb0cSchristos pollard_pminus1(BIGNUM *val, int hflag, int xflag)
3355e85fe34Schristos {
3365e85fe34Schristos 	BIGNUM *base, *rbase, *num, *i, *x;
3375e85fe34Schristos 
3385e85fe34Schristos 	base = BN_new();
3395e85fe34Schristos 	rbase = BN_new();
3405e85fe34Schristos 	num = BN_new();
3415e85fe34Schristos 	i = BN_new();
3425e85fe34Schristos 	x = BN_new();
3435e85fe34Schristos 
3445e85fe34Schristos 	BN_set_word(rbase, 1);
3455e85fe34Schristos newbase:
3465e85fe34Schristos 	if (!BN_add_word(rbase, 1))
3475e85fe34Schristos 		errx(1, "error in BN_add_word()");
3485e85fe34Schristos 	BN_set_word(i, 2);
3495e85fe34Schristos 	BN_copy(base, rbase);
3505e85fe34Schristos 
3515e85fe34Schristos 	for (;;) {
3525e85fe34Schristos 		BN_mod_exp(base, base, i, val, ctx);
3535e85fe34Schristos 		if (BN_is_one(base))
3545e85fe34Schristos 			goto newbase;
3555e85fe34Schristos 
3565e85fe34Schristos 		BN_copy(x, base);
3575e85fe34Schristos 		BN_sub_word(x, 1);
3585e85fe34Schristos 		if (!BN_gcd(x, x, val, ctx))
3595e85fe34Schristos 			errx(1, "error in BN_gcd()");
3605e85fe34Schristos 
3615e85fe34Schristos 		if (!BN_is_one(x)) {
3625e85fe34Schristos 			if (BN_is_prime_ex(x, PRIME_CHECKS, NULL, NULL) == 1)
363f1aebb0cSchristos 				pr_print(x, hflag, xflag);
3645e85fe34Schristos 			else
365f1aebb0cSchristos 				pollard_pminus1(x, hflag, xflag);
3665e85fe34Schristos 			fflush(stdout);
3675e85fe34Schristos 
3685e85fe34Schristos 			BN_div(num, NULL, val, x, ctx);
3695e85fe34Schristos 			if (BN_is_one(num))
3705e85fe34Schristos 				return;
3715e85fe34Schristos 			if (BN_is_prime_ex(num, PRIME_CHECKS, NULL,
3725e85fe34Schristos 			    NULL) == 1) {
373f1aebb0cSchristos 				pr_print(num, hflag, xflag);
3745e85fe34Schristos 				fflush(stdout);
3755e85fe34Schristos 				return;
3765e85fe34Schristos 			}
3775e85fe34Schristos 			BN_copy(val, num);
3785e85fe34Schristos 		}
3795e85fe34Schristos 		if (!BN_add_word(i, 1))
3805e85fe34Schristos 			errx(1, "error in BN_add_word()");
3815e85fe34Schristos 	}
3825e85fe34Schristos }
3835e85fe34Schristos 
384a311a773Ssimonb /*
385a311a773Ssimonb  * Sigh..  No _decimal_ output to file functions in BN.
386a311a773Ssimonb  */
387e0ba63feSdholland static void
BN_print_dec_fp(FILE * fp,const BIGNUM * num)388a311a773Ssimonb BN_print_dec_fp(FILE *fp, const BIGNUM *num)
389a311a773Ssimonb {
390a311a773Ssimonb 	char *buf;
391a311a773Ssimonb 
392a311a773Ssimonb 	buf = BN_bn2dec(num);
393a311a773Ssimonb 	if (buf == NULL)
394a311a773Ssimonb 		return;	/* XXX do anything here? */
395cbd2e3d5Sjoerg 	fprintf(fp, "%s", buf);
396a311a773Ssimonb 	free(buf);
39742fb1b9dScgd }
39842fb1b9dScgd 
39969757aeeSitojun #else
40069757aeeSitojun 
4015e85fe34Schristos static void
BN_print_fp(FILE * fp,const BIGNUM * num)4025e85fe34Schristos BN_print_fp(FILE *fp, const BIGNUM *num)
4035e85fe34Schristos {
4045e85fe34Schristos 	fprintf(fp, "%lx", (unsigned long)*num);
4055e85fe34Schristos }
4065e85fe34Schristos 
4075e85fe34Schristos static void
BN_print_dec_fp(FILE * fp,const BIGNUM * num)4085e85fe34Schristos BN_print_dec_fp(FILE *fp, const BIGNUM *num)
4095e85fe34Schristos {
4105e85fe34Schristos 	fprintf(fp, "%lu", (unsigned long)*num);
4115e85fe34Schristos }
4125e85fe34Schristos 
4135e85fe34Schristos static int
BN_dec2bn(BIGNUM ** a,const char * str)4145e85fe34Schristos BN_dec2bn(BIGNUM **a, const char *str)
4155e85fe34Schristos {
4165e85fe34Schristos 	char *p;
4175e85fe34Schristos 
4185e85fe34Schristos 	errno = 0;
4195e85fe34Schristos 	**a = strtoul(str, &p, 10);
4205e85fe34Schristos 	return (errno == 0 ? 1 : 0);	/* OpenSSL returns 0 on error! */
4215e85fe34Schristos }
4225e85fe34Schristos 
4235e85fe34Schristos static int
BN_hex2bn(BIGNUM ** a,const char * str)4245e85fe34Schristos BN_hex2bn(BIGNUM **a, const char *str)
4255e85fe34Schristos {
4265e85fe34Schristos 	char *p;
4275e85fe34Schristos 
4285e85fe34Schristos 	errno = 0;
4295e85fe34Schristos 	**a = strtoul(str, &p, 16);
4305e85fe34Schristos 	return (errno == 0 ? 1 : 0);	/* OpenSSL returns 0 on error! */
43169757aeeSitojun }
43269757aeeSitojun 
433e0ba63feSdholland static BN_ULONG
BN_div_word(BIGNUM * a,BN_ULONG b)43469757aeeSitojun BN_div_word(BIGNUM *a, BN_ULONG b)
43569757aeeSitojun {
43669757aeeSitojun 	BN_ULONG mod;
43769757aeeSitojun 
43869757aeeSitojun 	mod = *a % b;
43969757aeeSitojun 	*a /= b;
44069757aeeSitojun 	return mod;
44169757aeeSitojun }
4425e85fe34Schristos 
443c5aeb8a7Schristos static BIGNUM *
BN_dup(const BIGNUM * a)444c5aeb8a7Schristos BN_dup(const BIGNUM *a)
445c5aeb8a7Schristos {
446c5aeb8a7Schristos 	BIGNUM *b = BN_new();
447c5aeb8a7Schristos 	BN_copy(b, a);
448c5aeb8a7Schristos 	return b;
449c5aeb8a7Schristos }
450c5aeb8a7Schristos 
45169757aeeSitojun #endif
4525e85fe34Schristos 
4535e85fe34Schristos /* Convert string pointed to by *str to a bignum.  */
4545e85fe34Schristos static void
convert_str2bn(BIGNUM ** val,char * p)4555e85fe34Schristos convert_str2bn(BIGNUM **val, char *p)
4565e85fe34Schristos {
4575e85fe34Schristos 	int n = 0;
4585e85fe34Schristos 
4595e85fe34Schristos 	if (*p == '+') p++;
4605e85fe34Schristos 	if (*p == '-')
4615e85fe34Schristos 		errx(1, "negative numbers aren't permitted.");
462a17b1cd2Schristos 	if (*p == '0' && (p[1] == 'x' || p[1] == 'X')) {
4632c61d0e8Schristos 		n = BN_hex2bn(val, p + 2);
4645e85fe34Schristos 	} else {
465662c0e24Schristos 		n = BN_dec2bn(val, p);
4665e85fe34Schristos 	}
4675e85fe34Schristos 	if (n == 0)
4685e85fe34Schristos 		errx(1, "%s: illegal numeric format.", p);
4695e85fe34Schristos }
470