xref: /onnv-gate/usr/src/common/bignum/bignumimpl.c (revision 6557:c6c4f66aed66)
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
5*6557Sfr41279  * Common Development and Distribution License (the "License").
6*6557Sfr41279  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*6557Sfr41279  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #define	big_div_pos_fast big_div_pos
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include "bignum.h"
310Sstevel@tonic-gate 
320Sstevel@tonic-gate /*
330Sstevel@tonic-gate  * Configuration guide
340Sstevel@tonic-gate  * -------------------
350Sstevel@tonic-gate  *
360Sstevel@tonic-gate  * There are 4 preprocessor symbols used to configure the bignum
370Sstevel@tonic-gate  * implementation.  This file contains no logic to configure based on
380Sstevel@tonic-gate  * processor; we leave that to the Makefiles to specify.
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  * USE_FLOATING_POINT
410Sstevel@tonic-gate  *   Meaning: There is support for a fast floating-point implementation of
420Sstevel@tonic-gate  *   Montgomery multiply.
430Sstevel@tonic-gate  *
440Sstevel@tonic-gate  * PSR_MUL
450Sstevel@tonic-gate  *   Meaning: There are processor-specific versions of the low level
460Sstevel@tonic-gate  *   functions to implement big_mul.  Those functions are: big_mul_set_vec,
470Sstevel@tonic-gate  *   big_mul_add_vec, big_mul_vec, and big_sqr_vec.  PSR_MUL implies support
480Sstevel@tonic-gate  *   for all 4 functions.  You cannot pick and choose which subset of these
490Sstevel@tonic-gate  *   functions to support; that would lead to a rat's nest of #ifdefs.
500Sstevel@tonic-gate  *
510Sstevel@tonic-gate  * HWCAP
520Sstevel@tonic-gate  *   Meaning: Call multiply support functions through a function pointer.
530Sstevel@tonic-gate  *   On x86, there are multiple implementations for differnt hardware
540Sstevel@tonic-gate  *   capabilities, such as MMX, SSE2, etc.  Tests are made at run-time, when
550Sstevel@tonic-gate  *   a function is first used.  So, the support functions are called through
560Sstevel@tonic-gate  *   a function pointer.  There is no need for that on Sparc, because there
570Sstevel@tonic-gate  *   is only one implementation; support functions are called directly.
580Sstevel@tonic-gate  *   Later, if there were some new VIS instruction, or something, and a
590Sstevel@tonic-gate  *   run-time test were needed, rather than variant kernel modules and
600Sstevel@tonic-gate  *   libraries, then HWCAP would be defined for Sparc, as well.
610Sstevel@tonic-gate  *
620Sstevel@tonic-gate  * UMUL64
630Sstevel@tonic-gate  *   Meaning: It is safe to use generic C code that assumes the existence
640Sstevel@tonic-gate  *   of a 32 x 32 --> 64 bit unsigned multiply.  If this is not defined,
650Sstevel@tonic-gate  *   then the generic code for big_mul_add_vec() must necessarily be very slow,
660Sstevel@tonic-gate  *   because it must fall back to using 16 x 16 --> 32 bit multiplication.
670Sstevel@tonic-gate  *
680Sstevel@tonic-gate  */
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 
710Sstevel@tonic-gate #ifdef	_KERNEL
72*6557Sfr41279 #include <sys/ddi.h>
73*6557Sfr41279 #include <sys/mdesc.h>
74*6557Sfr41279 #include <sys/crypto/common.h>
750Sstevel@tonic-gate 
760Sstevel@tonic-gate #include <sys/types.h>
770Sstevel@tonic-gate #include <sys/kmem.h>
780Sstevel@tonic-gate #include <sys/param.h>
790Sstevel@tonic-gate #include <sys/sunddi.h>
800Sstevel@tonic-gate 
810Sstevel@tonic-gate #define	big_malloc(size)	kmem_alloc(size, KM_NOSLEEP)
820Sstevel@tonic-gate #define	big_free(ptr, size)	kmem_free(ptr, size)
830Sstevel@tonic-gate 
840Sstevel@tonic-gate void *
850Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize)
860Sstevel@tonic-gate {
870Sstevel@tonic-gate 	void *rv;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	rv = kmem_alloc(newsize, KM_NOSLEEP);
900Sstevel@tonic-gate 	if (rv != NULL)
910Sstevel@tonic-gate 		bcopy(from, rv, oldsize);
920Sstevel@tonic-gate 	kmem_free(from, oldsize);
930Sstevel@tonic-gate 	return (rv);
940Sstevel@tonic-gate }
950Sstevel@tonic-gate 
960Sstevel@tonic-gate #else	/* _KERNEL */
970Sstevel@tonic-gate 
980Sstevel@tonic-gate #include <stdlib.h>
990Sstevel@tonic-gate #include <stdio.h>
100*6557Sfr41279 #include <assert.h>
101*6557Sfr41279 #define	ASSERT	assert
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate #ifndef MALLOC_DEBUG
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate #define	big_malloc(size)	malloc(size)
1060Sstevel@tonic-gate #define	big_free(ptr, size)	free(ptr)
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate #else
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate void
1110Sstevel@tonic-gate big_free(void *ptr, size_t size)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate 	printf("freed %d bytes at %p\n", size, ptr);
1140Sstevel@tonic-gate 	free(ptr);
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate void *
1180Sstevel@tonic-gate big_malloc(size_t size)
1190Sstevel@tonic-gate {
1200Sstevel@tonic-gate 	void *rv;
1210Sstevel@tonic-gate 	rv = malloc(size);
1220Sstevel@tonic-gate 	printf("malloced %d bytes, addr:%p\n", size, rv);
1230Sstevel@tonic-gate 	return (rv);
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate #endif /* MALLOC_DEBUG */
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate #define	big_realloc(x, y, z) realloc((x), (z))
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate void
1300Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a)
1310Sstevel@tonic-gate {
1320Sstevel@tonic-gate 	int i;
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	(void) printf("\n%s\n%d\n", aname, a->sign*a->len);
1350Sstevel@tonic-gate 	for (i = a->len - 1; i >= 0; i--) {
136*6557Sfr41279 #ifdef BIGNUM_CHUNK_32
1370Sstevel@tonic-gate 		(void) printf("%08x ", a->value[i]);
138*6557Sfr41279 		if ((i % 8 == 0) && (i != 0)) {
139*6557Sfr41279 			(void) printf("\n");
140*6557Sfr41279 		}
141*6557Sfr41279 #else
142*6557Sfr41279 		(void) printf("%08x %08x ", (uint32_t)((a->value[i]) >> 32),
143*6557Sfr41279 		    (uint32_t)((a->value[i]) & 0xffffffff));
144*6557Sfr41279 		if ((i % 4 == 0) && (i != 0)) {
145*6557Sfr41279 			(void) printf("\n");
146*6557Sfr41279 		}
147*6557Sfr41279 #endif
1480Sstevel@tonic-gate 	}
1490Sstevel@tonic-gate 	(void) printf("\n");
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate #endif	/* _KERNEL */
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 
155*6557Sfr41279 /* size in BIG_CHUNK_SIZE-bit words */
1560Sstevel@tonic-gate BIG_ERR_CODE
1570Sstevel@tonic-gate big_init(BIGNUM *number, int size)
1580Sstevel@tonic-gate {
159*6557Sfr41279 	number->value = big_malloc(sizeof (BIG_CHUNK_TYPE) * size);
1600Sstevel@tonic-gate 	if (number->value == NULL) {
1610Sstevel@tonic-gate 		return (BIG_NO_MEM);
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 	number->size = size;
1640Sstevel@tonic-gate 	number->len = 0;
1650Sstevel@tonic-gate 	number->sign = 1;
1660Sstevel@tonic-gate 	number->malloced = 1;
1670Sstevel@tonic-gate 	return (BIG_OK);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate 
170*6557Sfr41279 /* size in BIG_CHUNK_SIZE-bit words */
1710Sstevel@tonic-gate BIG_ERR_CODE
172*6557Sfr41279 big_init1(BIGNUM *number, int size, BIG_CHUNK_TYPE *buf, int bufsize)
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate 	if ((buf == NULL) || (size > bufsize)) {
175*6557Sfr41279 		number->value = big_malloc(sizeof (BIG_CHUNK_TYPE) * size);
1760Sstevel@tonic-gate 		if (number->value == NULL) {
1770Sstevel@tonic-gate 			return (BIG_NO_MEM);
1780Sstevel@tonic-gate 		}
1790Sstevel@tonic-gate 		number->size = size;
1800Sstevel@tonic-gate 		number->malloced = 1;
1810Sstevel@tonic-gate 	} else {
1820Sstevel@tonic-gate 		number->value = buf;
1830Sstevel@tonic-gate 		number->size = bufsize;
1840Sstevel@tonic-gate 		number->malloced = 0;
1850Sstevel@tonic-gate 	}
1860Sstevel@tonic-gate 		number->len = 0;
1870Sstevel@tonic-gate 		number->sign = 1;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	return (BIG_OK);
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate void
1930Sstevel@tonic-gate big_finish(BIGNUM *number)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate 	if (number->malloced == 1) {
196*6557Sfr41279 		big_free(number->value,
197*6557Sfr41279 		    sizeof (BIG_CHUNK_TYPE) * number->size);
1980Sstevel@tonic-gate 		number->malloced = 0;
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate 
202*6557Sfr41279 
2030Sstevel@tonic-gate /*
204*6557Sfr41279  *  bn->size should be at least
205*6557Sfr41279  * (len + sizeof (BIG_CHUNK_TYPE) - 1) / sizeof (BIG_CHUNK_TYPE) bytes
2060Sstevel@tonic-gate  * converts from byte-big-endian format to bignum format (words in
2070Sstevel@tonic-gate  * little endian order, but bytes within the words big endian)
2080Sstevel@tonic-gate  */
2090Sstevel@tonic-gate void
2100Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len)
2110Sstevel@tonic-gate {
2120Sstevel@tonic-gate 	int		i, j, offs;
213*6557Sfr41279 	BIG_CHUNK_TYPE	word;
2140Sstevel@tonic-gate 	uchar_t		*knwordp;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate #ifdef	_LP64
217*6557Sfr41279 	offs = (uint32_t)len % sizeof (BIG_CHUNK_TYPE);
218*6557Sfr41279 	bn->len = (uint32_t)len / sizeof (BIG_CHUNK_TYPE);
219*6557Sfr41279 
220*6557Sfr41279 	for (i = 0; i < (uint32_t)len / sizeof (BIG_CHUNK_TYPE); i++) {
2210Sstevel@tonic-gate #else	/* !_LP64 */
222*6557Sfr41279 	offs = len % sizeof (BIG_CHUNK_TYPE);
223*6557Sfr41279 	bn->len = len / sizeof (BIG_CHUNK_TYPE);
224*6557Sfr41279 	for (i = 0; i < len / sizeof (BIG_CHUNK_TYPE); i++) {
2250Sstevel@tonic-gate #endif	/* _LP64 */
226*6557Sfr41279 		knwordp = &(kn[len - sizeof (BIG_CHUNK_TYPE) * (i + 1)]);
2270Sstevel@tonic-gate 		word = knwordp[0];
228*6557Sfr41279 		for (j = 1; j < sizeof (BIG_CHUNK_TYPE); j++) {
2290Sstevel@tonic-gate 			word = (word << 8)+ knwordp[j];
2300Sstevel@tonic-gate 		}
2310Sstevel@tonic-gate 		bn->value[i] = word;
2320Sstevel@tonic-gate 	}
2330Sstevel@tonic-gate 	if (offs > 0) {
2340Sstevel@tonic-gate 		word = kn[0];
2350Sstevel@tonic-gate 		for (i = 1; i < offs; i++) word = (word << 8) + kn[i];
2360Sstevel@tonic-gate 		bn->value[bn->len++] = word;
2370Sstevel@tonic-gate 	}
2380Sstevel@tonic-gate 	while ((bn->len > 1) && (bn->value[bn->len-1] == 0)) {
2390Sstevel@tonic-gate 		bn->len --;
2400Sstevel@tonic-gate 	}
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate /*
2440Sstevel@tonic-gate  * copies the least significant len bytes if
245*6557Sfr41279  * len < bn->len * sizeof (BIG_CHUNK_TYPE)
2460Sstevel@tonic-gate  * converts from bignum format to byte-big-endian format.
247*6557Sfr41279  * bignum format is words of type  BIG_CHUNK_TYPE in little endian order.
2480Sstevel@tonic-gate  */
2490Sstevel@tonic-gate void
2500Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len)
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate 	int		i, j, offs;
253*6557Sfr41279 	BIG_CHUNK_TYPE	word;
254*6557Sfr41279 
255*6557Sfr41279 	if (len < sizeof (BIG_CHUNK_TYPE) * bn->len) {
2560Sstevel@tonic-gate #ifdef	_LP64
257*6557Sfr41279 		for (i = 0; i < (uint32_t)len / sizeof (BIG_CHUNK_TYPE); i++) {
2580Sstevel@tonic-gate #else	/* !_LP64 */
259*6557Sfr41279 		for (i = 0; i < len / sizeof (BIG_CHUNK_TYPE); i++) {
2600Sstevel@tonic-gate #endif	/* _LP64 */
2610Sstevel@tonic-gate 			word = bn->value[i];
262*6557Sfr41279 			for (j = 0; j < sizeof (BIG_CHUNK_TYPE); j++) {
263*6557Sfr41279 				kn[len - sizeof (BIG_CHUNK_TYPE) * i - j - 1] =
2640Sstevel@tonic-gate 				    word & 0xff;
2650Sstevel@tonic-gate 				word = word >> 8;
2660Sstevel@tonic-gate 			}
2670Sstevel@tonic-gate 		}
2680Sstevel@tonic-gate #ifdef	_LP64
269*6557Sfr41279 		offs = (uint32_t)len % sizeof (BIG_CHUNK_TYPE);
2700Sstevel@tonic-gate #else	/* !_LP64 */
271*6557Sfr41279 		offs = len % sizeof (BIG_CHUNK_TYPE);
2720Sstevel@tonic-gate #endif	/* _LP64 */
2730Sstevel@tonic-gate 		if (offs > 0) {
274*6557Sfr41279 			word = bn->value[len / sizeof (BIG_CHUNK_TYPE)];
2750Sstevel@tonic-gate #ifdef	_LP64
276*6557Sfr41279 			for (i =  (uint32_t)len % sizeof (BIG_CHUNK_TYPE);
277*6557Sfr41279 			    i > 0; i --) {
2780Sstevel@tonic-gate #else	/* !_LP64 */
279*6557Sfr41279 			for (i = len % sizeof (BIG_CHUNK_TYPE);
280*6557Sfr41279 			    i > 0; i --) {
2810Sstevel@tonic-gate #endif	/* _LP64 */
282*6557Sfr41279 				kn[i - 1] = word & 0xff;
283*6557Sfr41279 				word = word >> 8;
284*6557Sfr41279 			}
2850Sstevel@tonic-gate 		}
2860Sstevel@tonic-gate 	} else {
2870Sstevel@tonic-gate 		for (i = 0; i < bn->len; i++) {
2880Sstevel@tonic-gate 			word = bn->value[i];
289*6557Sfr41279 			for (j = 0; j < sizeof (BIG_CHUNK_TYPE); j++) {
290*6557Sfr41279 				kn[len - sizeof (BIG_CHUNK_TYPE) * i - j - 1] =
2910Sstevel@tonic-gate 				    word & 0xff;
2920Sstevel@tonic-gate 				word = word >> 8;
2930Sstevel@tonic-gate 			}
2940Sstevel@tonic-gate 		}
2950Sstevel@tonic-gate #ifdef	_LP64
296*6557Sfr41279 		for (i = 0;
297*6557Sfr41279 		    i < (uint32_t)len - sizeof (BIG_CHUNK_TYPE) * bn->len;
2980Sstevel@tonic-gate 		    i++) {
2990Sstevel@tonic-gate #else	/* !_LP64 */
300*6557Sfr41279 		for (i = 0; i < len - sizeof (BIG_CHUNK_TYPE) * bn->len; i++) {
3010Sstevel@tonic-gate #endif	/* _LP64 */
3020Sstevel@tonic-gate 			kn[i] = 0;
3030Sstevel@tonic-gate 		}
3040Sstevel@tonic-gate 	}
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate int
3090Sstevel@tonic-gate big_bitlength(BIGNUM *a)
3100Sstevel@tonic-gate {
311*6557Sfr41279 	int		l = 0, b = 0;
312*6557Sfr41279 	BIG_CHUNK_TYPE	c;
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	l = a->len - 1;
3150Sstevel@tonic-gate 	while ((l > 0) && (a->value[l] == 0)) {
3160Sstevel@tonic-gate 		l--;
3170Sstevel@tonic-gate 	}
318*6557Sfr41279 	b = sizeof (BIG_CHUNK_TYPE) * BITSINBYTE;
3190Sstevel@tonic-gate 	c = a->value[l];
320*6557Sfr41279 	while ((b > 1) && ((c & BIG_CHUNK_HIGHBIT) == 0)) {
3210Sstevel@tonic-gate 		c = c << 1;
3220Sstevel@tonic-gate 		b--;
3230Sstevel@tonic-gate 	}
324*6557Sfr41279 
325*6557Sfr41279 	return (l * sizeof (BIG_CHUNK_TYPE) * BITSINBYTE + b);
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate BIG_ERR_CODE
3300Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src)
3310Sstevel@tonic-gate {
332*6557Sfr41279 	BIG_CHUNK_TYPE	*newptr;
333*6557Sfr41279 	int		i, len;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	len = src->len;
336*6557Sfr41279 	while ((len > 1) && (src->value[len - 1] == 0)) {
3370Sstevel@tonic-gate 		len--;
338*6557Sfr41279 	}
3390Sstevel@tonic-gate 	src->len = len;
3400Sstevel@tonic-gate 	if (dest->size < len) {
3410Sstevel@tonic-gate 		if (dest->malloced == 1) {
342*6557Sfr41279 			newptr = (BIG_CHUNK_TYPE *)big_realloc(dest->value,
343*6557Sfr41279 			    sizeof (BIG_CHUNK_TYPE) * dest->size,
344*6557Sfr41279 			    sizeof (BIG_CHUNK_TYPE) * len);
3450Sstevel@tonic-gate 		} else {
346*6557Sfr41279 			newptr = (BIG_CHUNK_TYPE *)
347*6557Sfr41279 			    big_malloc(sizeof (BIG_CHUNK_TYPE) * len);
348*6557Sfr41279 			if (newptr != NULL) {
349*6557Sfr41279 				dest->malloced = 1;
350*6557Sfr41279 			}
3510Sstevel@tonic-gate 		}
352*6557Sfr41279 		if (newptr == NULL) {
3530Sstevel@tonic-gate 			return (BIG_NO_MEM);
354*6557Sfr41279 		}
3550Sstevel@tonic-gate 		dest->value = newptr;
3560Sstevel@tonic-gate 		dest->size = len;
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 	dest->len = len;
3590Sstevel@tonic-gate 	dest->sign = src->sign;
360*6557Sfr41279 	for (i = 0; i < len; i++) {
361*6557Sfr41279 		dest->value[i] = src->value[i];
362*6557Sfr41279 	}
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	return (BIG_OK);
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate BIG_ERR_CODE
3690Sstevel@tonic-gate big_extend(BIGNUM *number, int size)
3700Sstevel@tonic-gate {
371*6557Sfr41279 	BIG_CHUNK_TYPE	*newptr;
3720Sstevel@tonic-gate 	int		i;
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	if (number->size >= size)
3750Sstevel@tonic-gate 		return (BIG_OK);
3760Sstevel@tonic-gate 	if (number->malloced) {
377*6557Sfr41279 		number->value = big_realloc(number->value,
378*6557Sfr41279 		    sizeof (BIG_CHUNK_TYPE) * number->size,
379*6557Sfr41279 		    sizeof (BIG_CHUNK_TYPE) * size);
3800Sstevel@tonic-gate 	} else {
381*6557Sfr41279 		newptr = big_malloc(sizeof (BIG_CHUNK_TYPE) * size);
3820Sstevel@tonic-gate 		if (newptr != NULL) {
3830Sstevel@tonic-gate 			for (i = 0; i < number->size; i++) {
3840Sstevel@tonic-gate 				newptr[i] = number->value[i];
3850Sstevel@tonic-gate 			}
3860Sstevel@tonic-gate 		}
3870Sstevel@tonic-gate 		number->value = newptr;
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 
390*6557Sfr41279 	if (number->value == NULL) {
3910Sstevel@tonic-gate 		return (BIG_NO_MEM);
392*6557Sfr41279 	}
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	number->size = size;
3950Sstevel@tonic-gate 	number->malloced = 1;
3960Sstevel@tonic-gate 	return (BIG_OK);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 
400*6557Sfr41279 /* returns 1 if n == 0 */
4010Sstevel@tonic-gate int
4020Sstevel@tonic-gate big_is_zero(BIGNUM *n)
4030Sstevel@tonic-gate {
404*6557Sfr41279 	int	i, result;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	result = 1;
407*6557Sfr41279 	for (i = 0; i < n->len; i++) {
408*6557Sfr41279 		if (n->value[i] != 0) {
409*6557Sfr41279 			result = 0;
410*6557Sfr41279 		}
411*6557Sfr41279 	}
4120Sstevel@tonic-gate 	return (result);
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate BIG_ERR_CODE
4170Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
4180Sstevel@tonic-gate {
419*6557Sfr41279 	int		i, shorter, longer;
420*6557Sfr41279 	BIG_CHUNK_TYPE	cy, ai;
421*6557Sfr41279 	BIG_CHUNK_TYPE	*r, *a, *b, *c;
422*6557Sfr41279 	BIG_ERR_CODE	err;
423*6557Sfr41279 	BIGNUM		*longerarg;
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	if (aa->len > bb->len) {
4260Sstevel@tonic-gate 		shorter = bb->len;
4270Sstevel@tonic-gate 		longer = aa->len;
428*6557Sfr41279 		longerarg = aa;
4290Sstevel@tonic-gate 	} else {
4300Sstevel@tonic-gate 		shorter = aa->len;
4310Sstevel@tonic-gate 		longer = bb->len;
432*6557Sfr41279 		longerarg = bb;
4330Sstevel@tonic-gate 	}
4340Sstevel@tonic-gate 	if (result->size < longer + 1) {
4350Sstevel@tonic-gate 		err = big_extend(result, longer + 1);
436*6557Sfr41279 		if (err != BIG_OK) {
4370Sstevel@tonic-gate 			return (err);
438*6557Sfr41279 		}
4390Sstevel@tonic-gate 	}
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	r = result->value;
4420Sstevel@tonic-gate 	a = aa->value;
4430Sstevel@tonic-gate 	b = bb->value;
444*6557Sfr41279 	c = longerarg->value;
4450Sstevel@tonic-gate 	cy = 0;
4460Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
4470Sstevel@tonic-gate 		ai = a[i];
4480Sstevel@tonic-gate 		r[i] = ai + b[i] + cy;
449*6557Sfr41279 		if (r[i] > ai) {
450*6557Sfr41279 			cy = 0;
451*6557Sfr41279 		} else if (r[i] < ai) {
452*6557Sfr41279 			cy = 1;
453*6557Sfr41279 		}
4540Sstevel@tonic-gate 	}
4550Sstevel@tonic-gate 	for (; i < longer; i++) {
4560Sstevel@tonic-gate 		ai = c[i];
4570Sstevel@tonic-gate 		r[i] = ai + cy;
458*6557Sfr41279 		if (r[i] >= ai) {
459*6557Sfr41279 			cy = 0;
460*6557Sfr41279 		}
4610Sstevel@tonic-gate 	}
4620Sstevel@tonic-gate 	if (cy == 1) {
4630Sstevel@tonic-gate 		r[i] = cy;
4640Sstevel@tonic-gate 		result->len = longer + 1;
4650Sstevel@tonic-gate 	} else {
4660Sstevel@tonic-gate 		result->len = longer;
4670Sstevel@tonic-gate 	}
4680Sstevel@tonic-gate 	result->sign = 1;
4690Sstevel@tonic-gate 	return (BIG_OK);
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */
4740Sstevel@tonic-gate void
475*6557Sfr41279 big_sub_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, BIG_CHUNK_TYPE *b, int len)
4760Sstevel@tonic-gate {
477*6557Sfr41279 	int		i;
478*6557Sfr41279 	BIG_CHUNK_TYPE	cy, ai;
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	cy = 1;
4810Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
4820Sstevel@tonic-gate 		ai = a[i];
4830Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
484*6557Sfr41279 		if (r[i] > ai) {
485*6557Sfr41279 			cy = 0;
486*6557Sfr41279 		} else if (r[i] < ai) {
487*6557Sfr41279 			cy = 1;
488*6557Sfr41279 		}
4890Sstevel@tonic-gate 	}
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate /* result=aa-bb  it is assumed that aa>=bb */
4940Sstevel@tonic-gate BIG_ERR_CODE
4950Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
4960Sstevel@tonic-gate {
497*6557Sfr41279 	int		i, shorter;
498*6557Sfr41279 	BIG_CHUNK_TYPE	cy = 1, ai;
499*6557Sfr41279 	BIG_CHUNK_TYPE	*r, *a, *b;
500*6557Sfr41279 	BIG_ERR_CODE	err = BIG_OK;
501*6557Sfr41279 
502*6557Sfr41279 	if (aa->len > bb->len) {
503*6557Sfr41279 		shorter = bb->len;
504*6557Sfr41279 	} else {
505*6557Sfr41279 		shorter = aa->len;
506*6557Sfr41279 	}
5070Sstevel@tonic-gate 	if (result->size < aa->len) {
5080Sstevel@tonic-gate 		err = big_extend(result, aa->len);
509*6557Sfr41279 		if (err != BIG_OK) {
5100Sstevel@tonic-gate 			return (err);
511*6557Sfr41279 		}
5120Sstevel@tonic-gate 	}
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	r = result->value;
5150Sstevel@tonic-gate 	a = aa->value;
5160Sstevel@tonic-gate 	b = bb->value;
5170Sstevel@tonic-gate 	result->len = aa->len;
5180Sstevel@tonic-gate 	cy = 1;
5190Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
5200Sstevel@tonic-gate 		ai = a[i];
5210Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
522*6557Sfr41279 		if (r[i] > ai) {
523*6557Sfr41279 			cy = 0;
524*6557Sfr41279 		} else if (r[i] < ai) {
525*6557Sfr41279 			cy = 1;
526*6557Sfr41279 		}
5270Sstevel@tonic-gate 	}
5280Sstevel@tonic-gate 	for (; i < aa->len; i++) {
5290Sstevel@tonic-gate 		ai = a[i];
5300Sstevel@tonic-gate 		r[i] = ai + (~0) + cy;
531*6557Sfr41279 		if (r[i] < ai) {
532*6557Sfr41279 			cy = 1;
533*6557Sfr41279 		}
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 	result->sign = 1;
536*6557Sfr41279 
537*6557Sfr41279 	if (cy == 0) {
5380Sstevel@tonic-gate 		return (BIG_INVALID_ARGS);
539*6557Sfr41279 	} else {
5400Sstevel@tonic-gate 		return (BIG_OK);
541*6557Sfr41279 	}
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */
5460Sstevel@tonic-gate int
5470Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb)
5480Sstevel@tonic-gate {
549*6557Sfr41279 	int	i;
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	if (aa->len > bb->len) {
5520Sstevel@tonic-gate 		for (i = aa->len - 1; i > bb->len - 1; i--) {
553*6557Sfr41279 			if (aa->value[i] > 0) {
5540Sstevel@tonic-gate 				return (1);
555*6557Sfr41279 			}
5560Sstevel@tonic-gate 		}
5570Sstevel@tonic-gate 	} else if (aa->len < bb->len) {
5580Sstevel@tonic-gate 		for (i = bb->len - 1; i > aa->len - 1; i--) {
559*6557Sfr41279 			if (bb->value[i] > 0) {
5600Sstevel@tonic-gate 				return (-1);
561*6557Sfr41279 			}
5620Sstevel@tonic-gate 		}
563*6557Sfr41279 	} else {
564*6557Sfr41279 		i = aa->len-1;
565*6557Sfr41279 	}
5660Sstevel@tonic-gate 	for (; i >= 0; i--) {
567*6557Sfr41279 		if (aa->value[i] > bb->value[i]) {
5680Sstevel@tonic-gate 			return (1);
569*6557Sfr41279 		} else if (aa->value[i] < bb->value[i]) {
5700Sstevel@tonic-gate 			return (-1);
571*6557Sfr41279 		}
5720Sstevel@tonic-gate 	}
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	return (0);
5750Sstevel@tonic-gate }
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate BIG_ERR_CODE
5790Sstevel@tonic-gate big_sub(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
5800Sstevel@tonic-gate {
581*6557Sfr41279 	BIG_ERR_CODE	err;
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == 1)) {
584*6557Sfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
5850Sstevel@tonic-gate 			return (err);
586*6557Sfr41279 		}
5870Sstevel@tonic-gate 		result->sign = 1;
5880Sstevel@tonic-gate 	} else if ((aa->sign == -1) && (bb->sign == 1)) {
589*6557Sfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
5900Sstevel@tonic-gate 			return (err);
591*6557Sfr41279 		}
5920Sstevel@tonic-gate 		result->sign = -1;
5930Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
5940Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
595*6557Sfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
5960Sstevel@tonic-gate 				return (err);
597*6557Sfr41279 			}
5980Sstevel@tonic-gate 			result->sign = 1;
5990Sstevel@tonic-gate 		} else {
600*6557Sfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6010Sstevel@tonic-gate 				return (err);
602*6557Sfr41279 			}
6030Sstevel@tonic-gate 			result->sign = -1;
6040Sstevel@tonic-gate 		}
6050Sstevel@tonic-gate 	} else {
6060Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
607*6557Sfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6080Sstevel@tonic-gate 				return (err);
609*6557Sfr41279 			}
6100Sstevel@tonic-gate 			result->sign = -1;
6110Sstevel@tonic-gate 		} else {
612*6557Sfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6130Sstevel@tonic-gate 				return (err);
614*6557Sfr41279 			}
6150Sstevel@tonic-gate 			result->sign = 1;
6160Sstevel@tonic-gate 		}
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate 	return (BIG_OK);
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate BIG_ERR_CODE
6230Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
6240Sstevel@tonic-gate {
625*6557Sfr41279 	BIG_ERR_CODE	err;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == -1)) {
628*6557Sfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
6290Sstevel@tonic-gate 			return (err);
630*6557Sfr41279 		}
6310Sstevel@tonic-gate 		result->sign = -1;
6320Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
633*6557Sfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
6340Sstevel@tonic-gate 			return (err);
635*6557Sfr41279 		}
6360Sstevel@tonic-gate 		result->sign = 1;
6370Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == -1)) {
6380Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
639*6557Sfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6400Sstevel@tonic-gate 				return (err);
641*6557Sfr41279 			}
6420Sstevel@tonic-gate 			result->sign = 1;
6430Sstevel@tonic-gate 		} else {
644*6557Sfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6450Sstevel@tonic-gate 				return (err);
646*6557Sfr41279 			}
6470Sstevel@tonic-gate 			result->sign = -1;
6480Sstevel@tonic-gate 		}
6490Sstevel@tonic-gate 	} else {
6500Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
651*6557Sfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6520Sstevel@tonic-gate 				return (err);
653*6557Sfr41279 			}
6540Sstevel@tonic-gate 			result->sign = -1;
6550Sstevel@tonic-gate 		} else {
656*6557Sfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6570Sstevel@tonic-gate 				return (err);
658*6557Sfr41279 			}
6590Sstevel@tonic-gate 			result->sign = 1;
6600Sstevel@tonic-gate 		}
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate 	return (BIG_OK);
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 
666*6557Sfr41279 /* result = aa/2 */
6670Sstevel@tonic-gate BIG_ERR_CODE
6680Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa)
6690Sstevel@tonic-gate {
670*6557Sfr41279 	BIG_ERR_CODE	err;
671*6557Sfr41279 	int		i;
672*6557Sfr41279 	BIG_CHUNK_TYPE	cy, cy1;
673*6557Sfr41279 	BIG_CHUNK_TYPE	*a, *r;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	if (result->size < aa->len) {
6760Sstevel@tonic-gate 		err = big_extend(result, aa->len);
677*6557Sfr41279 		if (err != BIG_OK) {
6780Sstevel@tonic-gate 			return (err);
679*6557Sfr41279 		}
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	result->len = aa->len;
6830Sstevel@tonic-gate 	a = aa->value;
6840Sstevel@tonic-gate 	r = result->value;
6850Sstevel@tonic-gate 	cy = 0;
686*6557Sfr41279 	for (i = aa->len - 1; i >= 0; i--) {
687*6557Sfr41279 		cy1 = a[i] << (BIG_CHUNK_SIZE - 1);
688*6557Sfr41279 		r[i] = (cy | (a[i] >> 1));
6890Sstevel@tonic-gate 		cy = cy1;
6900Sstevel@tonic-gate 	}
691*6557Sfr41279 	if (r[result->len - 1] == 0) {
692*6557Sfr41279 		result->len--;
693*6557Sfr41279 	}
694*6557Sfr41279 
6950Sstevel@tonic-gate 	return (BIG_OK);
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate 
698*6557Sfr41279 /* result  =  aa*2 */
6990Sstevel@tonic-gate BIG_ERR_CODE
7000Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa)
7010Sstevel@tonic-gate {
702*6557Sfr41279 	BIG_ERR_CODE	err;
703*6557Sfr41279 	int		i, rsize;
704*6557Sfr41279 	BIG_CHUNK_TYPE	cy, cy1;
705*6557Sfr41279 	BIG_CHUNK_TYPE	*a, *r;
706*6557Sfr41279 
707*6557Sfr41279 	if ((aa->len > 0) &&
708*6557Sfr41279 	    ((aa->value[aa->len - 1] & BIG_CHUNK_HIGHBIT) != 0)) {
7090Sstevel@tonic-gate 		rsize = aa->len + 1;
710*6557Sfr41279 	} else {
711*6557Sfr41279 		rsize = aa->len;
712*6557Sfr41279 	}
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	if (result->size < rsize) {
7150Sstevel@tonic-gate 		err = big_extend(result, rsize);
7160Sstevel@tonic-gate 		if (err != BIG_OK)
7170Sstevel@tonic-gate 			return (err);
7180Sstevel@tonic-gate 	}
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	a = aa->value;
7210Sstevel@tonic-gate 	r = result->value;
722*6557Sfr41279 	if (rsize == aa->len + 1) {
723*6557Sfr41279 		r[rsize - 1] = 1;
724*6557Sfr41279 	}
7250Sstevel@tonic-gate 	cy = 0;
7260Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
727*6557Sfr41279 		cy1 = a[i] >> (BIG_CHUNK_SIZE - 1);
7280Sstevel@tonic-gate 		r[i] = (cy | (a[i] << 1));
7290Sstevel@tonic-gate 		cy = cy1;
7300Sstevel@tonic-gate 	}
7310Sstevel@tonic-gate 	result->len = rsize;
7320Sstevel@tonic-gate 	return (BIG_OK);
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate 
735*6557Sfr41279 
736*6557Sfr41279 /*
737*6557Sfr41279  * returns aa mod b, aa must be nonneg, b must be a max
738*6557Sfr41279  * (BIG_CHUNK_SIZE / 2)-bit integer
739*6557Sfr41279  */
740*6557Sfr41279 static uint32_t
741*6557Sfr41279 big_modhalf_pos(BIGNUM *aa, uint32_t b)
7420Sstevel@tonic-gate {
743*6557Sfr41279 	int		i;
744*6557Sfr41279 	BIG_CHUNK_TYPE	rem;
745*6557Sfr41279 
746*6557Sfr41279 	if (aa->len == 0) {
7470Sstevel@tonic-gate 		return (0);
748*6557Sfr41279 	}
7490Sstevel@tonic-gate 	rem = aa->value[aa->len - 1] % b;
7500Sstevel@tonic-gate 	for (i = aa->len - 2; i >= 0; i--) {
751*6557Sfr41279 		rem = ((rem << (BIG_CHUNK_SIZE / 2)) |
752*6557Sfr41279 		    (aa->value[i] >> (BIG_CHUNK_SIZE / 2))) % b;
753*6557Sfr41279 		rem = ((rem << (BIG_CHUNK_SIZE / 2)) |
754*6557Sfr41279 		    (aa->value[i] & BIG_CHUNK_LOWHALFBITS)) % b;
7550Sstevel@tonic-gate 	}
756*6557Sfr41279 
757*6557Sfr41279 	return ((uint32_t)rem);
7580Sstevel@tonic-gate }
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate /*
762*6557Sfr41279  * result = aa - (2^BIG_CHUNK_SIZE)^lendiff * bb
7630Sstevel@tonic-gate  * result->size should be at least aa->len at entry
7640Sstevel@tonic-gate  * aa, bb, and result should be positive
7650Sstevel@tonic-gate  */
7660Sstevel@tonic-gate void
7670Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
7680Sstevel@tonic-gate {
7690Sstevel@tonic-gate 	int i, lendiff;
7700Sstevel@tonic-gate 	BIGNUM res1, aa1;
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
7730Sstevel@tonic-gate 	res1.size = result->size - lendiff;
7740Sstevel@tonic-gate 	res1.malloced = 0;
7750Sstevel@tonic-gate 	res1.value = result->value + lendiff;
7760Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
7770Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
7780Sstevel@tonic-gate 	aa1.len = bb->len;
7790Sstevel@tonic-gate 	aa1.sign = 1;
7800Sstevel@tonic-gate 	(void) big_sub_pos(&res1, &aa1, bb);
7810Sstevel@tonic-gate 	if (result->value != aa->value) {
7820Sstevel@tonic-gate 		for (i = 0; i < lendiff; i++) {
7830Sstevel@tonic-gate 			result->value[i] = aa->value[i];
7840Sstevel@tonic-gate 		}
7850Sstevel@tonic-gate 	}
7860Sstevel@tonic-gate 	result->len = aa->len;
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate /*
7910Sstevel@tonic-gate  * returns 1, 0, or -1 depending on whether |aa| > , ==, or <
792*6557Sfr41279  *					(2^BIG_CHUNK_SIZE)^lendiff * |bb|
7930Sstevel@tonic-gate  * aa->len should be >= bb->len
7940Sstevel@tonic-gate  */
7950Sstevel@tonic-gate int
7960Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb)
7970Sstevel@tonic-gate {
7980Sstevel@tonic-gate 	int lendiff;
7990Sstevel@tonic-gate 	BIGNUM aa1;
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
8020Sstevel@tonic-gate 	aa1.len = bb->len;
8030Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
8040Sstevel@tonic-gate 	aa1.malloced = 0;
8050Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
8060Sstevel@tonic-gate 	return (big_cmp_abs(&aa1, bb));
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate /*
811*6557Sfr41279  * result = aa * b where b is a max. (BIG_CHUNK_SIZE / 2)-bit positive integer.
8120Sstevel@tonic-gate  * result should have enough space allocated.
8130Sstevel@tonic-gate  */
814*6557Sfr41279 static void
815*6557Sfr41279 big_mulhalf_low(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b)
8160Sstevel@tonic-gate {
817*6557Sfr41279 	int		i;
818*6557Sfr41279 	BIG_CHUNK_TYPE	t1, t2, ai, cy;
819*6557Sfr41279 	BIG_CHUNK_TYPE	*a, *r;
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	a = aa->value;
8220Sstevel@tonic-gate 	r = result->value;
8230Sstevel@tonic-gate 	cy = 0;
8240Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
8250Sstevel@tonic-gate 		ai = a[i];
826*6557Sfr41279 		t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy;
827*6557Sfr41279 		t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b +
828*6557Sfr41279 		    (t1 >> (BIG_CHUNK_SIZE / 2));
829*6557Sfr41279 		r[i] = (t1 & BIG_CHUNK_LOWHALFBITS) |
830*6557Sfr41279 		    (t2 << (BIG_CHUNK_SIZE / 2));
831*6557Sfr41279 		cy = t2 >> (BIG_CHUNK_SIZE / 2);
8320Sstevel@tonic-gate 	}
8330Sstevel@tonic-gate 	r[i] = cy;
8340Sstevel@tonic-gate 	result->len = aa->len + 1;
8350Sstevel@tonic-gate 	result->sign = aa->sign;
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate /*
840*6557Sfr41279  * result = aa * b * 2^(BIG_CHUNK_SIZE / 2) where b is a max.
841*6557Sfr41279  * (BIG_CHUNK_SIZE / 2)-bit positive integer.
8420Sstevel@tonic-gate  * result should have enough space allocated.
8430Sstevel@tonic-gate  */
844*6557Sfr41279 static void
845*6557Sfr41279 big_mulhalf_high(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b)
8460Sstevel@tonic-gate {
847*6557Sfr41279 	int		i;
848*6557Sfr41279 	BIG_CHUNK_TYPE	t1, t2, ai, cy, ri;
849*6557Sfr41279 	BIG_CHUNK_TYPE	*a, *r;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	a = aa->value;
8520Sstevel@tonic-gate 	r = result->value;
8530Sstevel@tonic-gate 	cy = 0;
8540Sstevel@tonic-gate 	ri = 0;
8550Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
8560Sstevel@tonic-gate 		ai = a[i];
857*6557Sfr41279 		t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy;
858*6557Sfr41279 		t2 = (ai >>  (BIG_CHUNK_SIZE / 2)) * b +
859*6557Sfr41279 		    (t1 >>  (BIG_CHUNK_SIZE / 2));
860*6557Sfr41279 		r[i] = (t1 <<  (BIG_CHUNK_SIZE / 2)) + ri;
861*6557Sfr41279 		ri = t2 & BIG_CHUNK_LOWHALFBITS;
862*6557Sfr41279 		cy = t2 >> (BIG_CHUNK_SIZE / 2);
8630Sstevel@tonic-gate 	}
864*6557Sfr41279 	r[i] = (cy <<  (BIG_CHUNK_SIZE / 2)) + ri;
8650Sstevel@tonic-gate 	result->len = aa->len + 1;
8660Sstevel@tonic-gate 	result->sign = aa->sign;
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate 
869*6557Sfr41279 
8700Sstevel@tonic-gate /* it is assumed that result->size is big enough */
8710Sstevel@tonic-gate void
8720Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs)
8730Sstevel@tonic-gate {
874*6557Sfr41279 	int		i;
875*6557Sfr41279 	BIG_CHUNK_TYPE	cy, ai;
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	if (offs == 0) {
8780Sstevel@tonic-gate 		if (result != aa) {
8790Sstevel@tonic-gate 			(void) big_copy(result, aa);
8800Sstevel@tonic-gate 		}
8810Sstevel@tonic-gate 		return;
8820Sstevel@tonic-gate 	}
8830Sstevel@tonic-gate 	cy = 0;
8840Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
8850Sstevel@tonic-gate 		ai = aa->value[i];
8860Sstevel@tonic-gate 		result->value[i] = (ai << offs) | cy;
887*6557Sfr41279 		cy = ai >> (BIG_CHUNK_SIZE - offs);
8880Sstevel@tonic-gate 	}
8890Sstevel@tonic-gate 	if (cy != 0) {
8900Sstevel@tonic-gate 		result->len = aa->len + 1;
8910Sstevel@tonic-gate 		result->value[result->len - 1] = cy;
8920Sstevel@tonic-gate 	} else {
8930Sstevel@tonic-gate 		result->len = aa->len;
8940Sstevel@tonic-gate 	}
8950Sstevel@tonic-gate 	result->sign = aa->sign;
8960Sstevel@tonic-gate }
8970Sstevel@tonic-gate 
898*6557Sfr41279 
8990Sstevel@tonic-gate /* it is assumed that result->size is big enough */
9000Sstevel@tonic-gate void
9010Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs)
9020Sstevel@tonic-gate {
903*6557Sfr41279 	int		 i;
904*6557Sfr41279 	BIG_CHUNK_TYPE	cy, ai;
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	if (offs == 0) {
9070Sstevel@tonic-gate 		if (result != aa) {
9080Sstevel@tonic-gate 			(void) big_copy(result, aa);
9090Sstevel@tonic-gate 		}
9100Sstevel@tonic-gate 		return;
9110Sstevel@tonic-gate 	}
9120Sstevel@tonic-gate 	cy = aa->value[0] >> offs;
9130Sstevel@tonic-gate 	for (i = 1; i < aa->len; i++) {
9140Sstevel@tonic-gate 		ai = aa->value[i];
915*6557Sfr41279 		result->value[i-1] = (ai << (BIG_CHUNK_SIZE - offs)) | cy;
9160Sstevel@tonic-gate 		cy = ai >> offs;
9170Sstevel@tonic-gate 	}
9180Sstevel@tonic-gate 	result->len = aa->len;
9190Sstevel@tonic-gate 	result->value[result->len - 1] = cy;
9200Sstevel@tonic-gate 	result->sign = aa->sign;
9210Sstevel@tonic-gate }
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate /*
9250Sstevel@tonic-gate  * result = aa/bb   remainder = aa mod bb
9260Sstevel@tonic-gate  * it is assumed that aa and bb are positive
9270Sstevel@tonic-gate  */
9280Sstevel@tonic-gate BIG_ERR_CODE
9290Sstevel@tonic-gate big_div_pos_fast(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb)
9300Sstevel@tonic-gate {
931*6557Sfr41279 	BIG_ERR_CODE	err = BIG_OK;
932*6557Sfr41279 	int		i, alen, blen, tlen, rlen, offs;
933*6557Sfr41279 	BIG_CHUNK_TYPE	higha, highb, coeff;
934*6557Sfr41279 	BIG_CHUNK_TYPE	*a, *b;
935*6557Sfr41279 	BIGNUM		bbhigh, bblow, tresult, tmp1, tmp2;
936*6557Sfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
937*6557Sfr41279 	BIG_CHUNK_TYPE	tmp2value[BIGTMPSIZE];
938*6557Sfr41279 	BIG_CHUNK_TYPE	tresultvalue[BIGTMPSIZE];
939*6557Sfr41279 	BIG_CHUNK_TYPE	bblowvalue[BIGTMPSIZE];
940*6557Sfr41279 	BIG_CHUNK_TYPE	bbhighvalue[BIGTMPSIZE];
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	a = aa->value;
9430Sstevel@tonic-gate 	b = bb->value;
9440Sstevel@tonic-gate 	alen = aa->len;
9450Sstevel@tonic-gate 	blen = bb->len;
946*6557Sfr41279 	while ((alen > 1) && (a[alen - 1] == 0)) {
947*6557Sfr41279 		alen = alen - 1;
948*6557Sfr41279 	}
9490Sstevel@tonic-gate 	aa->len = alen;
950*6557Sfr41279 	while ((blen > 1) && (b[blen - 1] == 0)) {
951*6557Sfr41279 		blen = blen - 1;
952*6557Sfr41279 	}
9530Sstevel@tonic-gate 	bb->len = blen;
954*6557Sfr41279 	if ((blen == 1) && (b[0] == 0)) {
9550Sstevel@tonic-gate 		return (BIG_DIV_BY_0);
956*6557Sfr41279 	}
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	if (big_cmp_abs(aa, bb) < 0) {
9590Sstevel@tonic-gate 		if ((remainder != NULL) &&
960*6557Sfr41279 		    ((err = big_copy(remainder, aa)) != BIG_OK)) {
9610Sstevel@tonic-gate 			return (err);
962*6557Sfr41279 		}
9630Sstevel@tonic-gate 		if (result != NULL) {
9640Sstevel@tonic-gate 			result->len = 1;
9650Sstevel@tonic-gate 			result->sign = 1;
9660Sstevel@tonic-gate 			result->value[0] = 0;
9670Sstevel@tonic-gate 		}
9680Sstevel@tonic-gate 		return (BIG_OK);
9690Sstevel@tonic-gate 	}
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	if ((err = big_init1(&bblow, blen + 1,
9720Sstevel@tonic-gate 	    bblowvalue, arraysize(bblowvalue))) != BIG_OK)
9730Sstevel@tonic-gate 		return (err);
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	if ((err = big_init1(&bbhigh, blen + 1,
9760Sstevel@tonic-gate 	    bbhighvalue, arraysize(bbhighvalue))) != BIG_OK)
9770Sstevel@tonic-gate 		goto ret1;
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	if ((err = big_init1(&tmp1, alen + 2,
9800Sstevel@tonic-gate 	    tmp1value, arraysize(tmp1value))) != BIG_OK)
9810Sstevel@tonic-gate 		goto ret2;
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, blen + 2,
9840Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
9850Sstevel@tonic-gate 		goto ret3;
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	if ((err = big_init1(&tresult, alen - blen + 2,
9880Sstevel@tonic-gate 	    tresultvalue, arraysize(tresultvalue))) != BIG_OK)
9890Sstevel@tonic-gate 		goto ret4;
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	offs = 0;
992*6557Sfr41279 	highb = b[blen - 1];
993*6557Sfr41279 	if (highb >= (BIG_CHUNK_HALF_HIGHBIT << 1)) {
994*6557Sfr41279 		highb = highb >> (BIG_CHUNK_SIZE / 2);
995*6557Sfr41279 		offs = (BIG_CHUNK_SIZE / 2);
9960Sstevel@tonic-gate 	}
997*6557Sfr41279 	while ((highb & BIG_CHUNK_HALF_HIGHBIT) == 0) {
998*6557Sfr41279 		highb = highb << 1;
9990Sstevel@tonic-gate 		offs++;
10000Sstevel@tonic-gate 	}
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	big_shiftleft(&bblow, bb, offs);
1003*6557Sfr41279 
1004*6557Sfr41279 	if (offs <= (BIG_CHUNK_SIZE / 2 - 1)) {
1005*6557Sfr41279 		big_shiftleft(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2);
10060Sstevel@tonic-gate 	} else {
1007*6557Sfr41279 		big_shiftright(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2);
10080Sstevel@tonic-gate 	}
10090Sstevel@tonic-gate 	if (bbhigh.value[bbhigh.len - 1] == 0) {
10100Sstevel@tonic-gate 		bbhigh.len--;
10110Sstevel@tonic-gate 	} else {
10120Sstevel@tonic-gate 		bbhigh.value[bbhigh.len] = 0;
10130Sstevel@tonic-gate 	}
10140Sstevel@tonic-gate 
1015*6557Sfr41279 	highb = bblow.value[bblow.len - 1];
1016*6557Sfr41279 
10170Sstevel@tonic-gate 	big_shiftleft(&tmp1, aa, offs);
10180Sstevel@tonic-gate 	rlen = tmp1.len - bblow.len + 1;
10190Sstevel@tonic-gate 	tresult.len = rlen;
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	tmp1.len++;
10220Sstevel@tonic-gate 	tlen = tmp1.len;
10230Sstevel@tonic-gate 	tmp1.value[tmp1.len - 1] = 0;
10240Sstevel@tonic-gate 	for (i = 0; i < rlen; i++) {
1025*6557Sfr41279 		higha = (tmp1.value[tlen - 1] << (BIG_CHUNK_SIZE / 2)) +
1026*6557Sfr41279 		    (tmp1.value[tlen - 2] >> (BIG_CHUNK_SIZE / 2));
10270Sstevel@tonic-gate 		coeff = higha / (highb + 1);
1028*6557Sfr41279 		big_mulhalf_high(&tmp2, &bblow, coeff);
10290Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
10300Sstevel@tonic-gate 		bbhigh.len++;
10310Sstevel@tonic-gate 		while (tmp1.value[tlen - 1] > 0) {
10320Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
10330Sstevel@tonic-gate 			coeff++;
10340Sstevel@tonic-gate 		}
10350Sstevel@tonic-gate 		bbhigh.len--;
10360Sstevel@tonic-gate 		tlen--;
10370Sstevel@tonic-gate 		tmp1.len--;
10380Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) {
10390Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
10400Sstevel@tonic-gate 			coeff++;
10410Sstevel@tonic-gate 		}
1042*6557Sfr41279 		tresult.value[rlen - i - 1] = coeff << (BIG_CHUNK_SIZE / 2);
10430Sstevel@tonic-gate 		higha = tmp1.value[tlen - 1];
10440Sstevel@tonic-gate 		coeff = higha / (highb + 1);
1045*6557Sfr41279 		big_mulhalf_low(&tmp2, &bblow, coeff);
10460Sstevel@tonic-gate 		tmp2.len--;
10470Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
10480Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bblow) >= 0) {
10490Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bblow);
10500Sstevel@tonic-gate 			coeff++;
10510Sstevel@tonic-gate 		}
10520Sstevel@tonic-gate 		tresult.value[rlen - i - 1] =
10530Sstevel@tonic-gate 		    tresult.value[rlen - i - 1] + coeff;
10540Sstevel@tonic-gate 	}
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 	big_shiftright(&tmp1, &tmp1, offs);
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	err = BIG_OK;
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 	if ((remainder != NULL) &&
10610Sstevel@tonic-gate 	    ((err = big_copy(remainder, &tmp1)) != BIG_OK))
10620Sstevel@tonic-gate 		goto ret;
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	if (result != NULL)
10650Sstevel@tonic-gate 		err = big_copy(result, &tresult);
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate ret:
10680Sstevel@tonic-gate 	big_finish(&tresult);
10690Sstevel@tonic-gate ret4:
10700Sstevel@tonic-gate 	big_finish(&tmp1);
10710Sstevel@tonic-gate ret3:
10720Sstevel@tonic-gate 	big_finish(&tmp2);
10730Sstevel@tonic-gate ret2:
10740Sstevel@tonic-gate 	big_finish(&bbhigh);
10750Sstevel@tonic-gate ret1:
10760Sstevel@tonic-gate 	big_finish(&bblow);
10770Sstevel@tonic-gate 	return (err);
10780Sstevel@tonic-gate }
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate /*
10810Sstevel@tonic-gate  * If there is no processor-specific integer implementation of
10820Sstevel@tonic-gate  * the lower level multiply functions, then this code is provided
10830Sstevel@tonic-gate  * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and
10840Sstevel@tonic-gate  * big_sqr_vec().
10850Sstevel@tonic-gate  *
10860Sstevel@tonic-gate  * There are two generic implementations.  One that assumes that
10870Sstevel@tonic-gate  * there is hardware and C compiler support for a 32 x 32 --> 64
10880Sstevel@tonic-gate  * bit unsigned multiply, but otherwise is not specific to any
10890Sstevel@tonic-gate  * processor, platform, or ISA.
10900Sstevel@tonic-gate  *
10910Sstevel@tonic-gate  * The other makes very few assumptions about hardware capabilities.
10920Sstevel@tonic-gate  * It does not even assume that there is any implementation of a
10930Sstevel@tonic-gate  * 32 x 32 --> 64 bit multiply that is accessible to C code and
10940Sstevel@tonic-gate  * appropriate to use.  It falls constructs 32 x 32 --> 64 bit
10950Sstevel@tonic-gate  * multiplies from 16 x 16 --> 32 bit multiplies.
10960Sstevel@tonic-gate  *
10970Sstevel@tonic-gate  */
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate #if !defined(PSR_MUL)
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate #ifdef UMUL64
11020Sstevel@tonic-gate 
1103*6557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
1104*6557Sfr41279 
11050Sstevel@tonic-gate #define	UNROLL8
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_PREFETCH(R) \
11080Sstevel@tonic-gate 	p = pf * d; \
11090Sstevel@tonic-gate 	pf = (uint64_t)a[R+1]; \
11100Sstevel@tonic-gate 	t = p + cy; \
11110Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11120Sstevel@tonic-gate 	cy = t >> 32
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_NOPREFETCH(R) \
11150Sstevel@tonic-gate 	p = pf * d; \
11160Sstevel@tonic-gate 	t = p + cy; \
11170Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11180Sstevel@tonic-gate 	cy = t >> 32
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_PREFETCH(R) \
11210Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
11220Sstevel@tonic-gate 	p = pf * d; \
11230Sstevel@tonic-gate 	pf = (uint64_t)a[R+1]; \
11240Sstevel@tonic-gate 	t = p + t + cy; \
11250Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11260Sstevel@tonic-gate 	cy = t >> 32
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_NOPREFETCH(R) \
11290Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
11300Sstevel@tonic-gate 	p = pf * d; \
11310Sstevel@tonic-gate 	t = p + t + cy; \
11320Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11330Sstevel@tonic-gate 	cy = t >> 32
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate #ifdef UNROLL8
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate #define	UNROLL 8
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate /*
11400Sstevel@tonic-gate  * r = a * b
11410Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
11420Sstevel@tonic-gate  */
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate uint32_t
11450Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
11460Sstevel@tonic-gate {
11470Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	if (len == 0)
11500Sstevel@tonic-gate 		return (0);
11510Sstevel@tonic-gate 	cy = 0;
11520Sstevel@tonic-gate 	d = (uint64_t)b;
11530Sstevel@tonic-gate 	pf = (uint64_t)a[0];
11540Sstevel@tonic-gate 	while (len > UNROLL) {
11550Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
11560Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
11570Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
11580Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
11590Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
11600Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
11610Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
11620Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(7);
11630Sstevel@tonic-gate 		r += UNROLL;
11640Sstevel@tonic-gate 		a += UNROLL;
11650Sstevel@tonic-gate 		len -= UNROLL;
11660Sstevel@tonic-gate 	}
11670Sstevel@tonic-gate 	if (len == UNROLL) {
11680Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
11690Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
11700Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
11710Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
11720Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
11730Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
11740Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
11750Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(7);
11760Sstevel@tonic-gate 		return ((uint32_t)cy);
11770Sstevel@tonic-gate 	}
11780Sstevel@tonic-gate 	while (len > 1) {
11790Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
11800Sstevel@tonic-gate 		++r;
11810Sstevel@tonic-gate 		++a;
11820Sstevel@tonic-gate 		--len;
11830Sstevel@tonic-gate 	}
11840Sstevel@tonic-gate 	if (len > 0) {
11850Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(0);
11860Sstevel@tonic-gate 	}
11870Sstevel@tonic-gate 	return ((uint32_t)cy);
11880Sstevel@tonic-gate }
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate /*
11910Sstevel@tonic-gate  * r += a * b
11920Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
11930Sstevel@tonic-gate  */
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate uint32_t
11960Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
11970Sstevel@tonic-gate {
11980Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 	if (len == 0)
12010Sstevel@tonic-gate 		return (0);
12020Sstevel@tonic-gate 	cy = 0;
12030Sstevel@tonic-gate 	d = (uint64_t)b;
12040Sstevel@tonic-gate 	pf = (uint64_t)a[0];
12050Sstevel@tonic-gate 	while (len > 8) {
12060Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12070Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
12080Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
12090Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
12100Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
12110Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
12120Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
12130Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(7);
12140Sstevel@tonic-gate 		r += 8;
12150Sstevel@tonic-gate 		a += 8;
12160Sstevel@tonic-gate 		len -= 8;
12170Sstevel@tonic-gate 	}
12180Sstevel@tonic-gate 	if (len == 8) {
12190Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12200Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
12210Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
12220Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
12230Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
12240Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
12250Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
12260Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(7);
12270Sstevel@tonic-gate 		return ((uint32_t)cy);
12280Sstevel@tonic-gate 	}
12290Sstevel@tonic-gate 	while (len > 1) {
12300Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12310Sstevel@tonic-gate 		++r;
12320Sstevel@tonic-gate 		++a;
12330Sstevel@tonic-gate 		--len;
12340Sstevel@tonic-gate 	}
12350Sstevel@tonic-gate 	if (len > 0) {
12360Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(0);
12370Sstevel@tonic-gate 	}
12380Sstevel@tonic-gate 	return ((uint32_t)cy);
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate #endif /* UNROLL8 */
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate void
12430Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
12440Sstevel@tonic-gate {
12450Sstevel@tonic-gate 	uint32_t *tr, *ta;
12460Sstevel@tonic-gate 	int tlen, row, col;
12470Sstevel@tonic-gate 	uint64_t p, s, t, t2, cy;
12480Sstevel@tonic-gate 	uint32_t d;
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	tr = r + 1;
12510Sstevel@tonic-gate 	ta = a;
12520Sstevel@tonic-gate 	tlen = len - 1;
12530Sstevel@tonic-gate 	tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]);
12540Sstevel@tonic-gate 	while (--tlen > 0) {
12550Sstevel@tonic-gate 		tr += 2;
12560Sstevel@tonic-gate 		++ta;
12570Sstevel@tonic-gate 		tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]);
12580Sstevel@tonic-gate 	}
12590Sstevel@tonic-gate 	s = (uint64_t)a[0];
12600Sstevel@tonic-gate 	s = s * s;
12610Sstevel@tonic-gate 	r[0] = (uint32_t)s;
12620Sstevel@tonic-gate 	cy = s >> 32;
12630Sstevel@tonic-gate 	p = ((uint64_t)r[1] << 1) + cy;
12640Sstevel@tonic-gate 	r[1] = (uint32_t)p;
12650Sstevel@tonic-gate 	cy = p >> 32;
12660Sstevel@tonic-gate 	row = 1;
12670Sstevel@tonic-gate 	col = 2;
12680Sstevel@tonic-gate 	while (row < len) {
12690Sstevel@tonic-gate 		s = (uint64_t)a[row];
12700Sstevel@tonic-gate 		s = s * s;
12710Sstevel@tonic-gate 		p = (uint64_t)r[col] << 1;
12720Sstevel@tonic-gate 		t = p + s;
12730Sstevel@tonic-gate 		d = (uint32_t)t;
12740Sstevel@tonic-gate 		t2 = (uint64_t)d + cy;
12750Sstevel@tonic-gate 		r[col] = (uint32_t)t2;
12760Sstevel@tonic-gate 		cy = (t >> 32) + (t2 >> 32);
12770Sstevel@tonic-gate 		if (row == len - 1)
12780Sstevel@tonic-gate 			break;
12790Sstevel@tonic-gate 		p = ((uint64_t)r[col+1] << 1) + cy;
12800Sstevel@tonic-gate 		r[col+1] = (uint32_t)p;
12810Sstevel@tonic-gate 		cy = p >> 32;
12820Sstevel@tonic-gate 		++row;
12830Sstevel@tonic-gate 		col += 2;
12840Sstevel@tonic-gate 	}
12850Sstevel@tonic-gate 	r[col+1] = (uint32_t)cy;
12860Sstevel@tonic-gate }
12870Sstevel@tonic-gate 
1288*6557Sfr41279 #else /* BIG_CHUNK_SIZE == 64 */
1289*6557Sfr41279 
1290*6557Sfr41279 /*
1291*6557Sfr41279  * r = r + a * digit, r and a are vectors of length len
1292*6557Sfr41279  * returns the carry digit
1293*6557Sfr41279  */
1294*6557Sfr41279 BIG_CHUNK_TYPE
1295*6557Sfr41279 big_mul_add_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len,
1296*6557Sfr41279     BIG_CHUNK_TYPE digit)
1297*6557Sfr41279 {
1298*6557Sfr41279 	BIG_CHUNK_TYPE	cy, cy1, retcy, dlow, dhigh;
1299*6557Sfr41279 	int		i;
1300*6557Sfr41279 
1301*6557Sfr41279 	cy1 = 0;
1302*6557Sfr41279 	dlow = digit & BIG_CHUNK_LOWHALFBITS;
1303*6557Sfr41279 	dhigh = digit >> (BIG_CHUNK_SIZE / 2);
1304*6557Sfr41279 	for (i = 0; i < len; i++) {
1305*6557Sfr41279 		cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
1306*6557Sfr41279 		    dlow * (a[i] & BIG_CHUNK_LOWHALFBITS) +
1307*6557Sfr41279 		    (r[i] & BIG_CHUNK_LOWHALFBITS);
1308*6557Sfr41279 		cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) +
1309*6557Sfr41279 		    dlow * (a[i] >> (BIG_CHUNK_SIZE / 2)) +
1310*6557Sfr41279 		    (r[i] >> (BIG_CHUNK_SIZE / 2));
1311*6557Sfr41279 		r[i] = (cy & BIG_CHUNK_LOWHALFBITS) |
1312*6557Sfr41279 		    (cy1 << (BIG_CHUNK_SIZE / 2));
1313*6557Sfr41279 	}
1314*6557Sfr41279 	retcy = cy1 >> (BIG_CHUNK_SIZE / 2);
1315*6557Sfr41279 
1316*6557Sfr41279 	cy1 = r[0] & BIG_CHUNK_LOWHALFBITS;
1317*6557Sfr41279 	for (i = 0; i < len - 1; i++) {
1318*6557Sfr41279 		cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
1319*6557Sfr41279 		    dhigh * (a[i] & BIG_CHUNK_LOWHALFBITS) +
1320*6557Sfr41279 		    (r[i] >> (BIG_CHUNK_SIZE / 2));
1321*6557Sfr41279 		r[i] = (cy1 & BIG_CHUNK_LOWHALFBITS) |
1322*6557Sfr41279 		    (cy << (BIG_CHUNK_SIZE / 2));
1323*6557Sfr41279 		cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) +
1324*6557Sfr41279 		    dhigh * (a[i] >> (BIG_CHUNK_SIZE / 2)) +
1325*6557Sfr41279 		    (r[i + 1] & BIG_CHUNK_LOWHALFBITS);
1326*6557Sfr41279 	}
1327*6557Sfr41279 	cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
1328*6557Sfr41279 	    dhigh * (a[len - 1] & BIG_CHUNK_LOWHALFBITS) +
1329*6557Sfr41279 	    (r[len - 1] >> (BIG_CHUNK_SIZE / 2));
1330*6557Sfr41279 	r[len - 1] = (cy1 & BIG_CHUNK_LOWHALFBITS) |
1331*6557Sfr41279 	    (cy << (BIG_CHUNK_SIZE / 2));
1332*6557Sfr41279 	retcy = (cy >> (BIG_CHUNK_SIZE / 2)) +
1333*6557Sfr41279 	    dhigh * (a[len - 1] >> (BIG_CHUNK_SIZE / 2)) + retcy;
1334*6557Sfr41279 
1335*6557Sfr41279 	return (retcy);
1336*6557Sfr41279 }
1337*6557Sfr41279 
1338*6557Sfr41279 
1339*6557Sfr41279 /*
1340*6557Sfr41279  * r = a * digit, r and a are vectors of length len
1341*6557Sfr41279  * returns the carry digit
1342*6557Sfr41279  */
1343*6557Sfr41279 BIG_CHUNK_TYPE
1344*6557Sfr41279 big_mul_set_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len,
1345*6557Sfr41279     BIG_CHUNK_TYPE digit)
1346*6557Sfr41279 {
1347*6557Sfr41279 	int	i;
1348*6557Sfr41279 
1349*6557Sfr41279 	ASSERT(r != a);
1350*6557Sfr41279 	for (i = 0; i < len; i++) {
1351*6557Sfr41279 		r[i] = 0;
1352*6557Sfr41279 	}
1353*6557Sfr41279 	return (big_mul_add_vec(r, a, len, digit));
1354*6557Sfr41279 }
1355*6557Sfr41279 
1356*6557Sfr41279 void
1357*6557Sfr41279 big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len)
1358*6557Sfr41279 {
1359*6557Sfr41279 	int i;
1360*6557Sfr41279 
1361*6557Sfr41279 	ASSERT(r != a);
1362*6557Sfr41279 	r[len] = big_mul_set_vec(r, a, len, a[0]);
1363*6557Sfr41279 	for (i = 1; i < len; ++i)
1364*6557Sfr41279 		r[len + i] = big_mul_add_vec(r+i, a, len, a[i]);
1365*6557Sfr41279 }
1366*6557Sfr41279 
1367*6557Sfr41279 #endif /* BIG_CHUNK_SIZE == 32/64 */
1368*6557Sfr41279 
13690Sstevel@tonic-gate #else /* ! UMUL64 */
13700Sstevel@tonic-gate 
1371*6557Sfr41279 #if (BIG_CHUNK_SIZE != 32)
1372*6557Sfr41279 #error Don't use 64-bit chunks without defining UMUL64
1373*6557Sfr41279 #endif
1374*6557Sfr41279 
1375*6557Sfr41279 
13760Sstevel@tonic-gate /*
13770Sstevel@tonic-gate  * r = r + a * digit, r and a are vectors of length len
13780Sstevel@tonic-gate  * returns the carry digit
13790Sstevel@tonic-gate  */
13800Sstevel@tonic-gate uint32_t
13810Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
13820Sstevel@tonic-gate {
13830Sstevel@tonic-gate 	uint32_t cy, cy1, retcy, dlow, dhigh;
13840Sstevel@tonic-gate 	int i;
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 	cy1 = 0;
13870Sstevel@tonic-gate 	dlow = digit & 0xffff;
13880Sstevel@tonic-gate 	dhigh = digit >> 16;
13890Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
13900Sstevel@tonic-gate 		cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff);
13910Sstevel@tonic-gate 		cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16);
13920Sstevel@tonic-gate 		r[i] = (cy & 0xffff) | (cy1 << 16);
13930Sstevel@tonic-gate 	}
13940Sstevel@tonic-gate 	retcy = cy1 >> 16;
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate 	cy1 = r[0] & 0xffff;
13970Sstevel@tonic-gate 	for (i = 0; i < len - 1; i++) {
13980Sstevel@tonic-gate 		cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16);
13990Sstevel@tonic-gate 		r[i] = (cy1 & 0xffff) | (cy << 16);
14000Sstevel@tonic-gate 		cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff);
14010Sstevel@tonic-gate 	}
14020Sstevel@tonic-gate 	cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16);
14030Sstevel@tonic-gate 	r[len - 1] = (cy1 & 0xffff) | (cy << 16);
14040Sstevel@tonic-gate 	retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy;
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	return (retcy);
14070Sstevel@tonic-gate }
14080Sstevel@tonic-gate 
1409*6557Sfr41279 
14100Sstevel@tonic-gate /*
14110Sstevel@tonic-gate  * r = a * digit, r and a are vectors of length len
14120Sstevel@tonic-gate  * returns the carry digit
14130Sstevel@tonic-gate  */
14140Sstevel@tonic-gate uint32_t
14150Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
14160Sstevel@tonic-gate {
1417*6557Sfr41279 	int	i;
1418*6557Sfr41279 
1419*6557Sfr41279 	ASSERT(r != a);
1420*6557Sfr41279 	for (i = 0; i < len; i++) {
1421*6557Sfr41279 		r[i] = 0;
1422*6557Sfr41279 	}
1423*6557Sfr41279 
14240Sstevel@tonic-gate 	return (big_mul_add_vec(r, a, len, digit));
14250Sstevel@tonic-gate }
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate void
14280Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
14290Sstevel@tonic-gate {
14300Sstevel@tonic-gate 	int i;
14310Sstevel@tonic-gate 
1432*6557Sfr41279 	ASSERT(r != a);
14330Sstevel@tonic-gate 	r[len] = big_mul_set_vec(r, a, len, a[0]);
14340Sstevel@tonic-gate 	for (i = 1; i < len; ++i)
14350Sstevel@tonic-gate 		r[len + i] = big_mul_add_vec(r+i, a, len, a[i]);
14360Sstevel@tonic-gate }
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate #endif /* UMUL64 */
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate void
1441*6557Sfr41279 big_mul_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int alen,
1442*6557Sfr41279     BIG_CHUNK_TYPE *b, int blen)
14430Sstevel@tonic-gate {
14440Sstevel@tonic-gate 	int i;
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 	r[alen] = big_mul_set_vec(r, a, alen, b[0]);
14470Sstevel@tonic-gate 	for (i = 1; i < blen; ++i)
14480Sstevel@tonic-gate 		r[alen + i] = big_mul_add_vec(r+i, a, alen, b[i]);
14490Sstevel@tonic-gate }
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 
14520Sstevel@tonic-gate #endif /* ! PSR_MUL */
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate /*
14560Sstevel@tonic-gate  * result = aa * bb  result->value should be big enough to hold the result
14570Sstevel@tonic-gate  *
14580Sstevel@tonic-gate  * Implementation: Standard grammar school algorithm
14590Sstevel@tonic-gate  *
14600Sstevel@tonic-gate  */
14610Sstevel@tonic-gate BIG_ERR_CODE
14620Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
14630Sstevel@tonic-gate {
1464*6557Sfr41279 	BIGNUM		tmp1;
1465*6557Sfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
1466*6557Sfr41279 	BIG_CHUNK_TYPE	*r, *t, *a, *b;
1467*6557Sfr41279 	BIG_ERR_CODE	err;
1468*6557Sfr41279 	int		i, alen, blen, rsize, sign, diff;
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	if (aa == bb) {
14710Sstevel@tonic-gate 		diff = 0;
14720Sstevel@tonic-gate 	} else {
14730Sstevel@tonic-gate 		diff = big_cmp_abs(aa, bb);
14740Sstevel@tonic-gate 		if (diff < 0) {
14750Sstevel@tonic-gate 			BIGNUM *tt;
14760Sstevel@tonic-gate 			tt = aa;
14770Sstevel@tonic-gate 			aa = bb;
14780Sstevel@tonic-gate 			bb = tt;
14790Sstevel@tonic-gate 		}
14800Sstevel@tonic-gate 	}
14810Sstevel@tonic-gate 	a = aa->value;
14820Sstevel@tonic-gate 	b = bb->value;
14830Sstevel@tonic-gate 	alen = aa->len;
14840Sstevel@tonic-gate 	blen = bb->len;
1485*6557Sfr41279 	while ((alen > 1) && (a[alen - 1] == 0)) {
1486*6557Sfr41279 		alen--;
1487*6557Sfr41279 	}
14880Sstevel@tonic-gate 	aa->len = alen;
1489*6557Sfr41279 	while ((blen > 1) && (b[blen - 1] == 0)) {
1490*6557Sfr41279 		blen--;
1491*6557Sfr41279 	}
14920Sstevel@tonic-gate 	bb->len = blen;
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 	rsize = alen + blen;
14950Sstevel@tonic-gate 	if (result->size < rsize) {
14960Sstevel@tonic-gate 		err = big_extend(result, rsize);
1497*6557Sfr41279 		if (err != BIG_OK) {
14980Sstevel@tonic-gate 			return (err);
1499*6557Sfr41279 		}
15000Sstevel@tonic-gate 		/* aa or bb might be an alias to result */
15010Sstevel@tonic-gate 		a = aa->value;
15020Sstevel@tonic-gate 		b = bb->value;
15030Sstevel@tonic-gate 	}
15040Sstevel@tonic-gate 	r = result->value;
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) {
15070Sstevel@tonic-gate 		result->len = 1;
15080Sstevel@tonic-gate 		result->sign = 1;
15090Sstevel@tonic-gate 		r[0] = 0;
15100Sstevel@tonic-gate 		return (BIG_OK);
15110Sstevel@tonic-gate 	}
15120Sstevel@tonic-gate 	sign = aa->sign * bb->sign;
15130Sstevel@tonic-gate 	if ((alen == 1) && (a[0] == 1)) {
1514*6557Sfr41279 		for (i = 0; i < blen; i++) {
1515*6557Sfr41279 			r[i] = b[i];
1516*6557Sfr41279 		}
15170Sstevel@tonic-gate 		result->len = blen;
15180Sstevel@tonic-gate 		result->sign = sign;
15190Sstevel@tonic-gate 		return (BIG_OK);
15200Sstevel@tonic-gate 	}
15210Sstevel@tonic-gate 	if ((blen == 1) && (b[0] == 1)) {
1522*6557Sfr41279 		for (i = 0; i < alen; i++) {
1523*6557Sfr41279 			r[i] = a[i];
1524*6557Sfr41279 		}
15250Sstevel@tonic-gate 		result->len = alen;
15260Sstevel@tonic-gate 		result->sign = sign;
15270Sstevel@tonic-gate 		return (BIG_OK);
15280Sstevel@tonic-gate 	}
15290Sstevel@tonic-gate 
1530*6557Sfr41279 	if ((err = big_init1(&tmp1, rsize,
1531*6557Sfr41279 	    tmp1value, arraysize(tmp1value))) != BIG_OK) {
15320Sstevel@tonic-gate 		return (err);
1533*6557Sfr41279 	}
1534*6557Sfr41279 	(void) big_copy(&tmp1, aa);
15350Sstevel@tonic-gate 	t = tmp1.value;
1536*6557Sfr41279 
1537*6557Sfr41279 	for (i = 0; i < rsize; i++) {
1538*6557Sfr41279 		t[i] = 0;
1539*6557Sfr41279 	}
1540*6557Sfr41279 
1541*6557Sfr41279 	if (diff == 0 && alen > 2) {
15420Sstevel@tonic-gate 		BIG_SQR_VEC(t, a, alen);
1543*6557Sfr41279 	} else if (blen > 0) {
15440Sstevel@tonic-gate 		BIG_MUL_VEC(t, a, alen, b, blen);
1545*6557Sfr41279 	}
1546*6557Sfr41279 
1547*6557Sfr41279 	if (t[rsize - 1] == 0) {
1548*6557Sfr41279 		tmp1.len = rsize - 1;
1549*6557Sfr41279 	} else {
1550*6557Sfr41279 		tmp1.len = rsize;
1551*6557Sfr41279 	}
1552*6557Sfr41279 	if ((err = big_copy(result, &tmp1)) != BIG_OK) {
15530Sstevel@tonic-gate 		return (err);
1554*6557Sfr41279 	}
15550Sstevel@tonic-gate 	result->sign = sign;
15560Sstevel@tonic-gate 
1557*6557Sfr41279 	big_finish(&tmp1);
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 	return (BIG_OK);
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate /*
15640Sstevel@tonic-gate  * caller must ensure that  a < n,  b < n  and  ret->size >=  2 * n->len + 1
15650Sstevel@tonic-gate  * and that ret is not n
15660Sstevel@tonic-gate  */
15670Sstevel@tonic-gate BIG_ERR_CODE
1568*6557Sfr41279 big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, BIG_CHUNK_TYPE n0)
15690Sstevel@tonic-gate {
1570*6557Sfr41279 	int	i, j, nlen, needsubtract;
1571*6557Sfr41279 	BIG_CHUNK_TYPE	*nn, *rr;
1572*6557Sfr41279 	BIG_CHUNK_TYPE	digit, c;
1573*6557Sfr41279 	BIG_ERR_CODE	err;
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate 	nlen = n->len;
15760Sstevel@tonic-gate 	nn = n->value;
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	rr = ret->value;
15790Sstevel@tonic-gate 
1580*6557Sfr41279 	if ((err = big_mul(ret, a, b)) != BIG_OK) {
15810Sstevel@tonic-gate 		return (err);
1582*6557Sfr41279 	}
15830Sstevel@tonic-gate 
15840Sstevel@tonic-gate 	rr = ret->value;
1585*6557Sfr41279 	for (i = ret->len; i < 2 * nlen + 1; i++) {
1586*6557Sfr41279 		rr[i] = 0;
1587*6557Sfr41279 	}
15880Sstevel@tonic-gate 	for (i = 0; i < nlen; i++) {
15890Sstevel@tonic-gate 		digit = rr[i];
15900Sstevel@tonic-gate 		digit = digit * n0;
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 		c = BIG_MUL_ADD_VEC(rr + i, nn, nlen, digit);
15930Sstevel@tonic-gate 		j = i + nlen;
15940Sstevel@tonic-gate 		rr[j] += c;
15950Sstevel@tonic-gate 		while (rr[j] < c) {
15960Sstevel@tonic-gate 			rr[j + 1] += 1;
15970Sstevel@tonic-gate 			j++;
15980Sstevel@tonic-gate 			c = 1;
15990Sstevel@tonic-gate 		}
16000Sstevel@tonic-gate 	}
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 	needsubtract = 0;
16030Sstevel@tonic-gate 	if ((rr[2 * nlen]  != 0))
16040Sstevel@tonic-gate 		needsubtract = 1;
16050Sstevel@tonic-gate 	else {
16060Sstevel@tonic-gate 		for (i = 2 * nlen - 1; i >= nlen; i--) {
16070Sstevel@tonic-gate 			if (rr[i] > nn[i - nlen]) {
16080Sstevel@tonic-gate 				needsubtract = 1;
16090Sstevel@tonic-gate 				break;
1610*6557Sfr41279 			} else if (rr[i] < nn[i - nlen]) {
1611*6557Sfr41279 				break;
1612*6557Sfr41279 			}
16130Sstevel@tonic-gate 		}
16140Sstevel@tonic-gate 	}
16150Sstevel@tonic-gate 	if (needsubtract)
16160Sstevel@tonic-gate 		big_sub_vec(rr, rr + nlen, nn, nlen);
16170Sstevel@tonic-gate 	else {
1618*6557Sfr41279 		for (i = 0; i < nlen; i++) {
16190Sstevel@tonic-gate 			rr[i] = rr[i + nlen];
1620*6557Sfr41279 		}
16210Sstevel@tonic-gate 	}
1622*6557Sfr41279 	for (i = nlen - 1; (i >= 0) && (rr[i] == 0); i--)
1623*6557Sfr41279 		;
16240Sstevel@tonic-gate 	ret->len = i+1;
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate 	return (BIG_OK);
16270Sstevel@tonic-gate }
16280Sstevel@tonic-gate 
1629*6557Sfr41279 
1630*6557Sfr41279 BIG_CHUNK_TYPE
1631*6557Sfr41279 big_n0(BIG_CHUNK_TYPE n)
16320Sstevel@tonic-gate {
1633*6557Sfr41279 	int		i;
1634*6557Sfr41279 	BIG_CHUNK_TYPE	result, tmp;
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	result = 0;
1637*6557Sfr41279 	tmp = BIG_CHUNK_ALLBITS;
1638*6557Sfr41279 	for (i = 0; i < BIG_CHUNK_SIZE; i++) {
16390Sstevel@tonic-gate 		if ((tmp & 1) == 1) {
1640*6557Sfr41279 			result = (result >> 1) | BIG_CHUNK_HIGHBIT;
16410Sstevel@tonic-gate 			tmp = tmp - n;
1642*6557Sfr41279 		} else {
1643*6557Sfr41279 			result = (result >> 1);
1644*6557Sfr41279 		}
16450Sstevel@tonic-gate 		tmp = tmp >> 1;
16460Sstevel@tonic-gate 	}
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 	return (result);
16490Sstevel@tonic-gate }
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate int
16530Sstevel@tonic-gate big_numbits(BIGNUM *n)
16540Sstevel@tonic-gate {
1655*6557Sfr41279 	int		i, j;
1656*6557Sfr41279 	BIG_CHUNK_TYPE	t;
1657*6557Sfr41279 
1658*6557Sfr41279 	for (i = n->len - 1; i > 0; i--) {
1659*6557Sfr41279 		if (n->value[i] != 0) {
1660*6557Sfr41279 			break;
1661*6557Sfr41279 		}
1662*6557Sfr41279 	}
16630Sstevel@tonic-gate 	t = n->value[i];
1664*6557Sfr41279 	for (j = BIG_CHUNK_SIZE; j > 0; j--) {
1665*6557Sfr41279 		if ((t & BIG_CHUNK_HIGHBIT) == 0) {
16660Sstevel@tonic-gate 			t = t << 1;
1667*6557Sfr41279 		} else {
1668*6557Sfr41279 			return (BIG_CHUNK_SIZE * i + j);
1669*6557Sfr41279 		}
16700Sstevel@tonic-gate 	}
16710Sstevel@tonic-gate 	return (0);
16720Sstevel@tonic-gate }
16730Sstevel@tonic-gate 
1674*6557Sfr41279 
16750Sstevel@tonic-gate /* caller must make sure that a < n */
16760Sstevel@tonic-gate BIG_ERR_CODE
16770Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n)
16780Sstevel@tonic-gate {
1679*6557Sfr41279 	BIGNUM		rr;
1680*6557Sfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
1681*6557Sfr41279 	int		len, i;
1682*6557Sfr41279 	BIG_ERR_CODE	err;
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	rr.malloced = 0;
16850Sstevel@tonic-gate 	len = n->len;
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1,
1688*6557Sfr41279 	    rrvalue, arraysize(rrvalue))) != BIG_OK) {
16890Sstevel@tonic-gate 		return (err);
1690*6557Sfr41279 	}
1691*6557Sfr41279 
1692*6557Sfr41279 	for (i = 0; i < 2 * len; i++) {
1693*6557Sfr41279 		rr.value[i] = 0;
1694*6557Sfr41279 	}
16950Sstevel@tonic-gate 	rr.value[2 * len] = 1;
16960Sstevel@tonic-gate 	rr.len = 2 * len + 1;
1697*6557Sfr41279 	if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) {
16980Sstevel@tonic-gate 		goto ret;
1699*6557Sfr41279 	}
17000Sstevel@tonic-gate 	err = big_copy(result, &rr);
17010Sstevel@tonic-gate ret:
1702*6557Sfr41279 	big_finish(&rr);
17030Sstevel@tonic-gate 	return (err);
17040Sstevel@tonic-gate }
17050Sstevel@tonic-gate 
1706*6557Sfr41279 
17070Sstevel@tonic-gate /* caller must make sure that a < n */
17080Sstevel@tonic-gate BIG_ERR_CODE
1709*6557Sfr41279 big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, BIG_CHUNK_TYPE n0,
1710*6557Sfr41279     BIGNUM *n_rr)
17110Sstevel@tonic-gate {
1712*6557Sfr41279 	BIGNUM		rr;
1713*6557Sfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
1714*6557Sfr41279 	int		len, i;
1715*6557Sfr41279 	BIG_ERR_CODE	err;
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 	rr.malloced = 0;
17180Sstevel@tonic-gate 	len = n->len;
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue)))
1721*6557Sfr41279 	    != BIG_OK) {
1722*6557Sfr41279 		return (err);
1723*6557Sfr41279 	}
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 	if (n_rr == NULL) {
1726*6557Sfr41279 		for (i = 0; i < 2 * len; i++) {
1727*6557Sfr41279 			rr.value[i] = 0;
1728*6557Sfr41279 		}
17290Sstevel@tonic-gate 		rr.value[2 * len] = 1;
17300Sstevel@tonic-gate 		rr.len = 2 * len + 1;
1731*6557Sfr41279 		if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) {
17320Sstevel@tonic-gate 			goto ret;
1733*6557Sfr41279 		}
17340Sstevel@tonic-gate 		n_rr = &rr;
17350Sstevel@tonic-gate 	}
17360Sstevel@tonic-gate 
1737*6557Sfr41279 	if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK) {
17380Sstevel@tonic-gate 		goto ret;
1739*6557Sfr41279 	}
17400Sstevel@tonic-gate 	err = big_copy(result, &rr);
1741*6557Sfr41279 
17420Sstevel@tonic-gate ret:
1743*6557Sfr41279 	big_finish(&rr);
17440Sstevel@tonic-gate 	return (err);
17450Sstevel@tonic-gate }
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 
1748*6557Sfr41279 #ifdef	USE_FLOATING_POINT
1749*6557Sfr41279 #define	big_modexp_ncp_float	big_modexp_ncp_sw
1750*6557Sfr41279 #else
1751*6557Sfr41279 #define	big_modexp_ncp_int	big_modexp_ncp_sw
1752*6557Sfr41279 #endif
1753*6557Sfr41279 
17540Sstevel@tonic-gate #define	MAX_EXP_BIT_GROUP_SIZE 6
17550Sstevel@tonic-gate #define	APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1))
17560Sstevel@tonic-gate 
1757*6557Sfr41279 /* ARGSUSED */
17580Sstevel@tonic-gate static BIG_ERR_CODE
1759*6557Sfr41279 big_modexp_ncp_int(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n,
1760*6557Sfr41279     BIGNUM *tmp, BIG_CHUNK_TYPE n0)
1761*6557Sfr41279 
17620Sstevel@tonic-gate {
1763*6557Sfr41279 	BIGNUM		apowers[APOWERS_MAX_SIZE];
1764*6557Sfr41279 	BIGNUM		tmp1;
1765*6557Sfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
1766*6557Sfr41279 	int		i, j, k, l, m, p;
1767*6557Sfr41279 	int		bit, bitind, bitcount, groupbits, apowerssize;
1768*6557Sfr41279 	int		nbits;
1769*6557Sfr41279 	BIG_ERR_CODE	err;
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 	nbits = big_numbits(e);
17720Sstevel@tonic-gate 	if (nbits < 50) {
17730Sstevel@tonic-gate 		groupbits = 1;
17740Sstevel@tonic-gate 		apowerssize = 1;
17750Sstevel@tonic-gate 	} else {
17760Sstevel@tonic-gate 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
17770Sstevel@tonic-gate 		apowerssize = 1 << (groupbits - 1);
17780Sstevel@tonic-gate 	}
17790Sstevel@tonic-gate 
1780*6557Sfr41279 
1781*6557Sfr41279 	if ((err = big_init1(&tmp1, 2 * n->len + 1,
1782*6557Sfr41279 	    tmp1value, arraysize(tmp1value))) != BIG_OK) {
17830Sstevel@tonic-gate 		return (err);
1784*6557Sfr41279 	}
1785*6557Sfr41279 
1786*6557Sfr41279 	/* set the malloced bit to help cleanup */
1787*6557Sfr41279 	for (i = 0; i < apowerssize; i++) {
1788*6557Sfr41279 		apowers[i].malloced = 0;
1789*6557Sfr41279 	}
1790*6557Sfr41279 	for (i = 0; i < apowerssize; i++) {
1791*6557Sfr41279 		if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) !=
1792*6557Sfr41279 		    BIG_OK) {
1793*6557Sfr41279 			goto ret;
1794*6557Sfr41279 		}
1795*6557Sfr41279 	}
1796*6557Sfr41279 
1797*6557Sfr41279 	(void) big_copy(&(apowers[0]), ma);
1798*6557Sfr41279 
1799*6557Sfr41279 	if ((err = big_mont_mul(&tmp1, ma, ma, n, n0)) != BIG_OK) {
1800*6557Sfr41279 		goto ret;
1801*6557Sfr41279 	}
1802*6557Sfr41279 	(void) big_copy(ma, &tmp1);
1803*6557Sfr41279 
1804*6557Sfr41279 	for (i = 1; i < apowerssize; i++) {
1805*6557Sfr41279 		if ((err = big_mont_mul(&tmp1, ma,
1806*6557Sfr41279 		    &(apowers[i-1]), n, n0)) != BIG_OK) {
1807*6557Sfr41279 			goto ret;
1808*6557Sfr41279 		}
1809*6557Sfr41279 		(void) big_copy(&apowers[i], &tmp1);
1810*6557Sfr41279 	}
1811*6557Sfr41279 
1812*6557Sfr41279 	bitind = nbits % BIG_CHUNK_SIZE;
1813*6557Sfr41279 	k = 0;
1814*6557Sfr41279 	l = 0;
1815*6557Sfr41279 	p = 0;
1816*6557Sfr41279 	bitcount = 0;
1817*6557Sfr41279 	for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) {
1818*6557Sfr41279 		for (j = bitind - 1; j >= 0; j--) {
1819*6557Sfr41279 			bit = (e->value[i] >> j) & 1;
1820*6557Sfr41279 			if ((bitcount == 0) && (bit == 0)) {
1821*6557Sfr41279 				if ((err = big_mont_mul(tmp,
1822*6557Sfr41279 				    tmp, tmp, n, n0)) != BIG_OK) {
1823*6557Sfr41279 					goto ret;
1824*6557Sfr41279 				}
1825*6557Sfr41279 			} else {
1826*6557Sfr41279 				bitcount++;
1827*6557Sfr41279 				p = p * 2 + bit;
1828*6557Sfr41279 				if (bit == 1) {
1829*6557Sfr41279 					k = k + l + 1;
1830*6557Sfr41279 					l = 0;
1831*6557Sfr41279 				} else {
1832*6557Sfr41279 					l++;
1833*6557Sfr41279 				}
1834*6557Sfr41279 				if (bitcount == groupbits) {
1835*6557Sfr41279 					for (m = 0; m < k; m++) {
1836*6557Sfr41279 						if ((err = big_mont_mul(tmp,
1837*6557Sfr41279 						    tmp, tmp, n, n0)) !=
1838*6557Sfr41279 						    BIG_OK) {
1839*6557Sfr41279 							goto ret;
1840*6557Sfr41279 						}
1841*6557Sfr41279 					}
1842*6557Sfr41279 					if ((err = big_mont_mul(tmp, tmp,
1843*6557Sfr41279 					    &(apowers[p >> (l + 1)]),
1844*6557Sfr41279 					    n, n0)) != BIG_OK) {
1845*6557Sfr41279 						goto ret;
1846*6557Sfr41279 					}
1847*6557Sfr41279 					for (m = 0; m < l; m++) {
1848*6557Sfr41279 						if ((err = big_mont_mul(tmp,
1849*6557Sfr41279 						    tmp, tmp, n, n0)) !=
1850*6557Sfr41279 						    BIG_OK) {
1851*6557Sfr41279 							goto ret;
1852*6557Sfr41279 						}
1853*6557Sfr41279 					}
1854*6557Sfr41279 					k = 0;
1855*6557Sfr41279 					l = 0;
1856*6557Sfr41279 					p = 0;
1857*6557Sfr41279 					bitcount = 0;
1858*6557Sfr41279 				}
1859*6557Sfr41279 			}
1860*6557Sfr41279 		}
1861*6557Sfr41279 		bitind = BIG_CHUNK_SIZE;
18620Sstevel@tonic-gate 	}
18630Sstevel@tonic-gate 
1864*6557Sfr41279 	for (m = 0; m < k; m++) {
1865*6557Sfr41279 		if ((err = big_mont_mul(tmp, tmp, tmp, n, n0)) != BIG_OK) {
1866*6557Sfr41279 			goto ret;
1867*6557Sfr41279 		}
1868*6557Sfr41279 	}
1869*6557Sfr41279 	if (p != 0) {
1870*6557Sfr41279 		if ((err = big_mont_mul(tmp, tmp,
1871*6557Sfr41279 		    &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK) {
1872*6557Sfr41279 			goto ret;
1873*6557Sfr41279 		}
1874*6557Sfr41279 	}
1875*6557Sfr41279 	for (m = 0; m < l; m++) {
1876*6557Sfr41279 		if ((err = big_mont_mul(result, tmp, tmp, n, n0)) != BIG_OK) {
1877*6557Sfr41279 			goto ret;
1878*6557Sfr41279 		}
1879*6557Sfr41279 	}
1880*6557Sfr41279 
1881*6557Sfr41279 ret:
1882*6557Sfr41279 	for (i = apowerssize - 1; i >= 0; i--) {
1883*6557Sfr41279 		big_finish(&(apowers[i]));
18840Sstevel@tonic-gate 	}
1885*6557Sfr41279 	big_finish(&tmp1);
1886*6557Sfr41279 
1887*6557Sfr41279 	return (err);
1888*6557Sfr41279 }
1889*6557Sfr41279 
1890*6557Sfr41279 
1891*6557Sfr41279 #ifdef USE_FLOATING_POINT
1892*6557Sfr41279 
1893*6557Sfr41279 #ifdef _KERNEL
1894*6557Sfr41279 
1895*6557Sfr41279 #include <sys/sysmacros.h>
1896*6557Sfr41279 #include <sys/regset.h>
1897*6557Sfr41279 #include <sys/fpu/fpusystm.h>
1898*6557Sfr41279 
1899*6557Sfr41279 /* the alignment for block stores to save fp registers */
1900*6557Sfr41279 #define	FPR_ALIGN	(64)
1901*6557Sfr41279 
1902*6557Sfr41279 extern void big_savefp(kfpu_t *);
1903*6557Sfr41279 extern void big_restorefp(kfpu_t *);
1904*6557Sfr41279 
1905*6557Sfr41279 #endif /* _KERNEL */
1906*6557Sfr41279 
1907*6557Sfr41279 /*
1908*6557Sfr41279  * This version makes use of floating point for performance
1909*6557Sfr41279  */
1910*6557Sfr41279 static BIG_ERR_CODE
1911*6557Sfr41279 big_modexp_ncp_float(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n,
1912*6557Sfr41279     BIGNUM *tmp, BIG_CHUNK_TYPE n0)
1913*6557Sfr41279 {
1914*6557Sfr41279 
1915*6557Sfr41279 	int		i, j, k, l, m, p, bit, bitind, bitcount, nlen;
1916*6557Sfr41279 	double		dn0;
1917*6557Sfr41279 	double		*dn, *dt, *d16r, *d32r;
1918*6557Sfr41279 	uint32_t	*nint, *prod;
1919*6557Sfr41279 	double		*apowers[APOWERS_MAX_SIZE];
1920*6557Sfr41279 	int		nbits, groupbits, apowerssize;
1921*6557Sfr41279 	BIG_ERR_CODE	err = BIG_OK;
1922*6557Sfr41279 
1923*6557Sfr41279 #ifdef _KERNEL
1924*6557Sfr41279 	uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN];
1925*6557Sfr41279 	kfpu_t *fpu;
1926*6557Sfr41279 
1927*6557Sfr41279 #ifdef DEBUG
1928*6557Sfr41279 	if (!fpu_exists)
1929*6557Sfr41279 		return (BIG_GENERAL_ERR);
1930*6557Sfr41279 #endif
1931*6557Sfr41279 
1932*6557Sfr41279 	fpu =  (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN);
1933*6557Sfr41279 	big_savefp(fpu);
1934*6557Sfr41279 
1935*6557Sfr41279 #endif /* _KERNEL */
1936*6557Sfr41279 
1937*6557Sfr41279 	nbits = big_numbits(e);
1938*6557Sfr41279 	if (nbits < 50) {
1939*6557Sfr41279 		groupbits = 1;
1940*6557Sfr41279 		apowerssize = 1;
1941*6557Sfr41279 	} else {
1942*6557Sfr41279 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
1943*6557Sfr41279 		apowerssize = 1 << (groupbits - 1);
1944*6557Sfr41279 	}
1945*6557Sfr41279 
1946*6557Sfr41279 	nlen = (BIG_CHUNK_SIZE / 32) * n->len;
19470Sstevel@tonic-gate 	dn0 = (double)(n0 & 0xffff);
19480Sstevel@tonic-gate 
19490Sstevel@tonic-gate 	dn = dt = d16r = d32r = NULL;
19500Sstevel@tonic-gate 	nint = prod = NULL;
19510Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
19520Sstevel@tonic-gate 		apowers[i] = NULL;
19530Sstevel@tonic-gate 	}
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate 	if ((dn = big_malloc(nlen * sizeof (double))) == NULL) {
19560Sstevel@tonic-gate 		err = BIG_NO_MEM;
19570Sstevel@tonic-gate 		goto ret;
19580Sstevel@tonic-gate 	}
19590Sstevel@tonic-gate 	if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) {
19600Sstevel@tonic-gate 		err = BIG_NO_MEM;
19610Sstevel@tonic-gate 		goto ret;
19620Sstevel@tonic-gate 	}
19630Sstevel@tonic-gate 	if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) {
19640Sstevel@tonic-gate 		err = BIG_NO_MEM;
19650Sstevel@tonic-gate 		goto ret;
19660Sstevel@tonic-gate 	}
19670Sstevel@tonic-gate 	if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) {
19680Sstevel@tonic-gate 		err = BIG_NO_MEM;
19690Sstevel@tonic-gate 		goto ret;
19700Sstevel@tonic-gate 	}
19710Sstevel@tonic-gate 	if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) {
19720Sstevel@tonic-gate 		err = BIG_NO_MEM;
19730Sstevel@tonic-gate 		goto ret;
19740Sstevel@tonic-gate 	}
19750Sstevel@tonic-gate 	if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) {
19760Sstevel@tonic-gate 		err = BIG_NO_MEM;
19770Sstevel@tonic-gate 		goto ret;
19780Sstevel@tonic-gate 	}
19790Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
19800Sstevel@tonic-gate 		if ((apowers[i] = big_malloc((2 * nlen + 1) *
19810Sstevel@tonic-gate 		    sizeof (double))) == NULL) {
19820Sstevel@tonic-gate 			err = BIG_NO_MEM;
19830Sstevel@tonic-gate 			goto ret;
19840Sstevel@tonic-gate 		}
19850Sstevel@tonic-gate 	}
19860Sstevel@tonic-gate 
1987*6557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
1988*6557Sfr41279 	for (i = 0; i < ma->len; i++) {
1989*6557Sfr41279 		nint[i] = ma->value[i];
1990*6557Sfr41279 	}
1991*6557Sfr41279 	for (; i < nlen; i++) {
1992*6557Sfr41279 		nint[i] = 0;
1993*6557Sfr41279 	}
1994*6557Sfr41279 #else
1995*6557Sfr41279 	for (i = 0; i < ma->len; i++) {
1996*6557Sfr41279 		nint[2 * i] = (uint32_t)(ma->value[i] & 0xffffffffULL);
1997*6557Sfr41279 		nint[2 * i + 1] = (uint32_t)(ma->value[i] >> 32);
1998*6557Sfr41279 	}
1999*6557Sfr41279 	for (i = ma->len * 2; i < nlen; i++) {
2000*6557Sfr41279 		nint[i] = 0;
2001*6557Sfr41279 	}
2002*6557Sfr41279 #endif
20030Sstevel@tonic-gate 	conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen);
20040Sstevel@tonic-gate 
2005*6557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
2006*6557Sfr41279 	for (i = 0; i < n->len; i++) {
2007*6557Sfr41279 		nint[i] = n->value[i];
2008*6557Sfr41279 	}
2009*6557Sfr41279 	for (; i < nlen; i++) {
2010*6557Sfr41279 		nint[i] = 0;
2011*6557Sfr41279 	}
2012*6557Sfr41279 #else
2013*6557Sfr41279 	for (i = 0; i < n->len; i++) {
2014*6557Sfr41279 		nint[2 * i] = (uint32_t)(n->value[i] & 0xffffffffULL);
2015*6557Sfr41279 		nint[2 * i + 1] = (uint32_t)(n->value[i] >> 32);
2016*6557Sfr41279 	}
2017*6557Sfr41279 	for (i = n->len * 2; i < nlen; i++) {
2018*6557Sfr41279 		nint[i] = 0;
2019*6557Sfr41279 	}
2020*6557Sfr41279 #endif
20210Sstevel@tonic-gate 	conv_i32_to_d32(dn, nint, nlen);
20220Sstevel@tonic-gate 
20230Sstevel@tonic-gate 	mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0);
20240Sstevel@tonic-gate 	conv_i32_to_d32(d32r, prod, nlen);
20250Sstevel@tonic-gate 	for (i = 1; i < apowerssize; i++) {
20260Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[i - 1],
20270Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
20280Sstevel@tonic-gate 		conv_i32_to_d16(apowers[i], prod, nlen);
20290Sstevel@tonic-gate 	}
20300Sstevel@tonic-gate 
2031*6557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
2032*6557Sfr41279 	for (i = 0; i < tmp->len; i++) {
2033*6557Sfr41279 		prod[i] = tmp->value[i];
2034*6557Sfr41279 	}
2035*6557Sfr41279 	for (; i < nlen + 1; i++) {
2036*6557Sfr41279 		prod[i] = 0;
2037*6557Sfr41279 	}
2038*6557Sfr41279 #else
2039*6557Sfr41279 	for (i = 0; i < tmp->len; i++) {
2040*6557Sfr41279 		prod[2 * i] = (uint32_t)(tmp->value[i] & 0xffffffffULL);
2041*6557Sfr41279 		prod[2 * i + 1] = (uint32_t)(tmp->value[i] >> 32);
2042*6557Sfr41279 	}
2043*6557Sfr41279 	for (i = tmp->len * 2; i < nlen + 1; i++) {
2044*6557Sfr41279 		prod[i] = 0;
2045*6557Sfr41279 	}
2046*6557Sfr41279 #endif
2047*6557Sfr41279 
2048*6557Sfr41279 	bitind = nbits % BIG_CHUNK_SIZE;
20490Sstevel@tonic-gate 	k = 0;
20500Sstevel@tonic-gate 	l = 0;
20510Sstevel@tonic-gate 	p = 0;
20520Sstevel@tonic-gate 	bitcount = 0;
2053*6557Sfr41279 	for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) {
20540Sstevel@tonic-gate 		for (j = bitind - 1; j >= 0; j--) {
20550Sstevel@tonic-gate 			bit = (e->value[i] >> j) & 1;
20560Sstevel@tonic-gate 			if ((bitcount == 0) && (bit == 0)) {
20570Sstevel@tonic-gate 				conv_i32_to_d32_and_d16(d32r, d16r,
20580Sstevel@tonic-gate 				    prod, nlen);
20590Sstevel@tonic-gate 				mont_mulf_noconv(prod, d32r, d16r,
20600Sstevel@tonic-gate 				    dt, dn, nint, nlen, dn0);
20610Sstevel@tonic-gate 			} else {
20620Sstevel@tonic-gate 				bitcount++;
20630Sstevel@tonic-gate 				p = p * 2 + bit;
20640Sstevel@tonic-gate 				if (bit == 1) {
20650Sstevel@tonic-gate 					k = k + l + 1;
20660Sstevel@tonic-gate 					l = 0;
20670Sstevel@tonic-gate 				} else {
20680Sstevel@tonic-gate 					l++;
20690Sstevel@tonic-gate 				}
20700Sstevel@tonic-gate 				if (bitcount == groupbits) {
20710Sstevel@tonic-gate 					for (m = 0; m < k; m++) {
2072*6557Sfr41279 						conv_i32_to_d32_and_d16(d32r,
2073*6557Sfr41279 						    d16r, prod, nlen);
20740Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
20750Sstevel@tonic-gate 						    d16r, dt, dn, nint,
20760Sstevel@tonic-gate 						    nlen, dn0);
20770Sstevel@tonic-gate 					}
20780Sstevel@tonic-gate 					conv_i32_to_d32(d32r, prod, nlen);
20790Sstevel@tonic-gate 					mont_mulf_noconv(prod, d32r,
20800Sstevel@tonic-gate 					    apowers[p >> (l+1)],
20810Sstevel@tonic-gate 					    dt, dn, nint, nlen, dn0);
20820Sstevel@tonic-gate 					for (m = 0; m < l; m++) {
2083*6557Sfr41279 						conv_i32_to_d32_and_d16(d32r,
2084*6557Sfr41279 						    d16r, prod, nlen);
20850Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
20860Sstevel@tonic-gate 						    d16r, dt, dn, nint,
20870Sstevel@tonic-gate 						    nlen, dn0);
20880Sstevel@tonic-gate 					}
20890Sstevel@tonic-gate 					k = 0;
20900Sstevel@tonic-gate 					l = 0;
20910Sstevel@tonic-gate 					p = 0;
20920Sstevel@tonic-gate 					bitcount = 0;
20930Sstevel@tonic-gate 				}
20940Sstevel@tonic-gate 			}
20950Sstevel@tonic-gate 		}
2096*6557Sfr41279 		bitind = BIG_CHUNK_SIZE;
20970Sstevel@tonic-gate 	}
20980Sstevel@tonic-gate 
20990Sstevel@tonic-gate 	for (m = 0; m < k; m++) {
21000Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
21010Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
21020Sstevel@tonic-gate 	}
21030Sstevel@tonic-gate 	if (p != 0) {
21040Sstevel@tonic-gate 		conv_i32_to_d32(d32r, prod, nlen);
21050Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)],
21060Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
21070Sstevel@tonic-gate 	}
21080Sstevel@tonic-gate 	for (m = 0; m < l; m++) {
21090Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
21100Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
21110Sstevel@tonic-gate 	}
21120Sstevel@tonic-gate 
2113*6557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
2114*6557Sfr41279 	for (i = 0; i < nlen; i++) {
2115*6557Sfr41279 		result->value[i] = prod[i];
2116*6557Sfr41279 	}
2117*6557Sfr41279 	for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--)
2118*6557Sfr41279 		;
2119*6557Sfr41279 #else
2120*6557Sfr41279 	for (i = 0; i < nlen / 2; i++) {
2121*6557Sfr41279 		result->value[i] = (uint64_t)(prod[2 * i]) +
2122*6557Sfr41279 		    (((uint64_t)(prod[2 * i + 1])) << 32);
2123*6557Sfr41279 	}
2124*6557Sfr41279 	for (i = nlen / 2 - 1; (i > 0) && (result->value[i] == 0); i--)
2125*6557Sfr41279 		;
2126*6557Sfr41279 #endif
2127*6557Sfr41279 	result->len = i + 1;
2128*6557Sfr41279 
21290Sstevel@tonic-gate ret:
21300Sstevel@tonic-gate 	for (i = apowerssize - 1; i >= 0; i--) {
21310Sstevel@tonic-gate 		if (apowers[i] != NULL)
21320Sstevel@tonic-gate 			big_free(apowers[i], (2 * nlen + 1) * sizeof (double));
21330Sstevel@tonic-gate 	}
2134*6557Sfr41279 	if (d32r != NULL) {
21350Sstevel@tonic-gate 		big_free(d32r, nlen * sizeof (double));
2136*6557Sfr41279 	}
2137*6557Sfr41279 	if (d16r != NULL) {
21380Sstevel@tonic-gate 		big_free(d16r, (2 * nlen + 1) * sizeof (double));
2139*6557Sfr41279 	}
2140*6557Sfr41279 	if (prod != NULL) {
21410Sstevel@tonic-gate 		big_free(prod, (nlen + 1) * sizeof (uint32_t));
2142*6557Sfr41279 	}
2143*6557Sfr41279 	if (nint != NULL) {
21440Sstevel@tonic-gate 		big_free(nint, nlen * sizeof (uint32_t));
2145*6557Sfr41279 	}
2146*6557Sfr41279 	if (dt != NULL) {
21470Sstevel@tonic-gate 		big_free(dt, (4 * nlen + 2) * sizeof (double));
2148*6557Sfr41279 	}
2149*6557Sfr41279 	if (dn != NULL) {
21500Sstevel@tonic-gate 		big_free(dn, nlen * sizeof (double));
2151*6557Sfr41279 	}
21520Sstevel@tonic-gate 
21530Sstevel@tonic-gate #ifdef _KERNEL
2154*6557Sfr41279 	big_restorefp(fpu);
21550Sstevel@tonic-gate #endif
21560Sstevel@tonic-gate 
21570Sstevel@tonic-gate 	return (err);
21580Sstevel@tonic-gate }
21590Sstevel@tonic-gate 
21600Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate 
21630Sstevel@tonic-gate BIG_ERR_CODE
2164*6557Sfr41279 big_modexp_ext(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr,
2165*6557Sfr41279     big_modexp_ncp_info_t *info)
21660Sstevel@tonic-gate {
2167*6557Sfr41279 	BIGNUM		ma, tmp, rr;
2168*6557Sfr41279 	BIG_CHUNK_TYPE	mavalue[BIGTMPSIZE];
2169*6557Sfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
2170*6557Sfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
2171*6557Sfr41279 	BIG_ERR_CODE	err;
2172*6557Sfr41279 	BIG_CHUNK_TYPE	n0;
2173*6557Sfr41279 
2174*6557Sfr41279 	if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue)))	!=
2175*6557Sfr41279 	    BIG_OK) {
21760Sstevel@tonic-gate 		return (err);
2177*6557Sfr41279 	}
2178*6557Sfr41279 	ma.len = 1;
2179*6557Sfr41279 	ma.value[0] = 0;
2180*6557Sfr41279 
2181*6557Sfr41279 	if ((err = big_init1(&tmp, 2 * n->len + 1,
2182*6557Sfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
21830Sstevel@tonic-gate 		goto ret1;
2184*6557Sfr41279 	}
2185*6557Sfr41279 
2186*6557Sfr41279 	/* set the malloced bit to help cleanup */
2187*6557Sfr41279 	rr.malloced = 0;
2188*6557Sfr41279 	if (n_rr == NULL) {
2189*6557Sfr41279 		if ((err = big_init1(&rr, 2 * n->len + 1,
2190*6557Sfr41279 		    rrvalue, arraysize(rrvalue))) != BIG_OK) {
2191*6557Sfr41279 			goto ret2;
2192*6557Sfr41279 		}
2193*6557Sfr41279 		if (big_mont_rr(&rr, n) != BIG_OK) {
2194*6557Sfr41279 			goto ret;
2195*6557Sfr41279 		}
2196*6557Sfr41279 		n_rr = &rr;
2197*6557Sfr41279 	}
2198*6557Sfr41279 
2199*6557Sfr41279 	n0 = big_n0(n->value[0]);
2200*6557Sfr41279 
2201*6557Sfr41279 	if (big_cmp_abs(a, n) > 0) {
2202*6557Sfr41279 		if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK) {
2203*6557Sfr41279 			goto ret;
2204*6557Sfr41279 		}
2205*6557Sfr41279 		err = big_mont_conv(&ma, &ma, n, n0, n_rr);
2206*6557Sfr41279 	} else {
2207*6557Sfr41279 		err = big_mont_conv(&ma, a, n, n0, n_rr);
2208*6557Sfr41279 	}
2209*6557Sfr41279 	if (err != BIG_OK) {
2210*6557Sfr41279 		goto ret;
2211*6557Sfr41279 	}
2212*6557Sfr41279 
2213*6557Sfr41279 	tmp.len = 1;
2214*6557Sfr41279 	tmp.value[0] = 1;
2215*6557Sfr41279 	if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK) {
2216*6557Sfr41279 		goto ret;
2217*6557Sfr41279 	}
2218*6557Sfr41279 
2219*6557Sfr41279 	if ((info != NULL) && (info->func != NULL)) {
2220*6557Sfr41279 		err = (*(info->func))(&tmp, &ma, e, n, &tmp, n0,
2221*6557Sfr41279 		    info->ncp, info->reqp);
2222*6557Sfr41279 	} else {
2223*6557Sfr41279 		err = big_modexp_ncp_sw(&tmp, &ma, e, n, &tmp, n0);
2224*6557Sfr41279 	}
2225*6557Sfr41279 	if (err != BIG_OK) {
2226*6557Sfr41279 		goto ret;
2227*6557Sfr41279 	}
2228*6557Sfr41279 
2229*6557Sfr41279 	ma.value[0] = 1;
2230*6557Sfr41279 	ma.len = 1;
2231*6557Sfr41279 	if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK) {
2232*6557Sfr41279 		goto ret;
2233*6557Sfr41279 	}
2234*6557Sfr41279 	err = big_copy(result, &tmp);
2235*6557Sfr41279 
2236*6557Sfr41279 ret:
2237*6557Sfr41279 	if (rr.malloced) {
2238*6557Sfr41279 		big_finish(&rr);
2239*6557Sfr41279 	}
2240*6557Sfr41279 ret2:
2241*6557Sfr41279 	big_finish(&tmp);
2242*6557Sfr41279 ret1:
2243*6557Sfr41279 	big_finish(&ma);
2244*6557Sfr41279 
2245*6557Sfr41279 	return (err);
2246*6557Sfr41279 }
2247*6557Sfr41279 
2248*6557Sfr41279 BIG_ERR_CODE
2249*6557Sfr41279 big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
2250*6557Sfr41279 {
2251*6557Sfr41279 	return (big_modexp_ext(result, a, e, n, n_rr, NULL));
2252*6557Sfr41279 }
2253*6557Sfr41279 
2254*6557Sfr41279 
2255*6557Sfr41279 BIG_ERR_CODE
2256*6557Sfr41279 big_modexp_crt_ext(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
2257*6557Sfr41279     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
2258*6557Sfr41279     BIGNUM *p_rr, BIGNUM *q_rr, big_modexp_ncp_info_t *info)
2259*6557Sfr41279 {
2260*6557Sfr41279 	BIGNUM		ap, aq, tmp;
2261*6557Sfr41279 	int		alen, biglen, sign;
2262*6557Sfr41279 	BIG_ERR_CODE	err;
2263*6557Sfr41279 
2264*6557Sfr41279 	if (p->len > q->len) {
2265*6557Sfr41279 		biglen = p->len;
2266*6557Sfr41279 	} else {
2267*6557Sfr41279 		biglen = q->len;
2268*6557Sfr41279 	}
2269*6557Sfr41279 
2270*6557Sfr41279 	if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK) {
2271*6557Sfr41279 		return (err);
2272*6557Sfr41279 	}
2273*6557Sfr41279 	if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK) {
2274*6557Sfr41279 		goto ret1;
2275*6557Sfr41279 	}
2276*6557Sfr41279 	if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK) {
22770Sstevel@tonic-gate 		goto ret2;
2278*6557Sfr41279 	}
22790Sstevel@tonic-gate 
22800Sstevel@tonic-gate 	/*
22810Sstevel@tonic-gate 	 * check whether a is too short - to avoid timing attacks
22820Sstevel@tonic-gate 	 */
22830Sstevel@tonic-gate 	alen = a->len;
22840Sstevel@tonic-gate 	while ((alen > p->len) && (a->value[alen - 1] == 0)) {
22850Sstevel@tonic-gate 		alen--;
22860Sstevel@tonic-gate 	}
22870Sstevel@tonic-gate 	if (alen < p->len + q->len) {
22880Sstevel@tonic-gate 		/*
22890Sstevel@tonic-gate 		 * a is too short, add p*q to it before
22900Sstevel@tonic-gate 		 * taking it modulo p and q
22910Sstevel@tonic-gate 		 * this will also affect timing, but this difference
22920Sstevel@tonic-gate 		 * does not depend on p or q, only on a
22930Sstevel@tonic-gate 		 * (in "normal" operation, this path will never be
22940Sstevel@tonic-gate 		 * taken, so it is not a performance penalty
22950Sstevel@tonic-gate 		 */
2296*6557Sfr41279 		if ((err = big_mul(&tmp, p, q)) != BIG_OK) {
22970Sstevel@tonic-gate 			goto ret;
2298*6557Sfr41279 		}
2299*6557Sfr41279 		if ((err = big_add(&tmp, &tmp, a)) != BIG_OK) {
2300*6557Sfr41279 			goto ret;
2301*6557Sfr41279 		}
2302*6557Sfr41279 		if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK) {
23030Sstevel@tonic-gate 			goto ret;
2304*6557Sfr41279 		}
2305*6557Sfr41279 		if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) {
23060Sstevel@tonic-gate 			goto ret;
2307*6557Sfr41279 		}
2308*6557Sfr41279 	} else {
2309*6557Sfr41279 		if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK) {
23100Sstevel@tonic-gate 			goto ret;
2311*6557Sfr41279 		}
2312*6557Sfr41279 		if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK) {
23130Sstevel@tonic-gate 			goto ret;
2314*6557Sfr41279 		}
23150Sstevel@tonic-gate 	}
23160Sstevel@tonic-gate 
2317*6557Sfr41279 	if ((err = big_modexp_ext(&ap, &ap, dmodpminus1, p, p_rr, info)) !=
2318*6557Sfr41279 	    BIG_OK) {
23190Sstevel@tonic-gate 		goto ret;
2320*6557Sfr41279 	}
2321*6557Sfr41279 	if ((err = big_modexp_ext(&aq, &aq, dmodqminus1, q, q_rr, info)) !=
2322*6557Sfr41279 	    BIG_OK) {
23230Sstevel@tonic-gate 		goto ret;
2324*6557Sfr41279 	}
2325*6557Sfr41279 	if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK) {
23260Sstevel@tonic-gate 		goto ret;
2327*6557Sfr41279 	}
2328*6557Sfr41279 	if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK) {
23290Sstevel@tonic-gate 		goto ret;
2330*6557Sfr41279 	}
23310Sstevel@tonic-gate 	sign = tmp.sign;
23320Sstevel@tonic-gate 	tmp.sign = 1;
2333*6557Sfr41279 	if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) {
23340Sstevel@tonic-gate 		goto ret;
2335*6557Sfr41279 	}
23360Sstevel@tonic-gate 	if ((sign == -1) && (!big_is_zero(&aq))) {
23370Sstevel@tonic-gate 		(void) big_sub_pos(&aq, q, &aq);
23380Sstevel@tonic-gate 	}
2339*6557Sfr41279 	if ((err = big_mul(&tmp, &aq, p)) != BIG_OK) {
23400Sstevel@tonic-gate 		goto ret;
2341*6557Sfr41279 	}
23420Sstevel@tonic-gate 	err = big_add_abs(result, &ap, &tmp);
23430Sstevel@tonic-gate 
23440Sstevel@tonic-gate ret:
23450Sstevel@tonic-gate 	big_finish(&tmp);
23460Sstevel@tonic-gate ret2:
23470Sstevel@tonic-gate 	big_finish(&aq);
23480Sstevel@tonic-gate ret1:
23490Sstevel@tonic-gate 	big_finish(&ap);
23500Sstevel@tonic-gate 
23510Sstevel@tonic-gate 	return (err);
23520Sstevel@tonic-gate }
23530Sstevel@tonic-gate 
23540Sstevel@tonic-gate 
2355*6557Sfr41279 BIG_ERR_CODE
2356*6557Sfr41279 big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
2357*6557Sfr41279     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
2358*6557Sfr41279     BIGNUM *p_rr, BIGNUM *q_rr)
2359*6557Sfr41279 {
2360*6557Sfr41279 	return (big_modexp_crt_ext(result, a, dmodpminus1, dmodqminus1,
2361*6557Sfr41279 	    p, q, pinvmodq, p_rr, q_rr, NULL));
2362*6557Sfr41279 }
2363*6557Sfr41279 
2364*6557Sfr41279 
2365*6557Sfr41279 static BIG_CHUNK_TYPE onearr[1] = {(BIG_CHUNK_TYPE)1};
2366*6557Sfr41279 BIGNUM big_One = {1, 1, 1, 0, onearr};
2367*6557Sfr41279 
2368*6557Sfr41279 static BIG_CHUNK_TYPE twoarr[1] = {(BIG_CHUNK_TYPE)2};
2369*6557Sfr41279 BIGNUM big_Two = {1, 1, 1, 0, twoarr};
2370*6557Sfr41279 
2371*6557Sfr41279 static BIG_CHUNK_TYPE fourarr[1] = {(BIG_CHUNK_TYPE)4};
2372*6557Sfr41279 static BIGNUM big_Four = {1, 1, 1, 0, fourarr};
2373*6557Sfr41279 
23740Sstevel@tonic-gate 
23750Sstevel@tonic-gate BIG_ERR_CODE
23760Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n)
23770Sstevel@tonic-gate {
2378*6557Sfr41279 	BIGNUM		*high, *low, *mid, *t;
2379*6557Sfr41279 	BIGNUM		t1, t2, t3, prod;
2380*6557Sfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
2381*6557Sfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
2382*6557Sfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
2383*6557Sfr41279 	BIG_CHUNK_TYPE	prodvalue[BIGTMPSIZE];
2384*6557Sfr41279 	int		i, nbits, diff, nrootbits, highbits;
2385*6557Sfr41279 	BIG_ERR_CODE	err;
23860Sstevel@tonic-gate 
23870Sstevel@tonic-gate 	nbits = big_numbits(n);
23880Sstevel@tonic-gate 
23890Sstevel@tonic-gate 	if ((err = big_init1(&t1, n->len + 1,
23900Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
23910Sstevel@tonic-gate 		return (err);
23920Sstevel@tonic-gate 	if ((err = big_init1(&t2, n->len + 1,
23930Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
23940Sstevel@tonic-gate 		goto ret1;
23950Sstevel@tonic-gate 	if ((err = big_init1(&t3, n->len + 1,
23960Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
23970Sstevel@tonic-gate 		goto ret2;
23980Sstevel@tonic-gate 	if ((err = big_init1(&prod, n->len + 1,
23990Sstevel@tonic-gate 	    prodvalue, arraysize(prodvalue))) != BIG_OK)
24000Sstevel@tonic-gate 		goto ret3;
24010Sstevel@tonic-gate 
24020Sstevel@tonic-gate 	nrootbits = (nbits + 1) / 2;
2403*6557Sfr41279 	t1.len = t2.len = t3.len = (nrootbits - 1) / BIG_CHUNK_SIZE + 1;
24040Sstevel@tonic-gate 	for (i = 0; i < t1.len; i++) {
24050Sstevel@tonic-gate 		t1.value[i] = 0;
2406*6557Sfr41279 		t2.value[i] = BIG_CHUNK_ALLBITS;
24070Sstevel@tonic-gate 	}
2408*6557Sfr41279 	highbits = nrootbits - BIG_CHUNK_SIZE * (t1.len - 1);
2409*6557Sfr41279 	if (highbits == BIG_CHUNK_SIZE) {
2410*6557Sfr41279 		t1.value[t1.len - 1] = BIG_CHUNK_HIGHBIT;
2411*6557Sfr41279 		t2.value[t2.len - 1] = BIG_CHUNK_ALLBITS;
24120Sstevel@tonic-gate 	} else {
2413*6557Sfr41279 		t1.value[t1.len - 1] = (BIG_CHUNK_TYPE)1 << (highbits - 1);
24140Sstevel@tonic-gate 		t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1;
24150Sstevel@tonic-gate 	}
2416*6557Sfr41279 
24170Sstevel@tonic-gate 	high = &t2;
24180Sstevel@tonic-gate 	low = &t1;
24190Sstevel@tonic-gate 	mid = &t3;
24200Sstevel@tonic-gate 
2421*6557Sfr41279 	if ((err = big_mul(&prod, high, high)) != BIG_OK) {
24220Sstevel@tonic-gate 		goto ret;
2423*6557Sfr41279 	}
24240Sstevel@tonic-gate 	diff = big_cmp_abs(&prod, n);
24250Sstevel@tonic-gate 	if (diff <= 0) {
24260Sstevel@tonic-gate 		err = big_copy(result, high);
24270Sstevel@tonic-gate 		goto ret;
24280Sstevel@tonic-gate 	}
24290Sstevel@tonic-gate 
24300Sstevel@tonic-gate 	(void) big_sub_pos(mid, high, low);
2431*6557Sfr41279 	while (big_cmp_abs(&big_One, mid) != 0) {
24320Sstevel@tonic-gate 		(void) big_add_abs(mid, high, low);
24330Sstevel@tonic-gate 		(void) big_half_pos(mid, mid);
24340Sstevel@tonic-gate 		if ((err = big_mul(&prod, mid, mid)) != BIG_OK)
24350Sstevel@tonic-gate 			goto ret;
24360Sstevel@tonic-gate 		diff = big_cmp_abs(&prod, n);
24370Sstevel@tonic-gate 		if (diff > 0) {
24380Sstevel@tonic-gate 			t = high;
24390Sstevel@tonic-gate 			high = mid;
24400Sstevel@tonic-gate 			mid = t;
24410Sstevel@tonic-gate 		} else if (diff < 0) {
24420Sstevel@tonic-gate 			t = low;
24430Sstevel@tonic-gate 			low = mid;
24440Sstevel@tonic-gate 			mid = t;
24450Sstevel@tonic-gate 		} else {
24460Sstevel@tonic-gate 			err = big_copy(result, low);
24470Sstevel@tonic-gate 			goto ret;
24480Sstevel@tonic-gate 		}
24490Sstevel@tonic-gate 		(void) big_sub_pos(mid, high, low);
24500Sstevel@tonic-gate 	}
24510Sstevel@tonic-gate 
24520Sstevel@tonic-gate 	err = big_copy(result, low);
24530Sstevel@tonic-gate ret:
24540Sstevel@tonic-gate 	if (prod.malloced) big_finish(&prod);
24550Sstevel@tonic-gate ret3:
24560Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
24570Sstevel@tonic-gate ret2:
24580Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
24590Sstevel@tonic-gate ret1:
24600Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
24610Sstevel@tonic-gate 
24620Sstevel@tonic-gate 	return (err);
24630Sstevel@tonic-gate }
24640Sstevel@tonic-gate 
24650Sstevel@tonic-gate 
24660Sstevel@tonic-gate BIG_ERR_CODE
24670Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm)
24680Sstevel@tonic-gate {
2469*6557Sfr41279 	BIGNUM		*t, *tmp2, *m, *n;
2470*6557Sfr41279 	BIGNUM		t1, t2, t3;
2471*6557Sfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
2472*6557Sfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
2473*6557Sfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
2474*6557Sfr41279 	int		len, err;
24750Sstevel@tonic-gate 
24760Sstevel@tonic-gate 	if (big_is_zero(nn) ||
24770Sstevel@tonic-gate 	    (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) {
24780Sstevel@tonic-gate 		*jac = 0;
24790Sstevel@tonic-gate 		return (BIG_OK);
24800Sstevel@tonic-gate 	}
24810Sstevel@tonic-gate 
2482*6557Sfr41279 	if (nn->len > mm->len) {
2483*6557Sfr41279 		len = nn->len;
2484*6557Sfr41279 	} else {
2485*6557Sfr41279 		len = mm->len;
2486*6557Sfr41279 	}
24870Sstevel@tonic-gate 
24880Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
2489*6557Sfr41279 	    t1value, arraysize(t1value))) != BIG_OK) {
24900Sstevel@tonic-gate 		return (err);
2491*6557Sfr41279 	}
24920Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
2493*6557Sfr41279 	    t2value, arraysize(t2value))) != BIG_OK) {
24940Sstevel@tonic-gate 		goto ret1;
2495*6557Sfr41279 	}
24960Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
2497*6557Sfr41279 	    t3value, arraysize(t3value))) != BIG_OK) {
24980Sstevel@tonic-gate 		goto ret2;
2499*6557Sfr41279 	}
25000Sstevel@tonic-gate 
25010Sstevel@tonic-gate 	n = &t1;
25020Sstevel@tonic-gate 	m = &t2;
25030Sstevel@tonic-gate 	tmp2 = &t3;
25040Sstevel@tonic-gate 
25050Sstevel@tonic-gate 	(void) big_copy(n, nn);
25060Sstevel@tonic-gate 	(void) big_copy(m, mm);
25070Sstevel@tonic-gate 
25080Sstevel@tonic-gate 	*jac = 1;
2509*6557Sfr41279 	while (big_cmp_abs(&big_One, m) != 0) {
25100Sstevel@tonic-gate 		if (big_is_zero(n)) {
25110Sstevel@tonic-gate 			*jac = 0;
25120Sstevel@tonic-gate 			goto ret;
25130Sstevel@tonic-gate 		}
25140Sstevel@tonic-gate 		if ((m->value[0] & 1) == 0) {
25150Sstevel@tonic-gate 			if (((n->value[0] & 7) == 3) ||
2516*6557Sfr41279 			    ((n->value[0] & 7) == 5))
2517*6557Sfr41279 				*jac = -*jac;
25180Sstevel@tonic-gate 			(void) big_half_pos(m, m);
25190Sstevel@tonic-gate 		} else if ((n->value[0] & 1) == 0) {
25200Sstevel@tonic-gate 			if (((m->value[0] & 7) == 3) ||
2521*6557Sfr41279 			    ((m->value[0] & 7) == 5))
2522*6557Sfr41279 				*jac = -*jac;
25230Sstevel@tonic-gate 			(void) big_half_pos(n, n);
25240Sstevel@tonic-gate 		} else {
25250Sstevel@tonic-gate 			if (((m->value[0] & 3) == 3) &&
25260Sstevel@tonic-gate 			    ((n->value[0] & 3) == 3)) {
25270Sstevel@tonic-gate 				*jac = -*jac;
25280Sstevel@tonic-gate 			}
2529*6557Sfr41279 			if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK) {
25300Sstevel@tonic-gate 				goto ret;
2531*6557Sfr41279 			}
25320Sstevel@tonic-gate 			t = tmp2;
25330Sstevel@tonic-gate 			tmp2 = m;
25340Sstevel@tonic-gate 			m = n;
25350Sstevel@tonic-gate 			n = t;
25360Sstevel@tonic-gate 		}
25370Sstevel@tonic-gate 	}
25380Sstevel@tonic-gate 	err = BIG_OK;
25390Sstevel@tonic-gate 
25400Sstevel@tonic-gate ret:
25410Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
25420Sstevel@tonic-gate ret2:
25430Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
25440Sstevel@tonic-gate ret1:
25450Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
25460Sstevel@tonic-gate 
25470Sstevel@tonic-gate 	return (err);
25480Sstevel@tonic-gate }
25490Sstevel@tonic-gate 
25500Sstevel@tonic-gate 
25510Sstevel@tonic-gate BIG_ERR_CODE
25520Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n)
25530Sstevel@tonic-gate {
2554*6557Sfr41279 	int		m, w, i;
2555*6557Sfr41279 	BIG_CHUNK_TYPE	bit;
2556*6557Sfr41279 	BIGNUM		ki, tmp, tmp2;
2557*6557Sfr41279 	BIG_CHUNK_TYPE	kivalue[BIGTMPSIZE];
2558*6557Sfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
2559*6557Sfr41279 	BIG_CHUNK_TYPE	tmp2value[BIGTMPSIZE];
2560*6557Sfr41279 	BIG_ERR_CODE	err;
2561*6557Sfr41279 
2562*6557Sfr41279 	if (big_cmp_abs(k, &big_One) == 0) {
25630Sstevel@tonic-gate 		(void) big_copy(Lk, p);
2564*6557Sfr41279 		(void) big_copy(Lkminus1, &big_Two);
25650Sstevel@tonic-gate 		return (BIG_OK);
25660Sstevel@tonic-gate 	}
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate 	if ((err = big_init1(&ki, k->len + 1,
25690Sstevel@tonic-gate 	    kivalue, arraysize(kivalue))) != BIG_OK)
25700Sstevel@tonic-gate 		return (err);
25710Sstevel@tonic-gate 
25720Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len +1,
25730Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
25740Sstevel@tonic-gate 		goto ret1;
25750Sstevel@tonic-gate 
25760Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, n->len,
25770Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
25780Sstevel@tonic-gate 		goto ret2;
25790Sstevel@tonic-gate 
25800Sstevel@tonic-gate 	m = big_numbits(k);
2581*6557Sfr41279 	ki.len = (m - 1) / BIG_CHUNK_SIZE + 1;
2582*6557Sfr41279 	w = (m - 1) / BIG_CHUNK_SIZE;
2583*6557Sfr41279 	bit = (BIG_CHUNK_TYPE)1 << ((m - 1) % BIG_CHUNK_SIZE);
2584*6557Sfr41279 	for (i = 0; i < ki.len; i++) {
2585*6557Sfr41279 		ki.value[i] = 0;
2586*6557Sfr41279 	}
25870Sstevel@tonic-gate 	ki.value[ki.len - 1] = bit;
2588*6557Sfr41279 	if (big_cmp_abs(k, &ki) != 0) {
25890Sstevel@tonic-gate 		(void) big_double(&ki, &ki);
2590*6557Sfr41279 	}
25910Sstevel@tonic-gate 	(void) big_sub_pos(&ki, &ki, k);
25920Sstevel@tonic-gate 
25930Sstevel@tonic-gate 	(void) big_copy(Lk, p);
2594*6557Sfr41279 	(void) big_copy(Lkminus1, &big_Two);
25950Sstevel@tonic-gate 
25960Sstevel@tonic-gate 	for (i = 0; i < m; i++) {
2597*6557Sfr41279 		if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK) {
25980Sstevel@tonic-gate 			goto ret;
2599*6557Sfr41279 		}
26000Sstevel@tonic-gate 		(void) big_add_abs(&tmp, &tmp, n);
26010Sstevel@tonic-gate 		(void) big_sub_pos(&tmp, &tmp, p);
2602*6557Sfr41279 		if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK) {
26030Sstevel@tonic-gate 			goto ret;
2604*6557Sfr41279 		}
26050Sstevel@tonic-gate 		if ((ki.value[w] & bit) != 0) {
26060Sstevel@tonic-gate 			if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) !=
2607*6557Sfr41279 			    BIG_OK) {
26080Sstevel@tonic-gate 				goto ret;
2609*6557Sfr41279 			}
26100Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
2611*6557Sfr41279 			(void) big_sub_pos(&tmp, &tmp, &big_Two);
26120Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) !=
2613*6557Sfr41279 			    BIG_OK) {
26140Sstevel@tonic-gate 				goto ret;
2615*6557Sfr41279 			}
26160Sstevel@tonic-gate 			(void) big_copy(Lk, &tmp2);
26170Sstevel@tonic-gate 		} else {
2618*6557Sfr41279 			if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK) {
26190Sstevel@tonic-gate 				goto ret;
2620*6557Sfr41279 			}
26210Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
2622*6557Sfr41279 			(void) big_sub_pos(&tmp, &tmp, &big_Two);
2623*6557Sfr41279 			if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK) {
26240Sstevel@tonic-gate 				goto ret;
2625*6557Sfr41279 			}
26260Sstevel@tonic-gate 			(void) big_copy(Lkminus1, &tmp2);
26270Sstevel@tonic-gate 		}
26280Sstevel@tonic-gate 		bit = bit >> 1;
26290Sstevel@tonic-gate 		if (bit == 0) {
2630*6557Sfr41279 			bit = BIG_CHUNK_HIGHBIT;
26310Sstevel@tonic-gate 			w--;
26320Sstevel@tonic-gate 		}
26330Sstevel@tonic-gate 	}
26340Sstevel@tonic-gate 
26350Sstevel@tonic-gate 	err = BIG_OK;
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate ret:
26380Sstevel@tonic-gate 	if (tmp2.malloced) big_finish(&tmp2);
26390Sstevel@tonic-gate ret2:
26400Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
26410Sstevel@tonic-gate ret1:
26420Sstevel@tonic-gate 	if (ki.malloced) big_finish(&ki);
26430Sstevel@tonic-gate 
26440Sstevel@tonic-gate 	return (err);
26450Sstevel@tonic-gate }
26460Sstevel@tonic-gate 
26470Sstevel@tonic-gate 
26480Sstevel@tonic-gate BIG_ERR_CODE
2649*6557Sfr41279 big_isprime_pos_ext(BIGNUM *n, big_modexp_ncp_info_t *info)
26500Sstevel@tonic-gate {
2651*6557Sfr41279 	BIGNUM		o, nminus1, tmp, Lkminus1, Lk;
2652*6557Sfr41279 	BIG_CHUNK_TYPE	ovalue[BIGTMPSIZE];
2653*6557Sfr41279 	BIG_CHUNK_TYPE	nminus1value[BIGTMPSIZE];
2654*6557Sfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
2655*6557Sfr41279 	BIG_CHUNK_TYPE	Lkminus1value[BIGTMPSIZE];
2656*6557Sfr41279 	BIG_CHUNK_TYPE	Lkvalue[BIGTMPSIZE];
2657*6557Sfr41279 	BIG_ERR_CODE	err;
2658*6557Sfr41279 	int		e, i, jac;
2659*6557Sfr41279 
2660*6557Sfr41279 	if (big_cmp_abs(n, &big_One) == 0) {
26610Sstevel@tonic-gate 		return (BIG_FALSE);
2662*6557Sfr41279 	}
2663*6557Sfr41279 	if (big_cmp_abs(n, &big_Two) == 0) {
26640Sstevel@tonic-gate 		return (BIG_TRUE);
2665*6557Sfr41279 	}
2666*6557Sfr41279 	if ((n->value[0] & 1) == 0) {
26670Sstevel@tonic-gate 		return (BIG_FALSE);
2668*6557Sfr41279 	}
2669*6557Sfr41279 
2670*6557Sfr41279 	if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) !=
2671*6557Sfr41279 	    BIG_OK) {
26720Sstevel@tonic-gate 		return (err);
2673*6557Sfr41279 	}
26740Sstevel@tonic-gate 
26750Sstevel@tonic-gate 	if ((err = big_init1(&nminus1, n->len,
2676*6557Sfr41279 	    nminus1value, arraysize(nminus1value))) != BIG_OK) {
26770Sstevel@tonic-gate 		goto ret1;
2678*6557Sfr41279 	}
26790Sstevel@tonic-gate 
26800Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len,
2681*6557Sfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
26820Sstevel@tonic-gate 		goto ret2;
2683*6557Sfr41279 	}
26840Sstevel@tonic-gate 
26850Sstevel@tonic-gate 	if ((err = big_init1(&Lkminus1, n->len,
2686*6557Sfr41279 	    Lkminus1value, arraysize(Lkminus1value))) != BIG_OK) {
26870Sstevel@tonic-gate 		goto ret3;
2688*6557Sfr41279 	}
26890Sstevel@tonic-gate 
26900Sstevel@tonic-gate 	if ((err = big_init1(&Lk, n->len,
2691*6557Sfr41279 	    Lkvalue, arraysize(Lkvalue))) != BIG_OK) {
26920Sstevel@tonic-gate 		goto ret4;
2693*6557Sfr41279 	}
2694*6557Sfr41279 
2695*6557Sfr41279 	(void) big_sub_pos(&o, n, &big_One); 	/* cannot fail */
26960Sstevel@tonic-gate 	(void) big_copy(&nminus1, &o);		/* cannot fail */
26970Sstevel@tonic-gate 	e = 0;
26980Sstevel@tonic-gate 	while ((o.value[0] & 1) == 0) {
26990Sstevel@tonic-gate 		e++;
27000Sstevel@tonic-gate 		(void) big_half_pos(&o, &o);  /* cannot fail */
27010Sstevel@tonic-gate 	}
2702*6557Sfr41279 	if ((err = big_modexp_ext(&tmp, &big_Two, &o, n, NULL, info)) !=
2703*6557Sfr41279 	    BIG_OK) {
27040Sstevel@tonic-gate 		goto ret;
2705*6557Sfr41279 	}
2706*6557Sfr41279 
27070Sstevel@tonic-gate 	i = 0;
27080Sstevel@tonic-gate 	while ((i < e) &&
2709*6557Sfr41279 	    (big_cmp_abs(&tmp, &big_One) != 0) &&
27100Sstevel@tonic-gate 	    (big_cmp_abs(&tmp, &nminus1) != 0)) {
2711*6557Sfr41279 		if ((err =
2712*6557Sfr41279 		    big_modexp_ext(&tmp, &tmp, &big_Two, n, NULL, info)) !=
2713*6557Sfr41279 		    BIG_OK)
27140Sstevel@tonic-gate 			goto ret;
27150Sstevel@tonic-gate 		i++;
27160Sstevel@tonic-gate 	}
2717*6557Sfr41279 
27180Sstevel@tonic-gate 	if (!((big_cmp_abs(&tmp, &nminus1) == 0) ||
2719*6557Sfr41279 	    ((i == 0) && (big_cmp_abs(&tmp, &big_One) == 0)))) {
27200Sstevel@tonic-gate 		err = BIG_FALSE;
27210Sstevel@tonic-gate 		goto ret;
27220Sstevel@tonic-gate 	}
27230Sstevel@tonic-gate 
2724*6557Sfr41279 	if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK) {
27250Sstevel@tonic-gate 		goto ret;
2726*6557Sfr41279 	}
2727*6557Sfr41279 
2728*6557Sfr41279 	if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK) {
27290Sstevel@tonic-gate 		goto ret;
2730*6557Sfr41279 	}
27310Sstevel@tonic-gate 	if (big_cmp_abs(&tmp, n) == 0) {
27320Sstevel@tonic-gate 		err = BIG_FALSE;
27330Sstevel@tonic-gate 		goto ret;
27340Sstevel@tonic-gate 	}
27350Sstevel@tonic-gate 
2736*6557Sfr41279 	(void) big_copy(&o, &big_Two);
27370Sstevel@tonic-gate 	do {
2738*6557Sfr41279 		(void) big_add_abs(&o, &o, &big_One);
2739*6557Sfr41279 		if ((err = big_mul(&tmp, &o, &o)) != BIG_OK) {
27400Sstevel@tonic-gate 			goto ret;
2741*6557Sfr41279 		}
2742*6557Sfr41279 		(void) big_sub_pos(&tmp, &tmp, &big_Four);
2743*6557Sfr41279 		if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK) {
27440Sstevel@tonic-gate 			goto ret;
2745*6557Sfr41279 		}
27460Sstevel@tonic-gate 	} while (jac != -1);
27470Sstevel@tonic-gate 
2748*6557Sfr41279 	(void) big_add_abs(&tmp, n, &big_One);
2749*6557Sfr41279 	if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK) {
27500Sstevel@tonic-gate 		goto ret;
2751*6557Sfr41279 	}
2752*6557Sfr41279 
2753*6557Sfr41279 	if ((big_cmp_abs(&Lkminus1, &o) == 0) &&
2754*6557Sfr41279 	    (big_cmp_abs(&Lk, &big_Two) == 0)) {
27550Sstevel@tonic-gate 		err = BIG_TRUE;
2756*6557Sfr41279 	} else {
2757*6557Sfr41279 		err = BIG_FALSE;
2758*6557Sfr41279 	}
27590Sstevel@tonic-gate 
27600Sstevel@tonic-gate ret:
27610Sstevel@tonic-gate 	if (Lk.malloced) big_finish(&Lk);
27620Sstevel@tonic-gate ret4:
27630Sstevel@tonic-gate 	if (Lkminus1.malloced) big_finish(&Lkminus1);
27640Sstevel@tonic-gate ret3:
27650Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
27660Sstevel@tonic-gate ret2:
27670Sstevel@tonic-gate 	if (nminus1.malloced) big_finish(&nminus1);
27680Sstevel@tonic-gate ret1:
27690Sstevel@tonic-gate 	if (o.malloced) big_finish(&o);
27700Sstevel@tonic-gate 
27710Sstevel@tonic-gate 	return (err);
27720Sstevel@tonic-gate }
27730Sstevel@tonic-gate 
27740Sstevel@tonic-gate 
2775*6557Sfr41279 BIG_ERR_CODE
2776*6557Sfr41279 big_isprime_pos(BIGNUM *n)
2777*6557Sfr41279 {
2778*6557Sfr41279 	return (big_isprime_pos_ext(n, NULL));
2779*6557Sfr41279 }
2780*6557Sfr41279 
2781*6557Sfr41279 
27820Sstevel@tonic-gate #define	SIEVESIZE 1000
27830Sstevel@tonic-gate 
27840Sstevel@tonic-gate uint32_t smallprimes[] =
27850Sstevel@tonic-gate {
27860Sstevel@tonic-gate 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
27870Sstevel@tonic-gate 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97
27880Sstevel@tonic-gate };
27890Sstevel@tonic-gate 
27900Sstevel@tonic-gate 
27910Sstevel@tonic-gate BIG_ERR_CODE
2792*6557Sfr41279 big_nextprime_pos_ext(BIGNUM *result, BIGNUM *n, big_modexp_ncp_info_t *info)
27930Sstevel@tonic-gate {
2794*6557Sfr41279 	BIG_ERR_CODE	err;
2795*6557Sfr41279 	int		sieve[SIEVESIZE];
2796*6557Sfr41279 	int		i;
2797*6557Sfr41279 	uint32_t	off, p;
2798*6557Sfr41279 
2799*6557Sfr41279 	if ((err = big_copy(result, n)) != BIG_OK) {
28000Sstevel@tonic-gate 		return (err);
2801*6557Sfr41279 	}
28020Sstevel@tonic-gate 	result->value[0] |= 1;
28031027Srobinson 	/* CONSTCOND */
28040Sstevel@tonic-gate 	while (1) {
28050Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0;
28060Sstevel@tonic-gate 		for (i = 0;
2807*6557Sfr41279 		    i < sizeof (smallprimes) / sizeof (smallprimes[0]); i++) {
28080Sstevel@tonic-gate 			p = smallprimes[i];
2809*6557Sfr41279 			off = big_modhalf_pos(result, p);
28100Sstevel@tonic-gate 			off = p - off;
2811*6557Sfr41279 			if ((off % 2) == 1) {
2812*6557Sfr41279 				off = off + p;
2813*6557Sfr41279 			}
2814*6557Sfr41279 			off = off / 2;
28150Sstevel@tonic-gate 			while (off < SIEVESIZE) {
28160Sstevel@tonic-gate 				sieve[off] = 1;
28170Sstevel@tonic-gate 				off = off + p;
28180Sstevel@tonic-gate 			}
28190Sstevel@tonic-gate 		}
28200Sstevel@tonic-gate 
28210Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) {
28220Sstevel@tonic-gate 			if (sieve[i] == 0) {
2823*6557Sfr41279 				err = big_isprime_pos_ext(result, info);
28240Sstevel@tonic-gate 				if (err != BIG_FALSE) {
2825*6557Sfr41279 					if (err != BIG_TRUE) {
28260Sstevel@tonic-gate 						return (err);
2827*6557Sfr41279 					} else {
2828*6557Sfr41279 						goto out;
2829*6557Sfr41279 					}
28300Sstevel@tonic-gate 				}
28310Sstevel@tonic-gate 
28320Sstevel@tonic-gate 			}
2833*6557Sfr41279 			if ((err = big_add_abs(result, result, &big_Two)) !=
2834*6557Sfr41279 			    BIG_OK) {
28350Sstevel@tonic-gate 				return (err);
2836*6557Sfr41279 			}
28370Sstevel@tonic-gate 		}
28380Sstevel@tonic-gate 	}
2839*6557Sfr41279 
2840*6557Sfr41279 out:
2841*6557Sfr41279 	return (BIG_OK);
2842*6557Sfr41279 }
2843*6557Sfr41279 
2844*6557Sfr41279 
2845*6557Sfr41279 BIG_ERR_CODE
2846*6557Sfr41279 big_nextprime_pos(BIGNUM *result, BIGNUM *n)
2847*6557Sfr41279 {
2848*6557Sfr41279 	return (big_nextprime_pos_ext(result, n, NULL));
28490Sstevel@tonic-gate }
28500Sstevel@tonic-gate 
28510Sstevel@tonic-gate 
28520Sstevel@tonic-gate BIG_ERR_CODE
28530Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n)
28540Sstevel@tonic-gate {
28550Sstevel@tonic-gate 	BIG_ERR_CODE err;
28560Sstevel@tonic-gate 
28570Sstevel@tonic-gate 
28580Sstevel@tonic-gate 	if ((err = big_copy(result, n)) != BIG_OK)
28590Sstevel@tonic-gate 		return (err);
28600Sstevel@tonic-gate 	result->value[0] |= 1;
2861*6557Sfr41279 	while ((err = big_isprime_pos_ext(result, NULL)) != BIG_TRUE) {
28620Sstevel@tonic-gate 		if (err != BIG_FALSE)
28630Sstevel@tonic-gate 			return (err);
2864*6557Sfr41279 		if ((err = big_add_abs(result, result, &big_Two)) != BIG_OK)
28650Sstevel@tonic-gate 			return (err);
28660Sstevel@tonic-gate 	}
28670Sstevel@tonic-gate 	return (BIG_OK);
28680Sstevel@tonic-gate }
28690Sstevel@tonic-gate 
28700Sstevel@tonic-gate 
28710Sstevel@tonic-gate /*
28720Sstevel@tonic-gate  * given m and e, computes the rest in the equation
28730Sstevel@tonic-gate  * gcd(m, e) = cm * m + ce * e
28740Sstevel@tonic-gate  */
28750Sstevel@tonic-gate BIG_ERR_CODE
28760Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e)
28770Sstevel@tonic-gate {
2878*6557Sfr41279 	BIGNUM		*xi, *ri, *riminus1, *riminus2, *t;
2879*6557Sfr41279 	BIGNUM		*vmi, *vei, *vmiminus1, *veiminus1;
2880*6557Sfr41279 	BIGNUM		t1, t2, t3, t4, t5, t6, t7, t8, tmp;
2881*6557Sfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
2882*6557Sfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
2883*6557Sfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
2884*6557Sfr41279 	BIG_CHUNK_TYPE	t4value[BIGTMPSIZE];
2885*6557Sfr41279 	BIG_CHUNK_TYPE	t5value[BIGTMPSIZE];
2886*6557Sfr41279 	BIG_CHUNK_TYPE	t6value[BIGTMPSIZE];
2887*6557Sfr41279 	BIG_CHUNK_TYPE	t7value[BIGTMPSIZE];
2888*6557Sfr41279 	BIG_CHUNK_TYPE	t8value[BIGTMPSIZE];
2889*6557Sfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
2890*6557Sfr41279 	BIG_ERR_CODE	err;
2891*6557Sfr41279 	int		len;
2892*6557Sfr41279 
2893*6557Sfr41279 	if (big_cmp_abs(m, e) >= 0) {
2894*6557Sfr41279 		len = m->len;
2895*6557Sfr41279 	} else {
2896*6557Sfr41279 		len = e->len;
2897*6557Sfr41279 	}
28980Sstevel@tonic-gate 
28990Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
2900*6557Sfr41279 	    t1value, arraysize(t1value))) != BIG_OK) {
29010Sstevel@tonic-gate 		return (err);
2902*6557Sfr41279 	}
29030Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
2904*6557Sfr41279 	    t2value, arraysize(t2value))) != BIG_OK) {
2905*6557Sfr41279 		goto ret1;
2906*6557Sfr41279 	}
29070Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
2908*6557Sfr41279 	    t3value, arraysize(t3value))) != BIG_OK) {
2909*6557Sfr41279 		goto ret2;
2910*6557Sfr41279 	}
29110Sstevel@tonic-gate 	if ((err = big_init1(&t4, len,
2912*6557Sfr41279 	    t4value, arraysize(t3value))) != BIG_OK) {
2913*6557Sfr41279 		goto ret3;
2914*6557Sfr41279 	}
29150Sstevel@tonic-gate 	if ((err = big_init1(&t5, len,
2916*6557Sfr41279 	    t5value, arraysize(t5value))) != BIG_OK) {
2917*6557Sfr41279 		goto ret4;
2918*6557Sfr41279 	}
29190Sstevel@tonic-gate 	if ((err = big_init1(&t6, len,
2920*6557Sfr41279 	    t6value, arraysize(t6value))) != BIG_OK) {
2921*6557Sfr41279 		goto ret5;
2922*6557Sfr41279 	}
29230Sstevel@tonic-gate 	if ((err = big_init1(&t7, len,
2924*6557Sfr41279 	    t7value, arraysize(t7value))) != BIG_OK) {
2925*6557Sfr41279 		goto ret6;
2926*6557Sfr41279 	}
29270Sstevel@tonic-gate 	if ((err = big_init1(&t8, len,
2928*6557Sfr41279 	    t8value, arraysize(t8value))) != BIG_OK) {
2929*6557Sfr41279 		goto ret7;
2930*6557Sfr41279 	}
29310Sstevel@tonic-gate 
29320Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * len,
2933*6557Sfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
29340Sstevel@tonic-gate 		goto ret8;
2935*6557Sfr41279 	}
29360Sstevel@tonic-gate 
29370Sstevel@tonic-gate 	ri = &t1;
29380Sstevel@tonic-gate 	ri->value[0] = 1;
29390Sstevel@tonic-gate 	ri->len = 1;
29400Sstevel@tonic-gate 	xi = &t2;
29410Sstevel@tonic-gate 	riminus1 = &t3;
29420Sstevel@tonic-gate 	riminus2 = &t4;
29430Sstevel@tonic-gate 	vmi = &t5;
29440Sstevel@tonic-gate 	vei = &t6;
29450Sstevel@tonic-gate 	vmiminus1 = &t7;
29460Sstevel@tonic-gate 	veiminus1 = &t8;
29470Sstevel@tonic-gate 
2948*6557Sfr41279 	(void) big_copy(vmiminus1, &big_One);
2949*6557Sfr41279 	(void) big_copy(vmi, &big_One);
2950*6557Sfr41279 	(void) big_copy(veiminus1, &big_One);
2951*6557Sfr41279 	(void) big_copy(xi, &big_One);
29520Sstevel@tonic-gate 	vei->len = 1;
29530Sstevel@tonic-gate 	vei->value[0] = 0;
29540Sstevel@tonic-gate 
29550Sstevel@tonic-gate 	(void) big_copy(riminus1, m);
29560Sstevel@tonic-gate 	(void) big_copy(ri, e);
29570Sstevel@tonic-gate 
29580Sstevel@tonic-gate 	while (!big_is_zero(ri)) {
29590Sstevel@tonic-gate 		t = riminus2;
29600Sstevel@tonic-gate 		riminus2 = riminus1;
29610Sstevel@tonic-gate 		riminus1 = ri;
29620Sstevel@tonic-gate 		ri = t;
2963*6557Sfr41279 		if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK) {
29640Sstevel@tonic-gate 			goto ret;
2965*6557Sfr41279 		}
2966*6557Sfr41279 		if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK) {
29670Sstevel@tonic-gate 			goto ret;
2968*6557Sfr41279 		}
29690Sstevel@tonic-gate 		t = vmiminus1;
29700Sstevel@tonic-gate 		vmiminus1 = vmi;
29710Sstevel@tonic-gate 		vmi = t;
2972*6557Sfr41279 		if ((err = big_mul(&tmp, vei, xi)) != BIG_OK) {
29730Sstevel@tonic-gate 			goto ret;
2974*6557Sfr41279 		}
2975*6557Sfr41279 		if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK) {
29760Sstevel@tonic-gate 			goto ret;
2977*6557Sfr41279 		}
29780Sstevel@tonic-gate 		t = veiminus1;
29790Sstevel@tonic-gate 		veiminus1 = vei;
29800Sstevel@tonic-gate 		vei = t;
2981*6557Sfr41279 		if ((err = big_div_pos(xi, ri, riminus2, riminus1)) !=
2982*6557Sfr41279 		    BIG_OK) {
29830Sstevel@tonic-gate 			goto ret;
2984*6557Sfr41279 		}
29850Sstevel@tonic-gate 	}
2986*6557Sfr41279 	if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK)) {
29870Sstevel@tonic-gate 		goto ret;
2988*6557Sfr41279 	}
2989*6557Sfr41279 	if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK)) {
29900Sstevel@tonic-gate 		goto ret;
2991*6557Sfr41279 	}
2992*6557Sfr41279 	if (ce != NULL) {
29930Sstevel@tonic-gate 		err = big_copy(ce, vei);
2994*6557Sfr41279 	}
29950Sstevel@tonic-gate ret:
29960Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
29970Sstevel@tonic-gate ret8:
29980Sstevel@tonic-gate 	if (t8.malloced) big_finish(&t8);
29990Sstevel@tonic-gate ret7:
30000Sstevel@tonic-gate 	if (t7.malloced) big_finish(&t7);
30010Sstevel@tonic-gate ret6:
30020Sstevel@tonic-gate 	if (t6.malloced) big_finish(&t6);
30030Sstevel@tonic-gate ret5:
30040Sstevel@tonic-gate 	if (t5.malloced) big_finish(&t5);
30050Sstevel@tonic-gate ret4:
30060Sstevel@tonic-gate 	if (t4.malloced) big_finish(&t4);
30070Sstevel@tonic-gate ret3:
30080Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
30090Sstevel@tonic-gate ret2:
30100Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
30110Sstevel@tonic-gate ret1:
30120Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
30130Sstevel@tonic-gate 
30140Sstevel@tonic-gate 	return (err);
30150Sstevel@tonic-gate }
3016