xref: /onnv-gate/usr/src/common/bignum/bignumimpl.c (revision 1027:b0e9118569f9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #define	big_div_pos_fast big_div_pos
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include "bignum.h"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate /*
340Sstevel@tonic-gate  * Configuration guide
350Sstevel@tonic-gate  * -------------------
360Sstevel@tonic-gate  *
370Sstevel@tonic-gate  * There are 4 preprocessor symbols used to configure the bignum
380Sstevel@tonic-gate  * implementation.  This file contains no logic to configure based on
390Sstevel@tonic-gate  * processor; we leave that to the Makefiles to specify.
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * USE_FLOATING_POINT
420Sstevel@tonic-gate  *   Meaning: There is support for a fast floating-point implementation of
430Sstevel@tonic-gate  *   Montgomery multiply.
440Sstevel@tonic-gate  *
450Sstevel@tonic-gate  * PSR_MUL
460Sstevel@tonic-gate  *   Meaning: There are processor-specific versions of the low level
470Sstevel@tonic-gate  *   functions to implement big_mul.  Those functions are: big_mul_set_vec,
480Sstevel@tonic-gate  *   big_mul_add_vec, big_mul_vec, and big_sqr_vec.  PSR_MUL implies support
490Sstevel@tonic-gate  *   for all 4 functions.  You cannot pick and choose which subset of these
500Sstevel@tonic-gate  *   functions to support; that would lead to a rat's nest of #ifdefs.
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  * HWCAP
530Sstevel@tonic-gate  *   Meaning: Call multiply support functions through a function pointer.
540Sstevel@tonic-gate  *   On x86, there are multiple implementations for differnt hardware
550Sstevel@tonic-gate  *   capabilities, such as MMX, SSE2, etc.  Tests are made at run-time, when
560Sstevel@tonic-gate  *   a function is first used.  So, the support functions are called through
570Sstevel@tonic-gate  *   a function pointer.  There is no need for that on Sparc, because there
580Sstevel@tonic-gate  *   is only one implementation; support functions are called directly.
590Sstevel@tonic-gate  *   Later, if there were some new VIS instruction, or something, and a
600Sstevel@tonic-gate  *   run-time test were needed, rather than variant kernel modules and
610Sstevel@tonic-gate  *   libraries, then HWCAP would be defined for Sparc, as well.
620Sstevel@tonic-gate  *
630Sstevel@tonic-gate  * UMUL64
640Sstevel@tonic-gate  *   Meaning: It is safe to use generic C code that assumes the existence
650Sstevel@tonic-gate  *   of a 32 x 32 --> 64 bit unsigned multiply.  If this is not defined,
660Sstevel@tonic-gate  *   then the generic code for big_mul_add_vec() must necessarily be very slow,
670Sstevel@tonic-gate  *   because it must fall back to using 16 x 16 --> 32 bit multiplication.
680Sstevel@tonic-gate  *
690Sstevel@tonic-gate  */
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 
720Sstevel@tonic-gate #ifdef	_KERNEL
730Sstevel@tonic-gate 
740Sstevel@tonic-gate #include <sys/types.h>
750Sstevel@tonic-gate #include <sys/kmem.h>
760Sstevel@tonic-gate #include <sys/param.h>
770Sstevel@tonic-gate #include <sys/sunddi.h>
780Sstevel@tonic-gate 
790Sstevel@tonic-gate #define	big_malloc(size)	kmem_alloc(size, KM_NOSLEEP)
800Sstevel@tonic-gate #define	big_free(ptr, size)	kmem_free(ptr, size)
810Sstevel@tonic-gate 
820Sstevel@tonic-gate void *
830Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize)
840Sstevel@tonic-gate {
850Sstevel@tonic-gate 	void *rv;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	rv = kmem_alloc(newsize, KM_NOSLEEP);
880Sstevel@tonic-gate 	if (rv != NULL)
890Sstevel@tonic-gate 		bcopy(from, rv, oldsize);
900Sstevel@tonic-gate 	kmem_free(from, oldsize);
910Sstevel@tonic-gate 	return (rv);
920Sstevel@tonic-gate }
930Sstevel@tonic-gate 
940Sstevel@tonic-gate #else	/* _KERNEL */
950Sstevel@tonic-gate 
960Sstevel@tonic-gate #include <stdlib.h>
970Sstevel@tonic-gate #include <stdio.h>
980Sstevel@tonic-gate 
990Sstevel@tonic-gate #ifndef MALLOC_DEBUG
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate #define	big_malloc(size)	malloc(size)
1020Sstevel@tonic-gate #define	big_free(ptr, size)	free(ptr)
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate #else
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate void
1070Sstevel@tonic-gate big_free(void *ptr, size_t size)
1080Sstevel@tonic-gate {
1090Sstevel@tonic-gate 	printf("freed %d bytes at %p\n", size, ptr);
1100Sstevel@tonic-gate 	free(ptr);
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate void *
1140Sstevel@tonic-gate big_malloc(size_t size)
1150Sstevel@tonic-gate {
1160Sstevel@tonic-gate 	void *rv;
1170Sstevel@tonic-gate 	rv = malloc(size);
1180Sstevel@tonic-gate 	printf("malloced %d bytes, addr:%p\n", size, rv);
1190Sstevel@tonic-gate 	return (rv);
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate #endif /* MALLOC_DEBUG */
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate #define	big_realloc(x, y, z) realloc((x), (z))
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate void
1260Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a)
1270Sstevel@tonic-gate {
1280Sstevel@tonic-gate 	int i;
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	(void) printf("\n%s\n%d\n", aname, a->sign*a->len);
1310Sstevel@tonic-gate 	for (i = a->len - 1; i >= 0; i--) {
1320Sstevel@tonic-gate 		(void) printf("%08x ", a->value[i]);
1330Sstevel@tonic-gate 		if ((i % 8 == 0) && (i != 0))
1340Sstevel@tonic-gate 		    (void) printf("\n");
1350Sstevel@tonic-gate 	}
1360Sstevel@tonic-gate 	(void) printf("\n");
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate #endif	/* _KERNEL */
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate /* size in 32-bit words */
1430Sstevel@tonic-gate BIG_ERR_CODE
1440Sstevel@tonic-gate big_init(BIGNUM *number, int size)
1450Sstevel@tonic-gate {
1460Sstevel@tonic-gate 	number->value = big_malloc(sizeof (uint32_t) * size);
1470Sstevel@tonic-gate 	if (number->value == NULL) {
1480Sstevel@tonic-gate 		return (BIG_NO_MEM);
1490Sstevel@tonic-gate 	}
1500Sstevel@tonic-gate 	number->size = size;
1510Sstevel@tonic-gate 	number->len = 0;
1520Sstevel@tonic-gate 	number->sign = 1;
1530Sstevel@tonic-gate 	number->malloced = 1;
1540Sstevel@tonic-gate 	return (BIG_OK);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate /* size in 32-bit words */
1580Sstevel@tonic-gate BIG_ERR_CODE
1590Sstevel@tonic-gate big_init1(BIGNUM *number, int size, uint32_t *buf, int bufsize)
1600Sstevel@tonic-gate {
1610Sstevel@tonic-gate 	if ((buf == NULL) || (size > bufsize)) {
1620Sstevel@tonic-gate 		number->value = big_malloc(sizeof (uint32_t) * size);
1630Sstevel@tonic-gate 		if (number->value == NULL) {
1640Sstevel@tonic-gate 			return (BIG_NO_MEM);
1650Sstevel@tonic-gate 		}
1660Sstevel@tonic-gate 		number->size = size;
1670Sstevel@tonic-gate 		number->malloced = 1;
1680Sstevel@tonic-gate 	} else {
1690Sstevel@tonic-gate 		number->value = buf;
1700Sstevel@tonic-gate 		number->size = bufsize;
1710Sstevel@tonic-gate 		number->malloced = 0;
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 		number->len = 0;
1740Sstevel@tonic-gate 		number->sign = 1;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	return (BIG_OK);
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate void
1800Sstevel@tonic-gate big_finish(BIGNUM *number)
1810Sstevel@tonic-gate {
1820Sstevel@tonic-gate 	if (number->malloced == 1) {
1830Sstevel@tonic-gate 		big_free(number->value, sizeof (uint32_t) * number->size);
1840Sstevel@tonic-gate 		number->malloced = 0;
1850Sstevel@tonic-gate 	}
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate /*
1890Sstevel@tonic-gate  *  bn->size should be at least (len + 3) / 4
1900Sstevel@tonic-gate  * converts from byte-big-endian format to bignum format (words in
1910Sstevel@tonic-gate  * little endian order, but bytes within the words big endian)
1920Sstevel@tonic-gate  */
1930Sstevel@tonic-gate void
1940Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate 	int		i, j, offs;
1970Sstevel@tonic-gate 	uint32_t	word;
1980Sstevel@tonic-gate 	uchar_t		*knwordp;
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate #ifdef	_LP64
2010Sstevel@tonic-gate 	/* LINTED */
2020Sstevel@tonic-gate 	offs = (uint32_t)len % sizeof (uint32_t);
2030Sstevel@tonic-gate 	/* LINTED */
2040Sstevel@tonic-gate 	bn->len = (uint32_t)len / sizeof (uint32_t);
2050Sstevel@tonic-gate 	/* LINTED */
2060Sstevel@tonic-gate 	for (i = 0; i < (uint32_t)len / sizeof (uint32_t); i++) {
2070Sstevel@tonic-gate #else	/* !_LP64 */
2080Sstevel@tonic-gate 	offs = len % sizeof (uint32_t);
2090Sstevel@tonic-gate 	bn->len = len / sizeof (uint32_t);
2100Sstevel@tonic-gate 	for (i = 0; i < len / sizeof (uint32_t); i++) {
2110Sstevel@tonic-gate #endif	/* _LP64 */
2120Sstevel@tonic-gate 		knwordp = &(kn[len - sizeof (uint32_t) * (i + 1)]);
2130Sstevel@tonic-gate 		word = knwordp[0];
2140Sstevel@tonic-gate 		for (j = 1; j < sizeof (uint32_t); j++) {
2150Sstevel@tonic-gate 			word = (word << 8)+ knwordp[j];
2160Sstevel@tonic-gate 		}
2170Sstevel@tonic-gate 		bn->value[i] = word;
2180Sstevel@tonic-gate 	}
2190Sstevel@tonic-gate 	if (offs > 0) {
2200Sstevel@tonic-gate 		word = kn[0];
2210Sstevel@tonic-gate 		for (i = 1; i < offs; i++) word = (word << 8) + kn[i];
2220Sstevel@tonic-gate 		bn->value[bn->len++] = word;
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 	while ((bn->len > 1) && (bn->value[bn->len-1] == 0)) {
2250Sstevel@tonic-gate 		bn->len --;
2260Sstevel@tonic-gate 	}
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate /*
2300Sstevel@tonic-gate  * copies the least significant len bytes if
2310Sstevel@tonic-gate  * len < bn->len * sizeof (uint32_t)
2320Sstevel@tonic-gate  * converts from bignum format to byte-big-endian format.
2330Sstevel@tonic-gate  * bignum format is words in little endian order,
2340Sstevel@tonic-gate  * but bytes within words in native byte order.
2350Sstevel@tonic-gate  */
2360Sstevel@tonic-gate void
2370Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len)
2380Sstevel@tonic-gate {
2390Sstevel@tonic-gate 	int		i, j, offs;
2400Sstevel@tonic-gate 	uint32_t	word;
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	if (len < sizeof (uint32_t) * bn->len) {
2430Sstevel@tonic-gate #ifdef	_LP64
2440Sstevel@tonic-gate 		/* LINTED */
2450Sstevel@tonic-gate 		for (i = 0; i < (uint32_t)len / sizeof (uint32_t); i++) {
2460Sstevel@tonic-gate #else	/* !_LP64 */
2470Sstevel@tonic-gate 		for (i = 0; i < len / sizeof (uint32_t); i++) {
2480Sstevel@tonic-gate #endif	/* _LP64 */
2490Sstevel@tonic-gate 			word = bn->value[i];
2500Sstevel@tonic-gate 			for (j = 0; j < sizeof (uint32_t); j++) {
2510Sstevel@tonic-gate 				kn[len - sizeof (uint32_t) * i - j - 1] =
2520Sstevel@tonic-gate 				    word & 0xff;
2530Sstevel@tonic-gate 				word = word >> 8;
2540Sstevel@tonic-gate 			}
2550Sstevel@tonic-gate 		}
2560Sstevel@tonic-gate #ifdef	_LP64
2570Sstevel@tonic-gate 		/* LINTED */
2580Sstevel@tonic-gate 		offs = (uint32_t)len % sizeof (uint32_t);
2590Sstevel@tonic-gate #else	/* !_LP64 */
2600Sstevel@tonic-gate 		offs = len % sizeof (uint32_t);
2610Sstevel@tonic-gate #endif	/* _LP64 */
2620Sstevel@tonic-gate 		if (offs > 0) {
2630Sstevel@tonic-gate 			word = bn->value[len / sizeof (uint32_t)];
2640Sstevel@tonic-gate #ifdef	_LP64
2650Sstevel@tonic-gate 			    /* LINTED */
2660Sstevel@tonic-gate 			    for (i =  (uint32_t)len % sizeof (uint32_t);
2670Sstevel@tonic-gate 				i > 0; i --) {
2680Sstevel@tonic-gate #else	/* !_LP64 */
2690Sstevel@tonic-gate 			    for (i = len % sizeof (uint32_t); i > 0; i --) {
2700Sstevel@tonic-gate #endif	/* _LP64 */
2710Sstevel@tonic-gate 				    kn[i - 1] = word & 0xff;
2720Sstevel@tonic-gate 				    word = word >> 8;
2730Sstevel@tonic-gate 			    }
2740Sstevel@tonic-gate 		}
2750Sstevel@tonic-gate 	} else {
2760Sstevel@tonic-gate 		for (i = 0; i < bn->len; i++) {
2770Sstevel@tonic-gate 			word = bn->value[i];
2780Sstevel@tonic-gate 			for (j = 0; j < sizeof (uint32_t); j++) {
2790Sstevel@tonic-gate 				kn[len - sizeof (uint32_t) * i - j - 1] =
2800Sstevel@tonic-gate 				    word & 0xff;
2810Sstevel@tonic-gate 				word = word >> 8;
2820Sstevel@tonic-gate 			}
2830Sstevel@tonic-gate 		}
2840Sstevel@tonic-gate #ifdef	_LP64
2850Sstevel@tonic-gate 		/* LINTED */
2860Sstevel@tonic-gate 		for (i = 0; i < (uint32_t)len - sizeof (uint32_t) * bn->len;
2870Sstevel@tonic-gate 		    i++) {
2880Sstevel@tonic-gate #else	/* !_LP64 */
2890Sstevel@tonic-gate 		for (i = 0; i < len - sizeof (uint32_t) * bn->len; i++) {
2900Sstevel@tonic-gate #endif	/* _LP64 */
2910Sstevel@tonic-gate 			kn[i] = 0;
2920Sstevel@tonic-gate 		}
2930Sstevel@tonic-gate 	}
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate int
2980Sstevel@tonic-gate big_bitlength(BIGNUM *a)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	int		l, b;
3010Sstevel@tonic-gate 	uint32_t	c;
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	l = a->len - 1;
3040Sstevel@tonic-gate 	while ((l > 0) && (a->value[l] == 0)) {
3050Sstevel@tonic-gate 		l--;
3060Sstevel@tonic-gate 	}
3070Sstevel@tonic-gate 	b = sizeof (uint32_t) * 8;
3080Sstevel@tonic-gate 	c = a->value[l];
3090Sstevel@tonic-gate 	while ((b > 1) && ((c & 0x80000000) == 0)) {
3100Sstevel@tonic-gate 		c = c << 1;
3110Sstevel@tonic-gate 		b--;
3120Sstevel@tonic-gate 	}
3130Sstevel@tonic-gate 	return (l * (int)sizeof (uint32_t) * 8 + b);
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate BIG_ERR_CODE
3180Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src)
3190Sstevel@tonic-gate {
3200Sstevel@tonic-gate 	uint32_t *newptr;
3210Sstevel@tonic-gate 	int i, len;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	len = src->len;
3240Sstevel@tonic-gate 	while ((len > 1) && (src->value[len - 1] == 0))
3250Sstevel@tonic-gate 		len--;
3260Sstevel@tonic-gate 	src->len = len;
3270Sstevel@tonic-gate 	if (dest->size < len) {
3280Sstevel@tonic-gate 		if (dest->malloced == 1) {
3290Sstevel@tonic-gate 			newptr = (uint32_t *)big_realloc(dest->value,
3300Sstevel@tonic-gate 			    sizeof (uint32_t) * dest->size,
3310Sstevel@tonic-gate 			    sizeof (uint32_t) * len);
3320Sstevel@tonic-gate 		} else {
3330Sstevel@tonic-gate 			newptr = (uint32_t *)
3340Sstevel@tonic-gate 			    big_malloc(sizeof (uint32_t) * len);
3350Sstevel@tonic-gate 			if (newptr != NULL) dest->malloced = 1;
3360Sstevel@tonic-gate 		}
3370Sstevel@tonic-gate 		if (newptr == NULL)
3380Sstevel@tonic-gate 			return (BIG_NO_MEM);
3390Sstevel@tonic-gate 		dest->value = newptr;
3400Sstevel@tonic-gate 		dest->size = len;
3410Sstevel@tonic-gate 	}
3420Sstevel@tonic-gate 	dest->len = len;
3430Sstevel@tonic-gate 	dest->sign = src->sign;
3440Sstevel@tonic-gate 	for (i = 0; i < len; i++) dest->value[i] = src->value[i];
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	return (BIG_OK);
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate BIG_ERR_CODE
3510Sstevel@tonic-gate big_extend(BIGNUM *number, int size)
3520Sstevel@tonic-gate {
3530Sstevel@tonic-gate 	uint32_t	*newptr;
3540Sstevel@tonic-gate 	int		i;
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	if (number->size >= size)
3570Sstevel@tonic-gate 		return (BIG_OK);
3580Sstevel@tonic-gate 	if (number->malloced) {
3590Sstevel@tonic-gate 		number->value =
3600Sstevel@tonic-gate 		    big_realloc(number->value,
3610Sstevel@tonic-gate 			sizeof (uint32_t) * number->size,
3620Sstevel@tonic-gate 			sizeof (uint32_t) * size);
3630Sstevel@tonic-gate 	} else {
3640Sstevel@tonic-gate 		newptr = big_malloc(sizeof (uint32_t) * size);
3650Sstevel@tonic-gate 		if (newptr != NULL) {
3660Sstevel@tonic-gate 			for (i = 0; i < number->size; i++) {
3670Sstevel@tonic-gate 				newptr[i] = number->value[i];
3680Sstevel@tonic-gate 			}
3690Sstevel@tonic-gate 		}
3700Sstevel@tonic-gate 		number->value = newptr;
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	if (number->value == NULL)
3740Sstevel@tonic-gate 		return (BIG_NO_MEM);
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	number->size = size;
3770Sstevel@tonic-gate 	number->malloced = 1;
3780Sstevel@tonic-gate 	return (BIG_OK);
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate int
3830Sstevel@tonic-gate big_is_zero(BIGNUM *n)
3840Sstevel@tonic-gate {
3850Sstevel@tonic-gate 	int i, result;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	result = 1;
3880Sstevel@tonic-gate 	for (i = 0; i < n->len; i++)
3890Sstevel@tonic-gate 		if (n->value[i] != 0) result = 0;
3900Sstevel@tonic-gate 	return (result);
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate BIG_ERR_CODE
3950Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
3960Sstevel@tonic-gate {
3970Sstevel@tonic-gate 	int i, shorter, longer;
3980Sstevel@tonic-gate 	uint32_t cy, ai;
3990Sstevel@tonic-gate 	uint32_t *r, *a, *b, *c;
4000Sstevel@tonic-gate 	BIG_ERR_CODE err;
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	if (aa->len > bb->len) {
4030Sstevel@tonic-gate 		shorter = bb->len;
4040Sstevel@tonic-gate 		longer = aa->len;
4050Sstevel@tonic-gate 		c = aa->value;
4060Sstevel@tonic-gate 	} else {
4070Sstevel@tonic-gate 		shorter = aa->len;
4080Sstevel@tonic-gate 		longer = bb->len;
4090Sstevel@tonic-gate 		c = bb->value;
4100Sstevel@tonic-gate 	}
4110Sstevel@tonic-gate 	if (result->size < longer + 1) {
4120Sstevel@tonic-gate 		err = big_extend(result, longer + 1);
4130Sstevel@tonic-gate 		if (err != BIG_OK)
4140Sstevel@tonic-gate 			return (err);
4150Sstevel@tonic-gate 	}
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	r = result->value;
4180Sstevel@tonic-gate 	a = aa->value;
4190Sstevel@tonic-gate 	b = bb->value;
4200Sstevel@tonic-gate 	cy = 0;
4210Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
4220Sstevel@tonic-gate 		ai = a[i];
4230Sstevel@tonic-gate 		r[i] = ai + b[i] + cy;
4240Sstevel@tonic-gate 		if (r[i] > ai) cy = 0;
4250Sstevel@tonic-gate 		else if (r[i] < ai) cy = 1;
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate 	for (; i < longer; i++) {
4280Sstevel@tonic-gate 		ai = c[i];
4290Sstevel@tonic-gate 		r[i] = ai + cy;
4300Sstevel@tonic-gate 		if (r[i] >= ai) cy = 0;
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate 	if (cy == 1) {
4330Sstevel@tonic-gate 		r[i] = cy;
4340Sstevel@tonic-gate 		result->len = longer + 1;
4350Sstevel@tonic-gate 	} else {
4360Sstevel@tonic-gate 		result->len = longer;
4370Sstevel@tonic-gate 	}
4380Sstevel@tonic-gate 	result->sign = 1;
4390Sstevel@tonic-gate 	return (BIG_OK);
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */
4440Sstevel@tonic-gate void
4450Sstevel@tonic-gate big_sub_vec(uint32_t *r, uint32_t *a, uint32_t *b, int len)
4460Sstevel@tonic-gate {
4470Sstevel@tonic-gate 	int i;
4480Sstevel@tonic-gate 	uint32_t cy, ai;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	cy = 1;
4510Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
4520Sstevel@tonic-gate 		ai = a[i];
4530Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
4540Sstevel@tonic-gate 		if (r[i] > ai) cy = 0;
4550Sstevel@tonic-gate 		else if (r[i] < ai) cy = 1;
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate /* result=aa-bb  it is assumed that aa>=bb */
4610Sstevel@tonic-gate BIG_ERR_CODE
4620Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
4630Sstevel@tonic-gate {
4640Sstevel@tonic-gate 	int i, shorter;
4650Sstevel@tonic-gate 	uint32_t cy, ai;
4660Sstevel@tonic-gate 	uint32_t *r, *a, *b;
4670Sstevel@tonic-gate 	BIG_ERR_CODE err;
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	if (aa->len > bb->len) shorter = bb->len;
4700Sstevel@tonic-gate 	else shorter = aa->len;
4710Sstevel@tonic-gate 	if (result->size < aa->len) {
4720Sstevel@tonic-gate 		err = big_extend(result, aa->len);
4730Sstevel@tonic-gate 		if (err != BIG_OK)
4740Sstevel@tonic-gate 			return (err);
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	r = result->value;
4780Sstevel@tonic-gate 	a = aa->value;
4790Sstevel@tonic-gate 	b = bb->value;
4800Sstevel@tonic-gate 	result->len = aa->len;
4810Sstevel@tonic-gate 	cy = 1;
4820Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
4830Sstevel@tonic-gate 		ai = a[i];
4840Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
4850Sstevel@tonic-gate 		if (r[i] > ai) cy = 0;
4860Sstevel@tonic-gate 		else if (r[i] < ai) cy = 1;
4870Sstevel@tonic-gate 	}
4880Sstevel@tonic-gate 	for (; i < aa->len; i++) {
4890Sstevel@tonic-gate 		ai = a[i];
4900Sstevel@tonic-gate 		r[i] = ai + (~0) + cy;
4910Sstevel@tonic-gate 		if (r[i] < ai) cy = 1;
4920Sstevel@tonic-gate 	}
4930Sstevel@tonic-gate 	result->sign = 1;
4940Sstevel@tonic-gate 	if (cy == 0)
4950Sstevel@tonic-gate 		return (BIG_INVALID_ARGS);
4960Sstevel@tonic-gate 	else
4970Sstevel@tonic-gate 		return (BIG_OK);
4980Sstevel@tonic-gate }
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */
5020Sstevel@tonic-gate int
5030Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb)
5040Sstevel@tonic-gate {
5050Sstevel@tonic-gate 	int i;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	if (aa->len > bb->len) {
5080Sstevel@tonic-gate 		for (i = aa->len - 1; i > bb->len - 1; i--) {
5090Sstevel@tonic-gate 			if (aa->value[i] > 0)
5100Sstevel@tonic-gate 				return (1);
5110Sstevel@tonic-gate 		}
5120Sstevel@tonic-gate 	} else if (aa->len < bb->len) {
5130Sstevel@tonic-gate 		for (i = bb->len - 1; i > aa->len - 1; i--) {
5140Sstevel@tonic-gate 			if (bb->value[i] > 0)
5150Sstevel@tonic-gate 				return (-1);
5160Sstevel@tonic-gate 		}
5170Sstevel@tonic-gate 	} else i = aa->len-1;
5180Sstevel@tonic-gate 	for (; i >= 0; i--) {
5190Sstevel@tonic-gate 		if (aa->value[i] > bb->value[i])
5200Sstevel@tonic-gate 			return (1);
5210Sstevel@tonic-gate 		else if (aa->value[i] < bb->value[i])
5220Sstevel@tonic-gate 			return (-1);
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	return (0);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate BIG_ERR_CODE
5300Sstevel@tonic-gate big_sub(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
5310Sstevel@tonic-gate {
5320Sstevel@tonic-gate 	BIG_ERR_CODE err;
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == 1)) {
5350Sstevel@tonic-gate 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK)
5360Sstevel@tonic-gate 			return (err);
5370Sstevel@tonic-gate 		result->sign = 1;
5380Sstevel@tonic-gate 	} else if ((aa->sign == -1) && (bb->sign == 1)) {
5390Sstevel@tonic-gate 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK)
5400Sstevel@tonic-gate 			return (err);
5410Sstevel@tonic-gate 		result->sign = -1;
5420Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
5430Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
5440Sstevel@tonic-gate 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK)
5450Sstevel@tonic-gate 				return (err);
5460Sstevel@tonic-gate 			result->sign = 1;
5470Sstevel@tonic-gate 		} else {
5480Sstevel@tonic-gate 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK)
5490Sstevel@tonic-gate 				return (err);
5500Sstevel@tonic-gate 			result->sign = -1;
5510Sstevel@tonic-gate 		}
5520Sstevel@tonic-gate 	} else {
5530Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
5540Sstevel@tonic-gate 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK)
5550Sstevel@tonic-gate 				return (err);
5560Sstevel@tonic-gate 			result->sign = -1;
5570Sstevel@tonic-gate 		} else {
5580Sstevel@tonic-gate 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK)
5590Sstevel@tonic-gate 				return (err);
5600Sstevel@tonic-gate 			result->sign = 1;
5610Sstevel@tonic-gate 		}
5620Sstevel@tonic-gate 	}
5630Sstevel@tonic-gate 	return (BIG_OK);
5640Sstevel@tonic-gate }
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate BIG_ERR_CODE
5690Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
5700Sstevel@tonic-gate {
5710Sstevel@tonic-gate 	BIG_ERR_CODE err;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == -1)) {
5740Sstevel@tonic-gate 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK)
5750Sstevel@tonic-gate 			return (err);
5760Sstevel@tonic-gate 		result->sign = -1;
5770Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
5780Sstevel@tonic-gate 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK)
5790Sstevel@tonic-gate 			return (err);
5800Sstevel@tonic-gate 		result->sign = 1;
5810Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == -1)) {
5820Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
5830Sstevel@tonic-gate 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK)
5840Sstevel@tonic-gate 				return (err);
5850Sstevel@tonic-gate 			result->sign = 1;
5860Sstevel@tonic-gate 		} else {
5870Sstevel@tonic-gate 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK)
5880Sstevel@tonic-gate 				return (err);
5890Sstevel@tonic-gate 			result->sign = -1;
5900Sstevel@tonic-gate 		}
5910Sstevel@tonic-gate 	} else {
5920Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
5930Sstevel@tonic-gate 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK)
5940Sstevel@tonic-gate 				return (err);
5950Sstevel@tonic-gate 			result->sign = -1;
5960Sstevel@tonic-gate 		} else {
5970Sstevel@tonic-gate 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK)
5980Sstevel@tonic-gate 				return (err);
5990Sstevel@tonic-gate 			result->sign = 1;
6000Sstevel@tonic-gate 		}
6010Sstevel@tonic-gate 	}
6020Sstevel@tonic-gate 	return (BIG_OK);
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate /* result = aa/2 aa must be positive */
6070Sstevel@tonic-gate BIG_ERR_CODE
6080Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa)
6090Sstevel@tonic-gate {
6100Sstevel@tonic-gate 	BIG_ERR_CODE err;
6110Sstevel@tonic-gate 	int i;
6120Sstevel@tonic-gate 	uint32_t cy, cy1;
6130Sstevel@tonic-gate 	uint32_t *a, *r;
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	if (result->size < aa->len) {
6160Sstevel@tonic-gate 		err = big_extend(result, aa->len);
6170Sstevel@tonic-gate 		if (err != BIG_OK)
6180Sstevel@tonic-gate 			return (err);
6190Sstevel@tonic-gate 	}
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	result->len = aa->len;
6220Sstevel@tonic-gate 	a = aa->value;
6230Sstevel@tonic-gate 	r = result->value;
6240Sstevel@tonic-gate 	cy = 0;
6250Sstevel@tonic-gate 	for (i = aa->len-1; i >= 0; i--) {
6260Sstevel@tonic-gate 		cy1 = a[i] << 31;
6270Sstevel@tonic-gate 		r[i] = (cy|(a[i] >> 1));
6280Sstevel@tonic-gate 		cy = cy1;
6290Sstevel@tonic-gate 	}
6300Sstevel@tonic-gate 	if (r[result->len-1] == 0) result->len--;
6310Sstevel@tonic-gate 	return (BIG_OK);
6320Sstevel@tonic-gate }
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate /* result  =  aa*2 aa must be positive */
6350Sstevel@tonic-gate BIG_ERR_CODE
6360Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa)
6370Sstevel@tonic-gate {
6380Sstevel@tonic-gate 	BIG_ERR_CODE err;
6390Sstevel@tonic-gate 	int i, rsize;
6400Sstevel@tonic-gate 	uint32_t cy, cy1;
6410Sstevel@tonic-gate 	uint32_t *a, *r;
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	if ((aa->len > 0) && ((aa->value[aa->len - 1] & 0x80000000) != 0))
6440Sstevel@tonic-gate 		rsize = aa->len + 1;
6450Sstevel@tonic-gate 	else rsize = aa->len;
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	if (result->size < rsize) {
6480Sstevel@tonic-gate 		err = big_extend(result, rsize);
6490Sstevel@tonic-gate 		if (err != BIG_OK)
6500Sstevel@tonic-gate 			return (err);
6510Sstevel@tonic-gate 	}
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	a = aa->value;
6540Sstevel@tonic-gate 	r = result->value;
6550Sstevel@tonic-gate 	if (rsize == aa->len + 1) r[rsize - 1] = 1;
6560Sstevel@tonic-gate 	cy = 0;
6570Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
6580Sstevel@tonic-gate 		cy1 = a[i] >> 31;
6590Sstevel@tonic-gate 		r[i] = (cy | (a[i] << 1));
6600Sstevel@tonic-gate 		cy = cy1;
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate 	result->len = rsize;
6630Sstevel@tonic-gate 	return (BIG_OK);
6640Sstevel@tonic-gate }
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate /* returns aa mod b, aa must be nonneg, b must be a max 16-bit integer */
6670Sstevel@tonic-gate uint32_t
6680Sstevel@tonic-gate big_mod16_pos(BIGNUM *aa, uint32_t b)
6690Sstevel@tonic-gate {
6700Sstevel@tonic-gate 	int i;
6710Sstevel@tonic-gate 	uint32_t rem;
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	if (aa->len == 0)
6740Sstevel@tonic-gate 		return (0);
6750Sstevel@tonic-gate 	rem = aa->value[aa->len - 1] % b;
6760Sstevel@tonic-gate 	for (i = aa->len - 2; i >= 0; i--) {
6770Sstevel@tonic-gate 		rem = ((rem << 16) | (aa->value[i] >> 16)) % b;
6780Sstevel@tonic-gate 		rem = ((rem << 16) | (aa->value[i] & 0xffff)) % b;
6790Sstevel@tonic-gate 	}
6800Sstevel@tonic-gate 	return (rem);
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate /*
6850Sstevel@tonic-gate  * result = aa - (2^32)^lendiff * bb
6860Sstevel@tonic-gate  * result->size should be at least aa->len at entry
6870Sstevel@tonic-gate  * aa, bb, and result should be positive
6880Sstevel@tonic-gate  */
6890Sstevel@tonic-gate void
6900Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
6910Sstevel@tonic-gate {
6920Sstevel@tonic-gate 	int i, lendiff;
6930Sstevel@tonic-gate 	BIGNUM res1, aa1;
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
6960Sstevel@tonic-gate 	res1.size = result->size - lendiff;
6970Sstevel@tonic-gate 	res1.malloced = 0;
6980Sstevel@tonic-gate 	res1.value = result->value + lendiff;
6990Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
7000Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
7010Sstevel@tonic-gate 	aa1.len = bb->len;
7020Sstevel@tonic-gate 	aa1.sign = 1;
7030Sstevel@tonic-gate 	(void) big_sub_pos(&res1, &aa1, bb);
7040Sstevel@tonic-gate 	if (result->value != aa->value) {
7050Sstevel@tonic-gate 		for (i = 0; i < lendiff; i++) {
7060Sstevel@tonic-gate 			result->value[i] = aa->value[i];
7070Sstevel@tonic-gate 		}
7080Sstevel@tonic-gate 	}
7090Sstevel@tonic-gate 	result->len = aa->len;
7100Sstevel@tonic-gate }
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate /*
7140Sstevel@tonic-gate  * returns 1, 0, or -1 depending on whether |aa| > , ==, or <
7150Sstevel@tonic-gate  *							(2^32)^lendiff * |bb|
7160Sstevel@tonic-gate  * aa->len should be >= bb->len
7170Sstevel@tonic-gate  */
7180Sstevel@tonic-gate int
7190Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb)
7200Sstevel@tonic-gate {
7210Sstevel@tonic-gate 	int lendiff;
7220Sstevel@tonic-gate 	BIGNUM aa1;
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
7250Sstevel@tonic-gate 	aa1.len = bb->len;
7260Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
7270Sstevel@tonic-gate 	aa1.malloced = 0;
7280Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
7290Sstevel@tonic-gate 	return (big_cmp_abs(&aa1, bb));
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate /*
7340Sstevel@tonic-gate  * result = aa * b where b is a max. 16-bit positive integer.
7350Sstevel@tonic-gate  * result should have enough space allocated.
7360Sstevel@tonic-gate  */
7370Sstevel@tonic-gate void
7380Sstevel@tonic-gate big_mul16_low(BIGNUM *result, BIGNUM *aa, uint32_t b)
7390Sstevel@tonic-gate {
7400Sstevel@tonic-gate 	int i;
7410Sstevel@tonic-gate 	uint32_t t1, t2, ai, cy;
7420Sstevel@tonic-gate 	uint32_t *a, *r;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	a = aa->value;
7450Sstevel@tonic-gate 	r = result->value;
7460Sstevel@tonic-gate 	cy = 0;
7470Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
7480Sstevel@tonic-gate 		ai = a[i];
7490Sstevel@tonic-gate 		t1 = (ai & 0xffff) * b + cy;
7500Sstevel@tonic-gate 		t2 = (ai >> 16) * b + (t1 >> 16);
7510Sstevel@tonic-gate 		r[i] = (t1 & 0xffff) | (t2 << 16);
7520Sstevel@tonic-gate 		cy = t2 >> 16;
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate 	r[i] = cy;
7550Sstevel@tonic-gate 	result->len = aa->len + 1;
7560Sstevel@tonic-gate 	result->sign = aa->sign;
7570Sstevel@tonic-gate }
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate /*
7610Sstevel@tonic-gate  * result = aa * b * 2^16 where b is a max. 16-bit positive integer.
7620Sstevel@tonic-gate  * result should have enough space allocated.
7630Sstevel@tonic-gate  */
7640Sstevel@tonic-gate void
7650Sstevel@tonic-gate big_mul16_high(BIGNUM *result, BIGNUM *aa, uint32_t b)
7660Sstevel@tonic-gate {
7670Sstevel@tonic-gate 	int i;
7680Sstevel@tonic-gate 	uint32_t t1, t2, ai, cy, ri;
7690Sstevel@tonic-gate 	uint32_t *a, *r;
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	a = aa->value;
7720Sstevel@tonic-gate 	r = result->value;
7730Sstevel@tonic-gate 	cy = 0;
7740Sstevel@tonic-gate 	ri = 0;
7750Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
7760Sstevel@tonic-gate 		ai = a[i];
7770Sstevel@tonic-gate 		t1 = (ai & 0xffff) * b + cy;
7780Sstevel@tonic-gate 		t2 = (ai >> 16) * b + (t1 >> 16);
7790Sstevel@tonic-gate 		r[i] = (t1 << 16) + ri;
7800Sstevel@tonic-gate 		ri = t2 & 0xffff;
7810Sstevel@tonic-gate 		cy = t2 >> 16;
7820Sstevel@tonic-gate 	}
7830Sstevel@tonic-gate 	r[i] = (cy << 16) + ri;
7840Sstevel@tonic-gate 	result->len = aa->len + 1;
7850Sstevel@tonic-gate 	result->sign = aa->sign;
7860Sstevel@tonic-gate }
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate /* it is assumed that result->size is big enough */
7890Sstevel@tonic-gate void
7900Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs)
7910Sstevel@tonic-gate {
7920Sstevel@tonic-gate 	int i;
7930Sstevel@tonic-gate 	uint32_t cy, ai;
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	if (offs == 0) {
7960Sstevel@tonic-gate 		if (result != aa) {
7970Sstevel@tonic-gate 			(void) big_copy(result, aa);
7980Sstevel@tonic-gate 		}
7990Sstevel@tonic-gate 		return;
8000Sstevel@tonic-gate 	}
8010Sstevel@tonic-gate 	cy = 0;
8020Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
8030Sstevel@tonic-gate 		ai = aa->value[i];
8040Sstevel@tonic-gate 		result->value[i] = (ai << offs) | cy;
8050Sstevel@tonic-gate 		cy = ai >> (32 - offs);
8060Sstevel@tonic-gate 	}
8070Sstevel@tonic-gate 	if (cy != 0) {
8080Sstevel@tonic-gate 		result->len = aa->len + 1;
8090Sstevel@tonic-gate 		result->value[result->len - 1] = cy;
8100Sstevel@tonic-gate 	} else {
8110Sstevel@tonic-gate 		result->len = aa->len;
8120Sstevel@tonic-gate 	}
8130Sstevel@tonic-gate 	result->sign = aa->sign;
8140Sstevel@tonic-gate }
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate /* it is assumed that result->size is big enough */
8170Sstevel@tonic-gate void
8180Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs)
8190Sstevel@tonic-gate {
8200Sstevel@tonic-gate 	int i;
8210Sstevel@tonic-gate 	uint32_t cy, ai;
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	if (offs == 0) {
8240Sstevel@tonic-gate 		if (result != aa) {
8250Sstevel@tonic-gate 			(void) big_copy(result, aa);
8260Sstevel@tonic-gate 		}
8270Sstevel@tonic-gate 		return;
8280Sstevel@tonic-gate 	}
8290Sstevel@tonic-gate 	cy = aa->value[0] >> offs;
8300Sstevel@tonic-gate 	for (i = 1; i < aa->len; i++) {
8310Sstevel@tonic-gate 		ai = aa->value[i];
8320Sstevel@tonic-gate 		result->value[i-1] = (ai << (32 - offs)) | cy;
8330Sstevel@tonic-gate 		cy = ai >> offs;
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 	result->len = aa->len;
8360Sstevel@tonic-gate 	result->value[result->len - 1] = cy;
8370Sstevel@tonic-gate 	result->sign = aa->sign;
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate /*
8420Sstevel@tonic-gate  * result = aa/bb   remainder = aa mod bb
8430Sstevel@tonic-gate  * it is assumed that aa and bb are positive
8440Sstevel@tonic-gate  */
8450Sstevel@tonic-gate BIG_ERR_CODE
8460Sstevel@tonic-gate big_div_pos_fast(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb)
8470Sstevel@tonic-gate {
8480Sstevel@tonic-gate 	BIG_ERR_CODE err;
8490Sstevel@tonic-gate 	int i, alen, blen, tlen, rlen, offs;
8500Sstevel@tonic-gate 	uint32_t higha, highb, coeff;
8510Sstevel@tonic-gate 	uint64_t highb64;
8520Sstevel@tonic-gate 	uint32_t *a, *b;
8530Sstevel@tonic-gate 	BIGNUM bbhigh, bblow, tresult, tmp1, tmp2;
8540Sstevel@tonic-gate 	uint32_t tmp1value[BIGTMPSIZE];
8550Sstevel@tonic-gate 	uint32_t tmp2value[BIGTMPSIZE];
8560Sstevel@tonic-gate 	uint32_t tresultvalue[BIGTMPSIZE];
8570Sstevel@tonic-gate 	uint32_t bblowvalue[BIGTMPSIZE];
8580Sstevel@tonic-gate 	uint32_t bbhighvalue[BIGTMPSIZE];
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	a = aa->value;
8610Sstevel@tonic-gate 	b = bb->value;
8620Sstevel@tonic-gate 	alen = aa->len;
8630Sstevel@tonic-gate 	blen = bb->len;
8640Sstevel@tonic-gate 	while ((alen > 1) && (a[alen - 1] == 0)) alen = alen - 1;
8650Sstevel@tonic-gate 	aa->len = alen;
8660Sstevel@tonic-gate 	while ((blen > 1) && (b[blen - 1] == 0)) blen = blen - 1;
8670Sstevel@tonic-gate 	bb->len = blen;
8680Sstevel@tonic-gate 	if ((blen == 1) && (b[0] == 0))
8690Sstevel@tonic-gate 		return (BIG_DIV_BY_0);
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	if (big_cmp_abs(aa, bb) < 0) {
8720Sstevel@tonic-gate 		if ((remainder != NULL) &&
8730Sstevel@tonic-gate 		    ((err = big_copy(remainder, aa)) != BIG_OK))
8740Sstevel@tonic-gate 			return (err);
8750Sstevel@tonic-gate 		if (result != NULL) {
8760Sstevel@tonic-gate 			result->len = 1;
8770Sstevel@tonic-gate 			result->sign = 1;
8780Sstevel@tonic-gate 			result->value[0] = 0;
8790Sstevel@tonic-gate 		}
8800Sstevel@tonic-gate 		return (BIG_OK);
8810Sstevel@tonic-gate 	}
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	if ((err = big_init1(&bblow, blen + 1,
8840Sstevel@tonic-gate 	    bblowvalue, arraysize(bblowvalue))) != BIG_OK)
8850Sstevel@tonic-gate 		return (err);
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	if ((err = big_init1(&bbhigh, blen + 1,
8880Sstevel@tonic-gate 	    bbhighvalue, arraysize(bbhighvalue))) != BIG_OK)
8890Sstevel@tonic-gate 		goto ret1;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	if ((err = big_init1(&tmp1, alen + 2,
8920Sstevel@tonic-gate 	    tmp1value, arraysize(tmp1value))) != BIG_OK)
8930Sstevel@tonic-gate 		goto ret2;
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, blen + 2,
8960Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
8970Sstevel@tonic-gate 		goto ret3;
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	if ((err = big_init1(&tresult, alen - blen + 2,
9000Sstevel@tonic-gate 	    tresultvalue, arraysize(tresultvalue))) != BIG_OK)
9010Sstevel@tonic-gate 		goto ret4;
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	offs = 0;
9040Sstevel@tonic-gate 	if (blen > 1) {
9050Sstevel@tonic-gate 		highb64 = (((uint64_t)(b[blen - 1])) << 32) |
9060Sstevel@tonic-gate 		    ((uint64_t)(b[blen - 2]));
9070Sstevel@tonic-gate 	} else {
9080Sstevel@tonic-gate 		highb64 = (((uint64_t)(b[blen - 1])) << 32);
9090Sstevel@tonic-gate 	}
9100Sstevel@tonic-gate 	if (highb64 >= 0x1000000000000ull) {
9110Sstevel@tonic-gate 		highb64 = highb64 >> 16;
9120Sstevel@tonic-gate 		offs = 16;
9130Sstevel@tonic-gate 	}
9140Sstevel@tonic-gate 	while ((highb64 & 0x800000000000ull) == 0) {
9150Sstevel@tonic-gate 		highb64 = highb64 << 1;
9160Sstevel@tonic-gate 		offs++;
9170Sstevel@tonic-gate 	}
9180Sstevel@tonic-gate #ifdef	_LP64
9190Sstevel@tonic-gate 	/* LINTED */
9200Sstevel@tonic-gate 	highb = (highb64 >> 32) & 0xffffffff;
9210Sstevel@tonic-gate #else	/* !_LP64 */
9220Sstevel@tonic-gate 	highb = highb64 >> 32;
9230Sstevel@tonic-gate #endif	/* _LP64 */
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	big_shiftleft(&bblow, bb, offs);
9260Sstevel@tonic-gate 	if (offs <= 15) {
9270Sstevel@tonic-gate 		big_shiftleft(&bbhigh, &bblow, 16);
9280Sstevel@tonic-gate 	} else {
9290Sstevel@tonic-gate 		big_shiftright(&bbhigh, &bblow, 16);
9300Sstevel@tonic-gate 	}
9310Sstevel@tonic-gate 	if (bbhigh.value[bbhigh.len - 1] == 0) {
9320Sstevel@tonic-gate 		bbhigh.len--;
9330Sstevel@tonic-gate 	} else {
9340Sstevel@tonic-gate 		bbhigh.value[bbhigh.len] = 0;
9350Sstevel@tonic-gate 	}
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	big_shiftleft(&tmp1, aa, offs);
9380Sstevel@tonic-gate 	rlen = tmp1.len - bblow.len + 1;
9390Sstevel@tonic-gate 	tresult.len = rlen;
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	tmp1.len++;
9420Sstevel@tonic-gate 	tlen = tmp1.len;
9430Sstevel@tonic-gate 	tmp1.value[tmp1.len - 1] = 0;
9440Sstevel@tonic-gate 	for (i = 0; i < rlen; i++) {
9450Sstevel@tonic-gate 		higha = (tmp1.value[tlen - 1] << 16) +
9460Sstevel@tonic-gate 		    (tmp1.value[tlen - 2] >> 16);
9470Sstevel@tonic-gate 		coeff = higha / (highb + 1);
9480Sstevel@tonic-gate 		big_mul16_high(&tmp2, &bblow, coeff);
9490Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
9500Sstevel@tonic-gate 		bbhigh.len++;
9510Sstevel@tonic-gate 		while (tmp1.value[tlen - 1] > 0) {
9520Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
9530Sstevel@tonic-gate 			coeff++;
9540Sstevel@tonic-gate 		}
9550Sstevel@tonic-gate 		bbhigh.len--;
9560Sstevel@tonic-gate 		tlen--;
9570Sstevel@tonic-gate 		tmp1.len--;
9580Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) {
9590Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
9600Sstevel@tonic-gate 			coeff++;
9610Sstevel@tonic-gate 		}
9620Sstevel@tonic-gate 		tresult.value[rlen - i - 1] = coeff << 16;
9630Sstevel@tonic-gate 		higha = tmp1.value[tlen - 1];
9640Sstevel@tonic-gate 		coeff = higha / (highb + 1);
9650Sstevel@tonic-gate 		big_mul16_low(&tmp2, &bblow, coeff);
9660Sstevel@tonic-gate 		tmp2.len--;
9670Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
9680Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bblow) >= 0) {
9690Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bblow);
9700Sstevel@tonic-gate 			coeff++;
9710Sstevel@tonic-gate 		}
9720Sstevel@tonic-gate 		tresult.value[rlen - i - 1] =
9730Sstevel@tonic-gate 		    tresult.value[rlen - i - 1] + coeff;
9740Sstevel@tonic-gate 	}
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	big_shiftright(&tmp1, &tmp1, offs);
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	err = BIG_OK;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	if ((remainder != NULL) &&
9810Sstevel@tonic-gate 	    ((err = big_copy(remainder, &tmp1)) != BIG_OK))
9820Sstevel@tonic-gate 		goto ret;
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	if (result != NULL)
9850Sstevel@tonic-gate 		err = big_copy(result, &tresult);
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate ret:
9880Sstevel@tonic-gate 	big_finish(&tresult);
9890Sstevel@tonic-gate ret4:
9900Sstevel@tonic-gate 	big_finish(&tmp1);
9910Sstevel@tonic-gate ret3:
9920Sstevel@tonic-gate 	big_finish(&tmp2);
9930Sstevel@tonic-gate ret2:
9940Sstevel@tonic-gate 	big_finish(&bbhigh);
9950Sstevel@tonic-gate ret1:
9960Sstevel@tonic-gate 	big_finish(&bblow);
9970Sstevel@tonic-gate 	return (err);
9980Sstevel@tonic-gate }
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate /*
10010Sstevel@tonic-gate  * If there is no processor-specific integer implementation of
10020Sstevel@tonic-gate  * the lower level multiply functions, then this code is provided
10030Sstevel@tonic-gate  * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and
10040Sstevel@tonic-gate  * big_sqr_vec().
10050Sstevel@tonic-gate  *
10060Sstevel@tonic-gate  * There are two generic implementations.  One that assumes that
10070Sstevel@tonic-gate  * there is hardware and C compiler support for a 32 x 32 --> 64
10080Sstevel@tonic-gate  * bit unsigned multiply, but otherwise is not specific to any
10090Sstevel@tonic-gate  * processor, platform, or ISA.
10100Sstevel@tonic-gate  *
10110Sstevel@tonic-gate  * The other makes very few assumptions about hardware capabilities.
10120Sstevel@tonic-gate  * It does not even assume that there is any implementation of a
10130Sstevel@tonic-gate  * 32 x 32 --> 64 bit multiply that is accessible to C code and
10140Sstevel@tonic-gate  * appropriate to use.  It falls constructs 32 x 32 --> 64 bit
10150Sstevel@tonic-gate  * multiplies from 16 x 16 --> 32 bit multiplies.
10160Sstevel@tonic-gate  *
10170Sstevel@tonic-gate  */
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate #if !defined(PSR_MUL)
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate #ifdef UMUL64
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate #define	UNROLL8
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_PREFETCH(R) \
10260Sstevel@tonic-gate 	p = pf * d; \
10270Sstevel@tonic-gate 	pf = (uint64_t)a[R+1]; \
10280Sstevel@tonic-gate 	t = p + cy; \
10290Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
10300Sstevel@tonic-gate 	cy = t >> 32
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_NOPREFETCH(R) \
10330Sstevel@tonic-gate 	p = pf * d; \
10340Sstevel@tonic-gate 	t = p + cy; \
10350Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
10360Sstevel@tonic-gate 	cy = t >> 32
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_PREFETCH(R) \
10390Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
10400Sstevel@tonic-gate 	p = pf * d; \
10410Sstevel@tonic-gate 	pf = (uint64_t)a[R+1]; \
10420Sstevel@tonic-gate 	t = p + t + cy; \
10430Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
10440Sstevel@tonic-gate 	cy = t >> 32
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_NOPREFETCH(R) \
10470Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
10480Sstevel@tonic-gate 	p = pf * d; \
10490Sstevel@tonic-gate 	t = p + t + cy; \
10500Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
10510Sstevel@tonic-gate 	cy = t >> 32
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate #ifdef UNROLL8
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate #define	UNROLL 8
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate /*
10580Sstevel@tonic-gate  * r = a * b
10590Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
10600Sstevel@tonic-gate  */
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate uint32_t
10630Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
10640Sstevel@tonic-gate {
10650Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	if (len == 0)
10680Sstevel@tonic-gate 		return (0);
10690Sstevel@tonic-gate 	cy = 0;
10700Sstevel@tonic-gate 	d = (uint64_t)b;
10710Sstevel@tonic-gate 	pf = (uint64_t)a[0];
10720Sstevel@tonic-gate 	while (len > UNROLL) {
10730Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
10740Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
10750Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
10760Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
10770Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
10780Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
10790Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
10800Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(7);
10810Sstevel@tonic-gate 		r += UNROLL;
10820Sstevel@tonic-gate 		a += UNROLL;
10830Sstevel@tonic-gate 		len -= UNROLL;
10840Sstevel@tonic-gate 	}
10850Sstevel@tonic-gate 	if (len == UNROLL) {
10860Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
10870Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
10880Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
10890Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
10900Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
10910Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
10920Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
10930Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(7);
10940Sstevel@tonic-gate 		return ((uint32_t)cy);
10950Sstevel@tonic-gate 	}
10960Sstevel@tonic-gate 	while (len > 1) {
10970Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
10980Sstevel@tonic-gate 		++r;
10990Sstevel@tonic-gate 		++a;
11000Sstevel@tonic-gate 		--len;
11010Sstevel@tonic-gate 	}
11020Sstevel@tonic-gate 	if (len > 0) {
11030Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(0);
11040Sstevel@tonic-gate 	}
11050Sstevel@tonic-gate 	return ((uint32_t)cy);
11060Sstevel@tonic-gate }
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate /*
11090Sstevel@tonic-gate  * r += a * b
11100Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
11110Sstevel@tonic-gate  */
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate uint32_t
11140Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
11150Sstevel@tonic-gate {
11160Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 	if (len == 0)
11190Sstevel@tonic-gate 		return (0);
11200Sstevel@tonic-gate 	cy = 0;
11210Sstevel@tonic-gate 	d = (uint64_t)b;
11220Sstevel@tonic-gate 	pf = (uint64_t)a[0];
11230Sstevel@tonic-gate 	while (len > 8) {
11240Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
11250Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
11260Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
11270Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
11280Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
11290Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
11300Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
11310Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(7);
11320Sstevel@tonic-gate 		r += 8;
11330Sstevel@tonic-gate 		a += 8;
11340Sstevel@tonic-gate 		len -= 8;
11350Sstevel@tonic-gate 	}
11360Sstevel@tonic-gate 	if (len == 8) {
11370Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
11380Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
11390Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
11400Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
11410Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
11420Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
11430Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
11440Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(7);
11450Sstevel@tonic-gate 		return ((uint32_t)cy);
11460Sstevel@tonic-gate 	}
11470Sstevel@tonic-gate 	while (len > 1) {
11480Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
11490Sstevel@tonic-gate 		++r;
11500Sstevel@tonic-gate 		++a;
11510Sstevel@tonic-gate 		--len;
11520Sstevel@tonic-gate 	}
11530Sstevel@tonic-gate 	if (len > 0) {
11540Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(0);
11550Sstevel@tonic-gate 	}
11560Sstevel@tonic-gate 	return ((uint32_t)cy);
11570Sstevel@tonic-gate }
11580Sstevel@tonic-gate #endif /* UNROLL8 */
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate void
11610Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
11620Sstevel@tonic-gate {
11630Sstevel@tonic-gate 	uint32_t *tr, *ta;
11640Sstevel@tonic-gate 	int tlen, row, col;
11650Sstevel@tonic-gate 	uint64_t p, s, t, t2, cy;
11660Sstevel@tonic-gate 	uint32_t d;
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	tr = r + 1;
11690Sstevel@tonic-gate 	ta = a;
11700Sstevel@tonic-gate 	tlen = len - 1;
11710Sstevel@tonic-gate 	tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]);
11720Sstevel@tonic-gate 	while (--tlen > 0) {
11730Sstevel@tonic-gate 		tr += 2;
11740Sstevel@tonic-gate 		++ta;
11750Sstevel@tonic-gate 		tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]);
11760Sstevel@tonic-gate 	}
11770Sstevel@tonic-gate 	s = (uint64_t)a[0];
11780Sstevel@tonic-gate 	s = s * s;
11790Sstevel@tonic-gate 	r[0] = (uint32_t)s;
11800Sstevel@tonic-gate 	cy = s >> 32;
11810Sstevel@tonic-gate 	p = ((uint64_t)r[1] << 1) + cy;
11820Sstevel@tonic-gate 	r[1] = (uint32_t)p;
11830Sstevel@tonic-gate 	cy = p >> 32;
11840Sstevel@tonic-gate 	row = 1;
11850Sstevel@tonic-gate 	col = 2;
11860Sstevel@tonic-gate 	while (row < len) {
11870Sstevel@tonic-gate 		s = (uint64_t)a[row];
11880Sstevel@tonic-gate 		s = s * s;
11890Sstevel@tonic-gate 		p = (uint64_t)r[col] << 1;
11900Sstevel@tonic-gate 		t = p + s;
11910Sstevel@tonic-gate 		d = (uint32_t)t;
11920Sstevel@tonic-gate 		t2 = (uint64_t)d + cy;
11930Sstevel@tonic-gate 		r[col] = (uint32_t)t2;
11940Sstevel@tonic-gate 		cy = (t >> 32) + (t2 >> 32);
11950Sstevel@tonic-gate 		if (row == len - 1)
11960Sstevel@tonic-gate 			break;
11970Sstevel@tonic-gate 		p = ((uint64_t)r[col+1] << 1) + cy;
11980Sstevel@tonic-gate 		r[col+1] = (uint32_t)p;
11990Sstevel@tonic-gate 		cy = p >> 32;
12000Sstevel@tonic-gate 		++row;
12010Sstevel@tonic-gate 		col += 2;
12020Sstevel@tonic-gate 	}
12030Sstevel@tonic-gate 	r[col+1] = (uint32_t)cy;
12040Sstevel@tonic-gate }
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate #else /* ! UMUL64 */
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate /*
12090Sstevel@tonic-gate  * r = r + a * digit, r and a are vectors of length len
12100Sstevel@tonic-gate  * returns the carry digit
12110Sstevel@tonic-gate  */
12120Sstevel@tonic-gate uint32_t
12130Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
12140Sstevel@tonic-gate {
12150Sstevel@tonic-gate 	uint32_t cy, cy1, retcy, dlow, dhigh;
12160Sstevel@tonic-gate 	int i;
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	cy1 = 0;
12190Sstevel@tonic-gate 	dlow = digit & 0xffff;
12200Sstevel@tonic-gate 	dhigh = digit >> 16;
12210Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
12220Sstevel@tonic-gate 		cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff);
12230Sstevel@tonic-gate 		cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16);
12240Sstevel@tonic-gate 		r[i] = (cy & 0xffff) | (cy1 << 16);
12250Sstevel@tonic-gate 	}
12260Sstevel@tonic-gate 	retcy = cy1 >> 16;
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 	cy1 = r[0] & 0xffff;
12290Sstevel@tonic-gate 	for (i = 0; i < len - 1; i++) {
12300Sstevel@tonic-gate 		cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16);
12310Sstevel@tonic-gate 		r[i] = (cy1 & 0xffff) | (cy << 16);
12320Sstevel@tonic-gate 		cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff);
12330Sstevel@tonic-gate 	}
12340Sstevel@tonic-gate 	cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16);
12350Sstevel@tonic-gate 	r[len - 1] = (cy1 & 0xffff) | (cy << 16);
12360Sstevel@tonic-gate 	retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy;
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	return (retcy);
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate /*
12420Sstevel@tonic-gate  * r = a * digit, r and a are vectors of length len
12430Sstevel@tonic-gate  * returns the carry digit
12440Sstevel@tonic-gate  */
12450Sstevel@tonic-gate uint32_t
12460Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
12470Sstevel@tonic-gate {
12480Sstevel@tonic-gate 	return (big_mul_add_vec(r, a, len, digit));
12490Sstevel@tonic-gate }
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate void
12520Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
12530Sstevel@tonic-gate {
12540Sstevel@tonic-gate 	int i;
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 	r[len] = big_mul_set_vec(r, a, len, a[0]);
12570Sstevel@tonic-gate 	for (i = 1; i < len; ++i)
12580Sstevel@tonic-gate 		r[len + i] = big_mul_add_vec(r+i, a, len, a[i]);
12590Sstevel@tonic-gate }
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate #endif /* UMUL64 */
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate void
12640Sstevel@tonic-gate big_mul_vec(uint32_t *r, uint32_t *a, int alen, uint32_t *b, int blen)
12650Sstevel@tonic-gate {
12660Sstevel@tonic-gate 	int i;
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	r[alen] = big_mul_set_vec(r, a, alen, b[0]);
12690Sstevel@tonic-gate 	for (i = 1; i < blen; ++i)
12700Sstevel@tonic-gate 		r[alen + i] = big_mul_add_vec(r+i, a, alen, b[i]);
12710Sstevel@tonic-gate }
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate #endif /* ! PSR_MUL */
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate /*
12780Sstevel@tonic-gate  * result = aa * bb  result->value should be big enough to hold the result
12790Sstevel@tonic-gate  *
12800Sstevel@tonic-gate  * Implementation: Standard grammar school algorithm
12810Sstevel@tonic-gate  *
12820Sstevel@tonic-gate  */
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate BIG_ERR_CODE
12850Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
12860Sstevel@tonic-gate {
12870Sstevel@tonic-gate 	BIGNUM tmp1;
12880Sstevel@tonic-gate 	uint32_t tmp1value[BIGTMPSIZE];
12890Sstevel@tonic-gate 	uint32_t *r, *t, *a, *b;
12900Sstevel@tonic-gate 	BIG_ERR_CODE err;
12910Sstevel@tonic-gate 	int i, alen, blen, rsize, sign, diff;
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 	if (aa == bb) {
12940Sstevel@tonic-gate 		diff = 0;
12950Sstevel@tonic-gate 	} else {
12960Sstevel@tonic-gate 		diff = big_cmp_abs(aa, bb);
12970Sstevel@tonic-gate 		if (diff < 0) {
12980Sstevel@tonic-gate 			BIGNUM *tt;
12990Sstevel@tonic-gate 			tt = aa;
13000Sstevel@tonic-gate 			aa = bb;
13010Sstevel@tonic-gate 			bb = tt;
13020Sstevel@tonic-gate 		}
13030Sstevel@tonic-gate 	}
13040Sstevel@tonic-gate 	a = aa->value;
13050Sstevel@tonic-gate 	b = bb->value;
13060Sstevel@tonic-gate 	alen = aa->len;
13070Sstevel@tonic-gate 	blen = bb->len;
13080Sstevel@tonic-gate 	while ((alen > 1) && (a[alen - 1] == 0)) alen--;
13090Sstevel@tonic-gate 	aa->len = alen;
13100Sstevel@tonic-gate 	while ((blen > 1) && (b[blen - 1] == 0)) blen--;
13110Sstevel@tonic-gate 	bb->len = blen;
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 	rsize = alen + blen;
13140Sstevel@tonic-gate 	if (result->size < rsize) {
13150Sstevel@tonic-gate 		err = big_extend(result, rsize);
13160Sstevel@tonic-gate 		if (err != BIG_OK)
13170Sstevel@tonic-gate 			return (err);
13180Sstevel@tonic-gate 		/* aa or bb might be an alias to result */
13190Sstevel@tonic-gate 		a = aa->value;
13200Sstevel@tonic-gate 		b = bb->value;
13210Sstevel@tonic-gate 	}
13220Sstevel@tonic-gate 	r = result->value;
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 	if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) {
13250Sstevel@tonic-gate 		result->len = 1;
13260Sstevel@tonic-gate 		result->sign = 1;
13270Sstevel@tonic-gate 		r[0] = 0;
13280Sstevel@tonic-gate 		return (BIG_OK);
13290Sstevel@tonic-gate 	}
13300Sstevel@tonic-gate 	sign = aa->sign * bb->sign;
13310Sstevel@tonic-gate 	if ((alen == 1) && (a[0] == 1)) {
13320Sstevel@tonic-gate 		for (i = 0; i < blen; i++) r[i] = b[i];
13330Sstevel@tonic-gate 		result->len = blen;
13340Sstevel@tonic-gate 		result->sign = sign;
13350Sstevel@tonic-gate 		return (BIG_OK);
13360Sstevel@tonic-gate 	}
13370Sstevel@tonic-gate 	if ((blen == 1) && (b[0] == 1)) {
13380Sstevel@tonic-gate 		for (i = 0; i < alen; i++) r[i] = a[i];
13390Sstevel@tonic-gate 		result->len = alen;
13400Sstevel@tonic-gate 		result->sign = sign;
13410Sstevel@tonic-gate 		return (BIG_OK);
13420Sstevel@tonic-gate 	}
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 	err = big_init1(&tmp1, rsize, tmp1value, arraysize(tmp1value));
13450Sstevel@tonic-gate 	if (err != BIG_OK)
13460Sstevel@tonic-gate 		return (err);
13470Sstevel@tonic-gate 	t = tmp1.value;
13480Sstevel@tonic-gate 	for (i = 0; i < rsize; i++) t[i] = 0;
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	if (diff == 0 && alen > 2)
13510Sstevel@tonic-gate 		BIG_SQR_VEC(t, a, alen);
13520Sstevel@tonic-gate 	else if (blen > 0)
13530Sstevel@tonic-gate 		BIG_MUL_VEC(t, a, alen, b, blen);
13540Sstevel@tonic-gate 	if (t[rsize - 1] == 0)
13550Sstevel@tonic-gate 		--rsize;
13560Sstevel@tonic-gate 	tmp1.len = rsize;
13570Sstevel@tonic-gate 	if ((err = big_copy(result, &tmp1)) != BIG_OK)
13580Sstevel@tonic-gate 		return (err);
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	result->sign = sign;
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	if (tmp1.malloced) big_finish(&tmp1);
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate 	return (BIG_OK);
13650Sstevel@tonic-gate }
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate /*
13690Sstevel@tonic-gate  * caller must ensure that  a < n,  b < n  and  ret->size >=  2 * n->len + 1
13700Sstevel@tonic-gate  * and that ret is not n
13710Sstevel@tonic-gate  */
13720Sstevel@tonic-gate BIG_ERR_CODE
13730Sstevel@tonic-gate big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, uint32_t n0)
13740Sstevel@tonic-gate {
13750Sstevel@tonic-gate 	int i, j, nlen, needsubtract;
13760Sstevel@tonic-gate 	uint32_t *nn, *rr;
13770Sstevel@tonic-gate 	uint32_t digit, c;
13780Sstevel@tonic-gate 	BIG_ERR_CODE err;
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 	nlen = n->len;
13810Sstevel@tonic-gate 	nn = n->value;
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 	rr = ret->value;
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 	if ((err = big_mul(ret, a, b)) != BIG_OK)
13860Sstevel@tonic-gate 		return (err);
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 	rr = ret->value;
13890Sstevel@tonic-gate 	for (i = ret->len; i < 2 * nlen + 1; i++) rr[i] = 0;
13900Sstevel@tonic-gate 	for (i = 0; i < nlen; i++) {
13910Sstevel@tonic-gate 		digit = rr[i];
13920Sstevel@tonic-gate 		digit = digit * n0;
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate 		c = BIG_MUL_ADD_VEC(rr + i, nn, nlen, digit);
13950Sstevel@tonic-gate 		j = i + nlen;
13960Sstevel@tonic-gate 		rr[j] += c;
13970Sstevel@tonic-gate 		while (rr[j] < c) {
13980Sstevel@tonic-gate 			rr[j + 1] += 1;
13990Sstevel@tonic-gate 			j++;
14000Sstevel@tonic-gate 			c = 1;
14010Sstevel@tonic-gate 		}
14020Sstevel@tonic-gate 	}
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate 	needsubtract = 0;
14050Sstevel@tonic-gate 	if ((rr[2 * nlen]  != 0))
14060Sstevel@tonic-gate 		needsubtract = 1;
14070Sstevel@tonic-gate 	else {
14080Sstevel@tonic-gate 		for (i = 2 * nlen - 1; i >= nlen; i--) {
14090Sstevel@tonic-gate 			if (rr[i] > nn[i - nlen]) {
14100Sstevel@tonic-gate 				needsubtract = 1;
14110Sstevel@tonic-gate 				break;
14120Sstevel@tonic-gate 			} else if (rr[i] < nn[i - nlen]) break;
14130Sstevel@tonic-gate 		}
14140Sstevel@tonic-gate 	}
14150Sstevel@tonic-gate 	if (needsubtract)
14160Sstevel@tonic-gate 		big_sub_vec(rr, rr + nlen, nn, nlen);
14170Sstevel@tonic-gate 	else {
14180Sstevel@tonic-gate 		for (i = 0; i < nlen; i++)
14190Sstevel@tonic-gate 			rr[i] = rr[i + nlen];
14200Sstevel@tonic-gate 	}
14210Sstevel@tonic-gate 	for (i = nlen - 1; (i >= 0) && (rr[i] == 0); i--);
14220Sstevel@tonic-gate 	ret->len = i+1;
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 	return (BIG_OK);
14250Sstevel@tonic-gate }
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate uint32_t
14280Sstevel@tonic-gate big_n0(uint32_t n)
14290Sstevel@tonic-gate {
14300Sstevel@tonic-gate 	int i;
14310Sstevel@tonic-gate 	uint32_t result, tmp;
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	result = 0;
14340Sstevel@tonic-gate 	tmp = 0xffffffff;
14350Sstevel@tonic-gate 	for (i = 0; i < 32; i++) {
14360Sstevel@tonic-gate 		if ((tmp & 1) == 1) {
14370Sstevel@tonic-gate 			result = (result >> 1) | 0x80000000;
14380Sstevel@tonic-gate 			tmp = tmp - n;
14390Sstevel@tonic-gate 		} else  result = (result>>1);
14400Sstevel@tonic-gate 		tmp = tmp >> 1;
14410Sstevel@tonic-gate 	}
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 	return (result);
14440Sstevel@tonic-gate }
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate int
14480Sstevel@tonic-gate big_numbits(BIGNUM *n)
14490Sstevel@tonic-gate {
14500Sstevel@tonic-gate 	int i, j;
14510Sstevel@tonic-gate 	uint32_t t;
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	for (i = n->len - 1; i > 0; i--)
14540Sstevel@tonic-gate 		if (n->value[i] != 0) break;
14550Sstevel@tonic-gate 	t = n->value[i];
14560Sstevel@tonic-gate 	for (j = 32; j > 0; j--) {
14570Sstevel@tonic-gate 		if ((t & 0x80000000) == 0)
14580Sstevel@tonic-gate 			t = t << 1;
14590Sstevel@tonic-gate 		else
14600Sstevel@tonic-gate 			return (32 * i + j);
14610Sstevel@tonic-gate 	}
14620Sstevel@tonic-gate 	return (0);
14630Sstevel@tonic-gate }
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate /* caller must make sure that a < n */
14660Sstevel@tonic-gate BIG_ERR_CODE
14670Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n)
14680Sstevel@tonic-gate {
14690Sstevel@tonic-gate 	BIGNUM rr;
14700Sstevel@tonic-gate 	uint32_t rrvalue[BIGTMPSIZE];
14710Sstevel@tonic-gate 	int len, i;
14720Sstevel@tonic-gate 	BIG_ERR_CODE err;
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	rr.malloced = 0;
14750Sstevel@tonic-gate 	len = n->len;
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1,
14780Sstevel@tonic-gate 	    rrvalue, arraysize(rrvalue))) != BIG_OK)
14790Sstevel@tonic-gate 		return (err);
14800Sstevel@tonic-gate 
14810Sstevel@tonic-gate 	for (i = 0; i < 2 * len; i++) rr.value[i] = 0;
14820Sstevel@tonic-gate 	rr.value[2 * len] = 1;
14830Sstevel@tonic-gate 	rr.len = 2 * len + 1;
14840Sstevel@tonic-gate 	if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK)
14850Sstevel@tonic-gate 		goto ret;
14860Sstevel@tonic-gate 	err = big_copy(result, &rr);
14870Sstevel@tonic-gate ret:
14880Sstevel@tonic-gate 	if (rr.malloced) big_finish(&rr);
14890Sstevel@tonic-gate 	return (err);
14900Sstevel@tonic-gate }
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate /* caller must make sure that a < n */
14930Sstevel@tonic-gate BIG_ERR_CODE
14940Sstevel@tonic-gate big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, uint32_t n0, BIGNUM *n_rr)
14950Sstevel@tonic-gate {
14960Sstevel@tonic-gate 	BIGNUM rr;
14970Sstevel@tonic-gate 	uint32_t rrvalue[BIGTMPSIZE];
14980Sstevel@tonic-gate 	int len, i;
14990Sstevel@tonic-gate 	BIG_ERR_CODE err;
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	rr.malloced = 0;
15020Sstevel@tonic-gate 	len = n->len;
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue)))
15050Sstevel@tonic-gate 	    != BIG_OK)
15060Sstevel@tonic-gate 			return (err);
15070Sstevel@tonic-gate 
15080Sstevel@tonic-gate 	if (n_rr == NULL) {
15090Sstevel@tonic-gate 		for (i = 0; i < 2 * len; i++) rr.value[i] = 0;
15100Sstevel@tonic-gate 		rr.value[2 * len] = 1;
15110Sstevel@tonic-gate 		rr.len = 2 * len + 1;
15120Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK)
15130Sstevel@tonic-gate 			goto ret;
15140Sstevel@tonic-gate 		n_rr = &rr;
15150Sstevel@tonic-gate 	}
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK)
15180Sstevel@tonic-gate 		goto ret;
15190Sstevel@tonic-gate 	err = big_copy(result, &rr);
15200Sstevel@tonic-gate ret:
15210Sstevel@tonic-gate 	if (rr.malloced) big_finish(&rr);
15220Sstevel@tonic-gate 	return (err);
15230Sstevel@tonic-gate }
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate #define	MAX_EXP_BIT_GROUP_SIZE 6
15270Sstevel@tonic-gate #define	APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1))
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate #ifdef USE_FLOATING_POINT
15300Sstevel@tonic-gate 
15310Sstevel@tonic-gate /*
15320Sstevel@tonic-gate  * This version makes use of floating point for performance.
15330Sstevel@tonic-gate  */
15340Sstevel@tonic-gate static BIG_ERR_CODE
15350Sstevel@tonic-gate _big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
15360Sstevel@tonic-gate {
15370Sstevel@tonic-gate 	BIGNUM ma, tmp, rr;
15380Sstevel@tonic-gate 	uint32_t mavalue[BIGTMPSIZE];
15390Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
15400Sstevel@tonic-gate 	uint32_t rrvalue[BIGTMPSIZE];
15410Sstevel@tonic-gate 	int i, j, k, l, m, p, bit, bitind, bitcount, nlen;
15420Sstevel@tonic-gate 	BIG_ERR_CODE err;
15430Sstevel@tonic-gate 	uint32_t n0;
15440Sstevel@tonic-gate 	double dn0;
15450Sstevel@tonic-gate 	double *dn, *dt, *d16r, *d32r;
15460Sstevel@tonic-gate 	uint32_t *nint, *prod;
15470Sstevel@tonic-gate 	double *apowers[APOWERS_MAX_SIZE];
15480Sstevel@tonic-gate 	int nbits, groupbits, apowerssize;
15490Sstevel@tonic-gate 
15500Sstevel@tonic-gate 	nbits = big_numbits(e);
15510Sstevel@tonic-gate 	if (nbits < 50) {
15520Sstevel@tonic-gate 		groupbits = 1;
15530Sstevel@tonic-gate 		apowerssize = 1;
15540Sstevel@tonic-gate 	} else {
15550Sstevel@tonic-gate 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
15560Sstevel@tonic-gate 		apowerssize = 1 << (groupbits - 1);
15570Sstevel@tonic-gate 	}
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 	if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue)))	!=
15600Sstevel@tonic-gate 	    BIG_OK)
15610Sstevel@tonic-gate 		return (err);
15620Sstevel@tonic-gate 	ma.len = 1;
15630Sstevel@tonic-gate 	ma.value[0] = 0;
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len + 1,
15660Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
15670Sstevel@tonic-gate 		goto ret1;
15680Sstevel@tonic-gate 	tmp.len = 1;
15690Sstevel@tonic-gate 	tmp.value[0] = 0;
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 	rr.malloced = 0;
15720Sstevel@tonic-gate 	if (n_rr == NULL) {
15730Sstevel@tonic-gate 		if ((err = big_init1(&rr, 2 * n->len + 1,
15740Sstevel@tonic-gate 		    rrvalue, arraysize(rrvalue))) != BIG_OK)
15750Sstevel@tonic-gate 			goto ret2;
15760Sstevel@tonic-gate 		if (big_mont_rr(&rr, n) != BIG_OK)
15770Sstevel@tonic-gate 			goto ret2;
15780Sstevel@tonic-gate 		n_rr = &rr;
15790Sstevel@tonic-gate 	}
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate 	n0 = big_n0(n->value[0]);
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 	if (big_cmp_abs(a, n) > 0) {
15840Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK)
15850Sstevel@tonic-gate 			goto ret2;
15860Sstevel@tonic-gate 		err = big_mont_conv(&ma, &ma, n, n0, n_rr);
15870Sstevel@tonic-gate 	} else {
15880Sstevel@tonic-gate 		err = big_mont_conv(&ma, a, n, n0, n_rr);
15890Sstevel@tonic-gate 	}
15900Sstevel@tonic-gate 	if (err != BIG_OK)
15910Sstevel@tonic-gate 		goto ret3;
15920Sstevel@tonic-gate 
15930Sstevel@tonic-gate 	tmp.len = 1;
15940Sstevel@tonic-gate 	tmp.value[0] = 1;
15950Sstevel@tonic-gate 	if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK)
15960Sstevel@tonic-gate 		goto ret3;
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	nlen = n->len;
15990Sstevel@tonic-gate 	dn0 = (double)(n0 & 0xffff);
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	dn = dt = d16r = d32r = NULL;
16020Sstevel@tonic-gate 	nint = prod = NULL;
16030Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
16040Sstevel@tonic-gate 		apowers[i] = NULL;
16050Sstevel@tonic-gate 	}
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 	if ((dn = big_malloc(nlen * sizeof (double))) == NULL) {
16080Sstevel@tonic-gate 		err = BIG_NO_MEM;
16090Sstevel@tonic-gate 		goto ret;
16100Sstevel@tonic-gate 	}
16110Sstevel@tonic-gate 	if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) {
16120Sstevel@tonic-gate 		err = BIG_NO_MEM;
16130Sstevel@tonic-gate 		goto ret;
16140Sstevel@tonic-gate 	}
16150Sstevel@tonic-gate 	if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) {
16160Sstevel@tonic-gate 		err = BIG_NO_MEM;
16170Sstevel@tonic-gate 		goto ret;
16180Sstevel@tonic-gate 	}
16190Sstevel@tonic-gate 	if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) {
16200Sstevel@tonic-gate 		err = BIG_NO_MEM;
16210Sstevel@tonic-gate 		goto ret;
16220Sstevel@tonic-gate 	}
16230Sstevel@tonic-gate 	if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) {
16240Sstevel@tonic-gate 		err = BIG_NO_MEM;
16250Sstevel@tonic-gate 		goto ret;
16260Sstevel@tonic-gate 	}
16270Sstevel@tonic-gate 	if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) {
16280Sstevel@tonic-gate 		err = BIG_NO_MEM;
16290Sstevel@tonic-gate 		goto ret;
16300Sstevel@tonic-gate 	}
16310Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
16320Sstevel@tonic-gate 		if ((apowers[i] = big_malloc((2 * nlen + 1) *
16330Sstevel@tonic-gate 		    sizeof (double))) == NULL) {
16340Sstevel@tonic-gate 			err = BIG_NO_MEM;
16350Sstevel@tonic-gate 			goto ret;
16360Sstevel@tonic-gate 		}
16370Sstevel@tonic-gate 	}
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 	for (i = 0; i < ma.len; i++) nint[i] = ma.value[i];
16400Sstevel@tonic-gate 	for (; i < nlen; i++) nint[i] = 0;
16410Sstevel@tonic-gate 	conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen);
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 	for (i = 0; i < n->len; i++) nint[i] = n->value[i];
16440Sstevel@tonic-gate 	for (; i < nlen; i++) nint[i] = 0;
16450Sstevel@tonic-gate 	conv_i32_to_d32(dn, nint, nlen);
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0);
16480Sstevel@tonic-gate 	conv_i32_to_d32(d32r, prod, nlen);
16490Sstevel@tonic-gate 	for (i = 1; i < apowerssize; i++) {
16500Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[i - 1],
16510Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
16520Sstevel@tonic-gate 		conv_i32_to_d16(apowers[i], prod, nlen);
16530Sstevel@tonic-gate 	}
16540Sstevel@tonic-gate 
16550Sstevel@tonic-gate 	for (i = 0; i < tmp.len; i++) prod[i] = tmp.value[i];
16560Sstevel@tonic-gate 	for (; i < nlen + 1; i++) prod[i] = 0;
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate 	bitind = nbits % 32;
16590Sstevel@tonic-gate 	k = 0;
16600Sstevel@tonic-gate 	l = 0;
16610Sstevel@tonic-gate 	p = 0;
16620Sstevel@tonic-gate 	bitcount = 0;
16630Sstevel@tonic-gate 	for (i = nbits / 32; i >= 0; i--) {
16640Sstevel@tonic-gate 		for (j = bitind - 1; j >= 0; j--) {
16650Sstevel@tonic-gate 			bit = (e->value[i] >> j) & 1;
16660Sstevel@tonic-gate 			if ((bitcount == 0) && (bit == 0)) {
16670Sstevel@tonic-gate 				conv_i32_to_d32_and_d16(d32r, d16r,
16680Sstevel@tonic-gate 				    prod, nlen);
16690Sstevel@tonic-gate 				mont_mulf_noconv(prod, d32r, d16r,
16700Sstevel@tonic-gate 				    dt, dn, nint, nlen, dn0);
16710Sstevel@tonic-gate 			} else {
16720Sstevel@tonic-gate 				bitcount++;
16730Sstevel@tonic-gate 				p = p * 2 + bit;
16740Sstevel@tonic-gate 				if (bit == 1) {
16750Sstevel@tonic-gate 					k = k + l + 1;
16760Sstevel@tonic-gate 					l = 0;
16770Sstevel@tonic-gate 				} else {
16780Sstevel@tonic-gate 					l++;
16790Sstevel@tonic-gate 				}
16800Sstevel@tonic-gate 				if (bitcount == groupbits) {
16810Sstevel@tonic-gate 					for (m = 0; m < k; m++) {
16820Sstevel@tonic-gate 						conv_i32_to_d32_and_d16(
16830Sstevel@tonic-gate 							d32r, d16r,
16840Sstevel@tonic-gate 							prod, nlen);
16850Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
16860Sstevel@tonic-gate 						    d16r, dt, dn, nint,
16870Sstevel@tonic-gate 						    nlen, dn0);
16880Sstevel@tonic-gate 					}
16890Sstevel@tonic-gate 					conv_i32_to_d32(d32r, prod, nlen);
16900Sstevel@tonic-gate 					mont_mulf_noconv(prod, d32r,
16910Sstevel@tonic-gate 					    apowers[p >> (l+1)],
16920Sstevel@tonic-gate 					    dt, dn, nint, nlen, dn0);
16930Sstevel@tonic-gate 					for (m = 0; m < l; m++) {
16940Sstevel@tonic-gate 						conv_i32_to_d32_and_d16(
16950Sstevel@tonic-gate 							d32r, d16r,
16960Sstevel@tonic-gate 							prod, nlen);
16970Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
16980Sstevel@tonic-gate 						    d16r, dt, dn, nint,
16990Sstevel@tonic-gate 						    nlen, dn0);
17000Sstevel@tonic-gate 					}
17010Sstevel@tonic-gate 					k = 0;
17020Sstevel@tonic-gate 					l = 0;
17030Sstevel@tonic-gate 					p = 0;
17040Sstevel@tonic-gate 					bitcount = 0;
17050Sstevel@tonic-gate 				}
17060Sstevel@tonic-gate 			}
17070Sstevel@tonic-gate 		}
17080Sstevel@tonic-gate 		bitind = 32;
17090Sstevel@tonic-gate 	}
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate 	for (m = 0; m < k; m++) {
17120Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
17130Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
17140Sstevel@tonic-gate 	}
17150Sstevel@tonic-gate 	if (p != 0) {
17160Sstevel@tonic-gate 		conv_i32_to_d32(d32r, prod, nlen);
17170Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)],
17180Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
17190Sstevel@tonic-gate 	}
17200Sstevel@tonic-gate 	for (m = 0; m < l; m++) {
17210Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
17220Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
17230Sstevel@tonic-gate 	}
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 	ma.value[0] = 1;
17260Sstevel@tonic-gate 	ma.len = 1;
17270Sstevel@tonic-gate 	for (i = 0; i < nlen; i++) tmp.value[i] = prod[i];
17280Sstevel@tonic-gate 	for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--);
17290Sstevel@tonic-gate 	tmp.len = i + 1;
17300Sstevel@tonic-gate 	if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK)
17310Sstevel@tonic-gate 		goto ret;
17320Sstevel@tonic-gate 	err = big_copy(result, &tmp);
17330Sstevel@tonic-gate ret:
17340Sstevel@tonic-gate 	for (i = apowerssize - 1; i >= 0; i--) {
17350Sstevel@tonic-gate 		if (apowers[i] != NULL)
17360Sstevel@tonic-gate 			big_free(apowers[i], (2 * nlen + 1) * sizeof (double));
17370Sstevel@tonic-gate 	}
17380Sstevel@tonic-gate 	if (d32r != NULL)
17390Sstevel@tonic-gate 		big_free(d32r, nlen * sizeof (double));
17400Sstevel@tonic-gate 	if (d16r != NULL)
17410Sstevel@tonic-gate 		big_free(d16r, (2 * nlen + 1) * sizeof (double));
17420Sstevel@tonic-gate 	if (prod != NULL)
17430Sstevel@tonic-gate 		big_free(prod, (nlen + 1) * sizeof (uint32_t));
17440Sstevel@tonic-gate 	if (nint != NULL)
17450Sstevel@tonic-gate 		big_free(nint, nlen * sizeof (uint32_t));
17460Sstevel@tonic-gate 	if (dt != NULL)
17470Sstevel@tonic-gate 		big_free(dt, (4 * nlen + 2) * sizeof (double));
17480Sstevel@tonic-gate 	if (dn != NULL)
17490Sstevel@tonic-gate 		big_free(dn, nlen * sizeof (double));
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate ret3:
17520Sstevel@tonic-gate 	big_finish(&rr);
17530Sstevel@tonic-gate ret2:
17540Sstevel@tonic-gate 	big_finish(&tmp);
17550Sstevel@tonic-gate ret1:
17560Sstevel@tonic-gate 	big_finish(&ma);
17570Sstevel@tonic-gate 	return (err);
17580Sstevel@tonic-gate 
17590Sstevel@tonic-gate }
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate #ifdef _KERNEL
17620Sstevel@tonic-gate 
17630Sstevel@tonic-gate #include <sys/sysmacros.h>
17640Sstevel@tonic-gate #include <sys/regset.h>
17650Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate /* the alignment for block stores to save fp registers */
17680Sstevel@tonic-gate #define	FPR_ALIGN	(64)
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate extern void big_savefp(kfpu_t *);
17710Sstevel@tonic-gate extern void big_restorefp(kfpu_t *);
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate #endif /* _KERNEL */
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate BIG_ERR_CODE
17760Sstevel@tonic-gate big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
17770Sstevel@tonic-gate {
17780Sstevel@tonic-gate #ifdef _KERNEL
17790Sstevel@tonic-gate 	BIG_ERR_CODE rv;
17800Sstevel@tonic-gate 	uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN];
17810Sstevel@tonic-gate 	kfpu_t *fpu;
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate #ifdef DEBUG
17840Sstevel@tonic-gate 	if (!fpu_exists)
17850Sstevel@tonic-gate 		return (BIG_GENERAL_ERR);
17860Sstevel@tonic-gate #endif
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 	fpu =  (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN);
17890Sstevel@tonic-gate 	big_savefp(fpu);
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	rv = _big_modexp(result, a, e, n, n_rr);
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 	big_restorefp(fpu);
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 	return (rv);
17960Sstevel@tonic-gate #else
17970Sstevel@tonic-gate 	return (_big_modexp(result, a, e, n, n_rr));
17980Sstevel@tonic-gate #endif	/* _KERNEL */
17990Sstevel@tonic-gate }
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate #else /* ! USE_FLOATING_POINT */
18020Sstevel@tonic-gate 
18030Sstevel@tonic-gate /*
18040Sstevel@tonic-gate  * This version uses strictly integer math and is safe in the kernel
18050Sstevel@tonic-gate  * for all platforms.
18060Sstevel@tonic-gate  */
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate /*
18090Sstevel@tonic-gate  * computes a^e mod n
18100Sstevel@tonic-gate  * assumes a < n, n odd, result->value at least as long as n->value
18110Sstevel@tonic-gate  */
18120Sstevel@tonic-gate BIG_ERR_CODE
18130Sstevel@tonic-gate big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
18140Sstevel@tonic-gate {
18150Sstevel@tonic-gate 	BIGNUM ma, tmp, rr;
18160Sstevel@tonic-gate 	uint32_t mavalue[BIGTMPSIZE];
18170Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
18180Sstevel@tonic-gate 	uint32_t rrvalue[BIGTMPSIZE];
18190Sstevel@tonic-gate 	BIGNUM apowers[APOWERS_MAX_SIZE];
18200Sstevel@tonic-gate 	int i, j, k, l, m, p,
18210Sstevel@tonic-gate 	    bit, bitind, bitcount, groupbits, apowerssize;
18220Sstevel@tonic-gate 	BIG_ERR_CODE err;
18230Sstevel@tonic-gate 	uint32_t n0;
18240Sstevel@tonic-gate 
18250Sstevel@tonic-gate 	int nbits;
18260Sstevel@tonic-gate 
18270Sstevel@tonic-gate 	nbits = big_numbits(e);
18280Sstevel@tonic-gate 	if (nbits < 50) {
18290Sstevel@tonic-gate 		groupbits = 1;
18300Sstevel@tonic-gate 		apowerssize = 1;
18310Sstevel@tonic-gate 	} else {
18320Sstevel@tonic-gate 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
18330Sstevel@tonic-gate 		apowerssize = 1 << (groupbits - 1);
18340Sstevel@tonic-gate 	}
18350Sstevel@tonic-gate 
18360Sstevel@tonic-gate 	if ((err = big_init1(&ma, n->len,
18370Sstevel@tonic-gate 	    mavalue, arraysize(mavalue))) != BIG_OK)
18380Sstevel@tonic-gate 		return (err);
18390Sstevel@tonic-gate 	ma.len = 1;
18400Sstevel@tonic-gate 	ma.value[0] = 0;
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len + 1,
18430Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
18440Sstevel@tonic-gate 		goto ret1;
18450Sstevel@tonic-gate 	tmp.len = 1;
18460Sstevel@tonic-gate 	tmp.value[0] = 1;
18470Sstevel@tonic-gate 
18480Sstevel@tonic-gate 	n0 = big_n0(n->value[0]);
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate 	rr.malloced = 0;
18510Sstevel@tonic-gate 	if (n_rr == NULL) {
18520Sstevel@tonic-gate 		if ((err = big_init1(&rr, 2 * n->len + 1,
18530Sstevel@tonic-gate 		    rrvalue, arraysize(rrvalue))) != BIG_OK)
18540Sstevel@tonic-gate 			goto ret2;
18550Sstevel@tonic-gate 
18560Sstevel@tonic-gate 		if (big_mont_rr(&rr, n) != BIG_OK)
18570Sstevel@tonic-gate 			goto ret3;
18580Sstevel@tonic-gate 		n_rr = &rr;
18590Sstevel@tonic-gate 	}
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) apowers[i].malloced = 0;
18620Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
18630Sstevel@tonic-gate 		if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) !=
18640Sstevel@tonic-gate 		    BIG_OK)
18650Sstevel@tonic-gate 			goto ret;
18660Sstevel@tonic-gate 	}
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate 	if (big_cmp_abs(a, n) > 0) {
18690Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK)
18700Sstevel@tonic-gate 			goto ret;
18710Sstevel@tonic-gate 		err = big_mont_conv(&ma, &ma, n, n0, n_rr);
18720Sstevel@tonic-gate 	} else {
18730Sstevel@tonic-gate 		err = big_mont_conv(&ma, a, n, n0, n_rr);
18740Sstevel@tonic-gate 	}
18750Sstevel@tonic-gate 	if (err != BIG_OK) goto ret;
18760Sstevel@tonic-gate 
18770Sstevel@tonic-gate 	(void) big_copy(&(apowers[0]), &ma);
18780Sstevel@tonic-gate 	if ((err = big_mont_mul(&tmp, &ma, &ma, n, n0)) != BIG_OK)
18790Sstevel@tonic-gate 		goto ret;
18800Sstevel@tonic-gate 	(void) big_copy(&ma, &tmp);
18810Sstevel@tonic-gate 
18820Sstevel@tonic-gate 	for (i = 1; i < apowerssize; i++) {
18830Sstevel@tonic-gate 		if ((err = big_mont_mul(&tmp, &ma,
18840Sstevel@tonic-gate 		    &(apowers[i-1]), n, n0)) != BIG_OK)
18850Sstevel@tonic-gate 			goto ret;
18860Sstevel@tonic-gate 		(void) big_copy(&apowers[i], &tmp);
18870Sstevel@tonic-gate 	}
18880Sstevel@tonic-gate 
18890Sstevel@tonic-gate 	tmp.len = 1;
18900Sstevel@tonic-gate 	tmp.value[0] = 1;
18910Sstevel@tonic-gate 	if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK)
18920Sstevel@tonic-gate 		goto ret;
18930Sstevel@tonic-gate 
18940Sstevel@tonic-gate 	bitind = nbits % 32;
18950Sstevel@tonic-gate 	k = 0;
18960Sstevel@tonic-gate 	l = 0;
18970Sstevel@tonic-gate 	p = 0;
18980Sstevel@tonic-gate 	bitcount = 0;
18990Sstevel@tonic-gate 	for (i = nbits / 32; i >= 0; i--) {
19000Sstevel@tonic-gate 		for (j = bitind - 1; j >= 0; j--) {
19010Sstevel@tonic-gate 			bit = (e->value[i] >> j) & 1;
19020Sstevel@tonic-gate 			if ((bitcount == 0) && (bit == 0)) {
19030Sstevel@tonic-gate 				if ((err = big_mont_mul(&tmp,
19040Sstevel@tonic-gate 				    &tmp, &tmp, n, n0)) != BIG_OK)
19050Sstevel@tonic-gate 					goto ret;
19060Sstevel@tonic-gate 			} else {
19070Sstevel@tonic-gate 				bitcount++;
19080Sstevel@tonic-gate 				p = p * 2 + bit;
19090Sstevel@tonic-gate 				if (bit == 1) {
19100Sstevel@tonic-gate 					k = k + l + 1;
19110Sstevel@tonic-gate 					l = 0;
19120Sstevel@tonic-gate 				} else {
19130Sstevel@tonic-gate 					l++;
19140Sstevel@tonic-gate 				}
19150Sstevel@tonic-gate 				if (bitcount == groupbits) {
19160Sstevel@tonic-gate 					for (m = 0; m < k; m++) {
19170Sstevel@tonic-gate 						if ((err = big_mont_mul(&tmp,
19180Sstevel@tonic-gate 						    &tmp, &tmp, n, n0)) !=
19190Sstevel@tonic-gate 						    BIG_OK)
19200Sstevel@tonic-gate 							goto ret;
19210Sstevel@tonic-gate 					}
19220Sstevel@tonic-gate 					if ((err = big_mont_mul(&tmp, &tmp,
19230Sstevel@tonic-gate 					    &(apowers[p >> (l + 1)]),
19240Sstevel@tonic-gate 					    n, n0)) != BIG_OK)
19250Sstevel@tonic-gate 						goto ret;
19260Sstevel@tonic-gate 					for (m = 0; m < l; m++) {
19270Sstevel@tonic-gate 						if ((err = big_mont_mul(&tmp,
19280Sstevel@tonic-gate 						    &tmp, &tmp, n, n0)) !=
19290Sstevel@tonic-gate 						    BIG_OK)
19300Sstevel@tonic-gate 							goto ret;
19310Sstevel@tonic-gate 					}
19320Sstevel@tonic-gate 					k = 0;
19330Sstevel@tonic-gate 					l = 0;
19340Sstevel@tonic-gate 					p = 0;
19350Sstevel@tonic-gate 					bitcount = 0;
19360Sstevel@tonic-gate 				}
19370Sstevel@tonic-gate 			}
19380Sstevel@tonic-gate 		}
19390Sstevel@tonic-gate 		bitind = 32;
19400Sstevel@tonic-gate 	}
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 	for (m = 0; m < k; m++) {
19430Sstevel@tonic-gate 		if ((err = big_mont_mul(&tmp, &tmp, &tmp, n, n0)) != BIG_OK)
19440Sstevel@tonic-gate 			goto ret;
19450Sstevel@tonic-gate 	}
19460Sstevel@tonic-gate 	if (p != 0) {
19470Sstevel@tonic-gate 		if ((err = big_mont_mul(&tmp, &tmp,
19480Sstevel@tonic-gate 		    &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK)
19490Sstevel@tonic-gate 			goto ret;
19500Sstevel@tonic-gate 	}
19510Sstevel@tonic-gate 	for (m = 0; m < l; m++) {
19520Sstevel@tonic-gate 		if ((err = big_mont_mul(&tmp, &tmp, &tmp, n, n0)) != BIG_OK)
19530Sstevel@tonic-gate 			goto ret;
19540Sstevel@tonic-gate 	}
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	ma.value[0] = 1;
19570Sstevel@tonic-gate 	ma.len = 1;
19580Sstevel@tonic-gate 	if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK)
19590Sstevel@tonic-gate 		goto ret;
19600Sstevel@tonic-gate 	err = big_copy(result, &tmp);
19610Sstevel@tonic-gate ret:
19620Sstevel@tonic-gate 	for (i = apowerssize - 1; i >= 0; i--) {
19630Sstevel@tonic-gate 		big_finish(&(apowers[i]));
19640Sstevel@tonic-gate 	}
19650Sstevel@tonic-gate ret3:
19660Sstevel@tonic-gate 	if (rr.malloced) big_finish(&rr);
19670Sstevel@tonic-gate ret2:
19680Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
19690Sstevel@tonic-gate ret1:
19700Sstevel@tonic-gate 	if (ma.malloced) big_finish(&ma);
19710Sstevel@tonic-gate 	return (err);
19720Sstevel@tonic-gate }
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate BIG_ERR_CODE
19780Sstevel@tonic-gate big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
19790Sstevel@tonic-gate     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
19800Sstevel@tonic-gate     BIGNUM *p_rr, BIGNUM *q_rr)
19810Sstevel@tonic-gate {
19820Sstevel@tonic-gate 	BIGNUM ap, aq, tmp;
19830Sstevel@tonic-gate 	int alen, biglen, sign;
19840Sstevel@tonic-gate 	BIG_ERR_CODE err;
19850Sstevel@tonic-gate 
19860Sstevel@tonic-gate 	if (p->len > q->len) biglen = p->len;
19870Sstevel@tonic-gate 	else biglen = q->len;
19880Sstevel@tonic-gate 
19890Sstevel@tonic-gate 	if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK)
19900Sstevel@tonic-gate 		return (err);
19910Sstevel@tonic-gate 	if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK)
19920Sstevel@tonic-gate 		goto ret1;
19930Sstevel@tonic-gate 	if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK)
19940Sstevel@tonic-gate 		goto ret2;
19950Sstevel@tonic-gate 
19960Sstevel@tonic-gate 	/*
19970Sstevel@tonic-gate 	 * check whether a is too short - to avoid timing attacks
19980Sstevel@tonic-gate 	 */
19990Sstevel@tonic-gate 	alen = a->len;
20000Sstevel@tonic-gate 	while ((alen > p->len) && (a->value[alen - 1] == 0)) {
20010Sstevel@tonic-gate 		alen--;
20020Sstevel@tonic-gate 	}
20030Sstevel@tonic-gate 	if (alen < p->len + q->len) {
20040Sstevel@tonic-gate 		/*
20050Sstevel@tonic-gate 		 * a is too short, add p*q to it before
20060Sstevel@tonic-gate 		 * taking it modulo p and q
20070Sstevel@tonic-gate 		 * this will also affect timing, but this difference
20080Sstevel@tonic-gate 		 * does not depend on p or q, only on a
20090Sstevel@tonic-gate 		 * (in "normal" operation, this path will never be
20100Sstevel@tonic-gate 		 * taken, so it is not a performance penalty
20110Sstevel@tonic-gate 		 */
20120Sstevel@tonic-gate 		if ((err = big_mul(&tmp, p, q)) != BIG_OK)
20130Sstevel@tonic-gate 			goto ret;
20140Sstevel@tonic-gate 		if ((err = big_add(&tmp, &tmp, a)) != BIG_OK)
20150Sstevel@tonic-gate 			goto ret;
20160Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK)
20170Sstevel@tonic-gate 			goto ret;
20180Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK)
20190Sstevel@tonic-gate 			goto ret;
20200Sstevel@tonic-gate 	} else {
20210Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK)
20220Sstevel@tonic-gate 			goto ret;
20230Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK)
20240Sstevel@tonic-gate 			goto ret;
20250Sstevel@tonic-gate 	}
20260Sstevel@tonic-gate 
20270Sstevel@tonic-gate 	if ((err = big_modexp(&ap, &ap, dmodpminus1, p, p_rr)) != BIG_OK)
20280Sstevel@tonic-gate 		goto ret;
20290Sstevel@tonic-gate 	if ((err = big_modexp(&aq, &aq, dmodqminus1, q, q_rr)) != BIG_OK)
20300Sstevel@tonic-gate 		goto ret;
20310Sstevel@tonic-gate 	if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK)
20320Sstevel@tonic-gate 		goto ret;
20330Sstevel@tonic-gate 	if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK)
20340Sstevel@tonic-gate 		goto ret;
20350Sstevel@tonic-gate 	sign = tmp.sign;
20360Sstevel@tonic-gate 	tmp.sign = 1;
20370Sstevel@tonic-gate 	if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK)
20380Sstevel@tonic-gate 		goto ret;
20390Sstevel@tonic-gate 	if ((sign == -1) && (!big_is_zero(&aq))) {
20400Sstevel@tonic-gate 		(void) big_sub_pos(&aq, q, &aq);
20410Sstevel@tonic-gate 	}
20420Sstevel@tonic-gate 	if ((err = big_mul(&tmp, &aq, p)) != BIG_OK)
20430Sstevel@tonic-gate 		goto ret;
20440Sstevel@tonic-gate 	err = big_add_abs(result, &ap, &tmp);
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate ret:
20470Sstevel@tonic-gate 	big_finish(&tmp);
20480Sstevel@tonic-gate ret2:
20490Sstevel@tonic-gate 	big_finish(&aq);
20500Sstevel@tonic-gate ret1:
20510Sstevel@tonic-gate 	big_finish(&ap);
20520Sstevel@tonic-gate 
20530Sstevel@tonic-gate 	return (err);
20540Sstevel@tonic-gate }
20550Sstevel@tonic-gate 
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate uint32_t onearr[1] = {1};
20580Sstevel@tonic-gate BIGNUM One = {1, 1, 1, 0, onearr};
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate uint32_t twoarr[1] = {2};
20610Sstevel@tonic-gate BIGNUM Two = {1, 1, 1, 0, twoarr};
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate uint32_t fourarr[1] = {4};
20640Sstevel@tonic-gate BIGNUM Four = {1, 1, 1, 0, fourarr};
20650Sstevel@tonic-gate 
20660Sstevel@tonic-gate BIG_ERR_CODE
20670Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n)
20680Sstevel@tonic-gate {
20690Sstevel@tonic-gate 	BIGNUM *high, *low, *mid, *t;
20700Sstevel@tonic-gate 	BIGNUM t1, t2, t3, prod;
20710Sstevel@tonic-gate 	uint32_t t1value[BIGTMPSIZE];
20720Sstevel@tonic-gate 	uint32_t t2value[BIGTMPSIZE];
20730Sstevel@tonic-gate 	uint32_t t3value[BIGTMPSIZE];
20740Sstevel@tonic-gate 	uint32_t prodvalue[BIGTMPSIZE];
20750Sstevel@tonic-gate 	int i, nbits, diff, nrootbits, highbits;
20760Sstevel@tonic-gate 	BIG_ERR_CODE err;
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 	nbits = big_numbits(n);
20790Sstevel@tonic-gate 
20800Sstevel@tonic-gate 	if ((err = big_init1(&t1, n->len + 1,
20810Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
20820Sstevel@tonic-gate 		return (err);
20830Sstevel@tonic-gate 	if ((err = big_init1(&t2, n->len + 1,
20840Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
20850Sstevel@tonic-gate 		goto ret1;
20860Sstevel@tonic-gate 	if ((err = big_init1(&t3, n->len + 1,
20870Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
20880Sstevel@tonic-gate 		goto ret2;
20890Sstevel@tonic-gate 	if ((err = big_init1(&prod, n->len + 1,
20900Sstevel@tonic-gate 	    prodvalue, arraysize(prodvalue))) != BIG_OK)
20910Sstevel@tonic-gate 		goto ret3;
20920Sstevel@tonic-gate 
20930Sstevel@tonic-gate 	nrootbits = (nbits + 1) / 2;
20940Sstevel@tonic-gate 	t1.len = t2.len = t3.len = (nrootbits - 1) / 32 + 1;
20950Sstevel@tonic-gate 	for (i = 0; i < t1.len; i++) {
20960Sstevel@tonic-gate 		t1.value[i] = 0;
20970Sstevel@tonic-gate 		t2.value[i] = 0xffffffff;
20980Sstevel@tonic-gate 	}
20990Sstevel@tonic-gate 	highbits = nrootbits - 32 * (t1.len - 1);
21000Sstevel@tonic-gate 	if (highbits == 32) {
21010Sstevel@tonic-gate 		t1.value[t1.len - 1] = 0x80000000;
21020Sstevel@tonic-gate 		t2.value[t2.len - 1] = 0xffffffff;
21030Sstevel@tonic-gate 	} else {
21040Sstevel@tonic-gate 		t1.value[t1.len - 1] = 1 << (highbits - 1);
21050Sstevel@tonic-gate 		t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1;
21060Sstevel@tonic-gate 	}
21070Sstevel@tonic-gate 	high = &t2;
21080Sstevel@tonic-gate 	low = &t1;
21090Sstevel@tonic-gate 	mid = &t3;
21100Sstevel@tonic-gate 
21110Sstevel@tonic-gate 	if ((err = big_mul(&prod, high, high)) != BIG_OK)
21120Sstevel@tonic-gate 		goto ret;
21130Sstevel@tonic-gate 	diff = big_cmp_abs(&prod, n);
21140Sstevel@tonic-gate 	if (diff <= 0) {
21150Sstevel@tonic-gate 		err = big_copy(result, high);
21160Sstevel@tonic-gate 		goto ret;
21170Sstevel@tonic-gate 	}
21180Sstevel@tonic-gate 
21190Sstevel@tonic-gate 	(void) big_sub_pos(mid, high, low);
21200Sstevel@tonic-gate 	while (big_cmp_abs(&One, mid) != 0) {
21210Sstevel@tonic-gate 		(void) big_add_abs(mid, high, low);
21220Sstevel@tonic-gate 		(void) big_half_pos(mid, mid);
21230Sstevel@tonic-gate 		if ((err = big_mul(&prod, mid, mid)) != BIG_OK)
21240Sstevel@tonic-gate 			goto ret;
21250Sstevel@tonic-gate 		diff = big_cmp_abs(&prod, n);
21260Sstevel@tonic-gate 		if (diff > 0) {
21270Sstevel@tonic-gate 			t = high;
21280Sstevel@tonic-gate 			high = mid;
21290Sstevel@tonic-gate 			mid = t;
21300Sstevel@tonic-gate 		} else if (diff < 0) {
21310Sstevel@tonic-gate 			t = low;
21320Sstevel@tonic-gate 			low = mid;
21330Sstevel@tonic-gate 			mid = t;
21340Sstevel@tonic-gate 		} else {
21350Sstevel@tonic-gate 			err = big_copy(result, low);
21360Sstevel@tonic-gate 			goto ret;
21370Sstevel@tonic-gate 		}
21380Sstevel@tonic-gate 		(void) big_sub_pos(mid, high, low);
21390Sstevel@tonic-gate 	}
21400Sstevel@tonic-gate 
21410Sstevel@tonic-gate 	err = big_copy(result, low);
21420Sstevel@tonic-gate ret:
21430Sstevel@tonic-gate 	if (prod.malloced) big_finish(&prod);
21440Sstevel@tonic-gate ret3:
21450Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
21460Sstevel@tonic-gate ret2:
21470Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
21480Sstevel@tonic-gate ret1:
21490Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
21500Sstevel@tonic-gate 
21510Sstevel@tonic-gate 	return (err);
21520Sstevel@tonic-gate }
21530Sstevel@tonic-gate 
21540Sstevel@tonic-gate 
21550Sstevel@tonic-gate BIG_ERR_CODE
21560Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm)
21570Sstevel@tonic-gate {
21580Sstevel@tonic-gate 	BIGNUM *t, *tmp2, *m, *n;
21590Sstevel@tonic-gate 	BIGNUM t1, t2, t3;
21600Sstevel@tonic-gate 	uint32_t t1value[BIGTMPSIZE];
21610Sstevel@tonic-gate 	uint32_t t2value[BIGTMPSIZE];
21620Sstevel@tonic-gate 	uint32_t t3value[BIGTMPSIZE];
21630Sstevel@tonic-gate 	int len, err;
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 	if (big_is_zero(nn) ||
21660Sstevel@tonic-gate 	    (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) {
21670Sstevel@tonic-gate 		*jac = 0;
21680Sstevel@tonic-gate 		return (BIG_OK);
21690Sstevel@tonic-gate 	}
21700Sstevel@tonic-gate 
21710Sstevel@tonic-gate 	if (nn->len > mm->len) len = nn->len;
21720Sstevel@tonic-gate 	else len = mm->len;
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
21750Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
21760Sstevel@tonic-gate 		return (err);
21770Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
21780Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
21790Sstevel@tonic-gate 		goto ret1;
21800Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
21810Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
21820Sstevel@tonic-gate 		goto ret2;
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate 	n = &t1;
21850Sstevel@tonic-gate 	m = &t2;
21860Sstevel@tonic-gate 	tmp2 = &t3;
21870Sstevel@tonic-gate 
21880Sstevel@tonic-gate 	(void) big_copy(n, nn);
21890Sstevel@tonic-gate 	(void) big_copy(m, mm);
21900Sstevel@tonic-gate 
21910Sstevel@tonic-gate 	*jac = 1;
21920Sstevel@tonic-gate 	while (big_cmp_abs(&One, m) != 0) {
21930Sstevel@tonic-gate 		if (big_is_zero(n)) {
21940Sstevel@tonic-gate 			*jac = 0;
21950Sstevel@tonic-gate 			goto ret;
21960Sstevel@tonic-gate 		}
21970Sstevel@tonic-gate 		if ((m->value[0] & 1) == 0) {
21980Sstevel@tonic-gate 			if (((n->value[0] & 7) == 3) ||
21990Sstevel@tonic-gate 			    ((n->value[0] & 7) == 5)) *jac = -*jac;
22000Sstevel@tonic-gate 			(void) big_half_pos(m, m);
22010Sstevel@tonic-gate 		} else if ((n->value[0] & 1) == 0) {
22020Sstevel@tonic-gate 			if (((m->value[0] & 7) == 3) ||
22030Sstevel@tonic-gate 			    ((m->value[0] & 7) == 5)) *jac = -*jac;
22040Sstevel@tonic-gate 			(void) big_half_pos(n, n);
22050Sstevel@tonic-gate 		} else {
22060Sstevel@tonic-gate 			if (((m->value[0] & 3) == 3) &&
22070Sstevel@tonic-gate 			    ((n->value[0] & 3) == 3)) {
22080Sstevel@tonic-gate 				*jac = -*jac;
22090Sstevel@tonic-gate 			}
22100Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK)
22110Sstevel@tonic-gate 				goto ret;
22120Sstevel@tonic-gate 			t = tmp2;
22130Sstevel@tonic-gate 			tmp2 = m;
22140Sstevel@tonic-gate 			m = n;
22150Sstevel@tonic-gate 			n = t;
22160Sstevel@tonic-gate 		}
22170Sstevel@tonic-gate 	}
22180Sstevel@tonic-gate 	err = BIG_OK;
22190Sstevel@tonic-gate 
22200Sstevel@tonic-gate ret:
22210Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
22220Sstevel@tonic-gate ret2:
22230Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
22240Sstevel@tonic-gate ret1:
22250Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
22260Sstevel@tonic-gate 
22270Sstevel@tonic-gate 	return (err);
22280Sstevel@tonic-gate }
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate 
22310Sstevel@tonic-gate BIG_ERR_CODE
22320Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n)
22330Sstevel@tonic-gate {
22340Sstevel@tonic-gate 	int m, w, i;
22350Sstevel@tonic-gate 	uint32_t bit;
22360Sstevel@tonic-gate 	BIGNUM ki, tmp, tmp2;
22370Sstevel@tonic-gate 	uint32_t kivalue[BIGTMPSIZE];
22380Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
22390Sstevel@tonic-gate 	uint32_t tmp2value[BIGTMPSIZE];
22400Sstevel@tonic-gate 	BIG_ERR_CODE err;
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate 	if (big_cmp_abs(k, &One) == 0) {
22430Sstevel@tonic-gate 		(void) big_copy(Lk, p);
22440Sstevel@tonic-gate 		(void) big_copy(Lkminus1, &Two);
22450Sstevel@tonic-gate 		return (BIG_OK);
22460Sstevel@tonic-gate 	}
22470Sstevel@tonic-gate 
22480Sstevel@tonic-gate 	if ((err = big_init1(&ki, k->len + 1,
22490Sstevel@tonic-gate 	    kivalue, arraysize(kivalue))) != BIG_OK)
22500Sstevel@tonic-gate 		return (err);
22510Sstevel@tonic-gate 
22520Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len +1,
22530Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
22540Sstevel@tonic-gate 		goto ret1;
22550Sstevel@tonic-gate 
22560Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, n->len,
22570Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
22580Sstevel@tonic-gate 		goto ret2;
22590Sstevel@tonic-gate 
22600Sstevel@tonic-gate 	m = big_numbits(k);
22610Sstevel@tonic-gate 	ki.len = (m - 1) / 32 + 1;
22620Sstevel@tonic-gate 	w = (m - 1) / 32;
22630Sstevel@tonic-gate 	bit = 1 << ((m - 1) % 32);
22640Sstevel@tonic-gate 	for (i = 0; i < ki.len; i++) ki.value[i] = 0;
22650Sstevel@tonic-gate 	ki.value[ki.len - 1] = bit;
22660Sstevel@tonic-gate 	if (big_cmp_abs(k, &ki) != 0)
22670Sstevel@tonic-gate 		(void) big_double(&ki, &ki);
22680Sstevel@tonic-gate 	(void) big_sub_pos(&ki, &ki, k);
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate 	(void) big_copy(Lk, p);
22710Sstevel@tonic-gate 	(void) big_copy(Lkminus1, &Two);
22720Sstevel@tonic-gate 
22730Sstevel@tonic-gate 	for (i = 0; i < m; i++) {
22740Sstevel@tonic-gate 		if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK)
22750Sstevel@tonic-gate 			goto ret;
22760Sstevel@tonic-gate 		(void) big_add_abs(&tmp, &tmp, n);
22770Sstevel@tonic-gate 		(void) big_sub_pos(&tmp, &tmp, p);
22780Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK)
22790Sstevel@tonic-gate 			goto ret;
22800Sstevel@tonic-gate 
22810Sstevel@tonic-gate 		if ((ki.value[w] & bit) != 0) {
22820Sstevel@tonic-gate 			if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) !=
22830Sstevel@tonic-gate 			    BIG_OK)
22840Sstevel@tonic-gate 				goto ret;
22850Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
22860Sstevel@tonic-gate 			(void) big_sub_pos(&tmp, &tmp, &Two);
22870Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) !=
22880Sstevel@tonic-gate 			    BIG_OK)
22890Sstevel@tonic-gate 				goto ret;
22900Sstevel@tonic-gate 			(void) big_copy(Lk, &tmp2);
22910Sstevel@tonic-gate 		} else {
22920Sstevel@tonic-gate 			if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK)
22930Sstevel@tonic-gate 				goto ret;
22940Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
22950Sstevel@tonic-gate 			(void) big_sub_pos(&tmp, &tmp, &Two);
22960Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK)
22970Sstevel@tonic-gate 				goto ret;
22980Sstevel@tonic-gate 			(void) big_copy(Lkminus1, &tmp2);
22990Sstevel@tonic-gate 		}
23000Sstevel@tonic-gate 		bit = bit >> 1;
23010Sstevel@tonic-gate 		if (bit == 0) {
23020Sstevel@tonic-gate 			bit = 0x80000000;
23030Sstevel@tonic-gate 			w--;
23040Sstevel@tonic-gate 		}
23050Sstevel@tonic-gate 	}
23060Sstevel@tonic-gate 
23070Sstevel@tonic-gate 	err = BIG_OK;
23080Sstevel@tonic-gate 
23090Sstevel@tonic-gate ret:
23100Sstevel@tonic-gate 	if (tmp2.malloced) big_finish(&tmp2);
23110Sstevel@tonic-gate ret2:
23120Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
23130Sstevel@tonic-gate ret1:
23140Sstevel@tonic-gate 	if (ki.malloced) big_finish(&ki);
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate 	return (err);
23170Sstevel@tonic-gate }
23180Sstevel@tonic-gate 
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate BIG_ERR_CODE
23210Sstevel@tonic-gate big_isprime_pos(BIGNUM *n)
23220Sstevel@tonic-gate {
23230Sstevel@tonic-gate 	BIGNUM o, nminus1, tmp, Lkminus1, Lk;
23240Sstevel@tonic-gate 	uint32_t ovalue[BIGTMPSIZE];
23250Sstevel@tonic-gate 	uint32_t nminus1value[BIGTMPSIZE];
23260Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
23270Sstevel@tonic-gate 	uint32_t Lkminus1value[BIGTMPSIZE];
23280Sstevel@tonic-gate 	uint32_t Lkvalue[BIGTMPSIZE];
23290Sstevel@tonic-gate 	BIG_ERR_CODE err;
23300Sstevel@tonic-gate 	int e, i, jac;
23310Sstevel@tonic-gate 
23320Sstevel@tonic-gate 	if (big_cmp_abs(n, &One) == 0)
23330Sstevel@tonic-gate 		return (BIG_FALSE);
23340Sstevel@tonic-gate 	if (big_cmp_abs(n, &Two) == 0)
23350Sstevel@tonic-gate 		return (BIG_TRUE);
23360Sstevel@tonic-gate 	if ((n->value[0] & 1) == 0)
23370Sstevel@tonic-gate 		return (BIG_FALSE);
23380Sstevel@tonic-gate 
23390Sstevel@tonic-gate 	if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) != BIG_OK)
23400Sstevel@tonic-gate 		return (err);
23410Sstevel@tonic-gate 
23420Sstevel@tonic-gate 	if ((err = big_init1(&nminus1, n->len,
23430Sstevel@tonic-gate 	    nminus1value, arraysize(nminus1value))) != BIG_OK)
23440Sstevel@tonic-gate 		goto ret1;
23450Sstevel@tonic-gate 
23460Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len,
23470Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
23480Sstevel@tonic-gate 		goto ret2;
23490Sstevel@tonic-gate 
23500Sstevel@tonic-gate 	if ((err = big_init1(&Lkminus1, n->len,
23510Sstevel@tonic-gate 	    Lkminus1value, arraysize(Lkminus1value))) != BIG_OK)
23520Sstevel@tonic-gate 		goto ret3;
23530Sstevel@tonic-gate 
23540Sstevel@tonic-gate 	if ((err = big_init1(&Lk, n->len,
23550Sstevel@tonic-gate 	    Lkvalue, arraysize(Lkvalue))) != BIG_OK)
23560Sstevel@tonic-gate 		goto ret4;
23570Sstevel@tonic-gate 
23580Sstevel@tonic-gate 	(void) big_sub_pos(&o, n, &One); 	/* cannot fail */
23590Sstevel@tonic-gate 	(void) big_copy(&nminus1, &o);		/* cannot fail */
23600Sstevel@tonic-gate 	e = 0;
23610Sstevel@tonic-gate 	while ((o.value[0] & 1) == 0) {
23620Sstevel@tonic-gate 		e++;
23630Sstevel@tonic-gate 		(void) big_half_pos(&o, &o);  /* cannot fail */
23640Sstevel@tonic-gate 	}
23650Sstevel@tonic-gate 	if ((err = big_modexp(&tmp, &Two, &o, n, NULL)) != BIG_OK)
23660Sstevel@tonic-gate 		goto ret;
23670Sstevel@tonic-gate 	i = 0;
23680Sstevel@tonic-gate 	while ((i < e) &&
23690Sstevel@tonic-gate 	    (big_cmp_abs(&tmp, &One) != 0) &&
23700Sstevel@tonic-gate 	    (big_cmp_abs(&tmp, &nminus1) != 0)) {
23710Sstevel@tonic-gate 		if ((err = big_modexp(&tmp, &tmp, &Two, n, NULL)) !=  BIG_OK)
23720Sstevel@tonic-gate 			goto ret;
23730Sstevel@tonic-gate 		i++;
23740Sstevel@tonic-gate 	}
23750Sstevel@tonic-gate 	if (!((big_cmp_abs(&tmp, &nminus1) == 0) ||
23760Sstevel@tonic-gate 	    ((i == 0) && (big_cmp_abs(&tmp, &One) == 0)))) {
23770Sstevel@tonic-gate 		err = BIG_FALSE;
23780Sstevel@tonic-gate 		goto ret;
23790Sstevel@tonic-gate 	}
23800Sstevel@tonic-gate 
23810Sstevel@tonic-gate 	if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK)
23820Sstevel@tonic-gate 		goto ret;
23830Sstevel@tonic-gate 	if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK)
23840Sstevel@tonic-gate 		goto ret;
23850Sstevel@tonic-gate 	if (big_cmp_abs(&tmp, n) == 0) {
23860Sstevel@tonic-gate 		err = BIG_FALSE;
23870Sstevel@tonic-gate 		goto ret;
23880Sstevel@tonic-gate 	}
23890Sstevel@tonic-gate 
23900Sstevel@tonic-gate 	(void) big_copy(&o, &Two);
23910Sstevel@tonic-gate 	do {
23920Sstevel@tonic-gate 		(void) big_add_abs(&o, &o, &One);
23930Sstevel@tonic-gate 		if ((err = big_mul(&tmp, &o, &o)) != BIG_OK)
23940Sstevel@tonic-gate 			goto ret;
23950Sstevel@tonic-gate 		(void) big_sub_pos(&tmp, &tmp, &Four);
23960Sstevel@tonic-gate 		if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK)
23970Sstevel@tonic-gate 			goto ret;
23980Sstevel@tonic-gate 	} while (jac != -1);
23990Sstevel@tonic-gate 
24000Sstevel@tonic-gate 	(void) big_add_abs(&tmp, n, &One);
24010Sstevel@tonic-gate 	if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK)
24020Sstevel@tonic-gate 		goto ret;
24030Sstevel@tonic-gate 	if ((big_cmp_abs(&Lkminus1, &o) == 0) && (big_cmp_abs(&Lk, &Two) == 0))
24040Sstevel@tonic-gate 		err = BIG_TRUE;
24050Sstevel@tonic-gate 	else err = BIG_FALSE;
24060Sstevel@tonic-gate 
24070Sstevel@tonic-gate ret:
24080Sstevel@tonic-gate 	if (Lk.malloced) big_finish(&Lk);
24090Sstevel@tonic-gate ret4:
24100Sstevel@tonic-gate 	if (Lkminus1.malloced) big_finish(&Lkminus1);
24110Sstevel@tonic-gate ret3:
24120Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
24130Sstevel@tonic-gate ret2:
24140Sstevel@tonic-gate 	if (nminus1.malloced) big_finish(&nminus1);
24150Sstevel@tonic-gate ret1:
24160Sstevel@tonic-gate 	if (o.malloced) big_finish(&o);
24170Sstevel@tonic-gate 
24180Sstevel@tonic-gate 	return (err);
24190Sstevel@tonic-gate }
24200Sstevel@tonic-gate 
24210Sstevel@tonic-gate 
24220Sstevel@tonic-gate #define	SIEVESIZE 1000
24230Sstevel@tonic-gate 
24240Sstevel@tonic-gate uint32_t smallprimes[] =
24250Sstevel@tonic-gate {
24260Sstevel@tonic-gate 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
24270Sstevel@tonic-gate 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97
24280Sstevel@tonic-gate };
24290Sstevel@tonic-gate 
24300Sstevel@tonic-gate 
24310Sstevel@tonic-gate BIG_ERR_CODE
24320Sstevel@tonic-gate big_nextprime_pos(BIGNUM *result, BIGNUM *n)
24330Sstevel@tonic-gate {
24340Sstevel@tonic-gate 	BIG_ERR_CODE err;
24350Sstevel@tonic-gate 	int sieve[SIEVESIZE];
24360Sstevel@tonic-gate 	int i;
24370Sstevel@tonic-gate 	uint32_t off, p;
24380Sstevel@tonic-gate 
24390Sstevel@tonic-gate 	if ((err = big_copy(result, n)) != BIG_OK)
24400Sstevel@tonic-gate 		return (err);
24410Sstevel@tonic-gate 	result->value[0] |= 1;
2442*1027Srobinson 	/* CONSTCOND */
24430Sstevel@tonic-gate 	while (1) {
24440Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0;
24450Sstevel@tonic-gate 		for (i = 0;
24460Sstevel@tonic-gate 		    i < sizeof (smallprimes) / sizeof (uint32_t); i++) {
24470Sstevel@tonic-gate 			p = smallprimes[i];
24480Sstevel@tonic-gate 			off = big_mod16_pos(result, p);
24490Sstevel@tonic-gate 			off = p - off;
24500Sstevel@tonic-gate 			if ((off % 2) == 1) off = off + p;
24510Sstevel@tonic-gate 			off = off/2;
24520Sstevel@tonic-gate 			while (off < SIEVESIZE) {
24530Sstevel@tonic-gate 				sieve[off] = 1;
24540Sstevel@tonic-gate 				off = off + p;
24550Sstevel@tonic-gate 			}
24560Sstevel@tonic-gate 		}
24570Sstevel@tonic-gate 
24580Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) {
24590Sstevel@tonic-gate 			if (sieve[i] == 0) {
24600Sstevel@tonic-gate 				err = big_isprime_pos(result);
24610Sstevel@tonic-gate 				if (err != BIG_FALSE) {
24620Sstevel@tonic-gate 					if (err != BIG_TRUE)
24630Sstevel@tonic-gate 						return (err);
24640Sstevel@tonic-gate 					else
24650Sstevel@tonic-gate 						return (BIG_OK);
24660Sstevel@tonic-gate 				}
24670Sstevel@tonic-gate 
24680Sstevel@tonic-gate 			}
24690Sstevel@tonic-gate 			if ((err = big_add_abs(result, result, &Two)) !=
24700Sstevel@tonic-gate 			    BIG_OK)
24710Sstevel@tonic-gate 				return (err);
24720Sstevel@tonic-gate 		}
24730Sstevel@tonic-gate 	}
2474*1027Srobinson 	/* NOTREACHED */
24750Sstevel@tonic-gate }
24760Sstevel@tonic-gate 
24770Sstevel@tonic-gate 
24780Sstevel@tonic-gate BIG_ERR_CODE
24790Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n)
24800Sstevel@tonic-gate {
24810Sstevel@tonic-gate 	BIG_ERR_CODE err;
24820Sstevel@tonic-gate 
24830Sstevel@tonic-gate 
24840Sstevel@tonic-gate 	if ((err = big_copy(result, n)) != BIG_OK)
24850Sstevel@tonic-gate 		return (err);
24860Sstevel@tonic-gate 	result->value[0] |= 1;
24870Sstevel@tonic-gate 	while ((err = big_isprime_pos(result)) != BIG_TRUE) {
24880Sstevel@tonic-gate 		if (err != BIG_FALSE)
24890Sstevel@tonic-gate 			return (err);
24900Sstevel@tonic-gate 		if ((err = big_add_abs(result, result, &Two)) != BIG_OK)
24910Sstevel@tonic-gate 			return (err);
24920Sstevel@tonic-gate 	}
24930Sstevel@tonic-gate 	return (BIG_OK);
24940Sstevel@tonic-gate }
24950Sstevel@tonic-gate 
24960Sstevel@tonic-gate 
24970Sstevel@tonic-gate /*
24980Sstevel@tonic-gate  * given m and e, computes the rest in the equation
24990Sstevel@tonic-gate  * gcd(m, e) = cm * m + ce * e
25000Sstevel@tonic-gate  */
25010Sstevel@tonic-gate BIG_ERR_CODE
25020Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e)
25030Sstevel@tonic-gate {
25040Sstevel@tonic-gate 	BIGNUM *xi, *ri, *riminus1, *riminus2, *t,
25050Sstevel@tonic-gate 	    *vmi, *vei, *vmiminus1, *veiminus1;
25060Sstevel@tonic-gate 	BIGNUM t1, t2, t3, t4, t5, t6, t7, t8, tmp;
25070Sstevel@tonic-gate 	uint32_t t1value[BIGTMPSIZE];
25080Sstevel@tonic-gate 	uint32_t t2value[BIGTMPSIZE];
25090Sstevel@tonic-gate 	uint32_t t3value[BIGTMPSIZE];
25100Sstevel@tonic-gate 	uint32_t t4value[BIGTMPSIZE];
25110Sstevel@tonic-gate 	uint32_t t5value[BIGTMPSIZE];
25120Sstevel@tonic-gate 	uint32_t t6value[BIGTMPSIZE];
25130Sstevel@tonic-gate 	uint32_t t7value[BIGTMPSIZE];
25140Sstevel@tonic-gate 	uint32_t t8value[BIGTMPSIZE];
25150Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
25160Sstevel@tonic-gate 	BIG_ERR_CODE err;
25170Sstevel@tonic-gate 	int len;
25180Sstevel@tonic-gate 
25190Sstevel@tonic-gate 	if (big_cmp_abs(m, e) >= 0) len = m->len;
25200Sstevel@tonic-gate 	else len = e->len;
25210Sstevel@tonic-gate 
25220Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
25230Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
25240Sstevel@tonic-gate 		return (err);
25250Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
25260Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
25270Sstevel@tonic-gate 			goto ret1;
25280Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
25290Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
25300Sstevel@tonic-gate 			goto ret2;
25310Sstevel@tonic-gate 	if ((err = big_init1(&t4, len,
25320Sstevel@tonic-gate 	    t4value, arraysize(t3value))) != BIG_OK)
25330Sstevel@tonic-gate 			goto ret3;
25340Sstevel@tonic-gate 	if ((err = big_init1(&t5, len,
25350Sstevel@tonic-gate 	    t5value, arraysize(t5value))) != BIG_OK)
25360Sstevel@tonic-gate 			goto ret4;
25370Sstevel@tonic-gate 	if ((err = big_init1(&t6, len,
25380Sstevel@tonic-gate 	    t6value, arraysize(t6value))) != BIG_OK)
25390Sstevel@tonic-gate 			goto ret5;
25400Sstevel@tonic-gate 	if ((err = big_init1(&t7, len,
25410Sstevel@tonic-gate 	    t7value, arraysize(t7value))) != BIG_OK)
25420Sstevel@tonic-gate 			goto ret6;
25430Sstevel@tonic-gate 	if ((err = big_init1(&t8, len,
25440Sstevel@tonic-gate 	    t8value, arraysize(t8value))) != BIG_OK)
25450Sstevel@tonic-gate 			goto ret7;
25460Sstevel@tonic-gate 
25470Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * len,
25480Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
25490Sstevel@tonic-gate 		goto ret8;
25500Sstevel@tonic-gate 
25510Sstevel@tonic-gate 	ri = &t1;
25520Sstevel@tonic-gate 	ri->value[0] = 1;
25530Sstevel@tonic-gate 	ri->len = 1;
25540Sstevel@tonic-gate 	xi = &t2;
25550Sstevel@tonic-gate 	riminus1 = &t3;
25560Sstevel@tonic-gate 	riminus2 = &t4;
25570Sstevel@tonic-gate 	vmi = &t5;
25580Sstevel@tonic-gate 	vei = &t6;
25590Sstevel@tonic-gate 	vmiminus1 = &t7;
25600Sstevel@tonic-gate 	veiminus1 = &t8;
25610Sstevel@tonic-gate 
25620Sstevel@tonic-gate 	(void) big_copy(vmiminus1, &One);
25630Sstevel@tonic-gate 	(void) big_copy(vmi, &One);
25640Sstevel@tonic-gate 	(void) big_copy(veiminus1, &One);
25650Sstevel@tonic-gate 	(void) big_copy(xi, &One);
25660Sstevel@tonic-gate 	vei->len = 1;
25670Sstevel@tonic-gate 	vei->value[0] = 0;
25680Sstevel@tonic-gate 
25690Sstevel@tonic-gate 	(void) big_copy(riminus1, m);
25700Sstevel@tonic-gate 	(void) big_copy(ri, e);
25710Sstevel@tonic-gate 
25720Sstevel@tonic-gate 	while (!big_is_zero(ri)) {
25730Sstevel@tonic-gate 		t = riminus2;
25740Sstevel@tonic-gate 		riminus2 = riminus1;
25750Sstevel@tonic-gate 		riminus1 = ri;
25760Sstevel@tonic-gate 		ri = t;
25770Sstevel@tonic-gate 		if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK)
25780Sstevel@tonic-gate 			goto ret;
25790Sstevel@tonic-gate 		if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK)
25800Sstevel@tonic-gate 			goto ret;
25810Sstevel@tonic-gate 		t = vmiminus1;
25820Sstevel@tonic-gate 		vmiminus1 = vmi;
25830Sstevel@tonic-gate 		vmi = t;
25840Sstevel@tonic-gate 		if ((err = big_mul(&tmp, vei, xi)) != BIG_OK)
25850Sstevel@tonic-gate 			goto ret;
25860Sstevel@tonic-gate 		if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK)
25870Sstevel@tonic-gate 			goto ret;
25880Sstevel@tonic-gate 		t = veiminus1;
25890Sstevel@tonic-gate 		veiminus1 = vei;
25900Sstevel@tonic-gate 		vei = t;
25910Sstevel@tonic-gate 		if ((err = big_div_pos(xi, ri, riminus2, riminus1)) != BIG_OK)
25920Sstevel@tonic-gate 			goto ret;
25930Sstevel@tonic-gate 	}
25940Sstevel@tonic-gate 	if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK))
25950Sstevel@tonic-gate 		goto ret;
25960Sstevel@tonic-gate 	if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK))
25970Sstevel@tonic-gate 		goto ret;
25980Sstevel@tonic-gate 	if (ce != NULL)
25990Sstevel@tonic-gate 		err = big_copy(ce, vei);
26000Sstevel@tonic-gate ret:
26010Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
26020Sstevel@tonic-gate ret8:
26030Sstevel@tonic-gate 	if (t8.malloced) big_finish(&t8);
26040Sstevel@tonic-gate ret7:
26050Sstevel@tonic-gate 	if (t7.malloced) big_finish(&t7);
26060Sstevel@tonic-gate ret6:
26070Sstevel@tonic-gate 	if (t6.malloced) big_finish(&t6);
26080Sstevel@tonic-gate ret5:
26090Sstevel@tonic-gate 	if (t5.malloced) big_finish(&t5);
26100Sstevel@tonic-gate ret4:
26110Sstevel@tonic-gate 	if (t4.malloced) big_finish(&t4);
26120Sstevel@tonic-gate ret3:
26130Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
26140Sstevel@tonic-gate ret2:
26150Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
26160Sstevel@tonic-gate ret1:
26170Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
26180Sstevel@tonic-gate 
26190Sstevel@tonic-gate 	return (err);
26200Sstevel@tonic-gate }
2621