xref: /onnv-gate/usr/src/common/bignum/bignumimpl.c (revision 9302:c5903caf1c2d)
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
56557Sfr41279  * Common Development and Distribution License (the "License").
66557Sfr41279  * 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 /*
228933Sopensolaris@drydog.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * Configuration guide
280Sstevel@tonic-gate  * -------------------
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * There are 4 preprocessor symbols used to configure the bignum
310Sstevel@tonic-gate  * implementation.  This file contains no logic to configure based on
320Sstevel@tonic-gate  * processor; we leave that to the Makefiles to specify.
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * USE_FLOATING_POINT
350Sstevel@tonic-gate  *   Meaning: There is support for a fast floating-point implementation of
360Sstevel@tonic-gate  *   Montgomery multiply.
370Sstevel@tonic-gate  *
380Sstevel@tonic-gate  * PSR_MUL
390Sstevel@tonic-gate  *   Meaning: There are processor-specific versions of the low level
400Sstevel@tonic-gate  *   functions to implement big_mul.  Those functions are: big_mul_set_vec,
410Sstevel@tonic-gate  *   big_mul_add_vec, big_mul_vec, and big_sqr_vec.  PSR_MUL implies support
420Sstevel@tonic-gate  *   for all 4 functions.  You cannot pick and choose which subset of these
430Sstevel@tonic-gate  *   functions to support; that would lead to a rat's nest of #ifdefs.
440Sstevel@tonic-gate  *
450Sstevel@tonic-gate  * HWCAP
460Sstevel@tonic-gate  *   Meaning: Call multiply support functions through a function pointer.
478933Sopensolaris@drydog.com  *   On x86, there are multiple implementations for different hardware
480Sstevel@tonic-gate  *   capabilities, such as MMX, SSE2, etc.  Tests are made at run-time, when
490Sstevel@tonic-gate  *   a function is first used.  So, the support functions are called through
500Sstevel@tonic-gate  *   a function pointer.  There is no need for that on Sparc, because there
510Sstevel@tonic-gate  *   is only one implementation; support functions are called directly.
520Sstevel@tonic-gate  *   Later, if there were some new VIS instruction, or something, and a
530Sstevel@tonic-gate  *   run-time test were needed, rather than variant kernel modules and
540Sstevel@tonic-gate  *   libraries, then HWCAP would be defined for Sparc, as well.
550Sstevel@tonic-gate  *
560Sstevel@tonic-gate  * UMUL64
570Sstevel@tonic-gate  *   Meaning: It is safe to use generic C code that assumes the existence
580Sstevel@tonic-gate  *   of a 32 x 32 --> 64 bit unsigned multiply.  If this is not defined,
590Sstevel@tonic-gate  *   then the generic code for big_mul_add_vec() must necessarily be very slow,
600Sstevel@tonic-gate  *   because it must fall back to using 16 x 16 --> 32 bit multiplication.
610Sstevel@tonic-gate  *
620Sstevel@tonic-gate  */
630Sstevel@tonic-gate 
640Sstevel@tonic-gate 
658933Sopensolaris@drydog.com #include <sys/types.h>
668933Sopensolaris@drydog.com #include "bignum.h"
678933Sopensolaris@drydog.com 
680Sstevel@tonic-gate #ifdef	_KERNEL
696557Sfr41279 #include <sys/ddi.h>
706557Sfr41279 #include <sys/mdesc.h>
716557Sfr41279 #include <sys/crypto/common.h>
720Sstevel@tonic-gate 
730Sstevel@tonic-gate #include <sys/kmem.h>
740Sstevel@tonic-gate #include <sys/param.h>
750Sstevel@tonic-gate #include <sys/sunddi.h>
760Sstevel@tonic-gate 
778933Sopensolaris@drydog.com #else
788933Sopensolaris@drydog.com #include <stdlib.h>
798933Sopensolaris@drydog.com #include <stdio.h>
808933Sopensolaris@drydog.com #include <assert.h>
818933Sopensolaris@drydog.com #define	ASSERT	assert
828933Sopensolaris@drydog.com #endif	/* _KERNEL */
838933Sopensolaris@drydog.com 
84*9302Sopensolaris@drydog.com #ifdef __amd64
85*9302Sopensolaris@drydog.com #ifdef _KERNEL
86*9302Sopensolaris@drydog.com #include <sys/x86_archext.h>	/* cpuid_getvendor() */
87*9302Sopensolaris@drydog.com #include <sys/cpuvar.h>
88*9302Sopensolaris@drydog.com #else
89*9302Sopensolaris@drydog.com #include <sys/auxv.h>		/* getisax() */
90*9302Sopensolaris@drydog.com #endif  /* _KERNEL */
91*9302Sopensolaris@drydog.com #endif  /* __amd64 */
92*9302Sopensolaris@drydog.com 
93*9302Sopensolaris@drydog.com 
948933Sopensolaris@drydog.com #ifdef	_LP64 /* truncate 64-bit size_t to 32-bits */
958933Sopensolaris@drydog.com #define	UI32(ui)	((uint32_t)ui)
968933Sopensolaris@drydog.com #else /* size_t already 32-bits */
978933Sopensolaris@drydog.com #define	UI32(ui)	(ui)
988933Sopensolaris@drydog.com #endif
998933Sopensolaris@drydog.com 
1008933Sopensolaris@drydog.com 
1018933Sopensolaris@drydog.com #ifdef	_KERNEL
1020Sstevel@tonic-gate #define	big_malloc(size)	kmem_alloc(size, KM_NOSLEEP)
1030Sstevel@tonic-gate #define	big_free(ptr, size)	kmem_free(ptr, size)
1040Sstevel@tonic-gate 
105*9302Sopensolaris@drydog.com /*
106*9302Sopensolaris@drydog.com  * big_realloc()
107*9302Sopensolaris@drydog.com  * Allocate memory of newsize bytes and copy oldsize bytes
108*9302Sopensolaris@drydog.com  * to the newly-allocated memory, then free the
109*9302Sopensolaris@drydog.com  * previously-allocated memory.
110*9302Sopensolaris@drydog.com  * Note: newsize must be > oldsize
111*9302Sopensolaris@drydog.com  */
1120Sstevel@tonic-gate void *
1130Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize)
1140Sstevel@tonic-gate {
1150Sstevel@tonic-gate 	void *rv;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	rv = kmem_alloc(newsize, KM_NOSLEEP);
1180Sstevel@tonic-gate 	if (rv != NULL)
1190Sstevel@tonic-gate 		bcopy(from, rv, oldsize);
1200Sstevel@tonic-gate 	kmem_free(from, oldsize);
1210Sstevel@tonic-gate 	return (rv);
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate #else	/* _KERNEL */
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate #ifndef MALLOC_DEBUG
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate #define	big_malloc(size)	malloc(size)
1290Sstevel@tonic-gate #define	big_free(ptr, size)	free(ptr)
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate #else
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate void
1340Sstevel@tonic-gate big_free(void *ptr, size_t size)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 	printf("freed %d bytes at %p\n", size, ptr);
1370Sstevel@tonic-gate 	free(ptr);
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate void *
1410Sstevel@tonic-gate big_malloc(size_t size)
1420Sstevel@tonic-gate {
1430Sstevel@tonic-gate 	void *rv;
1440Sstevel@tonic-gate 	rv = malloc(size);
1450Sstevel@tonic-gate 	printf("malloced %d bytes, addr:%p\n", size, rv);
1460Sstevel@tonic-gate 	return (rv);
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate #endif /* MALLOC_DEBUG */
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate #define	big_realloc(x, y, z) realloc((x), (z))
1510Sstevel@tonic-gate 
1528933Sopensolaris@drydog.com 
1538933Sopensolaris@drydog.com /*
1548933Sopensolaris@drydog.com  * printbignum()
1558933Sopensolaris@drydog.com  * Print a BIGNUM type to stdout.
1568933Sopensolaris@drydog.com  */
1570Sstevel@tonic-gate void
1580Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate 	int i;
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	(void) printf("\n%s\n%d\n", aname, a->sign*a->len);
1630Sstevel@tonic-gate 	for (i = a->len - 1; i >= 0; i--) {
1646557Sfr41279 #ifdef BIGNUM_CHUNK_32
1650Sstevel@tonic-gate 		(void) printf("%08x ", a->value[i]);
1668933Sopensolaris@drydog.com 		if (((i & (BITSINBYTE - 1)) == 0) && (i != 0)) {
1676557Sfr41279 			(void) printf("\n");
1686557Sfr41279 		}
1696557Sfr41279 #else
1706557Sfr41279 		(void) printf("%08x %08x ", (uint32_t)((a->value[i]) >> 32),
1716557Sfr41279 		    (uint32_t)((a->value[i]) & 0xffffffff));
1728933Sopensolaris@drydog.com 		if (((i & 3) == 0) && (i != 0)) { /* end of this chunk */
1736557Sfr41279 			(void) printf("\n");
1746557Sfr41279 		}
1756557Sfr41279 #endif
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 	(void) printf("\n");
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate #endif	/* _KERNEL */
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 
183*9302Sopensolaris@drydog.com #ifdef  __amd64
184*9302Sopensolaris@drydog.com /*
185*9302Sopensolaris@drydog.com  * Return 1 if executing on Intel, otherwise 0 (e.g., AMD64).
186*9302Sopensolaris@drydog.com  */
187*9302Sopensolaris@drydog.com static int
188*9302Sopensolaris@drydog.com bignum_on_intel(void)
189*9302Sopensolaris@drydog.com {
190*9302Sopensolaris@drydog.com #ifdef _KERNEL
191*9302Sopensolaris@drydog.com 	return (cpuid_getvendor(CPU) == X86_VENDOR_Intel);
192*9302Sopensolaris@drydog.com #else
193*9302Sopensolaris@drydog.com 	uint_t  ui;
194*9302Sopensolaris@drydog.com 	(void) getisax(&ui, 1);
195*9302Sopensolaris@drydog.com 	return ((ui & AV_386_AMD_MMX) == 0);
196*9302Sopensolaris@drydog.com #endif  /* _KERNEL */
197*9302Sopensolaris@drydog.com }
198*9302Sopensolaris@drydog.com #endif  /* __amd64 */
199*9302Sopensolaris@drydog.com 
200*9302Sopensolaris@drydog.com 
2018933Sopensolaris@drydog.com /*
2028933Sopensolaris@drydog.com  * big_init()
2038933Sopensolaris@drydog.com  * Initialize and allocate memory for a BIGNUM type.
2048933Sopensolaris@drydog.com  *
2058933Sopensolaris@drydog.com  * big_init(number, size) is equivalent to big_init1(number, size, NULL, 0)
2068933Sopensolaris@drydog.com  *
2078933Sopensolaris@drydog.com  * Note: call big_finish() to free memory allocated by big_init().
2088933Sopensolaris@drydog.com  *
2098933Sopensolaris@drydog.com  * Input:
2108933Sopensolaris@drydog.com  * number	Uninitialized memory for BIGNUM
2118933Sopensolaris@drydog.com  * size		Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM
2128933Sopensolaris@drydog.com  *
2138933Sopensolaris@drydog.com  * Output:
2148933Sopensolaris@drydog.com  * number	Initialized BIGNUM
2158933Sopensolaris@drydog.com  *
2168933Sopensolaris@drydog.com  * Return BIG_OK on success or BIG_NO_MEM for an allocation error.
2178933Sopensolaris@drydog.com  */
2180Sstevel@tonic-gate BIG_ERR_CODE
2190Sstevel@tonic-gate big_init(BIGNUM *number, int size)
2200Sstevel@tonic-gate {
2218933Sopensolaris@drydog.com 	number->value = big_malloc(BIGNUM_WORDSIZE * size);
2220Sstevel@tonic-gate 	if (number->value == NULL) {
2230Sstevel@tonic-gate 		return (BIG_NO_MEM);
2240Sstevel@tonic-gate 	}
2250Sstevel@tonic-gate 	number->size = size;
2260Sstevel@tonic-gate 	number->len = 0;
2270Sstevel@tonic-gate 	number->sign = 1;
2280Sstevel@tonic-gate 	number->malloced = 1;
2290Sstevel@tonic-gate 	return (BIG_OK);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate 
2328933Sopensolaris@drydog.com 
2338933Sopensolaris@drydog.com /*
2348933Sopensolaris@drydog.com  * big_init1()
2358933Sopensolaris@drydog.com  * Initialize and, if needed, allocate memory for a BIGNUM type.
2368933Sopensolaris@drydog.com  * Use the buffer passed, buf, if any, instad of allocating memory
2378933Sopensolaris@drydog.com  * if it's at least "size" bytes.
2388933Sopensolaris@drydog.com  *
2398933Sopensolaris@drydog.com  * Note: call big_finish() to free memory allocated by big_init().
2408933Sopensolaris@drydog.com  *
2418933Sopensolaris@drydog.com  * Input:
2428933Sopensolaris@drydog.com  * number	Uninitialized memory for BIGNUM
2438933Sopensolaris@drydog.com  * size		Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM
2448933Sopensolaris@drydog.com  * buf		Buffer for storing a BIGNUM.
2458933Sopensolaris@drydog.com  *		If NULL, big_init1() will allocate a buffer
2468933Sopensolaris@drydog.com  * bufsize	Size, in BIG_CHUNK_SIZE_bit words, of buf
2478933Sopensolaris@drydog.com  *
2488933Sopensolaris@drydog.com  * Output:
2498933Sopensolaris@drydog.com  * number	Initialized BIGNUM
2508933Sopensolaris@drydog.com  *
2518933Sopensolaris@drydog.com  * Return BIG_OK on success or BIG_NO_MEM for an allocation error.
2528933Sopensolaris@drydog.com  */
2530Sstevel@tonic-gate BIG_ERR_CODE
2546557Sfr41279 big_init1(BIGNUM *number, int size, BIG_CHUNK_TYPE *buf, int bufsize)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate 	if ((buf == NULL) || (size > bufsize)) {
2578933Sopensolaris@drydog.com 		number->value = big_malloc(BIGNUM_WORDSIZE * size);
2580Sstevel@tonic-gate 		if (number->value == NULL) {
2590Sstevel@tonic-gate 			return (BIG_NO_MEM);
2600Sstevel@tonic-gate 		}
2610Sstevel@tonic-gate 		number->size = size;
2620Sstevel@tonic-gate 		number->malloced = 1;
2630Sstevel@tonic-gate 	} else {
2640Sstevel@tonic-gate 		number->value = buf;
2650Sstevel@tonic-gate 		number->size = bufsize;
2660Sstevel@tonic-gate 		number->malloced = 0;
2670Sstevel@tonic-gate 	}
2688933Sopensolaris@drydog.com 	number->len = 0;
2698933Sopensolaris@drydog.com 	number->sign = 1;
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	return (BIG_OK);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate 
2748933Sopensolaris@drydog.com 
2758933Sopensolaris@drydog.com /*
2768933Sopensolaris@drydog.com  * big_finish()
2778933Sopensolaris@drydog.com  * Free memory, if any, allocated by big_init() or big_init1().
2788933Sopensolaris@drydog.com  */
2790Sstevel@tonic-gate void
2800Sstevel@tonic-gate big_finish(BIGNUM *number)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate 	if (number->malloced == 1) {
2838933Sopensolaris@drydog.com 		big_free(number->value, BIGNUM_WORDSIZE * number->size);
2840Sstevel@tonic-gate 		number->malloced = 0;
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate 
2886557Sfr41279 
2890Sstevel@tonic-gate /*
2908933Sopensolaris@drydog.com  * bn->size should be at least
2918933Sopensolaris@drydog.com  * (len + BIGNUM_WORDSIZE - 1) / BIGNUM_WORDSIZE bytes
2920Sstevel@tonic-gate  * converts from byte-big-endian format to bignum format (words in
2930Sstevel@tonic-gate  * little endian order, but bytes within the words big endian)
2940Sstevel@tonic-gate  */
2950Sstevel@tonic-gate void
2960Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len)
2970Sstevel@tonic-gate {
2988933Sopensolaris@drydog.com 	int		i, j;
2998933Sopensolaris@drydog.com 	uint32_t	offs;
3008933Sopensolaris@drydog.com 	const uint32_t	slen = UI32(len);
3016557Sfr41279 	BIG_CHUNK_TYPE	word;
3020Sstevel@tonic-gate 	uchar_t		*knwordp;
3030Sstevel@tonic-gate 
3048933Sopensolaris@drydog.com 	if (slen == 0) {
3058933Sopensolaris@drydog.com 		bn->len = 1;
3068933Sopensolaris@drydog.com 		bn->value[0] = 0;
3078933Sopensolaris@drydog.com 		return;
3088933Sopensolaris@drydog.com 	}
3098933Sopensolaris@drydog.com 
3108933Sopensolaris@drydog.com 	offs = slen % BIGNUM_WORDSIZE;
3118933Sopensolaris@drydog.com 	bn->len = slen / BIGNUM_WORDSIZE;
3128933Sopensolaris@drydog.com 
3138933Sopensolaris@drydog.com 	for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) {
3148933Sopensolaris@drydog.com 		knwordp = &(kn[slen - BIGNUM_WORDSIZE * (i + 1)]);
3150Sstevel@tonic-gate 		word = knwordp[0];
3168933Sopensolaris@drydog.com 		for (j = 1; j < BIGNUM_WORDSIZE; j++) {
3178933Sopensolaris@drydog.com 			word = (word << BITSINBYTE) + knwordp[j];
3180Sstevel@tonic-gate 		}
3190Sstevel@tonic-gate 		bn->value[i] = word;
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 	if (offs > 0) {
3220Sstevel@tonic-gate 		word = kn[0];
3238933Sopensolaris@drydog.com 		for (i = 1; i < offs; i++) word = (word << BITSINBYTE) + kn[i];
3240Sstevel@tonic-gate 		bn->value[bn->len++] = word;
3250Sstevel@tonic-gate 	}
3268933Sopensolaris@drydog.com 	while ((bn->len > 1) && (bn->value[bn->len - 1] == 0)) {
3270Sstevel@tonic-gate 		bn->len --;
3280Sstevel@tonic-gate 	}
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate 
3318933Sopensolaris@drydog.com 
3320Sstevel@tonic-gate /*
3330Sstevel@tonic-gate  * copies the least significant len bytes if
3348933Sopensolaris@drydog.com  * len < bn->len * BIGNUM_WORDSIZE
3350Sstevel@tonic-gate  * converts from bignum format to byte-big-endian format.
3366557Sfr41279  * bignum format is words of type  BIG_CHUNK_TYPE in little endian order.
3370Sstevel@tonic-gate  */
3380Sstevel@tonic-gate void
3390Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len)
3400Sstevel@tonic-gate {
3418933Sopensolaris@drydog.com 	int		i, j;
3428933Sopensolaris@drydog.com 	uint32_t	offs;
3438933Sopensolaris@drydog.com 	const uint32_t	slen = UI32(len);
3446557Sfr41279 	BIG_CHUNK_TYPE	word;
3456557Sfr41279 
3468933Sopensolaris@drydog.com 	if (len < BIGNUM_WORDSIZE * bn->len) {
3478933Sopensolaris@drydog.com 		for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) {
3480Sstevel@tonic-gate 			word = bn->value[i];
3498933Sopensolaris@drydog.com 			for (j = 0; j < BIGNUM_WORDSIZE; j++) {
3508933Sopensolaris@drydog.com 				kn[slen - BIGNUM_WORDSIZE * i - j - 1] =
3510Sstevel@tonic-gate 				    word & 0xff;
3528933Sopensolaris@drydog.com 				word = word >> BITSINBYTE;
3530Sstevel@tonic-gate 			}
3540Sstevel@tonic-gate 		}
3558933Sopensolaris@drydog.com 		offs = slen % BIGNUM_WORDSIZE;
3560Sstevel@tonic-gate 		if (offs > 0) {
3578933Sopensolaris@drydog.com 			word = bn->value[slen / BIGNUM_WORDSIZE];
3588933Sopensolaris@drydog.com 			for (i =  slen % BIGNUM_WORDSIZE; i > 0; i --) {
3596557Sfr41279 				kn[i - 1] = word & 0xff;
3608933Sopensolaris@drydog.com 				word = word >> BITSINBYTE;
3616557Sfr41279 			}
3620Sstevel@tonic-gate 		}
3630Sstevel@tonic-gate 	} else {
3640Sstevel@tonic-gate 		for (i = 0; i < bn->len; i++) {
3650Sstevel@tonic-gate 			word = bn->value[i];
3668933Sopensolaris@drydog.com 			for (j = 0; j < BIGNUM_WORDSIZE; j++) {
3678933Sopensolaris@drydog.com 				kn[slen - BIGNUM_WORDSIZE * i - j - 1] =
3680Sstevel@tonic-gate 				    word & 0xff;
3698933Sopensolaris@drydog.com 				word = word >> BITSINBYTE;
3700Sstevel@tonic-gate 			}
3710Sstevel@tonic-gate 		}
3728933Sopensolaris@drydog.com 		for (i = 0; i < slen - BIGNUM_WORDSIZE * bn->len; i++) {
3730Sstevel@tonic-gate 			kn[i] = 0;
3740Sstevel@tonic-gate 		}
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate int
3800Sstevel@tonic-gate big_bitlength(BIGNUM *a)
3810Sstevel@tonic-gate {
3826557Sfr41279 	int		l = 0, b = 0;
3836557Sfr41279 	BIG_CHUNK_TYPE	c;
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	l = a->len - 1;
3860Sstevel@tonic-gate 	while ((l > 0) && (a->value[l] == 0)) {
3870Sstevel@tonic-gate 		l--;
3880Sstevel@tonic-gate 	}
3898933Sopensolaris@drydog.com 	b = BIG_CHUNK_SIZE;
3900Sstevel@tonic-gate 	c = a->value[l];
3916557Sfr41279 	while ((b > 1) && ((c & BIG_CHUNK_HIGHBIT) == 0)) {
3920Sstevel@tonic-gate 		c = c << 1;
3930Sstevel@tonic-gate 		b--;
3940Sstevel@tonic-gate 	}
3956557Sfr41279 
3968933Sopensolaris@drydog.com 	return (l * BIG_CHUNK_SIZE + b);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 
400*9302Sopensolaris@drydog.com /*
401*9302Sopensolaris@drydog.com  * big_copy()
402*9302Sopensolaris@drydog.com  * Copy BIGNUM src to dest, allocating memory if needed.
403*9302Sopensolaris@drydog.com  */
4040Sstevel@tonic-gate BIG_ERR_CODE
4050Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src)
4060Sstevel@tonic-gate {
4076557Sfr41279 	BIG_CHUNK_TYPE	*newptr;
4086557Sfr41279 	int		i, len;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	len = src->len;
4116557Sfr41279 	while ((len > 1) && (src->value[len - 1] == 0)) {
4120Sstevel@tonic-gate 		len--;
4136557Sfr41279 	}
4140Sstevel@tonic-gate 	src->len = len;
4150Sstevel@tonic-gate 	if (dest->size < len) {
4160Sstevel@tonic-gate 		if (dest->malloced == 1) {
4176557Sfr41279 			newptr = (BIG_CHUNK_TYPE *)big_realloc(dest->value,
4188933Sopensolaris@drydog.com 			    BIGNUM_WORDSIZE * dest->size,
4198933Sopensolaris@drydog.com 			    BIGNUM_WORDSIZE * len);
4200Sstevel@tonic-gate 		} else {
4216557Sfr41279 			newptr = (BIG_CHUNK_TYPE *)
4228933Sopensolaris@drydog.com 			    big_malloc(BIGNUM_WORDSIZE * len);
4236557Sfr41279 			if (newptr != NULL) {
4246557Sfr41279 				dest->malloced = 1;
4256557Sfr41279 			}
4260Sstevel@tonic-gate 		}
4276557Sfr41279 		if (newptr == NULL) {
4280Sstevel@tonic-gate 			return (BIG_NO_MEM);
4296557Sfr41279 		}
4300Sstevel@tonic-gate 		dest->value = newptr;
4310Sstevel@tonic-gate 		dest->size = len;
4320Sstevel@tonic-gate 	}
4330Sstevel@tonic-gate 	dest->len = len;
4340Sstevel@tonic-gate 	dest->sign = src->sign;
4356557Sfr41279 	for (i = 0; i < len; i++) {
4366557Sfr41279 		dest->value[i] = src->value[i];
4376557Sfr41279 	}
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	return (BIG_OK);
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 
443*9302Sopensolaris@drydog.com /*
444*9302Sopensolaris@drydog.com  * big_extend()
445*9302Sopensolaris@drydog.com  * Allocate memory to extend BIGNUM number to size bignum chunks,
446*9302Sopensolaris@drydog.com  * if not at least that size already.
447*9302Sopensolaris@drydog.com  */
4480Sstevel@tonic-gate BIG_ERR_CODE
4490Sstevel@tonic-gate big_extend(BIGNUM *number, int size)
4500Sstevel@tonic-gate {
4516557Sfr41279 	BIG_CHUNK_TYPE	*newptr;
4520Sstevel@tonic-gate 	int		i;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	if (number->size >= size)
4550Sstevel@tonic-gate 		return (BIG_OK);
4560Sstevel@tonic-gate 	if (number->malloced) {
4576557Sfr41279 		number->value = big_realloc(number->value,
4588933Sopensolaris@drydog.com 		    BIGNUM_WORDSIZE * number->size,
4598933Sopensolaris@drydog.com 		    BIGNUM_WORDSIZE * size);
4600Sstevel@tonic-gate 	} else {
4618933Sopensolaris@drydog.com 		newptr = big_malloc(BIGNUM_WORDSIZE * size);
4620Sstevel@tonic-gate 		if (newptr != NULL) {
4630Sstevel@tonic-gate 			for (i = 0; i < number->size; i++) {
4640Sstevel@tonic-gate 				newptr[i] = number->value[i];
4650Sstevel@tonic-gate 			}
4660Sstevel@tonic-gate 		}
4670Sstevel@tonic-gate 		number->value = newptr;
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 
4706557Sfr41279 	if (number->value == NULL) {
4710Sstevel@tonic-gate 		return (BIG_NO_MEM);
4726557Sfr41279 	}
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	number->size = size;
4750Sstevel@tonic-gate 	number->malloced = 1;
4760Sstevel@tonic-gate 	return (BIG_OK);
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 
4806557Sfr41279 /* returns 1 if n == 0 */
4810Sstevel@tonic-gate int
4820Sstevel@tonic-gate big_is_zero(BIGNUM *n)
4830Sstevel@tonic-gate {
4846557Sfr41279 	int	i, result;
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	result = 1;
4876557Sfr41279 	for (i = 0; i < n->len; i++) {
4886557Sfr41279 		if (n->value[i] != 0) {
4896557Sfr41279 			result = 0;
4906557Sfr41279 		}
4916557Sfr41279 	}
4920Sstevel@tonic-gate 	return (result);
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate BIG_ERR_CODE
4970Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
4980Sstevel@tonic-gate {
4996557Sfr41279 	int		i, shorter, longer;
5006557Sfr41279 	BIG_CHUNK_TYPE	cy, ai;
5016557Sfr41279 	BIG_CHUNK_TYPE	*r, *a, *b, *c;
5026557Sfr41279 	BIG_ERR_CODE	err;
5036557Sfr41279 	BIGNUM		*longerarg;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	if (aa->len > bb->len) {
5060Sstevel@tonic-gate 		shorter = bb->len;
5070Sstevel@tonic-gate 		longer = aa->len;
5086557Sfr41279 		longerarg = aa;
5090Sstevel@tonic-gate 	} else {
5100Sstevel@tonic-gate 		shorter = aa->len;
5110Sstevel@tonic-gate 		longer = bb->len;
5126557Sfr41279 		longerarg = bb;
5130Sstevel@tonic-gate 	}
5140Sstevel@tonic-gate 	if (result->size < longer + 1) {
5150Sstevel@tonic-gate 		err = big_extend(result, longer + 1);
5166557Sfr41279 		if (err != BIG_OK) {
5170Sstevel@tonic-gate 			return (err);
5186557Sfr41279 		}
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	r = result->value;
5220Sstevel@tonic-gate 	a = aa->value;
5230Sstevel@tonic-gate 	b = bb->value;
5246557Sfr41279 	c = longerarg->value;
5250Sstevel@tonic-gate 	cy = 0;
5260Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
5270Sstevel@tonic-gate 		ai = a[i];
5280Sstevel@tonic-gate 		r[i] = ai + b[i] + cy;
5296557Sfr41279 		if (r[i] > ai) {
5306557Sfr41279 			cy = 0;
5316557Sfr41279 		} else if (r[i] < ai) {
5326557Sfr41279 			cy = 1;
5336557Sfr41279 		}
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 	for (; i < longer; i++) {
5360Sstevel@tonic-gate 		ai = c[i];
5370Sstevel@tonic-gate 		r[i] = ai + cy;
5386557Sfr41279 		if (r[i] >= ai) {
5396557Sfr41279 			cy = 0;
5406557Sfr41279 		}
5410Sstevel@tonic-gate 	}
5420Sstevel@tonic-gate 	if (cy == 1) {
5430Sstevel@tonic-gate 		r[i] = cy;
5440Sstevel@tonic-gate 		result->len = longer + 1;
5450Sstevel@tonic-gate 	} else {
5460Sstevel@tonic-gate 		result->len = longer;
5470Sstevel@tonic-gate 	}
5480Sstevel@tonic-gate 	result->sign = 1;
5490Sstevel@tonic-gate 	return (BIG_OK);
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */
5540Sstevel@tonic-gate void
5556557Sfr41279 big_sub_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, BIG_CHUNK_TYPE *b, int len)
5560Sstevel@tonic-gate {
5576557Sfr41279 	int		i;
5586557Sfr41279 	BIG_CHUNK_TYPE	cy, ai;
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	cy = 1;
5610Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
5620Sstevel@tonic-gate 		ai = a[i];
5630Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
5646557Sfr41279 		if (r[i] > ai) {
5656557Sfr41279 			cy = 0;
5666557Sfr41279 		} else if (r[i] < ai) {
5676557Sfr41279 			cy = 1;
5686557Sfr41279 		}
5690Sstevel@tonic-gate 	}
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate /* result=aa-bb  it is assumed that aa>=bb */
5740Sstevel@tonic-gate BIG_ERR_CODE
5750Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
5760Sstevel@tonic-gate {
5776557Sfr41279 	int		i, shorter;
5786557Sfr41279 	BIG_CHUNK_TYPE	cy = 1, ai;
5796557Sfr41279 	BIG_CHUNK_TYPE	*r, *a, *b;
5806557Sfr41279 	BIG_ERR_CODE	err = BIG_OK;
5816557Sfr41279 
5826557Sfr41279 	if (aa->len > bb->len) {
5836557Sfr41279 		shorter = bb->len;
5846557Sfr41279 	} else {
5856557Sfr41279 		shorter = aa->len;
5866557Sfr41279 	}
5870Sstevel@tonic-gate 	if (result->size < aa->len) {
5880Sstevel@tonic-gate 		err = big_extend(result, aa->len);
5896557Sfr41279 		if (err != BIG_OK) {
5900Sstevel@tonic-gate 			return (err);
5916557Sfr41279 		}
5920Sstevel@tonic-gate 	}
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	r = result->value;
5950Sstevel@tonic-gate 	a = aa->value;
5960Sstevel@tonic-gate 	b = bb->value;
5970Sstevel@tonic-gate 	result->len = aa->len;
5980Sstevel@tonic-gate 	cy = 1;
5990Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
6000Sstevel@tonic-gate 		ai = a[i];
6010Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
6026557Sfr41279 		if (r[i] > ai) {
6036557Sfr41279 			cy = 0;
6046557Sfr41279 		} else if (r[i] < ai) {
6056557Sfr41279 			cy = 1;
6066557Sfr41279 		}
6070Sstevel@tonic-gate 	}
6080Sstevel@tonic-gate 	for (; i < aa->len; i++) {
6090Sstevel@tonic-gate 		ai = a[i];
6100Sstevel@tonic-gate 		r[i] = ai + (~0) + cy;
6116557Sfr41279 		if (r[i] < ai) {
6126557Sfr41279 			cy = 1;
6136557Sfr41279 		}
6140Sstevel@tonic-gate 	}
6150Sstevel@tonic-gate 	result->sign = 1;
6166557Sfr41279 
6176557Sfr41279 	if (cy == 0) {
6180Sstevel@tonic-gate 		return (BIG_INVALID_ARGS);
6196557Sfr41279 	} else {
6200Sstevel@tonic-gate 		return (BIG_OK);
6216557Sfr41279 	}
6220Sstevel@tonic-gate }
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */
6260Sstevel@tonic-gate int
6270Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb)
6280Sstevel@tonic-gate {
6296557Sfr41279 	int	i;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	if (aa->len > bb->len) {
6320Sstevel@tonic-gate 		for (i = aa->len - 1; i > bb->len - 1; i--) {
6336557Sfr41279 			if (aa->value[i] > 0) {
6340Sstevel@tonic-gate 				return (1);
6356557Sfr41279 			}
6360Sstevel@tonic-gate 		}
6370Sstevel@tonic-gate 	} else if (aa->len < bb->len) {
6380Sstevel@tonic-gate 		for (i = bb->len - 1; i > aa->len - 1; i--) {
6396557Sfr41279 			if (bb->value[i] > 0) {
6400Sstevel@tonic-gate 				return (-1);
6416557Sfr41279 			}
6420Sstevel@tonic-gate 		}
6436557Sfr41279 	} else {
6448933Sopensolaris@drydog.com 		i = aa->len - 1;
6456557Sfr41279 	}
6460Sstevel@tonic-gate 	for (; i >= 0; i--) {
6476557Sfr41279 		if (aa->value[i] > bb->value[i]) {
6480Sstevel@tonic-gate 			return (1);
6496557Sfr41279 		} else if (aa->value[i] < bb->value[i]) {
6500Sstevel@tonic-gate 			return (-1);
6516557Sfr41279 		}
6520Sstevel@tonic-gate 	}
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	return (0);
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate BIG_ERR_CODE
6590Sstevel@tonic-gate big_sub(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
6600Sstevel@tonic-gate {
6616557Sfr41279 	BIG_ERR_CODE	err;
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == 1)) {
6646557Sfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
6650Sstevel@tonic-gate 			return (err);
6666557Sfr41279 		}
6670Sstevel@tonic-gate 		result->sign = 1;
6680Sstevel@tonic-gate 	} else if ((aa->sign == -1) && (bb->sign == 1)) {
6696557Sfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
6700Sstevel@tonic-gate 			return (err);
6716557Sfr41279 		}
6720Sstevel@tonic-gate 		result->sign = -1;
6730Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
6740Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
6756557Sfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6760Sstevel@tonic-gate 				return (err);
6776557Sfr41279 			}
6780Sstevel@tonic-gate 			result->sign = 1;
6790Sstevel@tonic-gate 		} else {
6806557Sfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6810Sstevel@tonic-gate 				return (err);
6826557Sfr41279 			}
6830Sstevel@tonic-gate 			result->sign = -1;
6840Sstevel@tonic-gate 		}
6850Sstevel@tonic-gate 	} else {
6860Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
6876557Sfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6880Sstevel@tonic-gate 				return (err);
6896557Sfr41279 			}
6900Sstevel@tonic-gate 			result->sign = -1;
6910Sstevel@tonic-gate 		} else {
6926557Sfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6930Sstevel@tonic-gate 				return (err);
6946557Sfr41279 			}
6950Sstevel@tonic-gate 			result->sign = 1;
6960Sstevel@tonic-gate 		}
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 	return (BIG_OK);
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate BIG_ERR_CODE
7030Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
7040Sstevel@tonic-gate {
7056557Sfr41279 	BIG_ERR_CODE	err;
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == -1)) {
7086557Sfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
7090Sstevel@tonic-gate 			return (err);
7106557Sfr41279 		}
7110Sstevel@tonic-gate 		result->sign = -1;
7120Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
7136557Sfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
7140Sstevel@tonic-gate 			return (err);
7156557Sfr41279 		}
7160Sstevel@tonic-gate 		result->sign = 1;
7170Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == -1)) {
7180Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
7196557Sfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
7200Sstevel@tonic-gate 				return (err);
7216557Sfr41279 			}
7220Sstevel@tonic-gate 			result->sign = 1;
7230Sstevel@tonic-gate 		} else {
7246557Sfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
7250Sstevel@tonic-gate 				return (err);
7266557Sfr41279 			}
7270Sstevel@tonic-gate 			result->sign = -1;
7280Sstevel@tonic-gate 		}
7290Sstevel@tonic-gate 	} else {
7300Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
7316557Sfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
7320Sstevel@tonic-gate 				return (err);
7336557Sfr41279 			}
7340Sstevel@tonic-gate 			result->sign = -1;
7350Sstevel@tonic-gate 		} else {
7366557Sfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
7370Sstevel@tonic-gate 				return (err);
7386557Sfr41279 			}
7390Sstevel@tonic-gate 			result->sign = 1;
7400Sstevel@tonic-gate 		}
7410Sstevel@tonic-gate 	}
7420Sstevel@tonic-gate 	return (BIG_OK);
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 
7466557Sfr41279 /* result = aa/2 */
7470Sstevel@tonic-gate BIG_ERR_CODE
7480Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa)
7490Sstevel@tonic-gate {
7506557Sfr41279 	BIG_ERR_CODE	err;
7516557Sfr41279 	int		i;
7526557Sfr41279 	BIG_CHUNK_TYPE	cy, cy1;
7536557Sfr41279 	BIG_CHUNK_TYPE	*a, *r;
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	if (result->size < aa->len) {
7560Sstevel@tonic-gate 		err = big_extend(result, aa->len);
7576557Sfr41279 		if (err != BIG_OK) {
7580Sstevel@tonic-gate 			return (err);
7596557Sfr41279 		}
7600Sstevel@tonic-gate 	}
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	result->len = aa->len;
7630Sstevel@tonic-gate 	a = aa->value;
7640Sstevel@tonic-gate 	r = result->value;
7650Sstevel@tonic-gate 	cy = 0;
7666557Sfr41279 	for (i = aa->len - 1; i >= 0; i--) {
7676557Sfr41279 		cy1 = a[i] << (BIG_CHUNK_SIZE - 1);
7686557Sfr41279 		r[i] = (cy | (a[i] >> 1));
7690Sstevel@tonic-gate 		cy = cy1;
7700Sstevel@tonic-gate 	}
7716557Sfr41279 	if (r[result->len - 1] == 0) {
7726557Sfr41279 		result->len--;
7736557Sfr41279 	}
7746557Sfr41279 
7750Sstevel@tonic-gate 	return (BIG_OK);
7760Sstevel@tonic-gate }
7770Sstevel@tonic-gate 
7786557Sfr41279 /* result  =  aa*2 */
7790Sstevel@tonic-gate BIG_ERR_CODE
7800Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa)
7810Sstevel@tonic-gate {
7826557Sfr41279 	BIG_ERR_CODE	err;
7836557Sfr41279 	int		i, rsize;
7846557Sfr41279 	BIG_CHUNK_TYPE	cy, cy1;
7856557Sfr41279 	BIG_CHUNK_TYPE	*a, *r;
7866557Sfr41279 
7876557Sfr41279 	if ((aa->len > 0) &&
7886557Sfr41279 	    ((aa->value[aa->len - 1] & BIG_CHUNK_HIGHBIT) != 0)) {
7890Sstevel@tonic-gate 		rsize = aa->len + 1;
7906557Sfr41279 	} else {
7916557Sfr41279 		rsize = aa->len;
7926557Sfr41279 	}
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	if (result->size < rsize) {
7950Sstevel@tonic-gate 		err = big_extend(result, rsize);
7960Sstevel@tonic-gate 		if (err != BIG_OK)
7970Sstevel@tonic-gate 			return (err);
7980Sstevel@tonic-gate 	}
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	a = aa->value;
8010Sstevel@tonic-gate 	r = result->value;
8026557Sfr41279 	if (rsize == aa->len + 1) {
8036557Sfr41279 		r[rsize - 1] = 1;
8046557Sfr41279 	}
8050Sstevel@tonic-gate 	cy = 0;
8060Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
8076557Sfr41279 		cy1 = a[i] >> (BIG_CHUNK_SIZE - 1);
8080Sstevel@tonic-gate 		r[i] = (cy | (a[i] << 1));
8090Sstevel@tonic-gate 		cy = cy1;
8100Sstevel@tonic-gate 	}
8110Sstevel@tonic-gate 	result->len = rsize;
8120Sstevel@tonic-gate 	return (BIG_OK);
8130Sstevel@tonic-gate }
8140Sstevel@tonic-gate 
8156557Sfr41279 
8166557Sfr41279 /*
8176557Sfr41279  * returns aa mod b, aa must be nonneg, b must be a max
8186557Sfr41279  * (BIG_CHUNK_SIZE / 2)-bit integer
8196557Sfr41279  */
8206557Sfr41279 static uint32_t
8216557Sfr41279 big_modhalf_pos(BIGNUM *aa, uint32_t b)
8220Sstevel@tonic-gate {
8236557Sfr41279 	int		i;
8246557Sfr41279 	BIG_CHUNK_TYPE	rem;
8256557Sfr41279 
8266557Sfr41279 	if (aa->len == 0) {
8270Sstevel@tonic-gate 		return (0);
8286557Sfr41279 	}
8290Sstevel@tonic-gate 	rem = aa->value[aa->len - 1] % b;
8300Sstevel@tonic-gate 	for (i = aa->len - 2; i >= 0; i--) {
8316557Sfr41279 		rem = ((rem << (BIG_CHUNK_SIZE / 2)) |
8326557Sfr41279 		    (aa->value[i] >> (BIG_CHUNK_SIZE / 2))) % b;
8336557Sfr41279 		rem = ((rem << (BIG_CHUNK_SIZE / 2)) |
8346557Sfr41279 		    (aa->value[i] & BIG_CHUNK_LOWHALFBITS)) % b;
8350Sstevel@tonic-gate 	}
8366557Sfr41279 
8376557Sfr41279 	return ((uint32_t)rem);
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate /*
8426557Sfr41279  * result = aa - (2^BIG_CHUNK_SIZE)^lendiff * bb
8430Sstevel@tonic-gate  * result->size should be at least aa->len at entry
8440Sstevel@tonic-gate  * aa, bb, and result should be positive
8450Sstevel@tonic-gate  */
8460Sstevel@tonic-gate void
8470Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
8480Sstevel@tonic-gate {
8490Sstevel@tonic-gate 	int i, lendiff;
8500Sstevel@tonic-gate 	BIGNUM res1, aa1;
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
8530Sstevel@tonic-gate 	res1.size = result->size - lendiff;
8540Sstevel@tonic-gate 	res1.malloced = 0;
8550Sstevel@tonic-gate 	res1.value = result->value + lendiff;
8560Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
8570Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
8580Sstevel@tonic-gate 	aa1.len = bb->len;
8590Sstevel@tonic-gate 	aa1.sign = 1;
8600Sstevel@tonic-gate 	(void) big_sub_pos(&res1, &aa1, bb);
8610Sstevel@tonic-gate 	if (result->value != aa->value) {
8620Sstevel@tonic-gate 		for (i = 0; i < lendiff; i++) {
8630Sstevel@tonic-gate 			result->value[i] = aa->value[i];
8640Sstevel@tonic-gate 		}
8650Sstevel@tonic-gate 	}
8660Sstevel@tonic-gate 	result->len = aa->len;
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate /*
8710Sstevel@tonic-gate  * returns 1, 0, or -1 depending on whether |aa| > , ==, or <
8726557Sfr41279  *					(2^BIG_CHUNK_SIZE)^lendiff * |bb|
8730Sstevel@tonic-gate  * aa->len should be >= bb->len
8740Sstevel@tonic-gate  */
8750Sstevel@tonic-gate int
8760Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb)
8770Sstevel@tonic-gate {
8788933Sopensolaris@drydog.com 	int		lendiff;
8798933Sopensolaris@drydog.com 	BIGNUM		aa1;
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
8820Sstevel@tonic-gate 	aa1.len = bb->len;
8830Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
8840Sstevel@tonic-gate 	aa1.malloced = 0;
8850Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
8860Sstevel@tonic-gate 	return (big_cmp_abs(&aa1, bb));
8870Sstevel@tonic-gate }
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate /*
8916557Sfr41279  * result = aa * b where b is a max. (BIG_CHUNK_SIZE / 2)-bit positive integer.
8920Sstevel@tonic-gate  * result should have enough space allocated.
8930Sstevel@tonic-gate  */
8946557Sfr41279 static void
8956557Sfr41279 big_mulhalf_low(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b)
8960Sstevel@tonic-gate {
8976557Sfr41279 	int		i;
8986557Sfr41279 	BIG_CHUNK_TYPE	t1, t2, ai, cy;
8996557Sfr41279 	BIG_CHUNK_TYPE	*a, *r;
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	a = aa->value;
9020Sstevel@tonic-gate 	r = result->value;
9030Sstevel@tonic-gate 	cy = 0;
9040Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
9050Sstevel@tonic-gate 		ai = a[i];
9066557Sfr41279 		t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy;
9076557Sfr41279 		t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b +
9086557Sfr41279 		    (t1 >> (BIG_CHUNK_SIZE / 2));
9096557Sfr41279 		r[i] = (t1 & BIG_CHUNK_LOWHALFBITS) |
9106557Sfr41279 		    (t2 << (BIG_CHUNK_SIZE / 2));
9116557Sfr41279 		cy = t2 >> (BIG_CHUNK_SIZE / 2);
9120Sstevel@tonic-gate 	}
9130Sstevel@tonic-gate 	r[i] = cy;
9140Sstevel@tonic-gate 	result->len = aa->len + 1;
9150Sstevel@tonic-gate 	result->sign = aa->sign;
9160Sstevel@tonic-gate }
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate /*
9206557Sfr41279  * result = aa * b * 2^(BIG_CHUNK_SIZE / 2) where b is a max.
9216557Sfr41279  * (BIG_CHUNK_SIZE / 2)-bit positive integer.
9220Sstevel@tonic-gate  * result should have enough space allocated.
9230Sstevel@tonic-gate  */
9246557Sfr41279 static void
9256557Sfr41279 big_mulhalf_high(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b)
9260Sstevel@tonic-gate {
9276557Sfr41279 	int		i;
9286557Sfr41279 	BIG_CHUNK_TYPE	t1, t2, ai, cy, ri;
9296557Sfr41279 	BIG_CHUNK_TYPE	*a, *r;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	a = aa->value;
9320Sstevel@tonic-gate 	r = result->value;
9330Sstevel@tonic-gate 	cy = 0;
9340Sstevel@tonic-gate 	ri = 0;
9350Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
9360Sstevel@tonic-gate 		ai = a[i];
9376557Sfr41279 		t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy;
9386557Sfr41279 		t2 = (ai >>  (BIG_CHUNK_SIZE / 2)) * b +
9396557Sfr41279 		    (t1 >>  (BIG_CHUNK_SIZE / 2));
9406557Sfr41279 		r[i] = (t1 <<  (BIG_CHUNK_SIZE / 2)) + ri;
9416557Sfr41279 		ri = t2 & BIG_CHUNK_LOWHALFBITS;
9426557Sfr41279 		cy = t2 >> (BIG_CHUNK_SIZE / 2);
9430Sstevel@tonic-gate 	}
9446557Sfr41279 	r[i] = (cy <<  (BIG_CHUNK_SIZE / 2)) + ri;
9450Sstevel@tonic-gate 	result->len = aa->len + 1;
9460Sstevel@tonic-gate 	result->sign = aa->sign;
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate 
9496557Sfr41279 
9500Sstevel@tonic-gate /* it is assumed that result->size is big enough */
9510Sstevel@tonic-gate void
9520Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs)
9530Sstevel@tonic-gate {
9546557Sfr41279 	int		i;
9556557Sfr41279 	BIG_CHUNK_TYPE	cy, ai;
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	if (offs == 0) {
9580Sstevel@tonic-gate 		if (result != aa) {
9590Sstevel@tonic-gate 			(void) big_copy(result, aa);
9600Sstevel@tonic-gate 		}
9610Sstevel@tonic-gate 		return;
9620Sstevel@tonic-gate 	}
9630Sstevel@tonic-gate 	cy = 0;
9640Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
9650Sstevel@tonic-gate 		ai = aa->value[i];
9660Sstevel@tonic-gate 		result->value[i] = (ai << offs) | cy;
9676557Sfr41279 		cy = ai >> (BIG_CHUNK_SIZE - offs);
9680Sstevel@tonic-gate 	}
9690Sstevel@tonic-gate 	if (cy != 0) {
9700Sstevel@tonic-gate 		result->len = aa->len + 1;
9710Sstevel@tonic-gate 		result->value[result->len - 1] = cy;
9720Sstevel@tonic-gate 	} else {
9730Sstevel@tonic-gate 		result->len = aa->len;
9740Sstevel@tonic-gate 	}
9750Sstevel@tonic-gate 	result->sign = aa->sign;
9760Sstevel@tonic-gate }
9770Sstevel@tonic-gate 
9786557Sfr41279 
9790Sstevel@tonic-gate /* it is assumed that result->size is big enough */
9800Sstevel@tonic-gate void
9810Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs)
9820Sstevel@tonic-gate {
9836557Sfr41279 	int		 i;
9846557Sfr41279 	BIG_CHUNK_TYPE	cy, ai;
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	if (offs == 0) {
9870Sstevel@tonic-gate 		if (result != aa) {
9880Sstevel@tonic-gate 			(void) big_copy(result, aa);
9890Sstevel@tonic-gate 		}
9900Sstevel@tonic-gate 		return;
9910Sstevel@tonic-gate 	}
9920Sstevel@tonic-gate 	cy = aa->value[0] >> offs;
9930Sstevel@tonic-gate 	for (i = 1; i < aa->len; i++) {
9940Sstevel@tonic-gate 		ai = aa->value[i];
9958933Sopensolaris@drydog.com 		result->value[i - 1] = (ai << (BIG_CHUNK_SIZE - offs)) | cy;
9960Sstevel@tonic-gate 		cy = ai >> offs;
9970Sstevel@tonic-gate 	}
9980Sstevel@tonic-gate 	result->len = aa->len;
9990Sstevel@tonic-gate 	result->value[result->len - 1] = cy;
10000Sstevel@tonic-gate 	result->sign = aa->sign;
10010Sstevel@tonic-gate }
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate /*
10050Sstevel@tonic-gate  * result = aa/bb   remainder = aa mod bb
10060Sstevel@tonic-gate  * it is assumed that aa and bb are positive
10070Sstevel@tonic-gate  */
10080Sstevel@tonic-gate BIG_ERR_CODE
10098933Sopensolaris@drydog.com big_div_pos(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb)
10100Sstevel@tonic-gate {
10116557Sfr41279 	BIG_ERR_CODE	err = BIG_OK;
10126557Sfr41279 	int		i, alen, blen, tlen, rlen, offs;
10136557Sfr41279 	BIG_CHUNK_TYPE	higha, highb, coeff;
10146557Sfr41279 	BIG_CHUNK_TYPE	*a, *b;
10156557Sfr41279 	BIGNUM		bbhigh, bblow, tresult, tmp1, tmp2;
10166557Sfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
10176557Sfr41279 	BIG_CHUNK_TYPE	tmp2value[BIGTMPSIZE];
10186557Sfr41279 	BIG_CHUNK_TYPE	tresultvalue[BIGTMPSIZE];
10196557Sfr41279 	BIG_CHUNK_TYPE	bblowvalue[BIGTMPSIZE];
10206557Sfr41279 	BIG_CHUNK_TYPE	bbhighvalue[BIGTMPSIZE];
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	a = aa->value;
10230Sstevel@tonic-gate 	b = bb->value;
10240Sstevel@tonic-gate 	alen = aa->len;
10250Sstevel@tonic-gate 	blen = bb->len;
10266557Sfr41279 	while ((alen > 1) && (a[alen - 1] == 0)) {
10276557Sfr41279 		alen = alen - 1;
10286557Sfr41279 	}
10290Sstevel@tonic-gate 	aa->len = alen;
10306557Sfr41279 	while ((blen > 1) && (b[blen - 1] == 0)) {
10316557Sfr41279 		blen = blen - 1;
10326557Sfr41279 	}
10330Sstevel@tonic-gate 	bb->len = blen;
10346557Sfr41279 	if ((blen == 1) && (b[0] == 0)) {
10350Sstevel@tonic-gate 		return (BIG_DIV_BY_0);
10366557Sfr41279 	}
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	if (big_cmp_abs(aa, bb) < 0) {
10390Sstevel@tonic-gate 		if ((remainder != NULL) &&
10406557Sfr41279 		    ((err = big_copy(remainder, aa)) != BIG_OK)) {
10410Sstevel@tonic-gate 			return (err);
10426557Sfr41279 		}
10430Sstevel@tonic-gate 		if (result != NULL) {
10440Sstevel@tonic-gate 			result->len = 1;
10450Sstevel@tonic-gate 			result->sign = 1;
10460Sstevel@tonic-gate 			result->value[0] = 0;
10470Sstevel@tonic-gate 		}
10480Sstevel@tonic-gate 		return (BIG_OK);
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	if ((err = big_init1(&bblow, blen + 1,
10520Sstevel@tonic-gate 	    bblowvalue, arraysize(bblowvalue))) != BIG_OK)
10530Sstevel@tonic-gate 		return (err);
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	if ((err = big_init1(&bbhigh, blen + 1,
10560Sstevel@tonic-gate 	    bbhighvalue, arraysize(bbhighvalue))) != BIG_OK)
10570Sstevel@tonic-gate 		goto ret1;
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 	if ((err = big_init1(&tmp1, alen + 2,
10600Sstevel@tonic-gate 	    tmp1value, arraysize(tmp1value))) != BIG_OK)
10610Sstevel@tonic-gate 		goto ret2;
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, blen + 2,
10640Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
10650Sstevel@tonic-gate 		goto ret3;
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	if ((err = big_init1(&tresult, alen - blen + 2,
10680Sstevel@tonic-gate 	    tresultvalue, arraysize(tresultvalue))) != BIG_OK)
10690Sstevel@tonic-gate 		goto ret4;
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	offs = 0;
10726557Sfr41279 	highb = b[blen - 1];
10736557Sfr41279 	if (highb >= (BIG_CHUNK_HALF_HIGHBIT << 1)) {
10746557Sfr41279 		highb = highb >> (BIG_CHUNK_SIZE / 2);
10756557Sfr41279 		offs = (BIG_CHUNK_SIZE / 2);
10760Sstevel@tonic-gate 	}
10776557Sfr41279 	while ((highb & BIG_CHUNK_HALF_HIGHBIT) == 0) {
10786557Sfr41279 		highb = highb << 1;
10790Sstevel@tonic-gate 		offs++;
10800Sstevel@tonic-gate 	}
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	big_shiftleft(&bblow, bb, offs);
10836557Sfr41279 
10846557Sfr41279 	if (offs <= (BIG_CHUNK_SIZE / 2 - 1)) {
10856557Sfr41279 		big_shiftleft(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2);
10860Sstevel@tonic-gate 	} else {
10876557Sfr41279 		big_shiftright(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2);
10880Sstevel@tonic-gate 	}
10890Sstevel@tonic-gate 	if (bbhigh.value[bbhigh.len - 1] == 0) {
10900Sstevel@tonic-gate 		bbhigh.len--;
10910Sstevel@tonic-gate 	} else {
10920Sstevel@tonic-gate 		bbhigh.value[bbhigh.len] = 0;
10930Sstevel@tonic-gate 	}
10940Sstevel@tonic-gate 
10956557Sfr41279 	highb = bblow.value[bblow.len - 1];
10966557Sfr41279 
10970Sstevel@tonic-gate 	big_shiftleft(&tmp1, aa, offs);
10980Sstevel@tonic-gate 	rlen = tmp1.len - bblow.len + 1;
10990Sstevel@tonic-gate 	tresult.len = rlen;
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	tmp1.len++;
11020Sstevel@tonic-gate 	tlen = tmp1.len;
11030Sstevel@tonic-gate 	tmp1.value[tmp1.len - 1] = 0;
11040Sstevel@tonic-gate 	for (i = 0; i < rlen; i++) {
11056557Sfr41279 		higha = (tmp1.value[tlen - 1] << (BIG_CHUNK_SIZE / 2)) +
11066557Sfr41279 		    (tmp1.value[tlen - 2] >> (BIG_CHUNK_SIZE / 2));
11070Sstevel@tonic-gate 		coeff = higha / (highb + 1);
11086557Sfr41279 		big_mulhalf_high(&tmp2, &bblow, coeff);
11090Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
11100Sstevel@tonic-gate 		bbhigh.len++;
11110Sstevel@tonic-gate 		while (tmp1.value[tlen - 1] > 0) {
11120Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
11130Sstevel@tonic-gate 			coeff++;
11140Sstevel@tonic-gate 		}
11150Sstevel@tonic-gate 		bbhigh.len--;
11160Sstevel@tonic-gate 		tlen--;
11170Sstevel@tonic-gate 		tmp1.len--;
11180Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) {
11190Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
11200Sstevel@tonic-gate 			coeff++;
11210Sstevel@tonic-gate 		}
11226557Sfr41279 		tresult.value[rlen - i - 1] = coeff << (BIG_CHUNK_SIZE / 2);
11230Sstevel@tonic-gate 		higha = tmp1.value[tlen - 1];
11240Sstevel@tonic-gate 		coeff = higha / (highb + 1);
11256557Sfr41279 		big_mulhalf_low(&tmp2, &bblow, coeff);
11260Sstevel@tonic-gate 		tmp2.len--;
11270Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
11280Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bblow) >= 0) {
11290Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bblow);
11300Sstevel@tonic-gate 			coeff++;
11310Sstevel@tonic-gate 		}
11320Sstevel@tonic-gate 		tresult.value[rlen - i - 1] =
11330Sstevel@tonic-gate 		    tresult.value[rlen - i - 1] + coeff;
11340Sstevel@tonic-gate 	}
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	big_shiftright(&tmp1, &tmp1, offs);
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 	err = BIG_OK;
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	if ((remainder != NULL) &&
11410Sstevel@tonic-gate 	    ((err = big_copy(remainder, &tmp1)) != BIG_OK))
11420Sstevel@tonic-gate 		goto ret;
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 	if (result != NULL)
11450Sstevel@tonic-gate 		err = big_copy(result, &tresult);
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate ret:
11480Sstevel@tonic-gate 	big_finish(&tresult);
11490Sstevel@tonic-gate ret4:
11500Sstevel@tonic-gate 	big_finish(&tmp1);
11510Sstevel@tonic-gate ret3:
11520Sstevel@tonic-gate 	big_finish(&tmp2);
11530Sstevel@tonic-gate ret2:
11540Sstevel@tonic-gate 	big_finish(&bbhigh);
11550Sstevel@tonic-gate ret1:
11560Sstevel@tonic-gate 	big_finish(&bblow);
11570Sstevel@tonic-gate 	return (err);
11580Sstevel@tonic-gate }
11590Sstevel@tonic-gate 
11608933Sopensolaris@drydog.com 
11610Sstevel@tonic-gate /*
11620Sstevel@tonic-gate  * If there is no processor-specific integer implementation of
11630Sstevel@tonic-gate  * the lower level multiply functions, then this code is provided
11640Sstevel@tonic-gate  * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and
11650Sstevel@tonic-gate  * big_sqr_vec().
11660Sstevel@tonic-gate  *
11670Sstevel@tonic-gate  * There are two generic implementations.  One that assumes that
11680Sstevel@tonic-gate  * there is hardware and C compiler support for a 32 x 32 --> 64
11690Sstevel@tonic-gate  * bit unsigned multiply, but otherwise is not specific to any
11700Sstevel@tonic-gate  * processor, platform, or ISA.
11710Sstevel@tonic-gate  *
11720Sstevel@tonic-gate  * The other makes very few assumptions about hardware capabilities.
11730Sstevel@tonic-gate  * It does not even assume that there is any implementation of a
11740Sstevel@tonic-gate  * 32 x 32 --> 64 bit multiply that is accessible to C code and
11750Sstevel@tonic-gate  * appropriate to use.  It falls constructs 32 x 32 --> 64 bit
11760Sstevel@tonic-gate  * multiplies from 16 x 16 --> 32 bit multiplies.
11770Sstevel@tonic-gate  *
11780Sstevel@tonic-gate  */
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate #if !defined(PSR_MUL)
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate #ifdef UMUL64
11830Sstevel@tonic-gate 
11846557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
11856557Sfr41279 
11860Sstevel@tonic-gate #define	UNROLL8
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_PREFETCH(R) \
11890Sstevel@tonic-gate 	p = pf * d; \
11908933Sopensolaris@drydog.com 	pf = (uint64_t)a[R + 1]; \
11910Sstevel@tonic-gate 	t = p + cy; \
11920Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11930Sstevel@tonic-gate 	cy = t >> 32
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_NOPREFETCH(R) \
11960Sstevel@tonic-gate 	p = pf * d; \
11970Sstevel@tonic-gate 	t = p + cy; \
11980Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11990Sstevel@tonic-gate 	cy = t >> 32
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_PREFETCH(R) \
12020Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
12030Sstevel@tonic-gate 	p = pf * d; \
12048933Sopensolaris@drydog.com 	pf = (uint64_t)a[R + 1]; \
12050Sstevel@tonic-gate 	t = p + t + cy; \
12060Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
12070Sstevel@tonic-gate 	cy = t >> 32
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_NOPREFETCH(R) \
12100Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
12110Sstevel@tonic-gate 	p = pf * d; \
12120Sstevel@tonic-gate 	t = p + t + cy; \
12130Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
12140Sstevel@tonic-gate 	cy = t >> 32
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate #ifdef UNROLL8
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate #define	UNROLL 8
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate /*
12210Sstevel@tonic-gate  * r = a * b
12220Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
12230Sstevel@tonic-gate  */
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate uint32_t
12260Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
12270Sstevel@tonic-gate {
12280Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	if (len == 0)
12310Sstevel@tonic-gate 		return (0);
12320Sstevel@tonic-gate 	cy = 0;
12330Sstevel@tonic-gate 	d = (uint64_t)b;
12340Sstevel@tonic-gate 	pf = (uint64_t)a[0];
12350Sstevel@tonic-gate 	while (len > UNROLL) {
12360Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
12370Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
12380Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
12390Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
12400Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
12410Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
12420Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
12430Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(7);
12440Sstevel@tonic-gate 		r += UNROLL;
12450Sstevel@tonic-gate 		a += UNROLL;
12460Sstevel@tonic-gate 		len -= UNROLL;
12470Sstevel@tonic-gate 	}
12480Sstevel@tonic-gate 	if (len == UNROLL) {
12490Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
12500Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
12510Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
12520Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
12530Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
12540Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
12550Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
12560Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(7);
12570Sstevel@tonic-gate 		return ((uint32_t)cy);
12580Sstevel@tonic-gate 	}
12590Sstevel@tonic-gate 	while (len > 1) {
12600Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
12610Sstevel@tonic-gate 		++r;
12620Sstevel@tonic-gate 		++a;
12630Sstevel@tonic-gate 		--len;
12640Sstevel@tonic-gate 	}
12650Sstevel@tonic-gate 	if (len > 0) {
12660Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(0);
12670Sstevel@tonic-gate 	}
12680Sstevel@tonic-gate 	return ((uint32_t)cy);
12690Sstevel@tonic-gate }
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate /*
12720Sstevel@tonic-gate  * r += a * b
12730Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
12740Sstevel@tonic-gate  */
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate uint32_t
12770Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
12780Sstevel@tonic-gate {
12790Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 	if (len == 0)
12820Sstevel@tonic-gate 		return (0);
12830Sstevel@tonic-gate 	cy = 0;
12840Sstevel@tonic-gate 	d = (uint64_t)b;
12850Sstevel@tonic-gate 	pf = (uint64_t)a[0];
12860Sstevel@tonic-gate 	while (len > 8) {
12870Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12880Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
12890Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
12900Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
12910Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
12920Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
12930Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
12940Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(7);
12950Sstevel@tonic-gate 		r += 8;
12960Sstevel@tonic-gate 		a += 8;
12970Sstevel@tonic-gate 		len -= 8;
12980Sstevel@tonic-gate 	}
12990Sstevel@tonic-gate 	if (len == 8) {
13000Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
13010Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
13020Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
13030Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
13040Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
13050Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
13060Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
13070Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(7);
13080Sstevel@tonic-gate 		return ((uint32_t)cy);
13090Sstevel@tonic-gate 	}
13100Sstevel@tonic-gate 	while (len > 1) {
13110Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
13120Sstevel@tonic-gate 		++r;
13130Sstevel@tonic-gate 		++a;
13140Sstevel@tonic-gate 		--len;
13150Sstevel@tonic-gate 	}
13160Sstevel@tonic-gate 	if (len > 0) {
13170Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(0);
13180Sstevel@tonic-gate 	}
13190Sstevel@tonic-gate 	return ((uint32_t)cy);
13200Sstevel@tonic-gate }
13210Sstevel@tonic-gate #endif /* UNROLL8 */
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate void
13240Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
13250Sstevel@tonic-gate {
13268933Sopensolaris@drydog.com 	uint32_t	*tr, *ta;
13278933Sopensolaris@drydog.com 	int		tlen, row, col;
13288933Sopensolaris@drydog.com 	uint64_t	p, s, t, t2, cy;
13298933Sopensolaris@drydog.com 	uint32_t	d;
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 	tr = r + 1;
13320Sstevel@tonic-gate 	ta = a;
13330Sstevel@tonic-gate 	tlen = len - 1;
13340Sstevel@tonic-gate 	tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]);
13350Sstevel@tonic-gate 	while (--tlen > 0) {
13360Sstevel@tonic-gate 		tr += 2;
13370Sstevel@tonic-gate 		++ta;
13380Sstevel@tonic-gate 		tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]);
13390Sstevel@tonic-gate 	}
13400Sstevel@tonic-gate 	s = (uint64_t)a[0];
13410Sstevel@tonic-gate 	s = s * s;
13420Sstevel@tonic-gate 	r[0] = (uint32_t)s;
13430Sstevel@tonic-gate 	cy = s >> 32;
13440Sstevel@tonic-gate 	p = ((uint64_t)r[1] << 1) + cy;
13450Sstevel@tonic-gate 	r[1] = (uint32_t)p;
13460Sstevel@tonic-gate 	cy = p >> 32;
13470Sstevel@tonic-gate 	row = 1;
13480Sstevel@tonic-gate 	col = 2;
13490Sstevel@tonic-gate 	while (row < len) {
13500Sstevel@tonic-gate 		s = (uint64_t)a[row];
13510Sstevel@tonic-gate 		s = s * s;
13520Sstevel@tonic-gate 		p = (uint64_t)r[col] << 1;
13530Sstevel@tonic-gate 		t = p + s;
13540Sstevel@tonic-gate 		d = (uint32_t)t;
13550Sstevel@tonic-gate 		t2 = (uint64_t)d + cy;
13560Sstevel@tonic-gate 		r[col] = (uint32_t)t2;
13570Sstevel@tonic-gate 		cy = (t >> 32) + (t2 >> 32);
13580Sstevel@tonic-gate 		if (row == len - 1)
13590Sstevel@tonic-gate 			break;
13608933Sopensolaris@drydog.com 		p = ((uint64_t)r[col + 1] << 1) + cy;
13618933Sopensolaris@drydog.com 		r[col + 1] = (uint32_t)p;
13620Sstevel@tonic-gate 		cy = p >> 32;
13630Sstevel@tonic-gate 		++row;
13640Sstevel@tonic-gate 		col += 2;
13650Sstevel@tonic-gate 	}
13668933Sopensolaris@drydog.com 	r[col + 1] = (uint32_t)cy;
13670Sstevel@tonic-gate }
13680Sstevel@tonic-gate 
13696557Sfr41279 #else /* BIG_CHUNK_SIZE == 64 */
13706557Sfr41279 
13716557Sfr41279 /*
13726557Sfr41279  * r = r + a * digit, r and a are vectors of length len
13736557Sfr41279  * returns the carry digit
13746557Sfr41279  */
13756557Sfr41279 BIG_CHUNK_TYPE
13766557Sfr41279 big_mul_add_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len,
13776557Sfr41279     BIG_CHUNK_TYPE digit)
13786557Sfr41279 {
13796557Sfr41279 	BIG_CHUNK_TYPE	cy, cy1, retcy, dlow, dhigh;
13806557Sfr41279 	int		i;
13816557Sfr41279 
13826557Sfr41279 	cy1 = 0;
13836557Sfr41279 	dlow = digit & BIG_CHUNK_LOWHALFBITS;
13846557Sfr41279 	dhigh = digit >> (BIG_CHUNK_SIZE / 2);
13856557Sfr41279 	for (i = 0; i < len; i++) {
13866557Sfr41279 		cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
13876557Sfr41279 		    dlow * (a[i] & BIG_CHUNK_LOWHALFBITS) +
13886557Sfr41279 		    (r[i] & BIG_CHUNK_LOWHALFBITS);
13896557Sfr41279 		cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) +
13906557Sfr41279 		    dlow * (a[i] >> (BIG_CHUNK_SIZE / 2)) +
13916557Sfr41279 		    (r[i] >> (BIG_CHUNK_SIZE / 2));
13926557Sfr41279 		r[i] = (cy & BIG_CHUNK_LOWHALFBITS) |
13936557Sfr41279 		    (cy1 << (BIG_CHUNK_SIZE / 2));
13946557Sfr41279 	}
13956557Sfr41279 	retcy = cy1 >> (BIG_CHUNK_SIZE / 2);
13966557Sfr41279 
13976557Sfr41279 	cy1 = r[0] & BIG_CHUNK_LOWHALFBITS;
13986557Sfr41279 	for (i = 0; i < len - 1; i++) {
13996557Sfr41279 		cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
14006557Sfr41279 		    dhigh * (a[i] & BIG_CHUNK_LOWHALFBITS) +
14016557Sfr41279 		    (r[i] >> (BIG_CHUNK_SIZE / 2));
14026557Sfr41279 		r[i] = (cy1 & BIG_CHUNK_LOWHALFBITS) |
14036557Sfr41279 		    (cy << (BIG_CHUNK_SIZE / 2));
14046557Sfr41279 		cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) +
14056557Sfr41279 		    dhigh * (a[i] >> (BIG_CHUNK_SIZE / 2)) +
14066557Sfr41279 		    (r[i + 1] & BIG_CHUNK_LOWHALFBITS);
14076557Sfr41279 	}
14086557Sfr41279 	cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
14096557Sfr41279 	    dhigh * (a[len - 1] & BIG_CHUNK_LOWHALFBITS) +
14106557Sfr41279 	    (r[len - 1] >> (BIG_CHUNK_SIZE / 2));
14116557Sfr41279 	r[len - 1] = (cy1 & BIG_CHUNK_LOWHALFBITS) |
14126557Sfr41279 	    (cy << (BIG_CHUNK_SIZE / 2));
14136557Sfr41279 	retcy = (cy >> (BIG_CHUNK_SIZE / 2)) +
14146557Sfr41279 	    dhigh * (a[len - 1] >> (BIG_CHUNK_SIZE / 2)) + retcy;
14156557Sfr41279 
14166557Sfr41279 	return (retcy);
14176557Sfr41279 }
14186557Sfr41279 
14196557Sfr41279 
14206557Sfr41279 /*
14216557Sfr41279  * r = a * digit, r and a are vectors of length len
14226557Sfr41279  * returns the carry digit
14236557Sfr41279  */
14246557Sfr41279 BIG_CHUNK_TYPE
14256557Sfr41279 big_mul_set_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len,
14266557Sfr41279     BIG_CHUNK_TYPE digit)
14276557Sfr41279 {
14286557Sfr41279 	int	i;
14296557Sfr41279 
14306557Sfr41279 	ASSERT(r != a);
14316557Sfr41279 	for (i = 0; i < len; i++) {
14326557Sfr41279 		r[i] = 0;
14336557Sfr41279 	}
14346557Sfr41279 	return (big_mul_add_vec(r, a, len, digit));
14356557Sfr41279 }
14366557Sfr41279 
14376557Sfr41279 void
14386557Sfr41279 big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len)
14396557Sfr41279 {
14406557Sfr41279 	int i;
14416557Sfr41279 
14426557Sfr41279 	ASSERT(r != a);
14436557Sfr41279 	r[len] = big_mul_set_vec(r, a, len, a[0]);
14446557Sfr41279 	for (i = 1; i < len; ++i)
14458933Sopensolaris@drydog.com 		r[len + i] = big_mul_add_vec(r + i, a, len, a[i]);
14466557Sfr41279 }
14476557Sfr41279 
14486557Sfr41279 #endif /* BIG_CHUNK_SIZE == 32/64 */
14496557Sfr41279 
14508933Sopensolaris@drydog.com 
14510Sstevel@tonic-gate #else /* ! UMUL64 */
14520Sstevel@tonic-gate 
14536557Sfr41279 #if (BIG_CHUNK_SIZE != 32)
14546557Sfr41279 #error Don't use 64-bit chunks without defining UMUL64
14556557Sfr41279 #endif
14566557Sfr41279 
14576557Sfr41279 
14580Sstevel@tonic-gate /*
14590Sstevel@tonic-gate  * r = r + a * digit, r and a are vectors of length len
14600Sstevel@tonic-gate  * returns the carry digit
14610Sstevel@tonic-gate  */
14620Sstevel@tonic-gate uint32_t
14630Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
14640Sstevel@tonic-gate {
14650Sstevel@tonic-gate 	uint32_t cy, cy1, retcy, dlow, dhigh;
14660Sstevel@tonic-gate 	int i;
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	cy1 = 0;
14690Sstevel@tonic-gate 	dlow = digit & 0xffff;
14700Sstevel@tonic-gate 	dhigh = digit >> 16;
14710Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
14720Sstevel@tonic-gate 		cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff);
14730Sstevel@tonic-gate 		cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16);
14740Sstevel@tonic-gate 		r[i] = (cy & 0xffff) | (cy1 << 16);
14750Sstevel@tonic-gate 	}
14760Sstevel@tonic-gate 	retcy = cy1 >> 16;
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 	cy1 = r[0] & 0xffff;
14790Sstevel@tonic-gate 	for (i = 0; i < len - 1; i++) {
14800Sstevel@tonic-gate 		cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16);
14810Sstevel@tonic-gate 		r[i] = (cy1 & 0xffff) | (cy << 16);
14820Sstevel@tonic-gate 		cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff);
14830Sstevel@tonic-gate 	}
14840Sstevel@tonic-gate 	cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16);
14850Sstevel@tonic-gate 	r[len - 1] = (cy1 & 0xffff) | (cy << 16);
14860Sstevel@tonic-gate 	retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy;
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 	return (retcy);
14890Sstevel@tonic-gate }
14900Sstevel@tonic-gate 
14916557Sfr41279 
14920Sstevel@tonic-gate /*
14930Sstevel@tonic-gate  * r = a * digit, r and a are vectors of length len
14940Sstevel@tonic-gate  * returns the carry digit
14950Sstevel@tonic-gate  */
14960Sstevel@tonic-gate uint32_t
14970Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
14980Sstevel@tonic-gate {
14996557Sfr41279 	int	i;
15006557Sfr41279 
15016557Sfr41279 	ASSERT(r != a);
15026557Sfr41279 	for (i = 0; i < len; i++) {
15036557Sfr41279 		r[i] = 0;
15046557Sfr41279 	}
15056557Sfr41279 
15060Sstevel@tonic-gate 	return (big_mul_add_vec(r, a, len, digit));
15070Sstevel@tonic-gate }
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate void
15100Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
15110Sstevel@tonic-gate {
15120Sstevel@tonic-gate 	int i;
15130Sstevel@tonic-gate 
15146557Sfr41279 	ASSERT(r != a);
15150Sstevel@tonic-gate 	r[len] = big_mul_set_vec(r, a, len, a[0]);
15160Sstevel@tonic-gate 	for (i = 1; i < len; ++i)
15178933Sopensolaris@drydog.com 		r[len + i] = big_mul_add_vec(r + i, a, len, a[i]);
15180Sstevel@tonic-gate }
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate #endif /* UMUL64 */
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate void
15236557Sfr41279 big_mul_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int alen,
15246557Sfr41279     BIG_CHUNK_TYPE *b, int blen)
15250Sstevel@tonic-gate {
15260Sstevel@tonic-gate 	int i;
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate 	r[alen] = big_mul_set_vec(r, a, alen, b[0]);
15290Sstevel@tonic-gate 	for (i = 1; i < blen; ++i)
15308933Sopensolaris@drydog.com 		r[alen + i] = big_mul_add_vec(r + i, a, alen, b[i]);
15310Sstevel@tonic-gate }
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate #endif /* ! PSR_MUL */
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate /*
15380Sstevel@tonic-gate  * result = aa * bb  result->value should be big enough to hold the result
15390Sstevel@tonic-gate  *
15400Sstevel@tonic-gate  * Implementation: Standard grammar school algorithm
15410Sstevel@tonic-gate  *
15420Sstevel@tonic-gate  */
15430Sstevel@tonic-gate BIG_ERR_CODE
15440Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
15450Sstevel@tonic-gate {
15466557Sfr41279 	BIGNUM		tmp1;
15476557Sfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
15486557Sfr41279 	BIG_CHUNK_TYPE	*r, *t, *a, *b;
15496557Sfr41279 	BIG_ERR_CODE	err;
15506557Sfr41279 	int		i, alen, blen, rsize, sign, diff;
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 	if (aa == bb) {
15530Sstevel@tonic-gate 		diff = 0;
15540Sstevel@tonic-gate 	} else {
15550Sstevel@tonic-gate 		diff = big_cmp_abs(aa, bb);
15560Sstevel@tonic-gate 		if (diff < 0) {
15570Sstevel@tonic-gate 			BIGNUM *tt;
15580Sstevel@tonic-gate 			tt = aa;
15590Sstevel@tonic-gate 			aa = bb;
15600Sstevel@tonic-gate 			bb = tt;
15610Sstevel@tonic-gate 		}
15620Sstevel@tonic-gate 	}
15630Sstevel@tonic-gate 	a = aa->value;
15640Sstevel@tonic-gate 	b = bb->value;
15650Sstevel@tonic-gate 	alen = aa->len;
15660Sstevel@tonic-gate 	blen = bb->len;
15676557Sfr41279 	while ((alen > 1) && (a[alen - 1] == 0)) {
15686557Sfr41279 		alen--;
15696557Sfr41279 	}
15700Sstevel@tonic-gate 	aa->len = alen;
15716557Sfr41279 	while ((blen > 1) && (b[blen - 1] == 0)) {
15726557Sfr41279 		blen--;
15736557Sfr41279 	}
15740Sstevel@tonic-gate 	bb->len = blen;
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 	rsize = alen + blen;
15778933Sopensolaris@drydog.com 	ASSERT(rsize > 0);
15780Sstevel@tonic-gate 	if (result->size < rsize) {
15790Sstevel@tonic-gate 		err = big_extend(result, rsize);
15806557Sfr41279 		if (err != BIG_OK) {
15810Sstevel@tonic-gate 			return (err);
15826557Sfr41279 		}
15830Sstevel@tonic-gate 		/* aa or bb might be an alias to result */
15840Sstevel@tonic-gate 		a = aa->value;
15850Sstevel@tonic-gate 		b = bb->value;
15860Sstevel@tonic-gate 	}
15870Sstevel@tonic-gate 	r = result->value;
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate 	if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) {
15900Sstevel@tonic-gate 		result->len = 1;
15910Sstevel@tonic-gate 		result->sign = 1;
15920Sstevel@tonic-gate 		r[0] = 0;
15930Sstevel@tonic-gate 		return (BIG_OK);
15940Sstevel@tonic-gate 	}
15950Sstevel@tonic-gate 	sign = aa->sign * bb->sign;
15960Sstevel@tonic-gate 	if ((alen == 1) && (a[0] == 1)) {
15976557Sfr41279 		for (i = 0; i < blen; i++) {
15986557Sfr41279 			r[i] = b[i];
15996557Sfr41279 		}
16000Sstevel@tonic-gate 		result->len = blen;
16010Sstevel@tonic-gate 		result->sign = sign;
16020Sstevel@tonic-gate 		return (BIG_OK);
16030Sstevel@tonic-gate 	}
16040Sstevel@tonic-gate 	if ((blen == 1) && (b[0] == 1)) {
16056557Sfr41279 		for (i = 0; i < alen; i++) {
16066557Sfr41279 			r[i] = a[i];
16076557Sfr41279 		}
16080Sstevel@tonic-gate 		result->len = alen;
16090Sstevel@tonic-gate 		result->sign = sign;
16100Sstevel@tonic-gate 		return (BIG_OK);
16110Sstevel@tonic-gate 	}
16120Sstevel@tonic-gate 
16136557Sfr41279 	if ((err = big_init1(&tmp1, rsize,
16146557Sfr41279 	    tmp1value, arraysize(tmp1value))) != BIG_OK) {
16150Sstevel@tonic-gate 		return (err);
16166557Sfr41279 	}
16170Sstevel@tonic-gate 	t = tmp1.value;
16186557Sfr41279 
16196557Sfr41279 	for (i = 0; i < rsize; i++) {
16206557Sfr41279 		t[i] = 0;
16216557Sfr41279 	}
16226557Sfr41279 
16236557Sfr41279 	if (diff == 0 && alen > 2) {
16240Sstevel@tonic-gate 		BIG_SQR_VEC(t, a, alen);
16256557Sfr41279 	} else if (blen > 0) {
16260Sstevel@tonic-gate 		BIG_MUL_VEC(t, a, alen, b, blen);
16276557Sfr41279 	}
16286557Sfr41279 
16296557Sfr41279 	if (t[rsize - 1] == 0) {
16306557Sfr41279 		tmp1.len = rsize - 1;
16316557Sfr41279 	} else {
16326557Sfr41279 		tmp1.len = rsize;
16336557Sfr41279 	}
16348933Sopensolaris@drydog.com 
16358933Sopensolaris@drydog.com 	err = big_copy(result, &tmp1);
16368933Sopensolaris@drydog.com 
16370Sstevel@tonic-gate 	result->sign = sign;
16380Sstevel@tonic-gate 
16396557Sfr41279 	big_finish(&tmp1);
16400Sstevel@tonic-gate 
16418933Sopensolaris@drydog.com 	return (err);
16420Sstevel@tonic-gate }
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 
16450Sstevel@tonic-gate /*
1646*9302Sopensolaris@drydog.com  * big_mont_mul()
1647*9302Sopensolaris@drydog.com  * Montgomery multiplication.
1648*9302Sopensolaris@drydog.com  *
1649*9302Sopensolaris@drydog.com  * Caller must ensure that  a < n,  b < n,  ret->size >=  2 * n->len + 1,
1650*9302Sopensolaris@drydog.com  * and that ret is not n.
16510Sstevel@tonic-gate  */
16520Sstevel@tonic-gate BIG_ERR_CODE
16536557Sfr41279 big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, BIG_CHUNK_TYPE n0)
16540Sstevel@tonic-gate {
1655*9302Sopensolaris@drydog.com 	int		i, j, nlen, needsubtract;
1656*9302Sopensolaris@drydog.com 	BIG_CHUNK_TYPE	*nn, *rr, *rrplusi;
16576557Sfr41279 	BIG_CHUNK_TYPE	digit, c;
16586557Sfr41279 	BIG_ERR_CODE	err;
1659*9302Sopensolaris@drydog.com #ifdef	__amd64
1660*9302Sopensolaris@drydog.com #define	BIG_CPU_UNKNOWN	0
1661*9302Sopensolaris@drydog.com #define	BIG_CPU_AMD	1
1662*9302Sopensolaris@drydog.com #define	BIG_CPU_INTEL	2
1663*9302Sopensolaris@drydog.com 	static int	big_cpu = BIG_CPU_UNKNOWN;
1664*9302Sopensolaris@drydog.com 	BIG_CHUNK_TYPE	carry[BIGTMPSIZE];
1665*9302Sopensolaris@drydog.com 
1666*9302Sopensolaris@drydog.com 	if (big_cpu == BIG_CPU_UNKNOWN) {
1667*9302Sopensolaris@drydog.com 		big_cpu = 1 + bignum_on_intel();
1668*9302Sopensolaris@drydog.com 	}
1669*9302Sopensolaris@drydog.com #endif	/* __amd64 */
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate 	nlen = n->len;
16720Sstevel@tonic-gate 	nn = n->value;
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	rr = ret->value;
16750Sstevel@tonic-gate 
16766557Sfr41279 	if ((err = big_mul(ret, a, b)) != BIG_OK) {
16770Sstevel@tonic-gate 		return (err);
16786557Sfr41279 	}
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate 	rr = ret->value;
16816557Sfr41279 	for (i = ret->len; i < 2 * nlen + 1; i++) {
16826557Sfr41279 		rr[i] = 0;
16836557Sfr41279 	}
1684*9302Sopensolaris@drydog.com 
1685*9302Sopensolaris@drydog.com #ifdef	__amd64	/* pipelining optimization for Intel 64, but not AMD64 */
1686*9302Sopensolaris@drydog.com 	if ((big_cpu == BIG_CPU_INTEL) && (nlen <= BIGTMPSIZE)) {
1687*9302Sopensolaris@drydog.com 		/*
1688*9302Sopensolaris@drydog.com 		 * Perform the following in two for loops to reduce the
1689*9302Sopensolaris@drydog.com 		 * dependency between computing the carryover bits with
1690*9302Sopensolaris@drydog.com 		 * BIG_MUL_ADD_VEC() and adding them, thus improving pipelining.
1691*9302Sopensolaris@drydog.com 		 */
1692*9302Sopensolaris@drydog.com 		for (i = 0; i < nlen; i++) {
1693*9302Sopensolaris@drydog.com 			rrplusi = rr + i;
1694*9302Sopensolaris@drydog.com 			digit = *rrplusi * n0;
1695*9302Sopensolaris@drydog.com 			carry[i] = BIG_MUL_ADD_VEC(rrplusi, nn, nlen, digit);
1696*9302Sopensolaris@drydog.com 		}
1697*9302Sopensolaris@drydog.com 		for (i = 0; i < nlen; i++) {
1698*9302Sopensolaris@drydog.com 			j = i + nlen;
1699*9302Sopensolaris@drydog.com 			rr[j] += carry[i];
1700*9302Sopensolaris@drydog.com 			while (rr[j] < carry[i]) {
1701*9302Sopensolaris@drydog.com 				rr[++j] += 1;
1702*9302Sopensolaris@drydog.com 				carry[i] = 1;
1703*9302Sopensolaris@drydog.com 			}
1704*9302Sopensolaris@drydog.com 		}
1705*9302Sopensolaris@drydog.com 	} else
1706*9302Sopensolaris@drydog.com #endif	/* __amd64 */
1707*9302Sopensolaris@drydog.com 	{ /* no pipelining optimization */
1708*9302Sopensolaris@drydog.com 		for (i = 0; i < nlen; i++) {
1709*9302Sopensolaris@drydog.com 			rrplusi = rr + i;
1710*9302Sopensolaris@drydog.com 			digit = *rrplusi * n0;
1711*9302Sopensolaris@drydog.com 			c = BIG_MUL_ADD_VEC(rrplusi, nn, nlen, digit);
1712*9302Sopensolaris@drydog.com 			j = i + nlen;
1713*9302Sopensolaris@drydog.com 			rr[j] += c;
1714*9302Sopensolaris@drydog.com 			while (rr[j] < c) {
1715*9302Sopensolaris@drydog.com 				rr[++j] += 1;
1716*9302Sopensolaris@drydog.com 				c = 1;
1717*9302Sopensolaris@drydog.com 			}
17180Sstevel@tonic-gate 		}
17190Sstevel@tonic-gate 	}
17200Sstevel@tonic-gate 
17210Sstevel@tonic-gate 	needsubtract = 0;
17220Sstevel@tonic-gate 	if ((rr[2 * nlen]  != 0))
17230Sstevel@tonic-gate 		needsubtract = 1;
17240Sstevel@tonic-gate 	else {
17250Sstevel@tonic-gate 		for (i = 2 * nlen - 1; i >= nlen; i--) {
17260Sstevel@tonic-gate 			if (rr[i] > nn[i - nlen]) {
17270Sstevel@tonic-gate 				needsubtract = 1;
17280Sstevel@tonic-gate 				break;
17296557Sfr41279 			} else if (rr[i] < nn[i - nlen]) {
17306557Sfr41279 				break;
17316557Sfr41279 			}
17320Sstevel@tonic-gate 		}
17330Sstevel@tonic-gate 	}
17340Sstevel@tonic-gate 	if (needsubtract)
17350Sstevel@tonic-gate 		big_sub_vec(rr, rr + nlen, nn, nlen);
17360Sstevel@tonic-gate 	else {
17376557Sfr41279 		for (i = 0; i < nlen; i++) {
17380Sstevel@tonic-gate 			rr[i] = rr[i + nlen];
17396557Sfr41279 		}
17400Sstevel@tonic-gate 	}
17418933Sopensolaris@drydog.com 
17428933Sopensolaris@drydog.com 	/* Remove leading zeros, but keep at least 1 digit: */
17438933Sopensolaris@drydog.com 	for (i = nlen - 1; (i > 0) && (rr[i] == 0); i--)
17446557Sfr41279 		;
17458933Sopensolaris@drydog.com 	ret->len = i + 1;
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 	return (BIG_OK);
17480Sstevel@tonic-gate }
17490Sstevel@tonic-gate 
17506557Sfr41279 
17516557Sfr41279 BIG_CHUNK_TYPE
17526557Sfr41279 big_n0(BIG_CHUNK_TYPE n)
17530Sstevel@tonic-gate {
17546557Sfr41279 	int		i;
17556557Sfr41279 	BIG_CHUNK_TYPE	result, tmp;
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate 	result = 0;
17586557Sfr41279 	tmp = BIG_CHUNK_ALLBITS;
17596557Sfr41279 	for (i = 0; i < BIG_CHUNK_SIZE; i++) {
17600Sstevel@tonic-gate 		if ((tmp & 1) == 1) {
17616557Sfr41279 			result = (result >> 1) | BIG_CHUNK_HIGHBIT;
17620Sstevel@tonic-gate 			tmp = tmp - n;
17636557Sfr41279 		} else {
17646557Sfr41279 			result = (result >> 1);
17656557Sfr41279 		}
17660Sstevel@tonic-gate 		tmp = tmp >> 1;
17670Sstevel@tonic-gate 	}
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 	return (result);
17700Sstevel@tonic-gate }
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate int
17740Sstevel@tonic-gate big_numbits(BIGNUM *n)
17750Sstevel@tonic-gate {
17766557Sfr41279 	int		i, j;
17776557Sfr41279 	BIG_CHUNK_TYPE	t;
17786557Sfr41279 
17796557Sfr41279 	for (i = n->len - 1; i > 0; i--) {
17806557Sfr41279 		if (n->value[i] != 0) {
17816557Sfr41279 			break;
17826557Sfr41279 		}
17836557Sfr41279 	}
17840Sstevel@tonic-gate 	t = n->value[i];
17856557Sfr41279 	for (j = BIG_CHUNK_SIZE; j > 0; j--) {
17866557Sfr41279 		if ((t & BIG_CHUNK_HIGHBIT) == 0) {
17870Sstevel@tonic-gate 			t = t << 1;
17886557Sfr41279 		} else {
17896557Sfr41279 			return (BIG_CHUNK_SIZE * i + j);
17906557Sfr41279 		}
17910Sstevel@tonic-gate 	}
17920Sstevel@tonic-gate 	return (0);
17930Sstevel@tonic-gate }
17940Sstevel@tonic-gate 
17956557Sfr41279 
17960Sstevel@tonic-gate /* caller must make sure that a < n */
17970Sstevel@tonic-gate BIG_ERR_CODE
17980Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n)
17990Sstevel@tonic-gate {
18006557Sfr41279 	BIGNUM		rr;
18016557Sfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
18026557Sfr41279 	int		len, i;
18036557Sfr41279 	BIG_ERR_CODE	err;
18040Sstevel@tonic-gate 
18050Sstevel@tonic-gate 	rr.malloced = 0;
18060Sstevel@tonic-gate 	len = n->len;
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1,
18096557Sfr41279 	    rrvalue, arraysize(rrvalue))) != BIG_OK) {
18100Sstevel@tonic-gate 		return (err);
18116557Sfr41279 	}
18126557Sfr41279 
18136557Sfr41279 	for (i = 0; i < 2 * len; i++) {
18146557Sfr41279 		rr.value[i] = 0;
18156557Sfr41279 	}
18160Sstevel@tonic-gate 	rr.value[2 * len] = 1;
18170Sstevel@tonic-gate 	rr.len = 2 * len + 1;
18186557Sfr41279 	if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) {
18190Sstevel@tonic-gate 		goto ret;
18206557Sfr41279 	}
18210Sstevel@tonic-gate 	err = big_copy(result, &rr);
18220Sstevel@tonic-gate ret:
18236557Sfr41279 	big_finish(&rr);
18240Sstevel@tonic-gate 	return (err);
18250Sstevel@tonic-gate }
18260Sstevel@tonic-gate 
18276557Sfr41279 
18280Sstevel@tonic-gate /* caller must make sure that a < n */
18290Sstevel@tonic-gate BIG_ERR_CODE
18306557Sfr41279 big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, BIG_CHUNK_TYPE n0,
18316557Sfr41279     BIGNUM *n_rr)
18320Sstevel@tonic-gate {
18336557Sfr41279 	BIGNUM		rr;
18346557Sfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
18356557Sfr41279 	int		len, i;
18366557Sfr41279 	BIG_ERR_CODE	err;
18370Sstevel@tonic-gate 
18380Sstevel@tonic-gate 	rr.malloced = 0;
18390Sstevel@tonic-gate 	len = n->len;
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue)))
18426557Sfr41279 	    != BIG_OK) {
18436557Sfr41279 		return (err);
18446557Sfr41279 	}
18450Sstevel@tonic-gate 
18460Sstevel@tonic-gate 	if (n_rr == NULL) {
18476557Sfr41279 		for (i = 0; i < 2 * len; i++) {
18486557Sfr41279 			rr.value[i] = 0;
18496557Sfr41279 		}
18500Sstevel@tonic-gate 		rr.value[2 * len] = 1;
18510Sstevel@tonic-gate 		rr.len = 2 * len + 1;
18526557Sfr41279 		if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) {
18530Sstevel@tonic-gate 			goto ret;
18546557Sfr41279 		}
18550Sstevel@tonic-gate 		n_rr = &rr;
18560Sstevel@tonic-gate 	}
18570Sstevel@tonic-gate 
18586557Sfr41279 	if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK) {
18590Sstevel@tonic-gate 		goto ret;
18606557Sfr41279 	}
18610Sstevel@tonic-gate 	err = big_copy(result, &rr);
18626557Sfr41279 
18630Sstevel@tonic-gate ret:
18646557Sfr41279 	big_finish(&rr);
18650Sstevel@tonic-gate 	return (err);
18660Sstevel@tonic-gate }
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate 
18696557Sfr41279 #ifdef	USE_FLOATING_POINT
18706557Sfr41279 #define	big_modexp_ncp_float	big_modexp_ncp_sw
18716557Sfr41279 #else
18726557Sfr41279 #define	big_modexp_ncp_int	big_modexp_ncp_sw
18736557Sfr41279 #endif
18746557Sfr41279 
18750Sstevel@tonic-gate #define	MAX_EXP_BIT_GROUP_SIZE 6
18760Sstevel@tonic-gate #define	APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1))
18770Sstevel@tonic-gate 
18786557Sfr41279 /* ARGSUSED */
18790Sstevel@tonic-gate static BIG_ERR_CODE
18806557Sfr41279 big_modexp_ncp_int(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n,
18816557Sfr41279     BIGNUM *tmp, BIG_CHUNK_TYPE n0)
18826557Sfr41279 
18830Sstevel@tonic-gate {
18846557Sfr41279 	BIGNUM		apowers[APOWERS_MAX_SIZE];
18856557Sfr41279 	BIGNUM		tmp1;
18866557Sfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
18876557Sfr41279 	int		i, j, k, l, m, p;
18888933Sopensolaris@drydog.com 	uint32_t	bit, bitind, bitcount, groupbits, apowerssize;
18898933Sopensolaris@drydog.com 	uint32_t	nbits;
18906557Sfr41279 	BIG_ERR_CODE	err;
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	nbits = big_numbits(e);
18930Sstevel@tonic-gate 	if (nbits < 50) {
18940Sstevel@tonic-gate 		groupbits = 1;
18950Sstevel@tonic-gate 		apowerssize = 1;
18960Sstevel@tonic-gate 	} else {
18970Sstevel@tonic-gate 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
18980Sstevel@tonic-gate 		apowerssize = 1 << (groupbits - 1);
18990Sstevel@tonic-gate 	}
19000Sstevel@tonic-gate 
19016557Sfr41279 
19026557Sfr41279 	if ((err = big_init1(&tmp1, 2 * n->len + 1,
19036557Sfr41279 	    tmp1value, arraysize(tmp1value))) != BIG_OK) {
19040Sstevel@tonic-gate 		return (err);
19056557Sfr41279 	}
19066557Sfr41279 
19078933Sopensolaris@drydog.com 	/* clear the malloced bit to help cleanup */
19086557Sfr41279 	for (i = 0; i < apowerssize; i++) {
19096557Sfr41279 		apowers[i].malloced = 0;
19106557Sfr41279 	}
19118933Sopensolaris@drydog.com 
19126557Sfr41279 	for (i = 0; i < apowerssize; i++) {
19136557Sfr41279 		if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) !=
19146557Sfr41279 		    BIG_OK) {
19156557Sfr41279 			goto ret;
19166557Sfr41279 		}
19176557Sfr41279 	}
19186557Sfr41279 
19196557Sfr41279 	(void) big_copy(&(apowers[0]), ma);
19206557Sfr41279 
19216557Sfr41279 	if ((err = big_mont_mul(&tmp1, ma, ma, n, n0)) != BIG_OK) {
19226557Sfr41279 		goto ret;
19236557Sfr41279 	}
19246557Sfr41279 	(void) big_copy(ma, &tmp1);
19256557Sfr41279 
19266557Sfr41279 	for (i = 1; i < apowerssize; i++) {
19276557Sfr41279 		if ((err = big_mont_mul(&tmp1, ma,
19288933Sopensolaris@drydog.com 		    &(apowers[i - 1]), n, n0)) != BIG_OK) {
19296557Sfr41279 			goto ret;
19306557Sfr41279 		}
19316557Sfr41279 		(void) big_copy(&apowers[i], &tmp1);
19326557Sfr41279 	}
19336557Sfr41279 
19346557Sfr41279 	bitind = nbits % BIG_CHUNK_SIZE;
19356557Sfr41279 	k = 0;
19366557Sfr41279 	l = 0;
19376557Sfr41279 	p = 0;
19386557Sfr41279 	bitcount = 0;
19396557Sfr41279 	for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) {
19406557Sfr41279 		for (j = bitind - 1; j >= 0; j--) {
19416557Sfr41279 			bit = (e->value[i] >> j) & 1;
19426557Sfr41279 			if ((bitcount == 0) && (bit == 0)) {
19436557Sfr41279 				if ((err = big_mont_mul(tmp,
19446557Sfr41279 				    tmp, tmp, n, n0)) != BIG_OK) {
19456557Sfr41279 					goto ret;
19466557Sfr41279 				}
19476557Sfr41279 			} else {
19486557Sfr41279 				bitcount++;
19496557Sfr41279 				p = p * 2 + bit;
19506557Sfr41279 				if (bit == 1) {
19516557Sfr41279 					k = k + l + 1;
19526557Sfr41279 					l = 0;
19536557Sfr41279 				} else {
19546557Sfr41279 					l++;
19556557Sfr41279 				}
19566557Sfr41279 				if (bitcount == groupbits) {
19576557Sfr41279 					for (m = 0; m < k; m++) {
19586557Sfr41279 						if ((err = big_mont_mul(tmp,
19596557Sfr41279 						    tmp, tmp, n, n0)) !=
19606557Sfr41279 						    BIG_OK) {
19616557Sfr41279 							goto ret;
19626557Sfr41279 						}
19636557Sfr41279 					}
19646557Sfr41279 					if ((err = big_mont_mul(tmp, tmp,
19656557Sfr41279 					    &(apowers[p >> (l + 1)]),
19666557Sfr41279 					    n, n0)) != BIG_OK) {
19676557Sfr41279 						goto ret;
19686557Sfr41279 					}
19696557Sfr41279 					for (m = 0; m < l; m++) {
19706557Sfr41279 						if ((err = big_mont_mul(tmp,
19716557Sfr41279 						    tmp, tmp, n, n0)) !=
19726557Sfr41279 						    BIG_OK) {
19736557Sfr41279 							goto ret;
19746557Sfr41279 						}
19756557Sfr41279 					}
19766557Sfr41279 					k = 0;
19776557Sfr41279 					l = 0;
19786557Sfr41279 					p = 0;
19796557Sfr41279 					bitcount = 0;
19806557Sfr41279 				}
19816557Sfr41279 			}
19826557Sfr41279 		}
19836557Sfr41279 		bitind = BIG_CHUNK_SIZE;
19840Sstevel@tonic-gate 	}
19850Sstevel@tonic-gate 
19866557Sfr41279 	for (m = 0; m < k; m++) {
19876557Sfr41279 		if ((err = big_mont_mul(tmp, tmp, tmp, n, n0)) != BIG_OK) {
19886557Sfr41279 			goto ret;
19896557Sfr41279 		}
19906557Sfr41279 	}
19916557Sfr41279 	if (p != 0) {
19926557Sfr41279 		if ((err = big_mont_mul(tmp, tmp,
19936557Sfr41279 		    &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK) {
19946557Sfr41279 			goto ret;
19956557Sfr41279 		}
19966557Sfr41279 	}
19976557Sfr41279 	for (m = 0; m < l; m++) {
19986557Sfr41279 		if ((err = big_mont_mul(result, tmp, tmp, n, n0)) != BIG_OK) {
19996557Sfr41279 			goto ret;
20006557Sfr41279 		}
20016557Sfr41279 	}
20026557Sfr41279 
20036557Sfr41279 ret:
20046557Sfr41279 	for (i = apowerssize - 1; i >= 0; i--) {
20056557Sfr41279 		big_finish(&(apowers[i]));
20060Sstevel@tonic-gate 	}
20076557Sfr41279 	big_finish(&tmp1);
20086557Sfr41279 
20096557Sfr41279 	return (err);
20106557Sfr41279 }
20116557Sfr41279 
20126557Sfr41279 
20136557Sfr41279 #ifdef USE_FLOATING_POINT
20146557Sfr41279 
20156557Sfr41279 #ifdef _KERNEL
20166557Sfr41279 
20176557Sfr41279 #include <sys/sysmacros.h>
20186557Sfr41279 #include <sys/regset.h>
20196557Sfr41279 #include <sys/fpu/fpusystm.h>
20206557Sfr41279 
20216557Sfr41279 /* the alignment for block stores to save fp registers */
20226557Sfr41279 #define	FPR_ALIGN	(64)
20236557Sfr41279 
20246557Sfr41279 extern void big_savefp(kfpu_t *);
20256557Sfr41279 extern void big_restorefp(kfpu_t *);
20266557Sfr41279 
20276557Sfr41279 #endif /* _KERNEL */
20286557Sfr41279 
20296557Sfr41279 /*
20306557Sfr41279  * This version makes use of floating point for performance
20316557Sfr41279  */
20326557Sfr41279 static BIG_ERR_CODE
20336557Sfr41279 big_modexp_ncp_float(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n,
20346557Sfr41279     BIGNUM *tmp, BIG_CHUNK_TYPE n0)
20356557Sfr41279 {
20366557Sfr41279 
20378933Sopensolaris@drydog.com 	int		i, j, k, l, m, p;
20388933Sopensolaris@drydog.com 	uint32_t	bit, bitind, bitcount, nlen;
20396557Sfr41279 	double		dn0;
20406557Sfr41279 	double		*dn, *dt, *d16r, *d32r;
20416557Sfr41279 	uint32_t	*nint, *prod;
20426557Sfr41279 	double		*apowers[APOWERS_MAX_SIZE];
20438933Sopensolaris@drydog.com 	uint32_t	nbits, groupbits, apowerssize;
20446557Sfr41279 	BIG_ERR_CODE	err = BIG_OK;
20456557Sfr41279 
20466557Sfr41279 #ifdef _KERNEL
20476557Sfr41279 	uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN];
20486557Sfr41279 	kfpu_t *fpu;
20496557Sfr41279 
20506557Sfr41279 #ifdef DEBUG
20516557Sfr41279 	if (!fpu_exists)
20526557Sfr41279 		return (BIG_GENERAL_ERR);
20536557Sfr41279 #endif
20546557Sfr41279 
20556557Sfr41279 	fpu =  (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN);
20566557Sfr41279 	big_savefp(fpu);
20576557Sfr41279 
20586557Sfr41279 #endif /* _KERNEL */
20596557Sfr41279 
20606557Sfr41279 	nbits = big_numbits(e);
20616557Sfr41279 	if (nbits < 50) {
20626557Sfr41279 		groupbits = 1;
20636557Sfr41279 		apowerssize = 1;
20646557Sfr41279 	} else {
20656557Sfr41279 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
20666557Sfr41279 		apowerssize = 1 << (groupbits - 1);
20676557Sfr41279 	}
20686557Sfr41279 
20696557Sfr41279 	nlen = (BIG_CHUNK_SIZE / 32) * n->len;
20700Sstevel@tonic-gate 	dn0 = (double)(n0 & 0xffff);
20710Sstevel@tonic-gate 
20720Sstevel@tonic-gate 	dn = dt = d16r = d32r = NULL;
20730Sstevel@tonic-gate 	nint = prod = NULL;
20740Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
20750Sstevel@tonic-gate 		apowers[i] = NULL;
20760Sstevel@tonic-gate 	}
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 	if ((dn = big_malloc(nlen * sizeof (double))) == NULL) {
20790Sstevel@tonic-gate 		err = BIG_NO_MEM;
20800Sstevel@tonic-gate 		goto ret;
20810Sstevel@tonic-gate 	}
20820Sstevel@tonic-gate 	if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) {
20830Sstevel@tonic-gate 		err = BIG_NO_MEM;
20840Sstevel@tonic-gate 		goto ret;
20850Sstevel@tonic-gate 	}
20860Sstevel@tonic-gate 	if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) {
20870Sstevel@tonic-gate 		err = BIG_NO_MEM;
20880Sstevel@tonic-gate 		goto ret;
20890Sstevel@tonic-gate 	}
20900Sstevel@tonic-gate 	if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) {
20910Sstevel@tonic-gate 		err = BIG_NO_MEM;
20920Sstevel@tonic-gate 		goto ret;
20930Sstevel@tonic-gate 	}
20940Sstevel@tonic-gate 	if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) {
20950Sstevel@tonic-gate 		err = BIG_NO_MEM;
20960Sstevel@tonic-gate 		goto ret;
20970Sstevel@tonic-gate 	}
20980Sstevel@tonic-gate 	if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) {
20990Sstevel@tonic-gate 		err = BIG_NO_MEM;
21000Sstevel@tonic-gate 		goto ret;
21010Sstevel@tonic-gate 	}
21020Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
21030Sstevel@tonic-gate 		if ((apowers[i] = big_malloc((2 * nlen + 1) *
21040Sstevel@tonic-gate 		    sizeof (double))) == NULL) {
21050Sstevel@tonic-gate 			err = BIG_NO_MEM;
21060Sstevel@tonic-gate 			goto ret;
21070Sstevel@tonic-gate 		}
21080Sstevel@tonic-gate 	}
21090Sstevel@tonic-gate 
21106557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
21116557Sfr41279 	for (i = 0; i < ma->len; i++) {
21126557Sfr41279 		nint[i] = ma->value[i];
21136557Sfr41279 	}
21146557Sfr41279 	for (; i < nlen; i++) {
21156557Sfr41279 		nint[i] = 0;
21166557Sfr41279 	}
21176557Sfr41279 #else
21186557Sfr41279 	for (i = 0; i < ma->len; i++) {
21196557Sfr41279 		nint[2 * i] = (uint32_t)(ma->value[i] & 0xffffffffULL);
21206557Sfr41279 		nint[2 * i + 1] = (uint32_t)(ma->value[i] >> 32);
21216557Sfr41279 	}
21226557Sfr41279 	for (i = ma->len * 2; i < nlen; i++) {
21236557Sfr41279 		nint[i] = 0;
21246557Sfr41279 	}
21256557Sfr41279 #endif
21260Sstevel@tonic-gate 	conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen);
21270Sstevel@tonic-gate 
21286557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
21296557Sfr41279 	for (i = 0; i < n->len; i++) {
21306557Sfr41279 		nint[i] = n->value[i];
21316557Sfr41279 	}
21326557Sfr41279 	for (; i < nlen; i++) {
21336557Sfr41279 		nint[i] = 0;
21346557Sfr41279 	}
21356557Sfr41279 #else
21366557Sfr41279 	for (i = 0; i < n->len; i++) {
21376557Sfr41279 		nint[2 * i] = (uint32_t)(n->value[i] & 0xffffffffULL);
21386557Sfr41279 		nint[2 * i + 1] = (uint32_t)(n->value[i] >> 32);
21396557Sfr41279 	}
21406557Sfr41279 	for (i = n->len * 2; i < nlen; i++) {
21416557Sfr41279 		nint[i] = 0;
21426557Sfr41279 	}
21436557Sfr41279 #endif
21440Sstevel@tonic-gate 	conv_i32_to_d32(dn, nint, nlen);
21450Sstevel@tonic-gate 
21460Sstevel@tonic-gate 	mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0);
21470Sstevel@tonic-gate 	conv_i32_to_d32(d32r, prod, nlen);
21480Sstevel@tonic-gate 	for (i = 1; i < apowerssize; i++) {
21490Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[i - 1],
21500Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
21510Sstevel@tonic-gate 		conv_i32_to_d16(apowers[i], prod, nlen);
21520Sstevel@tonic-gate 	}
21530Sstevel@tonic-gate 
21546557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
21556557Sfr41279 	for (i = 0; i < tmp->len; i++) {
21566557Sfr41279 		prod[i] = tmp->value[i];
21576557Sfr41279 	}
21586557Sfr41279 	for (; i < nlen + 1; i++) {
21596557Sfr41279 		prod[i] = 0;
21606557Sfr41279 	}
21616557Sfr41279 #else
21626557Sfr41279 	for (i = 0; i < tmp->len; i++) {
21636557Sfr41279 		prod[2 * i] = (uint32_t)(tmp->value[i] & 0xffffffffULL);
21646557Sfr41279 		prod[2 * i + 1] = (uint32_t)(tmp->value[i] >> 32);
21656557Sfr41279 	}
21666557Sfr41279 	for (i = tmp->len * 2; i < nlen + 1; i++) {
21676557Sfr41279 		prod[i] = 0;
21686557Sfr41279 	}
21696557Sfr41279 #endif
21706557Sfr41279 
21716557Sfr41279 	bitind = nbits % BIG_CHUNK_SIZE;
21720Sstevel@tonic-gate 	k = 0;
21730Sstevel@tonic-gate 	l = 0;
21740Sstevel@tonic-gate 	p = 0;
21750Sstevel@tonic-gate 	bitcount = 0;
21766557Sfr41279 	for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) {
21770Sstevel@tonic-gate 		for (j = bitind - 1; j >= 0; j--) {
21780Sstevel@tonic-gate 			bit = (e->value[i] >> j) & 1;
21790Sstevel@tonic-gate 			if ((bitcount == 0) && (bit == 0)) {
21800Sstevel@tonic-gate 				conv_i32_to_d32_and_d16(d32r, d16r,
21810Sstevel@tonic-gate 				    prod, nlen);
21820Sstevel@tonic-gate 				mont_mulf_noconv(prod, d32r, d16r,
21830Sstevel@tonic-gate 				    dt, dn, nint, nlen, dn0);
21840Sstevel@tonic-gate 			} else {
21850Sstevel@tonic-gate 				bitcount++;
21860Sstevel@tonic-gate 				p = p * 2 + bit;
21870Sstevel@tonic-gate 				if (bit == 1) {
21880Sstevel@tonic-gate 					k = k + l + 1;
21890Sstevel@tonic-gate 					l = 0;
21900Sstevel@tonic-gate 				} else {
21910Sstevel@tonic-gate 					l++;
21920Sstevel@tonic-gate 				}
21930Sstevel@tonic-gate 				if (bitcount == groupbits) {
21940Sstevel@tonic-gate 					for (m = 0; m < k; m++) {
21956557Sfr41279 						conv_i32_to_d32_and_d16(d32r,
21966557Sfr41279 						    d16r, prod, nlen);
21970Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
21980Sstevel@tonic-gate 						    d16r, dt, dn, nint,
21990Sstevel@tonic-gate 						    nlen, dn0);
22000Sstevel@tonic-gate 					}
22010Sstevel@tonic-gate 					conv_i32_to_d32(d32r, prod, nlen);
22020Sstevel@tonic-gate 					mont_mulf_noconv(prod, d32r,
22038933Sopensolaris@drydog.com 					    apowers[p >> (l + 1)],
22040Sstevel@tonic-gate 					    dt, dn, nint, nlen, dn0);
22050Sstevel@tonic-gate 					for (m = 0; m < l; m++) {
22066557Sfr41279 						conv_i32_to_d32_and_d16(d32r,
22076557Sfr41279 						    d16r, prod, nlen);
22080Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
22090Sstevel@tonic-gate 						    d16r, dt, dn, nint,
22100Sstevel@tonic-gate 						    nlen, dn0);
22110Sstevel@tonic-gate 					}
22120Sstevel@tonic-gate 					k = 0;
22130Sstevel@tonic-gate 					l = 0;
22140Sstevel@tonic-gate 					p = 0;
22150Sstevel@tonic-gate 					bitcount = 0;
22160Sstevel@tonic-gate 				}
22170Sstevel@tonic-gate 			}
22180Sstevel@tonic-gate 		}
22196557Sfr41279 		bitind = BIG_CHUNK_SIZE;
22200Sstevel@tonic-gate 	}
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 	for (m = 0; m < k; m++) {
22230Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
22240Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
22250Sstevel@tonic-gate 	}
22260Sstevel@tonic-gate 	if (p != 0) {
22270Sstevel@tonic-gate 		conv_i32_to_d32(d32r, prod, nlen);
22280Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)],
22290Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
22300Sstevel@tonic-gate 	}
22310Sstevel@tonic-gate 	for (m = 0; m < l; m++) {
22320Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
22330Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
22340Sstevel@tonic-gate 	}
22350Sstevel@tonic-gate 
22366557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
22376557Sfr41279 	for (i = 0; i < nlen; i++) {
22386557Sfr41279 		result->value[i] = prod[i];
22396557Sfr41279 	}
22406557Sfr41279 	for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--)
22416557Sfr41279 		;
22426557Sfr41279 #else
22436557Sfr41279 	for (i = 0; i < nlen / 2; i++) {
22446557Sfr41279 		result->value[i] = (uint64_t)(prod[2 * i]) +
22456557Sfr41279 		    (((uint64_t)(prod[2 * i + 1])) << 32);
22466557Sfr41279 	}
22476557Sfr41279 	for (i = nlen / 2 - 1; (i > 0) && (result->value[i] == 0); i--)
22486557Sfr41279 		;
22496557Sfr41279 #endif
22506557Sfr41279 	result->len = i + 1;
22516557Sfr41279 
22520Sstevel@tonic-gate ret:
22530Sstevel@tonic-gate 	for (i = apowerssize - 1; i >= 0; i--) {
22540Sstevel@tonic-gate 		if (apowers[i] != NULL)
22550Sstevel@tonic-gate 			big_free(apowers[i], (2 * nlen + 1) * sizeof (double));
22560Sstevel@tonic-gate 	}
22576557Sfr41279 	if (d32r != NULL) {
22580Sstevel@tonic-gate 		big_free(d32r, nlen * sizeof (double));
22596557Sfr41279 	}
22606557Sfr41279 	if (d16r != NULL) {
22610Sstevel@tonic-gate 		big_free(d16r, (2 * nlen + 1) * sizeof (double));
22626557Sfr41279 	}
22636557Sfr41279 	if (prod != NULL) {
22640Sstevel@tonic-gate 		big_free(prod, (nlen + 1) * sizeof (uint32_t));
22656557Sfr41279 	}
22666557Sfr41279 	if (nint != NULL) {
22670Sstevel@tonic-gate 		big_free(nint, nlen * sizeof (uint32_t));
22686557Sfr41279 	}
22696557Sfr41279 	if (dt != NULL) {
22700Sstevel@tonic-gate 		big_free(dt, (4 * nlen + 2) * sizeof (double));
22716557Sfr41279 	}
22726557Sfr41279 	if (dn != NULL) {
22730Sstevel@tonic-gate 		big_free(dn, nlen * sizeof (double));
22746557Sfr41279 	}
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate #ifdef _KERNEL
22776557Sfr41279 	big_restorefp(fpu);
22780Sstevel@tonic-gate #endif
22790Sstevel@tonic-gate 
22800Sstevel@tonic-gate 	return (err);
22810Sstevel@tonic-gate }
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */
22840Sstevel@tonic-gate 
22850Sstevel@tonic-gate 
22860Sstevel@tonic-gate BIG_ERR_CODE
22876557Sfr41279 big_modexp_ext(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr,
22886557Sfr41279     big_modexp_ncp_info_t *info)
22890Sstevel@tonic-gate {
22906557Sfr41279 	BIGNUM		ma, tmp, rr;
22916557Sfr41279 	BIG_CHUNK_TYPE	mavalue[BIGTMPSIZE];
22926557Sfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
22936557Sfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
22946557Sfr41279 	BIG_ERR_CODE	err;
22956557Sfr41279 	BIG_CHUNK_TYPE	n0;
22966557Sfr41279 
22976557Sfr41279 	if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue)))	!=
22986557Sfr41279 	    BIG_OK) {
22990Sstevel@tonic-gate 		return (err);
23006557Sfr41279 	}
23016557Sfr41279 	ma.len = 1;
23026557Sfr41279 	ma.value[0] = 0;
23036557Sfr41279 
23046557Sfr41279 	if ((err = big_init1(&tmp, 2 * n->len + 1,
23056557Sfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
23060Sstevel@tonic-gate 		goto ret1;
23076557Sfr41279 	}
23086557Sfr41279 
23098933Sopensolaris@drydog.com 	/* clear the malloced bit to help cleanup */
23106557Sfr41279 	rr.malloced = 0;
23118933Sopensolaris@drydog.com 
23126557Sfr41279 	if (n_rr == NULL) {
23136557Sfr41279 		if ((err = big_init1(&rr, 2 * n->len + 1,
23146557Sfr41279 		    rrvalue, arraysize(rrvalue))) != BIG_OK) {
23156557Sfr41279 			goto ret2;
23166557Sfr41279 		}
23176557Sfr41279 		if (big_mont_rr(&rr, n) != BIG_OK) {
23186557Sfr41279 			goto ret;
23196557Sfr41279 		}
23206557Sfr41279 		n_rr = &rr;
23216557Sfr41279 	}
23226557Sfr41279 
23236557Sfr41279 	n0 = big_n0(n->value[0]);
23246557Sfr41279 
23256557Sfr41279 	if (big_cmp_abs(a, n) > 0) {
23266557Sfr41279 		if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK) {
23276557Sfr41279 			goto ret;
23286557Sfr41279 		}
23296557Sfr41279 		err = big_mont_conv(&ma, &ma, n, n0, n_rr);
23306557Sfr41279 	} else {
23316557Sfr41279 		err = big_mont_conv(&ma, a, n, n0, n_rr);
23326557Sfr41279 	}
23336557Sfr41279 	if (err != BIG_OK) {
23346557Sfr41279 		goto ret;
23356557Sfr41279 	}
23366557Sfr41279 
23376557Sfr41279 	tmp.len = 1;
23386557Sfr41279 	tmp.value[0] = 1;
23396557Sfr41279 	if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK) {
23406557Sfr41279 		goto ret;
23416557Sfr41279 	}
23426557Sfr41279 
23436557Sfr41279 	if ((info != NULL) && (info->func != NULL)) {
23446557Sfr41279 		err = (*(info->func))(&tmp, &ma, e, n, &tmp, n0,
23456557Sfr41279 		    info->ncp, info->reqp);
23466557Sfr41279 	} else {
23476557Sfr41279 		err = big_modexp_ncp_sw(&tmp, &ma, e, n, &tmp, n0);
23486557Sfr41279 	}
23496557Sfr41279 	if (err != BIG_OK) {
23506557Sfr41279 		goto ret;
23516557Sfr41279 	}
23526557Sfr41279 
23536557Sfr41279 	ma.value[0] = 1;
23546557Sfr41279 	ma.len = 1;
23556557Sfr41279 	if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK) {
23566557Sfr41279 		goto ret;
23576557Sfr41279 	}
23586557Sfr41279 	err = big_copy(result, &tmp);
23596557Sfr41279 
23606557Sfr41279 ret:
23616557Sfr41279 	if (rr.malloced) {
23626557Sfr41279 		big_finish(&rr);
23636557Sfr41279 	}
23646557Sfr41279 ret2:
23656557Sfr41279 	big_finish(&tmp);
23666557Sfr41279 ret1:
23676557Sfr41279 	big_finish(&ma);
23686557Sfr41279 
23696557Sfr41279 	return (err);
23706557Sfr41279 }
23716557Sfr41279 
23726557Sfr41279 BIG_ERR_CODE
23736557Sfr41279 big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
23746557Sfr41279 {
23756557Sfr41279 	return (big_modexp_ext(result, a, e, n, n_rr, NULL));
23766557Sfr41279 }
23776557Sfr41279 
23786557Sfr41279 
23796557Sfr41279 BIG_ERR_CODE
23806557Sfr41279 big_modexp_crt_ext(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
23816557Sfr41279     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
23826557Sfr41279     BIGNUM *p_rr, BIGNUM *q_rr, big_modexp_ncp_info_t *info)
23836557Sfr41279 {
23846557Sfr41279 	BIGNUM		ap, aq, tmp;
23856557Sfr41279 	int		alen, biglen, sign;
23866557Sfr41279 	BIG_ERR_CODE	err;
23876557Sfr41279 
23886557Sfr41279 	if (p->len > q->len) {
23896557Sfr41279 		biglen = p->len;
23906557Sfr41279 	} else {
23916557Sfr41279 		biglen = q->len;
23926557Sfr41279 	}
23936557Sfr41279 
23946557Sfr41279 	if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK) {
23956557Sfr41279 		return (err);
23966557Sfr41279 	}
23976557Sfr41279 	if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK) {
23986557Sfr41279 		goto ret1;
23996557Sfr41279 	}
24006557Sfr41279 	if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK) {
24010Sstevel@tonic-gate 		goto ret2;
24026557Sfr41279 	}
24030Sstevel@tonic-gate 
24040Sstevel@tonic-gate 	/*
24050Sstevel@tonic-gate 	 * check whether a is too short - to avoid timing attacks
24060Sstevel@tonic-gate 	 */
24070Sstevel@tonic-gate 	alen = a->len;
24080Sstevel@tonic-gate 	while ((alen > p->len) && (a->value[alen - 1] == 0)) {
24090Sstevel@tonic-gate 		alen--;
24100Sstevel@tonic-gate 	}
24110Sstevel@tonic-gate 	if (alen < p->len + q->len) {
24120Sstevel@tonic-gate 		/*
24130Sstevel@tonic-gate 		 * a is too short, add p*q to it before
24140Sstevel@tonic-gate 		 * taking it modulo p and q
24150Sstevel@tonic-gate 		 * this will also affect timing, but this difference
24160Sstevel@tonic-gate 		 * does not depend on p or q, only on a
24170Sstevel@tonic-gate 		 * (in "normal" operation, this path will never be
24180Sstevel@tonic-gate 		 * taken, so it is not a performance penalty
24190Sstevel@tonic-gate 		 */
24206557Sfr41279 		if ((err = big_mul(&tmp, p, q)) != BIG_OK) {
24210Sstevel@tonic-gate 			goto ret;
24226557Sfr41279 		}
24236557Sfr41279 		if ((err = big_add(&tmp, &tmp, a)) != BIG_OK) {
24246557Sfr41279 			goto ret;
24256557Sfr41279 		}
24266557Sfr41279 		if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK) {
24270Sstevel@tonic-gate 			goto ret;
24286557Sfr41279 		}
24296557Sfr41279 		if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) {
24300Sstevel@tonic-gate 			goto ret;
24316557Sfr41279 		}
24326557Sfr41279 	} else {
24336557Sfr41279 		if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK) {
24340Sstevel@tonic-gate 			goto ret;
24356557Sfr41279 		}
24366557Sfr41279 		if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK) {
24370Sstevel@tonic-gate 			goto ret;
24386557Sfr41279 		}
24390Sstevel@tonic-gate 	}
24400Sstevel@tonic-gate 
24416557Sfr41279 	if ((err = big_modexp_ext(&ap, &ap, dmodpminus1, p, p_rr, info)) !=
24426557Sfr41279 	    BIG_OK) {
24430Sstevel@tonic-gate 		goto ret;
24446557Sfr41279 	}
24456557Sfr41279 	if ((err = big_modexp_ext(&aq, &aq, dmodqminus1, q, q_rr, info)) !=
24466557Sfr41279 	    BIG_OK) {
24470Sstevel@tonic-gate 		goto ret;
24486557Sfr41279 	}
24496557Sfr41279 	if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK) {
24500Sstevel@tonic-gate 		goto ret;
24516557Sfr41279 	}
24526557Sfr41279 	if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK) {
24530Sstevel@tonic-gate 		goto ret;
24546557Sfr41279 	}
24550Sstevel@tonic-gate 	sign = tmp.sign;
24560Sstevel@tonic-gate 	tmp.sign = 1;
24576557Sfr41279 	if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) {
24580Sstevel@tonic-gate 		goto ret;
24596557Sfr41279 	}
24600Sstevel@tonic-gate 	if ((sign == -1) && (!big_is_zero(&aq))) {
24610Sstevel@tonic-gate 		(void) big_sub_pos(&aq, q, &aq);
24620Sstevel@tonic-gate 	}
24636557Sfr41279 	if ((err = big_mul(&tmp, &aq, p)) != BIG_OK) {
24640Sstevel@tonic-gate 		goto ret;
24656557Sfr41279 	}
24660Sstevel@tonic-gate 	err = big_add_abs(result, &ap, &tmp);
24670Sstevel@tonic-gate 
24680Sstevel@tonic-gate ret:
24690Sstevel@tonic-gate 	big_finish(&tmp);
24700Sstevel@tonic-gate ret2:
24710Sstevel@tonic-gate 	big_finish(&aq);
24720Sstevel@tonic-gate ret1:
24730Sstevel@tonic-gate 	big_finish(&ap);
24740Sstevel@tonic-gate 
24750Sstevel@tonic-gate 	return (err);
24760Sstevel@tonic-gate }
24770Sstevel@tonic-gate 
24780Sstevel@tonic-gate 
24796557Sfr41279 BIG_ERR_CODE
24806557Sfr41279 big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
24816557Sfr41279     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
24826557Sfr41279     BIGNUM *p_rr, BIGNUM *q_rr)
24836557Sfr41279 {
24846557Sfr41279 	return (big_modexp_crt_ext(result, a, dmodpminus1, dmodqminus1,
24856557Sfr41279 	    p, q, pinvmodq, p_rr, q_rr, NULL));
24866557Sfr41279 }
24876557Sfr41279 
24886557Sfr41279 
24896557Sfr41279 static BIG_CHUNK_TYPE onearr[1] = {(BIG_CHUNK_TYPE)1};
24906557Sfr41279 BIGNUM big_One = {1, 1, 1, 0, onearr};
24916557Sfr41279 
24926557Sfr41279 static BIG_CHUNK_TYPE twoarr[1] = {(BIG_CHUNK_TYPE)2};
24936557Sfr41279 BIGNUM big_Two = {1, 1, 1, 0, twoarr};
24946557Sfr41279 
24956557Sfr41279 static BIG_CHUNK_TYPE fourarr[1] = {(BIG_CHUNK_TYPE)4};
24966557Sfr41279 static BIGNUM big_Four = {1, 1, 1, 0, fourarr};
24976557Sfr41279 
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate BIG_ERR_CODE
25000Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n)
25010Sstevel@tonic-gate {
25026557Sfr41279 	BIGNUM		*high, *low, *mid, *t;
25036557Sfr41279 	BIGNUM		t1, t2, t3, prod;
25046557Sfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
25056557Sfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
25066557Sfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
25076557Sfr41279 	BIG_CHUNK_TYPE	prodvalue[BIGTMPSIZE];
25088933Sopensolaris@drydog.com 	int		i, diff;
25098933Sopensolaris@drydog.com 	uint32_t	nbits, nrootbits, highbits;
25106557Sfr41279 	BIG_ERR_CODE	err;
25110Sstevel@tonic-gate 
25120Sstevel@tonic-gate 	nbits = big_numbits(n);
25130Sstevel@tonic-gate 
25140Sstevel@tonic-gate 	if ((err = big_init1(&t1, n->len + 1,
25150Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
25160Sstevel@tonic-gate 		return (err);
25170Sstevel@tonic-gate 	if ((err = big_init1(&t2, n->len + 1,
25180Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
25190Sstevel@tonic-gate 		goto ret1;
25200Sstevel@tonic-gate 	if ((err = big_init1(&t3, n->len + 1,
25210Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
25220Sstevel@tonic-gate 		goto ret2;
25230Sstevel@tonic-gate 	if ((err = big_init1(&prod, n->len + 1,
25240Sstevel@tonic-gate 	    prodvalue, arraysize(prodvalue))) != BIG_OK)
25250Sstevel@tonic-gate 		goto ret3;
25260Sstevel@tonic-gate 
25270Sstevel@tonic-gate 	nrootbits = (nbits + 1) / 2;
25286557Sfr41279 	t1.len = t2.len = t3.len = (nrootbits - 1) / BIG_CHUNK_SIZE + 1;
25290Sstevel@tonic-gate 	for (i = 0; i < t1.len; i++) {
25300Sstevel@tonic-gate 		t1.value[i] = 0;
25316557Sfr41279 		t2.value[i] = BIG_CHUNK_ALLBITS;
25320Sstevel@tonic-gate 	}
25336557Sfr41279 	highbits = nrootbits - BIG_CHUNK_SIZE * (t1.len - 1);
25346557Sfr41279 	if (highbits == BIG_CHUNK_SIZE) {
25356557Sfr41279 		t1.value[t1.len - 1] = BIG_CHUNK_HIGHBIT;
25366557Sfr41279 		t2.value[t2.len - 1] = BIG_CHUNK_ALLBITS;
25370Sstevel@tonic-gate 	} else {
25386557Sfr41279 		t1.value[t1.len - 1] = (BIG_CHUNK_TYPE)1 << (highbits - 1);
25390Sstevel@tonic-gate 		t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1;
25400Sstevel@tonic-gate 	}
25416557Sfr41279 
25420Sstevel@tonic-gate 	high = &t2;
25430Sstevel@tonic-gate 	low = &t1;
25440Sstevel@tonic-gate 	mid = &t3;
25450Sstevel@tonic-gate 
25466557Sfr41279 	if ((err = big_mul(&prod, high, high)) != BIG_OK) {
25470Sstevel@tonic-gate 		goto ret;
25486557Sfr41279 	}
25490Sstevel@tonic-gate 	diff = big_cmp_abs(&prod, n);
25500Sstevel@tonic-gate 	if (diff <= 0) {
25510Sstevel@tonic-gate 		err = big_copy(result, high);
25520Sstevel@tonic-gate 		goto ret;
25530Sstevel@tonic-gate 	}
25540Sstevel@tonic-gate 
25550Sstevel@tonic-gate 	(void) big_sub_pos(mid, high, low);
25566557Sfr41279 	while (big_cmp_abs(&big_One, mid) != 0) {
25570Sstevel@tonic-gate 		(void) big_add_abs(mid, high, low);
25580Sstevel@tonic-gate 		(void) big_half_pos(mid, mid);
25590Sstevel@tonic-gate 		if ((err = big_mul(&prod, mid, mid)) != BIG_OK)
25600Sstevel@tonic-gate 			goto ret;
25610Sstevel@tonic-gate 		diff = big_cmp_abs(&prod, n);
25620Sstevel@tonic-gate 		if (diff > 0) {
25630Sstevel@tonic-gate 			t = high;
25640Sstevel@tonic-gate 			high = mid;
25650Sstevel@tonic-gate 			mid = t;
25660Sstevel@tonic-gate 		} else if (diff < 0) {
25670Sstevel@tonic-gate 			t = low;
25680Sstevel@tonic-gate 			low = mid;
25690Sstevel@tonic-gate 			mid = t;
25700Sstevel@tonic-gate 		} else {
25710Sstevel@tonic-gate 			err = big_copy(result, low);
25720Sstevel@tonic-gate 			goto ret;
25730Sstevel@tonic-gate 		}
25740Sstevel@tonic-gate 		(void) big_sub_pos(mid, high, low);
25750Sstevel@tonic-gate 	}
25760Sstevel@tonic-gate 
25770Sstevel@tonic-gate 	err = big_copy(result, low);
25780Sstevel@tonic-gate ret:
25790Sstevel@tonic-gate 	if (prod.malloced) big_finish(&prod);
25800Sstevel@tonic-gate ret3:
25810Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
25820Sstevel@tonic-gate ret2:
25830Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
25840Sstevel@tonic-gate ret1:
25850Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
25860Sstevel@tonic-gate 
25870Sstevel@tonic-gate 	return (err);
25880Sstevel@tonic-gate }
25890Sstevel@tonic-gate 
25900Sstevel@tonic-gate 
25910Sstevel@tonic-gate BIG_ERR_CODE
25920Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm)
25930Sstevel@tonic-gate {
25946557Sfr41279 	BIGNUM		*t, *tmp2, *m, *n;
25956557Sfr41279 	BIGNUM		t1, t2, t3;
25966557Sfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
25976557Sfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
25986557Sfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
25996557Sfr41279 	int		len, err;
26000Sstevel@tonic-gate 
26010Sstevel@tonic-gate 	if (big_is_zero(nn) ||
26020Sstevel@tonic-gate 	    (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) {
26030Sstevel@tonic-gate 		*jac = 0;
26040Sstevel@tonic-gate 		return (BIG_OK);
26050Sstevel@tonic-gate 	}
26060Sstevel@tonic-gate 
26076557Sfr41279 	if (nn->len > mm->len) {
26086557Sfr41279 		len = nn->len;
26096557Sfr41279 	} else {
26106557Sfr41279 		len = mm->len;
26116557Sfr41279 	}
26120Sstevel@tonic-gate 
26130Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
26146557Sfr41279 	    t1value, arraysize(t1value))) != BIG_OK) {
26150Sstevel@tonic-gate 		return (err);
26166557Sfr41279 	}
26170Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
26186557Sfr41279 	    t2value, arraysize(t2value))) != BIG_OK) {
26190Sstevel@tonic-gate 		goto ret1;
26206557Sfr41279 	}
26210Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
26226557Sfr41279 	    t3value, arraysize(t3value))) != BIG_OK) {
26230Sstevel@tonic-gate 		goto ret2;
26246557Sfr41279 	}
26250Sstevel@tonic-gate 
26260Sstevel@tonic-gate 	n = &t1;
26270Sstevel@tonic-gate 	m = &t2;
26280Sstevel@tonic-gate 	tmp2 = &t3;
26290Sstevel@tonic-gate 
26300Sstevel@tonic-gate 	(void) big_copy(n, nn);
26310Sstevel@tonic-gate 	(void) big_copy(m, mm);
26320Sstevel@tonic-gate 
26330Sstevel@tonic-gate 	*jac = 1;
26346557Sfr41279 	while (big_cmp_abs(&big_One, m) != 0) {
26350Sstevel@tonic-gate 		if (big_is_zero(n)) {
26360Sstevel@tonic-gate 			*jac = 0;
26370Sstevel@tonic-gate 			goto ret;
26380Sstevel@tonic-gate 		}
26390Sstevel@tonic-gate 		if ((m->value[0] & 1) == 0) {
26400Sstevel@tonic-gate 			if (((n->value[0] & 7) == 3) ||
26416557Sfr41279 			    ((n->value[0] & 7) == 5))
26426557Sfr41279 				*jac = -*jac;
26430Sstevel@tonic-gate 			(void) big_half_pos(m, m);
26440Sstevel@tonic-gate 		} else if ((n->value[0] & 1) == 0) {
26450Sstevel@tonic-gate 			if (((m->value[0] & 7) == 3) ||
26466557Sfr41279 			    ((m->value[0] & 7) == 5))
26476557Sfr41279 				*jac = -*jac;
26480Sstevel@tonic-gate 			(void) big_half_pos(n, n);
26490Sstevel@tonic-gate 		} else {
26500Sstevel@tonic-gate 			if (((m->value[0] & 3) == 3) &&
26510Sstevel@tonic-gate 			    ((n->value[0] & 3) == 3)) {
26520Sstevel@tonic-gate 				*jac = -*jac;
26530Sstevel@tonic-gate 			}
26546557Sfr41279 			if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK) {
26550Sstevel@tonic-gate 				goto ret;
26566557Sfr41279 			}
26570Sstevel@tonic-gate 			t = tmp2;
26580Sstevel@tonic-gate 			tmp2 = m;
26590Sstevel@tonic-gate 			m = n;
26600Sstevel@tonic-gate 			n = t;
26610Sstevel@tonic-gate 		}
26620Sstevel@tonic-gate 	}
26630Sstevel@tonic-gate 	err = BIG_OK;
26640Sstevel@tonic-gate 
26650Sstevel@tonic-gate ret:
26660Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
26670Sstevel@tonic-gate ret2:
26680Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
26690Sstevel@tonic-gate ret1:
26700Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
26710Sstevel@tonic-gate 
26720Sstevel@tonic-gate 	return (err);
26730Sstevel@tonic-gate }
26740Sstevel@tonic-gate 
26750Sstevel@tonic-gate 
26760Sstevel@tonic-gate BIG_ERR_CODE
26770Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n)
26780Sstevel@tonic-gate {
26798933Sopensolaris@drydog.com 	int		i;
26808933Sopensolaris@drydog.com 	uint32_t	m, w;
26816557Sfr41279 	BIG_CHUNK_TYPE	bit;
26826557Sfr41279 	BIGNUM		ki, tmp, tmp2;
26836557Sfr41279 	BIG_CHUNK_TYPE	kivalue[BIGTMPSIZE];
26846557Sfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
26856557Sfr41279 	BIG_CHUNK_TYPE	tmp2value[BIGTMPSIZE];
26866557Sfr41279 	BIG_ERR_CODE	err;
26876557Sfr41279 
26886557Sfr41279 	if (big_cmp_abs(k, &big_One) == 0) {
26890Sstevel@tonic-gate 		(void) big_copy(Lk, p);
26906557Sfr41279 		(void) big_copy(Lkminus1, &big_Two);
26910Sstevel@tonic-gate 		return (BIG_OK);
26920Sstevel@tonic-gate 	}
26930Sstevel@tonic-gate 
26940Sstevel@tonic-gate 	if ((err = big_init1(&ki, k->len + 1,
26950Sstevel@tonic-gate 	    kivalue, arraysize(kivalue))) != BIG_OK)
26960Sstevel@tonic-gate 		return (err);
26970Sstevel@tonic-gate 
26988933Sopensolaris@drydog.com 	if ((err = big_init1(&tmp, 2 * n->len + 1,
26990Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
27000Sstevel@tonic-gate 		goto ret1;
27010Sstevel@tonic-gate 
27020Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, n->len,
27030Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
27040Sstevel@tonic-gate 		goto ret2;
27050Sstevel@tonic-gate 
27060Sstevel@tonic-gate 	m = big_numbits(k);
27076557Sfr41279 	ki.len = (m - 1) / BIG_CHUNK_SIZE + 1;
27086557Sfr41279 	w = (m - 1) / BIG_CHUNK_SIZE;
27096557Sfr41279 	bit = (BIG_CHUNK_TYPE)1 << ((m - 1) % BIG_CHUNK_SIZE);
27106557Sfr41279 	for (i = 0; i < ki.len; i++) {
27116557Sfr41279 		ki.value[i] = 0;
27126557Sfr41279 	}
27130Sstevel@tonic-gate 	ki.value[ki.len - 1] = bit;
27146557Sfr41279 	if (big_cmp_abs(k, &ki) != 0) {
27150Sstevel@tonic-gate 		(void) big_double(&ki, &ki);
27166557Sfr41279 	}
27170Sstevel@tonic-gate 	(void) big_sub_pos(&ki, &ki, k);
27180Sstevel@tonic-gate 
27190Sstevel@tonic-gate 	(void) big_copy(Lk, p);
27206557Sfr41279 	(void) big_copy(Lkminus1, &big_Two);
27210Sstevel@tonic-gate 
27220Sstevel@tonic-gate 	for (i = 0; i < m; i++) {
27236557Sfr41279 		if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK) {
27240Sstevel@tonic-gate 			goto ret;
27256557Sfr41279 		}
27260Sstevel@tonic-gate 		(void) big_add_abs(&tmp, &tmp, n);
27270Sstevel@tonic-gate 		(void) big_sub_pos(&tmp, &tmp, p);
27286557Sfr41279 		if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK) {
27290Sstevel@tonic-gate 			goto ret;
27306557Sfr41279 		}
27310Sstevel@tonic-gate 		if ((ki.value[w] & bit) != 0) {
27320Sstevel@tonic-gate 			if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) !=
27336557Sfr41279 			    BIG_OK) {
27340Sstevel@tonic-gate 				goto ret;
27356557Sfr41279 			}
27360Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
27376557Sfr41279 			(void) big_sub_pos(&tmp, &tmp, &big_Two);
27380Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) !=
27396557Sfr41279 			    BIG_OK) {
27400Sstevel@tonic-gate 				goto ret;
27416557Sfr41279 			}
27420Sstevel@tonic-gate 			(void) big_copy(Lk, &tmp2);
27430Sstevel@tonic-gate 		} else {
27446557Sfr41279 			if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK) {
27450Sstevel@tonic-gate 				goto ret;
27466557Sfr41279 			}
27470Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
27486557Sfr41279 			(void) big_sub_pos(&tmp, &tmp, &big_Two);
27496557Sfr41279 			if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK) {
27500Sstevel@tonic-gate 				goto ret;
27516557Sfr41279 			}
27520Sstevel@tonic-gate 			(void) big_copy(Lkminus1, &tmp2);
27530Sstevel@tonic-gate 		}
27540Sstevel@tonic-gate 		bit = bit >> 1;
27550Sstevel@tonic-gate 		if (bit == 0) {
27566557Sfr41279 			bit = BIG_CHUNK_HIGHBIT;
27570Sstevel@tonic-gate 			w--;
27580Sstevel@tonic-gate 		}
27590Sstevel@tonic-gate 	}
27600Sstevel@tonic-gate 
27610Sstevel@tonic-gate 	err = BIG_OK;
27620Sstevel@tonic-gate 
27630Sstevel@tonic-gate ret:
27640Sstevel@tonic-gate 	if (tmp2.malloced) big_finish(&tmp2);
27650Sstevel@tonic-gate ret2:
27660Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
27670Sstevel@tonic-gate ret1:
27680Sstevel@tonic-gate 	if (ki.malloced) big_finish(&ki);
27690Sstevel@tonic-gate 
27700Sstevel@tonic-gate 	return (err);
27710Sstevel@tonic-gate }
27720Sstevel@tonic-gate 
27730Sstevel@tonic-gate 
27740Sstevel@tonic-gate BIG_ERR_CODE
27756557Sfr41279 big_isprime_pos_ext(BIGNUM *n, big_modexp_ncp_info_t *info)
27760Sstevel@tonic-gate {
27776557Sfr41279 	BIGNUM		o, nminus1, tmp, Lkminus1, Lk;
27786557Sfr41279 	BIG_CHUNK_TYPE	ovalue[BIGTMPSIZE];
27796557Sfr41279 	BIG_CHUNK_TYPE	nminus1value[BIGTMPSIZE];
27806557Sfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
27816557Sfr41279 	BIG_CHUNK_TYPE	Lkminus1value[BIGTMPSIZE];
27826557Sfr41279 	BIG_CHUNK_TYPE	Lkvalue[BIGTMPSIZE];
27836557Sfr41279 	BIG_ERR_CODE	err;
27846557Sfr41279 	int		e, i, jac;
27856557Sfr41279 
27866557Sfr41279 	if (big_cmp_abs(n, &big_One) == 0) {
27870Sstevel@tonic-gate 		return (BIG_FALSE);
27886557Sfr41279 	}
27896557Sfr41279 	if (big_cmp_abs(n, &big_Two) == 0) {
27900Sstevel@tonic-gate 		return (BIG_TRUE);
27916557Sfr41279 	}
27926557Sfr41279 	if ((n->value[0] & 1) == 0) {
27930Sstevel@tonic-gate 		return (BIG_FALSE);
27946557Sfr41279 	}
27956557Sfr41279 
27966557Sfr41279 	if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) !=
27976557Sfr41279 	    BIG_OK) {
27980Sstevel@tonic-gate 		return (err);
27996557Sfr41279 	}
28000Sstevel@tonic-gate 
28010Sstevel@tonic-gate 	if ((err = big_init1(&nminus1, n->len,
28026557Sfr41279 	    nminus1value, arraysize(nminus1value))) != BIG_OK) {
28030Sstevel@tonic-gate 		goto ret1;
28046557Sfr41279 	}
28050Sstevel@tonic-gate 
28060Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len,
28076557Sfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
28080Sstevel@tonic-gate 		goto ret2;
28096557Sfr41279 	}
28100Sstevel@tonic-gate 
28110Sstevel@tonic-gate 	if ((err = big_init1(&Lkminus1, n->len,
28126557Sfr41279 	    Lkminus1value, arraysize(Lkminus1value))) != BIG_OK) {
28130Sstevel@tonic-gate 		goto ret3;
28146557Sfr41279 	}
28150Sstevel@tonic-gate 
28160Sstevel@tonic-gate 	if ((err = big_init1(&Lk, n->len,
28176557Sfr41279 	    Lkvalue, arraysize(Lkvalue))) != BIG_OK) {
28180Sstevel@tonic-gate 		goto ret4;
28196557Sfr41279 	}
28206557Sfr41279 
28218933Sopensolaris@drydog.com 	(void) big_sub_pos(&o, n, &big_One);	/* cannot fail */
28220Sstevel@tonic-gate 	(void) big_copy(&nminus1, &o);		/* cannot fail */
28230Sstevel@tonic-gate 	e = 0;
28240Sstevel@tonic-gate 	while ((o.value[0] & 1) == 0) {
28250Sstevel@tonic-gate 		e++;
28260Sstevel@tonic-gate 		(void) big_half_pos(&o, &o);  /* cannot fail */
28270Sstevel@tonic-gate 	}
28286557Sfr41279 	if ((err = big_modexp_ext(&tmp, &big_Two, &o, n, NULL, info)) !=
28296557Sfr41279 	    BIG_OK) {
28300Sstevel@tonic-gate 		goto ret;
28316557Sfr41279 	}
28326557Sfr41279 
28330Sstevel@tonic-gate 	i = 0;
28340Sstevel@tonic-gate 	while ((i < e) &&
28356557Sfr41279 	    (big_cmp_abs(&tmp, &big_One) != 0) &&
28360Sstevel@tonic-gate 	    (big_cmp_abs(&tmp, &nminus1) != 0)) {
28376557Sfr41279 		if ((err =
28386557Sfr41279 		    big_modexp_ext(&tmp, &tmp, &big_Two, n, NULL, info)) !=
28396557Sfr41279 		    BIG_OK)
28400Sstevel@tonic-gate 			goto ret;
28410Sstevel@tonic-gate 		i++;
28420Sstevel@tonic-gate 	}
28436557Sfr41279 
28440Sstevel@tonic-gate 	if (!((big_cmp_abs(&tmp, &nminus1) == 0) ||
28456557Sfr41279 	    ((i == 0) && (big_cmp_abs(&tmp, &big_One) == 0)))) {
28460Sstevel@tonic-gate 		err = BIG_FALSE;
28470Sstevel@tonic-gate 		goto ret;
28480Sstevel@tonic-gate 	}
28490Sstevel@tonic-gate 
28506557Sfr41279 	if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK) {
28510Sstevel@tonic-gate 		goto ret;
28526557Sfr41279 	}
28536557Sfr41279 
28546557Sfr41279 	if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK) {
28550Sstevel@tonic-gate 		goto ret;
28566557Sfr41279 	}
28570Sstevel@tonic-gate 	if (big_cmp_abs(&tmp, n) == 0) {
28580Sstevel@tonic-gate 		err = BIG_FALSE;
28590Sstevel@tonic-gate 		goto ret;
28600Sstevel@tonic-gate 	}
28610Sstevel@tonic-gate 
28626557Sfr41279 	(void) big_copy(&o, &big_Two);
28630Sstevel@tonic-gate 	do {
28646557Sfr41279 		(void) big_add_abs(&o, &o, &big_One);
28656557Sfr41279 		if ((err = big_mul(&tmp, &o, &o)) != BIG_OK) {
28660Sstevel@tonic-gate 			goto ret;
28676557Sfr41279 		}
28686557Sfr41279 		(void) big_sub_pos(&tmp, &tmp, &big_Four);
28696557Sfr41279 		if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK) {
28700Sstevel@tonic-gate 			goto ret;
28716557Sfr41279 		}
28720Sstevel@tonic-gate 	} while (jac != -1);
28730Sstevel@tonic-gate 
28746557Sfr41279 	(void) big_add_abs(&tmp, n, &big_One);
28756557Sfr41279 	if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK) {
28760Sstevel@tonic-gate 		goto ret;
28776557Sfr41279 	}
28786557Sfr41279 
28796557Sfr41279 	if ((big_cmp_abs(&Lkminus1, &o) == 0) &&
28806557Sfr41279 	    (big_cmp_abs(&Lk, &big_Two) == 0)) {
28810Sstevel@tonic-gate 		err = BIG_TRUE;
28826557Sfr41279 	} else {
28836557Sfr41279 		err = BIG_FALSE;
28846557Sfr41279 	}
28850Sstevel@tonic-gate 
28860Sstevel@tonic-gate ret:
28870Sstevel@tonic-gate 	if (Lk.malloced) big_finish(&Lk);
28880Sstevel@tonic-gate ret4:
28890Sstevel@tonic-gate 	if (Lkminus1.malloced) big_finish(&Lkminus1);
28900Sstevel@tonic-gate ret3:
28910Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
28920Sstevel@tonic-gate ret2:
28930Sstevel@tonic-gate 	if (nminus1.malloced) big_finish(&nminus1);
28940Sstevel@tonic-gate ret1:
28950Sstevel@tonic-gate 	if (o.malloced) big_finish(&o);
28960Sstevel@tonic-gate 
28970Sstevel@tonic-gate 	return (err);
28980Sstevel@tonic-gate }
28990Sstevel@tonic-gate 
29000Sstevel@tonic-gate 
29016557Sfr41279 BIG_ERR_CODE
29026557Sfr41279 big_isprime_pos(BIGNUM *n)
29036557Sfr41279 {
29046557Sfr41279 	return (big_isprime_pos_ext(n, NULL));
29056557Sfr41279 }
29066557Sfr41279 
29076557Sfr41279 
29080Sstevel@tonic-gate #define	SIEVESIZE 1000
29090Sstevel@tonic-gate 
29100Sstevel@tonic-gate 
29110Sstevel@tonic-gate BIG_ERR_CODE
29126557Sfr41279 big_nextprime_pos_ext(BIGNUM *result, BIGNUM *n, big_modexp_ncp_info_t *info)
29130Sstevel@tonic-gate {
29148933Sopensolaris@drydog.com 	static const uint32_t smallprimes[] = {
29158933Sopensolaris@drydog.com 	    3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
29168933Sopensolaris@drydog.com 	    51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97 };
29176557Sfr41279 	BIG_ERR_CODE	err;
29186557Sfr41279 	int		sieve[SIEVESIZE];
29196557Sfr41279 	int		i;
29206557Sfr41279 	uint32_t	off, p;
29216557Sfr41279 
29226557Sfr41279 	if ((err = big_copy(result, n)) != BIG_OK) {
29230Sstevel@tonic-gate 		return (err);
29246557Sfr41279 	}
29250Sstevel@tonic-gate 	result->value[0] |= 1;
29261027Srobinson 	/* CONSTCOND */
29270Sstevel@tonic-gate 	while (1) {
29280Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0;
29290Sstevel@tonic-gate 		for (i = 0;
29306557Sfr41279 		    i < sizeof (smallprimes) / sizeof (smallprimes[0]); i++) {
29310Sstevel@tonic-gate 			p = smallprimes[i];
29326557Sfr41279 			off = big_modhalf_pos(result, p);
29330Sstevel@tonic-gate 			off = p - off;
29346557Sfr41279 			if ((off % 2) == 1) {
29356557Sfr41279 				off = off + p;
29366557Sfr41279 			}
29376557Sfr41279 			off = off / 2;
29380Sstevel@tonic-gate 			while (off < SIEVESIZE) {
29390Sstevel@tonic-gate 				sieve[off] = 1;
29400Sstevel@tonic-gate 				off = off + p;
29410Sstevel@tonic-gate 			}
29420Sstevel@tonic-gate 		}
29430Sstevel@tonic-gate 
29440Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) {
29450Sstevel@tonic-gate 			if (sieve[i] == 0) {
29466557Sfr41279 				err = big_isprime_pos_ext(result, info);
29470Sstevel@tonic-gate 				if (err != BIG_FALSE) {
29486557Sfr41279 					if (err != BIG_TRUE) {
29490Sstevel@tonic-gate 						return (err);
29506557Sfr41279 					} else {
29516557Sfr41279 						goto out;
29526557Sfr41279 					}
29530Sstevel@tonic-gate 				}
29540Sstevel@tonic-gate 
29550Sstevel@tonic-gate 			}
29566557Sfr41279 			if ((err = big_add_abs(result, result, &big_Two)) !=
29576557Sfr41279 			    BIG_OK) {
29580Sstevel@tonic-gate 				return (err);
29596557Sfr41279 			}
29600Sstevel@tonic-gate 		}
29610Sstevel@tonic-gate 	}
29626557Sfr41279 
29636557Sfr41279 out:
29646557Sfr41279 	return (BIG_OK);
29656557Sfr41279 }
29666557Sfr41279 
29676557Sfr41279 
29686557Sfr41279 BIG_ERR_CODE
29696557Sfr41279 big_nextprime_pos(BIGNUM *result, BIGNUM *n)
29706557Sfr41279 {
29716557Sfr41279 	return (big_nextprime_pos_ext(result, n, NULL));
29720Sstevel@tonic-gate }
29730Sstevel@tonic-gate 
29740Sstevel@tonic-gate 
29750Sstevel@tonic-gate BIG_ERR_CODE
29760Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n)
29770Sstevel@tonic-gate {
29780Sstevel@tonic-gate 	BIG_ERR_CODE err;
29790Sstevel@tonic-gate 
29800Sstevel@tonic-gate 
29810Sstevel@tonic-gate 	if ((err = big_copy(result, n)) != BIG_OK)
29820Sstevel@tonic-gate 		return (err);
29830Sstevel@tonic-gate 	result->value[0] |= 1;
29846557Sfr41279 	while ((err = big_isprime_pos_ext(result, NULL)) != BIG_TRUE) {
29850Sstevel@tonic-gate 		if (err != BIG_FALSE)
29860Sstevel@tonic-gate 			return (err);
29876557Sfr41279 		if ((err = big_add_abs(result, result, &big_Two)) != BIG_OK)
29880Sstevel@tonic-gate 			return (err);
29890Sstevel@tonic-gate 	}
29900Sstevel@tonic-gate 	return (BIG_OK);
29910Sstevel@tonic-gate }
29920Sstevel@tonic-gate 
29930Sstevel@tonic-gate 
29940Sstevel@tonic-gate /*
29950Sstevel@tonic-gate  * given m and e, computes the rest in the equation
29960Sstevel@tonic-gate  * gcd(m, e) = cm * m + ce * e
29970Sstevel@tonic-gate  */
29980Sstevel@tonic-gate BIG_ERR_CODE
29990Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e)
30000Sstevel@tonic-gate {
30016557Sfr41279 	BIGNUM		*xi, *ri, *riminus1, *riminus2, *t;
30026557Sfr41279 	BIGNUM		*vmi, *vei, *vmiminus1, *veiminus1;
30036557Sfr41279 	BIGNUM		t1, t2, t3, t4, t5, t6, t7, t8, tmp;
30046557Sfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
30056557Sfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
30066557Sfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
30076557Sfr41279 	BIG_CHUNK_TYPE	t4value[BIGTMPSIZE];
30086557Sfr41279 	BIG_CHUNK_TYPE	t5value[BIGTMPSIZE];
30096557Sfr41279 	BIG_CHUNK_TYPE	t6value[BIGTMPSIZE];
30106557Sfr41279 	BIG_CHUNK_TYPE	t7value[BIGTMPSIZE];
30116557Sfr41279 	BIG_CHUNK_TYPE	t8value[BIGTMPSIZE];
30126557Sfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
30136557Sfr41279 	BIG_ERR_CODE	err;
30146557Sfr41279 	int		len;
30156557Sfr41279 
30166557Sfr41279 	if (big_cmp_abs(m, e) >= 0) {
30176557Sfr41279 		len = m->len;
30186557Sfr41279 	} else {
30196557Sfr41279 		len = e->len;
30206557Sfr41279 	}
30210Sstevel@tonic-gate 
30220Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
30236557Sfr41279 	    t1value, arraysize(t1value))) != BIG_OK) {
30240Sstevel@tonic-gate 		return (err);
30256557Sfr41279 	}
30260Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
30276557Sfr41279 	    t2value, arraysize(t2value))) != BIG_OK) {
30286557Sfr41279 		goto ret1;
30296557Sfr41279 	}
30300Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
30316557Sfr41279 	    t3value, arraysize(t3value))) != BIG_OK) {
30326557Sfr41279 		goto ret2;
30336557Sfr41279 	}
30340Sstevel@tonic-gate 	if ((err = big_init1(&t4, len,
30356557Sfr41279 	    t4value, arraysize(t3value))) != BIG_OK) {
30366557Sfr41279 		goto ret3;
30376557Sfr41279 	}
30380Sstevel@tonic-gate 	if ((err = big_init1(&t5, len,
30396557Sfr41279 	    t5value, arraysize(t5value))) != BIG_OK) {
30406557Sfr41279 		goto ret4;
30416557Sfr41279 	}
30420Sstevel@tonic-gate 	if ((err = big_init1(&t6, len,
30436557Sfr41279 	    t6value, arraysize(t6value))) != BIG_OK) {
30446557Sfr41279 		goto ret5;
30456557Sfr41279 	}
30460Sstevel@tonic-gate 	if ((err = big_init1(&t7, len,
30476557Sfr41279 	    t7value, arraysize(t7value))) != BIG_OK) {
30486557Sfr41279 		goto ret6;
30496557Sfr41279 	}
30500Sstevel@tonic-gate 	if ((err = big_init1(&t8, len,
30516557Sfr41279 	    t8value, arraysize(t8value))) != BIG_OK) {
30526557Sfr41279 		goto ret7;
30536557Sfr41279 	}
30540Sstevel@tonic-gate 
30550Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * len,
30566557Sfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
30570Sstevel@tonic-gate 		goto ret8;
30586557Sfr41279 	}
30590Sstevel@tonic-gate 
30600Sstevel@tonic-gate 	ri = &t1;
30610Sstevel@tonic-gate 	ri->value[0] = 1;
30620Sstevel@tonic-gate 	ri->len = 1;
30630Sstevel@tonic-gate 	xi = &t2;
30640Sstevel@tonic-gate 	riminus1 = &t3;
30650Sstevel@tonic-gate 	riminus2 = &t4;
30660Sstevel@tonic-gate 	vmi = &t5;
30670Sstevel@tonic-gate 	vei = &t6;
30680Sstevel@tonic-gate 	vmiminus1 = &t7;
30690Sstevel@tonic-gate 	veiminus1 = &t8;
30700Sstevel@tonic-gate 
30716557Sfr41279 	(void) big_copy(vmiminus1, &big_One);
30726557Sfr41279 	(void) big_copy(vmi, &big_One);
30736557Sfr41279 	(void) big_copy(veiminus1, &big_One);
30746557Sfr41279 	(void) big_copy(xi, &big_One);
30750Sstevel@tonic-gate 	vei->len = 1;
30760Sstevel@tonic-gate 	vei->value[0] = 0;
30770Sstevel@tonic-gate 
30780Sstevel@tonic-gate 	(void) big_copy(riminus1, m);
30790Sstevel@tonic-gate 	(void) big_copy(ri, e);
30800Sstevel@tonic-gate 
30810Sstevel@tonic-gate 	while (!big_is_zero(ri)) {
30820Sstevel@tonic-gate 		t = riminus2;
30830Sstevel@tonic-gate 		riminus2 = riminus1;
30840Sstevel@tonic-gate 		riminus1 = ri;
30850Sstevel@tonic-gate 		ri = t;
30866557Sfr41279 		if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK) {
30870Sstevel@tonic-gate 			goto ret;
30886557Sfr41279 		}
30896557Sfr41279 		if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK) {
30900Sstevel@tonic-gate 			goto ret;
30916557Sfr41279 		}
30920Sstevel@tonic-gate 		t = vmiminus1;
30930Sstevel@tonic-gate 		vmiminus1 = vmi;
30940Sstevel@tonic-gate 		vmi = t;
30956557Sfr41279 		if ((err = big_mul(&tmp, vei, xi)) != BIG_OK) {
30960Sstevel@tonic-gate 			goto ret;
30976557Sfr41279 		}
30986557Sfr41279 		if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK) {
30990Sstevel@tonic-gate 			goto ret;
31006557Sfr41279 		}
31010Sstevel@tonic-gate 		t = veiminus1;
31020Sstevel@tonic-gate 		veiminus1 = vei;
31030Sstevel@tonic-gate 		vei = t;
31046557Sfr41279 		if ((err = big_div_pos(xi, ri, riminus2, riminus1)) !=
31056557Sfr41279 		    BIG_OK) {
31060Sstevel@tonic-gate 			goto ret;
31076557Sfr41279 		}
31080Sstevel@tonic-gate 	}
31096557Sfr41279 	if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK)) {
31100Sstevel@tonic-gate 		goto ret;
31116557Sfr41279 	}
31126557Sfr41279 	if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK)) {
31130Sstevel@tonic-gate 		goto ret;
31146557Sfr41279 	}
31156557Sfr41279 	if (ce != NULL) {
31160Sstevel@tonic-gate 		err = big_copy(ce, vei);
31176557Sfr41279 	}
31180Sstevel@tonic-gate ret:
31190Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
31200Sstevel@tonic-gate ret8:
31210Sstevel@tonic-gate 	if (t8.malloced) big_finish(&t8);
31220Sstevel@tonic-gate ret7:
31230Sstevel@tonic-gate 	if (t7.malloced) big_finish(&t7);
31240Sstevel@tonic-gate ret6:
31250Sstevel@tonic-gate 	if (t6.malloced) big_finish(&t6);
31260Sstevel@tonic-gate ret5:
31270Sstevel@tonic-gate 	if (t5.malloced) big_finish(&t5);
31280Sstevel@tonic-gate ret4:
31290Sstevel@tonic-gate 	if (t4.malloced) big_finish(&t4);
31300Sstevel@tonic-gate ret3:
31310Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
31320Sstevel@tonic-gate ret2:
31330Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
31340Sstevel@tonic-gate ret1:
31350Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
31360Sstevel@tonic-gate 
31370Sstevel@tonic-gate 	return (err);
31380Sstevel@tonic-gate }
3139