xref: /onnv-gate/usr/src/common/bignum/bignumimpl.c (revision 8933:16480dbef03d)
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 /*
22*8933Sopensolaris@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.
47*8933Sopensolaris@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 
65*8933Sopensolaris@drydog.com #include <sys/types.h>
66*8933Sopensolaris@drydog.com #include "bignum.h"
67*8933Sopensolaris@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 
77*8933Sopensolaris@drydog.com #else
78*8933Sopensolaris@drydog.com #include <stdlib.h>
79*8933Sopensolaris@drydog.com #include <stdio.h>
80*8933Sopensolaris@drydog.com #include <assert.h>
81*8933Sopensolaris@drydog.com #define	ASSERT	assert
82*8933Sopensolaris@drydog.com #endif	/* _KERNEL */
83*8933Sopensolaris@drydog.com 
84*8933Sopensolaris@drydog.com #ifdef	_LP64 /* truncate 64-bit size_t to 32-bits */
85*8933Sopensolaris@drydog.com #define	UI32(ui)	((uint32_t)ui)
86*8933Sopensolaris@drydog.com #else /* size_t already 32-bits */
87*8933Sopensolaris@drydog.com #define	UI32(ui)	(ui)
88*8933Sopensolaris@drydog.com #endif
89*8933Sopensolaris@drydog.com 
90*8933Sopensolaris@drydog.com 
91*8933Sopensolaris@drydog.com #ifdef	_KERNEL
920Sstevel@tonic-gate #define	big_malloc(size)	kmem_alloc(size, KM_NOSLEEP)
930Sstevel@tonic-gate #define	big_free(ptr, size)	kmem_free(ptr, size)
940Sstevel@tonic-gate 
950Sstevel@tonic-gate void *
960Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize)
970Sstevel@tonic-gate {
980Sstevel@tonic-gate 	void *rv;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	rv = kmem_alloc(newsize, KM_NOSLEEP);
1010Sstevel@tonic-gate 	if (rv != NULL)
1020Sstevel@tonic-gate 		bcopy(from, rv, oldsize);
1030Sstevel@tonic-gate 	kmem_free(from, oldsize);
1040Sstevel@tonic-gate 	return (rv);
1050Sstevel@tonic-gate }
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate #else	/* _KERNEL */
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate #ifndef MALLOC_DEBUG
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate #define	big_malloc(size)	malloc(size)
1120Sstevel@tonic-gate #define	big_free(ptr, size)	free(ptr)
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate #else
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate void
1170Sstevel@tonic-gate big_free(void *ptr, size_t size)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate 	printf("freed %d bytes at %p\n", size, ptr);
1200Sstevel@tonic-gate 	free(ptr);
1210Sstevel@tonic-gate }
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate void *
1240Sstevel@tonic-gate big_malloc(size_t size)
1250Sstevel@tonic-gate {
1260Sstevel@tonic-gate 	void *rv;
1270Sstevel@tonic-gate 	rv = malloc(size);
1280Sstevel@tonic-gate 	printf("malloced %d bytes, addr:%p\n", size, rv);
1290Sstevel@tonic-gate 	return (rv);
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate #endif /* MALLOC_DEBUG */
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate #define	big_realloc(x, y, z) realloc((x), (z))
1340Sstevel@tonic-gate 
135*8933Sopensolaris@drydog.com 
136*8933Sopensolaris@drydog.com /*
137*8933Sopensolaris@drydog.com  * printbignum()
138*8933Sopensolaris@drydog.com  * Print a BIGNUM type to stdout.
139*8933Sopensolaris@drydog.com  */
1400Sstevel@tonic-gate void
1410Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a)
1420Sstevel@tonic-gate {
1430Sstevel@tonic-gate 	int i;
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	(void) printf("\n%s\n%d\n", aname, a->sign*a->len);
1460Sstevel@tonic-gate 	for (i = a->len - 1; i >= 0; i--) {
1476557Sfr41279 #ifdef BIGNUM_CHUNK_32
1480Sstevel@tonic-gate 		(void) printf("%08x ", a->value[i]);
149*8933Sopensolaris@drydog.com 		if (((i & (BITSINBYTE - 1)) == 0) && (i != 0)) {
1506557Sfr41279 			(void) printf("\n");
1516557Sfr41279 		}
1526557Sfr41279 #else
1536557Sfr41279 		(void) printf("%08x %08x ", (uint32_t)((a->value[i]) >> 32),
1546557Sfr41279 		    (uint32_t)((a->value[i]) & 0xffffffff));
155*8933Sopensolaris@drydog.com 		if (((i & 3) == 0) && (i != 0)) { /* end of this chunk */
1566557Sfr41279 			(void) printf("\n");
1576557Sfr41279 		}
1586557Sfr41279 #endif
1590Sstevel@tonic-gate 	}
1600Sstevel@tonic-gate 	(void) printf("\n");
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate #endif	/* _KERNEL */
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 
166*8933Sopensolaris@drydog.com /*
167*8933Sopensolaris@drydog.com  * big_init()
168*8933Sopensolaris@drydog.com  * Initialize and allocate memory for a BIGNUM type.
169*8933Sopensolaris@drydog.com  *
170*8933Sopensolaris@drydog.com  * big_init(number, size) is equivalent to big_init1(number, size, NULL, 0)
171*8933Sopensolaris@drydog.com  *
172*8933Sopensolaris@drydog.com  * Note: call big_finish() to free memory allocated by big_init().
173*8933Sopensolaris@drydog.com  *
174*8933Sopensolaris@drydog.com  * Input:
175*8933Sopensolaris@drydog.com  * number	Uninitialized memory for BIGNUM
176*8933Sopensolaris@drydog.com  * size		Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM
177*8933Sopensolaris@drydog.com  *
178*8933Sopensolaris@drydog.com  * Output:
179*8933Sopensolaris@drydog.com  * number	Initialized BIGNUM
180*8933Sopensolaris@drydog.com  *
181*8933Sopensolaris@drydog.com  * Return BIG_OK on success or BIG_NO_MEM for an allocation error.
182*8933Sopensolaris@drydog.com  */
1830Sstevel@tonic-gate BIG_ERR_CODE
1840Sstevel@tonic-gate big_init(BIGNUM *number, int size)
1850Sstevel@tonic-gate {
186*8933Sopensolaris@drydog.com 	number->value = big_malloc(BIGNUM_WORDSIZE * size);
1870Sstevel@tonic-gate 	if (number->value == NULL) {
1880Sstevel@tonic-gate 		return (BIG_NO_MEM);
1890Sstevel@tonic-gate 	}
1900Sstevel@tonic-gate 	number->size = size;
1910Sstevel@tonic-gate 	number->len = 0;
1920Sstevel@tonic-gate 	number->sign = 1;
1930Sstevel@tonic-gate 	number->malloced = 1;
1940Sstevel@tonic-gate 	return (BIG_OK);
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
197*8933Sopensolaris@drydog.com 
198*8933Sopensolaris@drydog.com /*
199*8933Sopensolaris@drydog.com  * big_init1()
200*8933Sopensolaris@drydog.com  * Initialize and, if needed, allocate memory for a BIGNUM type.
201*8933Sopensolaris@drydog.com  * Use the buffer passed, buf, if any, instad of allocating memory
202*8933Sopensolaris@drydog.com  * if it's at least "size" bytes.
203*8933Sopensolaris@drydog.com  *
204*8933Sopensolaris@drydog.com  * Note: call big_finish() to free memory allocated by big_init().
205*8933Sopensolaris@drydog.com  *
206*8933Sopensolaris@drydog.com  * Input:
207*8933Sopensolaris@drydog.com  * number	Uninitialized memory for BIGNUM
208*8933Sopensolaris@drydog.com  * size		Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM
209*8933Sopensolaris@drydog.com  * buf		Buffer for storing a BIGNUM.
210*8933Sopensolaris@drydog.com  *		If NULL, big_init1() will allocate a buffer
211*8933Sopensolaris@drydog.com  * bufsize	Size, in BIG_CHUNK_SIZE_bit words, of buf
212*8933Sopensolaris@drydog.com  *
213*8933Sopensolaris@drydog.com  * Output:
214*8933Sopensolaris@drydog.com  * number	Initialized BIGNUM
215*8933Sopensolaris@drydog.com  *
216*8933Sopensolaris@drydog.com  * Return BIG_OK on success or BIG_NO_MEM for an allocation error.
217*8933Sopensolaris@drydog.com  */
2180Sstevel@tonic-gate BIG_ERR_CODE
2196557Sfr41279 big_init1(BIGNUM *number, int size, BIG_CHUNK_TYPE *buf, int bufsize)
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate 	if ((buf == NULL) || (size > bufsize)) {
222*8933Sopensolaris@drydog.com 		number->value = big_malloc(BIGNUM_WORDSIZE * size);
2230Sstevel@tonic-gate 		if (number->value == NULL) {
2240Sstevel@tonic-gate 			return (BIG_NO_MEM);
2250Sstevel@tonic-gate 		}
2260Sstevel@tonic-gate 		number->size = size;
2270Sstevel@tonic-gate 		number->malloced = 1;
2280Sstevel@tonic-gate 	} else {
2290Sstevel@tonic-gate 		number->value = buf;
2300Sstevel@tonic-gate 		number->size = bufsize;
2310Sstevel@tonic-gate 		number->malloced = 0;
2320Sstevel@tonic-gate 	}
233*8933Sopensolaris@drydog.com 	number->len = 0;
234*8933Sopensolaris@drydog.com 	number->sign = 1;
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	return (BIG_OK);
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate 
239*8933Sopensolaris@drydog.com 
240*8933Sopensolaris@drydog.com /*
241*8933Sopensolaris@drydog.com  * big_finish()
242*8933Sopensolaris@drydog.com  * Free memory, if any, allocated by big_init() or big_init1().
243*8933Sopensolaris@drydog.com  */
2440Sstevel@tonic-gate void
2450Sstevel@tonic-gate big_finish(BIGNUM *number)
2460Sstevel@tonic-gate {
2470Sstevel@tonic-gate 	if (number->malloced == 1) {
248*8933Sopensolaris@drydog.com 		big_free(number->value, BIGNUM_WORDSIZE * number->size);
2490Sstevel@tonic-gate 		number->malloced = 0;
2500Sstevel@tonic-gate 	}
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate 
2536557Sfr41279 
2540Sstevel@tonic-gate /*
255*8933Sopensolaris@drydog.com  * bn->size should be at least
256*8933Sopensolaris@drydog.com  * (len + BIGNUM_WORDSIZE - 1) / BIGNUM_WORDSIZE bytes
2570Sstevel@tonic-gate  * converts from byte-big-endian format to bignum format (words in
2580Sstevel@tonic-gate  * little endian order, but bytes within the words big endian)
2590Sstevel@tonic-gate  */
2600Sstevel@tonic-gate void
2610Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len)
2620Sstevel@tonic-gate {
263*8933Sopensolaris@drydog.com 	int		i, j;
264*8933Sopensolaris@drydog.com 	uint32_t	offs;
265*8933Sopensolaris@drydog.com 	const uint32_t	slen = UI32(len);
2666557Sfr41279 	BIG_CHUNK_TYPE	word;
2670Sstevel@tonic-gate 	uchar_t		*knwordp;
2680Sstevel@tonic-gate 
269*8933Sopensolaris@drydog.com 	if (slen == 0) {
270*8933Sopensolaris@drydog.com 		bn->len = 1;
271*8933Sopensolaris@drydog.com 		bn->value[0] = 0;
272*8933Sopensolaris@drydog.com 		return;
273*8933Sopensolaris@drydog.com 	}
274*8933Sopensolaris@drydog.com 
275*8933Sopensolaris@drydog.com 	offs = slen % BIGNUM_WORDSIZE;
276*8933Sopensolaris@drydog.com 	bn->len = slen / BIGNUM_WORDSIZE;
277*8933Sopensolaris@drydog.com 
278*8933Sopensolaris@drydog.com 	for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) {
279*8933Sopensolaris@drydog.com 		knwordp = &(kn[slen - BIGNUM_WORDSIZE * (i + 1)]);
2800Sstevel@tonic-gate 		word = knwordp[0];
281*8933Sopensolaris@drydog.com 		for (j = 1; j < BIGNUM_WORDSIZE; j++) {
282*8933Sopensolaris@drydog.com 			word = (word << BITSINBYTE) + knwordp[j];
2830Sstevel@tonic-gate 		}
2840Sstevel@tonic-gate 		bn->value[i] = word;
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 	if (offs > 0) {
2870Sstevel@tonic-gate 		word = kn[0];
288*8933Sopensolaris@drydog.com 		for (i = 1; i < offs; i++) word = (word << BITSINBYTE) + kn[i];
2890Sstevel@tonic-gate 		bn->value[bn->len++] = word;
2900Sstevel@tonic-gate 	}
291*8933Sopensolaris@drydog.com 	while ((bn->len > 1) && (bn->value[bn->len - 1] == 0)) {
2920Sstevel@tonic-gate 		bn->len --;
2930Sstevel@tonic-gate 	}
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate 
296*8933Sopensolaris@drydog.com 
2970Sstevel@tonic-gate /*
2980Sstevel@tonic-gate  * copies the least significant len bytes if
299*8933Sopensolaris@drydog.com  * len < bn->len * BIGNUM_WORDSIZE
3000Sstevel@tonic-gate  * converts from bignum format to byte-big-endian format.
3016557Sfr41279  * bignum format is words of type  BIG_CHUNK_TYPE in little endian order.
3020Sstevel@tonic-gate  */
3030Sstevel@tonic-gate void
3040Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len)
3050Sstevel@tonic-gate {
306*8933Sopensolaris@drydog.com 	int		i, j;
307*8933Sopensolaris@drydog.com 	uint32_t	offs;
308*8933Sopensolaris@drydog.com 	const uint32_t	slen = UI32(len);
3096557Sfr41279 	BIG_CHUNK_TYPE	word;
3106557Sfr41279 
311*8933Sopensolaris@drydog.com 	if (len < BIGNUM_WORDSIZE * bn->len) {
312*8933Sopensolaris@drydog.com 		for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) {
3130Sstevel@tonic-gate 			word = bn->value[i];
314*8933Sopensolaris@drydog.com 			for (j = 0; j < BIGNUM_WORDSIZE; j++) {
315*8933Sopensolaris@drydog.com 				kn[slen - BIGNUM_WORDSIZE * i - j - 1] =
3160Sstevel@tonic-gate 				    word & 0xff;
317*8933Sopensolaris@drydog.com 				word = word >> BITSINBYTE;
3180Sstevel@tonic-gate 			}
3190Sstevel@tonic-gate 		}
320*8933Sopensolaris@drydog.com 		offs = slen % BIGNUM_WORDSIZE;
3210Sstevel@tonic-gate 		if (offs > 0) {
322*8933Sopensolaris@drydog.com 			word = bn->value[slen / BIGNUM_WORDSIZE];
323*8933Sopensolaris@drydog.com 			for (i =  slen % BIGNUM_WORDSIZE; i > 0; i --) {
3246557Sfr41279 				kn[i - 1] = word & 0xff;
325*8933Sopensolaris@drydog.com 				word = word >> BITSINBYTE;
3266557Sfr41279 			}
3270Sstevel@tonic-gate 		}
3280Sstevel@tonic-gate 	} else {
3290Sstevel@tonic-gate 		for (i = 0; i < bn->len; i++) {
3300Sstevel@tonic-gate 			word = bn->value[i];
331*8933Sopensolaris@drydog.com 			for (j = 0; j < BIGNUM_WORDSIZE; j++) {
332*8933Sopensolaris@drydog.com 				kn[slen - BIGNUM_WORDSIZE * i - j - 1] =
3330Sstevel@tonic-gate 				    word & 0xff;
334*8933Sopensolaris@drydog.com 				word = word >> BITSINBYTE;
3350Sstevel@tonic-gate 			}
3360Sstevel@tonic-gate 		}
337*8933Sopensolaris@drydog.com 		for (i = 0; i < slen - BIGNUM_WORDSIZE * bn->len; i++) {
3380Sstevel@tonic-gate 			kn[i] = 0;
3390Sstevel@tonic-gate 		}
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate int
3450Sstevel@tonic-gate big_bitlength(BIGNUM *a)
3460Sstevel@tonic-gate {
3476557Sfr41279 	int		l = 0, b = 0;
3486557Sfr41279 	BIG_CHUNK_TYPE	c;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	l = a->len - 1;
3510Sstevel@tonic-gate 	while ((l > 0) && (a->value[l] == 0)) {
3520Sstevel@tonic-gate 		l--;
3530Sstevel@tonic-gate 	}
354*8933Sopensolaris@drydog.com 	b = BIG_CHUNK_SIZE;
3550Sstevel@tonic-gate 	c = a->value[l];
3566557Sfr41279 	while ((b > 1) && ((c & BIG_CHUNK_HIGHBIT) == 0)) {
3570Sstevel@tonic-gate 		c = c << 1;
3580Sstevel@tonic-gate 		b--;
3590Sstevel@tonic-gate 	}
3606557Sfr41279 
361*8933Sopensolaris@drydog.com 	return (l * BIG_CHUNK_SIZE + b);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate BIG_ERR_CODE
3660Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src)
3670Sstevel@tonic-gate {
3686557Sfr41279 	BIG_CHUNK_TYPE	*newptr;
3696557Sfr41279 	int		i, len;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	len = src->len;
3726557Sfr41279 	while ((len > 1) && (src->value[len - 1] == 0)) {
3730Sstevel@tonic-gate 		len--;
3746557Sfr41279 	}
3750Sstevel@tonic-gate 	src->len = len;
3760Sstevel@tonic-gate 	if (dest->size < len) {
3770Sstevel@tonic-gate 		if (dest->malloced == 1) {
3786557Sfr41279 			newptr = (BIG_CHUNK_TYPE *)big_realloc(dest->value,
379*8933Sopensolaris@drydog.com 			    BIGNUM_WORDSIZE * dest->size,
380*8933Sopensolaris@drydog.com 			    BIGNUM_WORDSIZE * len);
3810Sstevel@tonic-gate 		} else {
3826557Sfr41279 			newptr = (BIG_CHUNK_TYPE *)
383*8933Sopensolaris@drydog.com 			    big_malloc(BIGNUM_WORDSIZE * len);
3846557Sfr41279 			if (newptr != NULL) {
3856557Sfr41279 				dest->malloced = 1;
3866557Sfr41279 			}
3870Sstevel@tonic-gate 		}
3886557Sfr41279 		if (newptr == NULL) {
3890Sstevel@tonic-gate 			return (BIG_NO_MEM);
3906557Sfr41279 		}
3910Sstevel@tonic-gate 		dest->value = newptr;
3920Sstevel@tonic-gate 		dest->size = len;
3930Sstevel@tonic-gate 	}
3940Sstevel@tonic-gate 	dest->len = len;
3950Sstevel@tonic-gate 	dest->sign = src->sign;
3966557Sfr41279 	for (i = 0; i < len; i++) {
3976557Sfr41279 		dest->value[i] = src->value[i];
3986557Sfr41279 	}
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	return (BIG_OK);
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate BIG_ERR_CODE
4050Sstevel@tonic-gate big_extend(BIGNUM *number, int size)
4060Sstevel@tonic-gate {
4076557Sfr41279 	BIG_CHUNK_TYPE	*newptr;
4080Sstevel@tonic-gate 	int		i;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	if (number->size >= size)
4110Sstevel@tonic-gate 		return (BIG_OK);
4120Sstevel@tonic-gate 	if (number->malloced) {
4136557Sfr41279 		number->value = big_realloc(number->value,
414*8933Sopensolaris@drydog.com 		    BIGNUM_WORDSIZE * number->size,
415*8933Sopensolaris@drydog.com 		    BIGNUM_WORDSIZE * size);
4160Sstevel@tonic-gate 	} else {
417*8933Sopensolaris@drydog.com 		newptr = big_malloc(BIGNUM_WORDSIZE * size);
4180Sstevel@tonic-gate 		if (newptr != NULL) {
4190Sstevel@tonic-gate 			for (i = 0; i < number->size; i++) {
4200Sstevel@tonic-gate 				newptr[i] = number->value[i];
4210Sstevel@tonic-gate 			}
4220Sstevel@tonic-gate 		}
4230Sstevel@tonic-gate 		number->value = newptr;
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 
4266557Sfr41279 	if (number->value == NULL) {
4270Sstevel@tonic-gate 		return (BIG_NO_MEM);
4286557Sfr41279 	}
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	number->size = size;
4310Sstevel@tonic-gate 	number->malloced = 1;
4320Sstevel@tonic-gate 	return (BIG_OK);
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 
4366557Sfr41279 /* returns 1 if n == 0 */
4370Sstevel@tonic-gate int
4380Sstevel@tonic-gate big_is_zero(BIGNUM *n)
4390Sstevel@tonic-gate {
4406557Sfr41279 	int	i, result;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	result = 1;
4436557Sfr41279 	for (i = 0; i < n->len; i++) {
4446557Sfr41279 		if (n->value[i] != 0) {
4456557Sfr41279 			result = 0;
4466557Sfr41279 		}
4476557Sfr41279 	}
4480Sstevel@tonic-gate 	return (result);
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate BIG_ERR_CODE
4530Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
4540Sstevel@tonic-gate {
4556557Sfr41279 	int		i, shorter, longer;
4566557Sfr41279 	BIG_CHUNK_TYPE	cy, ai;
4576557Sfr41279 	BIG_CHUNK_TYPE	*r, *a, *b, *c;
4586557Sfr41279 	BIG_ERR_CODE	err;
4596557Sfr41279 	BIGNUM		*longerarg;
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	if (aa->len > bb->len) {
4620Sstevel@tonic-gate 		shorter = bb->len;
4630Sstevel@tonic-gate 		longer = aa->len;
4646557Sfr41279 		longerarg = aa;
4650Sstevel@tonic-gate 	} else {
4660Sstevel@tonic-gate 		shorter = aa->len;
4670Sstevel@tonic-gate 		longer = bb->len;
4686557Sfr41279 		longerarg = bb;
4690Sstevel@tonic-gate 	}
4700Sstevel@tonic-gate 	if (result->size < longer + 1) {
4710Sstevel@tonic-gate 		err = big_extend(result, longer + 1);
4726557Sfr41279 		if (err != BIG_OK) {
4730Sstevel@tonic-gate 			return (err);
4746557Sfr41279 		}
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	r = result->value;
4780Sstevel@tonic-gate 	a = aa->value;
4790Sstevel@tonic-gate 	b = bb->value;
4806557Sfr41279 	c = longerarg->value;
4810Sstevel@tonic-gate 	cy = 0;
4820Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
4830Sstevel@tonic-gate 		ai = a[i];
4840Sstevel@tonic-gate 		r[i] = ai + b[i] + cy;
4856557Sfr41279 		if (r[i] > ai) {
4866557Sfr41279 			cy = 0;
4876557Sfr41279 		} else if (r[i] < ai) {
4886557Sfr41279 			cy = 1;
4896557Sfr41279 		}
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate 	for (; i < longer; i++) {
4920Sstevel@tonic-gate 		ai = c[i];
4930Sstevel@tonic-gate 		r[i] = ai + cy;
4946557Sfr41279 		if (r[i] >= ai) {
4956557Sfr41279 			cy = 0;
4966557Sfr41279 		}
4970Sstevel@tonic-gate 	}
4980Sstevel@tonic-gate 	if (cy == 1) {
4990Sstevel@tonic-gate 		r[i] = cy;
5000Sstevel@tonic-gate 		result->len = longer + 1;
5010Sstevel@tonic-gate 	} else {
5020Sstevel@tonic-gate 		result->len = longer;
5030Sstevel@tonic-gate 	}
5040Sstevel@tonic-gate 	result->sign = 1;
5050Sstevel@tonic-gate 	return (BIG_OK);
5060Sstevel@tonic-gate }
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */
5100Sstevel@tonic-gate void
5116557Sfr41279 big_sub_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, BIG_CHUNK_TYPE *b, int len)
5120Sstevel@tonic-gate {
5136557Sfr41279 	int		i;
5146557Sfr41279 	BIG_CHUNK_TYPE	cy, ai;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	cy = 1;
5170Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
5180Sstevel@tonic-gate 		ai = a[i];
5190Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
5206557Sfr41279 		if (r[i] > ai) {
5216557Sfr41279 			cy = 0;
5226557Sfr41279 		} else if (r[i] < ai) {
5236557Sfr41279 			cy = 1;
5246557Sfr41279 		}
5250Sstevel@tonic-gate 	}
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate /* result=aa-bb  it is assumed that aa>=bb */
5300Sstevel@tonic-gate BIG_ERR_CODE
5310Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
5320Sstevel@tonic-gate {
5336557Sfr41279 	int		i, shorter;
5346557Sfr41279 	BIG_CHUNK_TYPE	cy = 1, ai;
5356557Sfr41279 	BIG_CHUNK_TYPE	*r, *a, *b;
5366557Sfr41279 	BIG_ERR_CODE	err = BIG_OK;
5376557Sfr41279 
5386557Sfr41279 	if (aa->len > bb->len) {
5396557Sfr41279 		shorter = bb->len;
5406557Sfr41279 	} else {
5416557Sfr41279 		shorter = aa->len;
5426557Sfr41279 	}
5430Sstevel@tonic-gate 	if (result->size < aa->len) {
5440Sstevel@tonic-gate 		err = big_extend(result, aa->len);
5456557Sfr41279 		if (err != BIG_OK) {
5460Sstevel@tonic-gate 			return (err);
5476557Sfr41279 		}
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	r = result->value;
5510Sstevel@tonic-gate 	a = aa->value;
5520Sstevel@tonic-gate 	b = bb->value;
5530Sstevel@tonic-gate 	result->len = aa->len;
5540Sstevel@tonic-gate 	cy = 1;
5550Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
5560Sstevel@tonic-gate 		ai = a[i];
5570Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
5586557Sfr41279 		if (r[i] > ai) {
5596557Sfr41279 			cy = 0;
5606557Sfr41279 		} else if (r[i] < ai) {
5616557Sfr41279 			cy = 1;
5626557Sfr41279 		}
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate 	for (; i < aa->len; i++) {
5650Sstevel@tonic-gate 		ai = a[i];
5660Sstevel@tonic-gate 		r[i] = ai + (~0) + cy;
5676557Sfr41279 		if (r[i] < ai) {
5686557Sfr41279 			cy = 1;
5696557Sfr41279 		}
5700Sstevel@tonic-gate 	}
5710Sstevel@tonic-gate 	result->sign = 1;
5726557Sfr41279 
5736557Sfr41279 	if (cy == 0) {
5740Sstevel@tonic-gate 		return (BIG_INVALID_ARGS);
5756557Sfr41279 	} else {
5760Sstevel@tonic-gate 		return (BIG_OK);
5776557Sfr41279 	}
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */
5820Sstevel@tonic-gate int
5830Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb)
5840Sstevel@tonic-gate {
5856557Sfr41279 	int	i;
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	if (aa->len > bb->len) {
5880Sstevel@tonic-gate 		for (i = aa->len - 1; i > bb->len - 1; i--) {
5896557Sfr41279 			if (aa->value[i] > 0) {
5900Sstevel@tonic-gate 				return (1);
5916557Sfr41279 			}
5920Sstevel@tonic-gate 		}
5930Sstevel@tonic-gate 	} else if (aa->len < bb->len) {
5940Sstevel@tonic-gate 		for (i = bb->len - 1; i > aa->len - 1; i--) {
5956557Sfr41279 			if (bb->value[i] > 0) {
5960Sstevel@tonic-gate 				return (-1);
5976557Sfr41279 			}
5980Sstevel@tonic-gate 		}
5996557Sfr41279 	} else {
600*8933Sopensolaris@drydog.com 		i = aa->len - 1;
6016557Sfr41279 	}
6020Sstevel@tonic-gate 	for (; i >= 0; i--) {
6036557Sfr41279 		if (aa->value[i] > bb->value[i]) {
6040Sstevel@tonic-gate 			return (1);
6056557Sfr41279 		} else if (aa->value[i] < bb->value[i]) {
6060Sstevel@tonic-gate 			return (-1);
6076557Sfr41279 		}
6080Sstevel@tonic-gate 	}
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	return (0);
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate BIG_ERR_CODE
6150Sstevel@tonic-gate big_sub(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
6160Sstevel@tonic-gate {
6176557Sfr41279 	BIG_ERR_CODE	err;
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == 1)) {
6206557Sfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
6210Sstevel@tonic-gate 			return (err);
6226557Sfr41279 		}
6230Sstevel@tonic-gate 		result->sign = 1;
6240Sstevel@tonic-gate 	} else if ((aa->sign == -1) && (bb->sign == 1)) {
6256557Sfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
6260Sstevel@tonic-gate 			return (err);
6276557Sfr41279 		}
6280Sstevel@tonic-gate 		result->sign = -1;
6290Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
6300Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
6316557Sfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6320Sstevel@tonic-gate 				return (err);
6336557Sfr41279 			}
6340Sstevel@tonic-gate 			result->sign = 1;
6350Sstevel@tonic-gate 		} else {
6366557Sfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6370Sstevel@tonic-gate 				return (err);
6386557Sfr41279 			}
6390Sstevel@tonic-gate 			result->sign = -1;
6400Sstevel@tonic-gate 		}
6410Sstevel@tonic-gate 	} else {
6420Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
6436557Sfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6440Sstevel@tonic-gate 				return (err);
6456557Sfr41279 			}
6460Sstevel@tonic-gate 			result->sign = -1;
6470Sstevel@tonic-gate 		} else {
6486557Sfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6490Sstevel@tonic-gate 				return (err);
6506557Sfr41279 			}
6510Sstevel@tonic-gate 			result->sign = 1;
6520Sstevel@tonic-gate 		}
6530Sstevel@tonic-gate 	}
6540Sstevel@tonic-gate 	return (BIG_OK);
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate BIG_ERR_CODE
6590Sstevel@tonic-gate big_add(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 
7026557Sfr41279 /* result = aa/2 */
7030Sstevel@tonic-gate BIG_ERR_CODE
7040Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa)
7050Sstevel@tonic-gate {
7066557Sfr41279 	BIG_ERR_CODE	err;
7076557Sfr41279 	int		i;
7086557Sfr41279 	BIG_CHUNK_TYPE	cy, cy1;
7096557Sfr41279 	BIG_CHUNK_TYPE	*a, *r;
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	if (result->size < aa->len) {
7120Sstevel@tonic-gate 		err = big_extend(result, aa->len);
7136557Sfr41279 		if (err != BIG_OK) {
7140Sstevel@tonic-gate 			return (err);
7156557Sfr41279 		}
7160Sstevel@tonic-gate 	}
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	result->len = aa->len;
7190Sstevel@tonic-gate 	a = aa->value;
7200Sstevel@tonic-gate 	r = result->value;
7210Sstevel@tonic-gate 	cy = 0;
7226557Sfr41279 	for (i = aa->len - 1; i >= 0; i--) {
7236557Sfr41279 		cy1 = a[i] << (BIG_CHUNK_SIZE - 1);
7246557Sfr41279 		r[i] = (cy | (a[i] >> 1));
7250Sstevel@tonic-gate 		cy = cy1;
7260Sstevel@tonic-gate 	}
7276557Sfr41279 	if (r[result->len - 1] == 0) {
7286557Sfr41279 		result->len--;
7296557Sfr41279 	}
7306557Sfr41279 
7310Sstevel@tonic-gate 	return (BIG_OK);
7320Sstevel@tonic-gate }
7330Sstevel@tonic-gate 
7346557Sfr41279 /* result  =  aa*2 */
7350Sstevel@tonic-gate BIG_ERR_CODE
7360Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa)
7370Sstevel@tonic-gate {
7386557Sfr41279 	BIG_ERR_CODE	err;
7396557Sfr41279 	int		i, rsize;
7406557Sfr41279 	BIG_CHUNK_TYPE	cy, cy1;
7416557Sfr41279 	BIG_CHUNK_TYPE	*a, *r;
7426557Sfr41279 
7436557Sfr41279 	if ((aa->len > 0) &&
7446557Sfr41279 	    ((aa->value[aa->len - 1] & BIG_CHUNK_HIGHBIT) != 0)) {
7450Sstevel@tonic-gate 		rsize = aa->len + 1;
7466557Sfr41279 	} else {
7476557Sfr41279 		rsize = aa->len;
7486557Sfr41279 	}
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	if (result->size < rsize) {
7510Sstevel@tonic-gate 		err = big_extend(result, rsize);
7520Sstevel@tonic-gate 		if (err != BIG_OK)
7530Sstevel@tonic-gate 			return (err);
7540Sstevel@tonic-gate 	}
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	a = aa->value;
7570Sstevel@tonic-gate 	r = result->value;
7586557Sfr41279 	if (rsize == aa->len + 1) {
7596557Sfr41279 		r[rsize - 1] = 1;
7606557Sfr41279 	}
7610Sstevel@tonic-gate 	cy = 0;
7620Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
7636557Sfr41279 		cy1 = a[i] >> (BIG_CHUNK_SIZE - 1);
7640Sstevel@tonic-gate 		r[i] = (cy | (a[i] << 1));
7650Sstevel@tonic-gate 		cy = cy1;
7660Sstevel@tonic-gate 	}
7670Sstevel@tonic-gate 	result->len = rsize;
7680Sstevel@tonic-gate 	return (BIG_OK);
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate 
7716557Sfr41279 
7726557Sfr41279 /*
7736557Sfr41279  * returns aa mod b, aa must be nonneg, b must be a max
7746557Sfr41279  * (BIG_CHUNK_SIZE / 2)-bit integer
7756557Sfr41279  */
7766557Sfr41279 static uint32_t
7776557Sfr41279 big_modhalf_pos(BIGNUM *aa, uint32_t b)
7780Sstevel@tonic-gate {
7796557Sfr41279 	int		i;
7806557Sfr41279 	BIG_CHUNK_TYPE	rem;
7816557Sfr41279 
7826557Sfr41279 	if (aa->len == 0) {
7830Sstevel@tonic-gate 		return (0);
7846557Sfr41279 	}
7850Sstevel@tonic-gate 	rem = aa->value[aa->len - 1] % b;
7860Sstevel@tonic-gate 	for (i = aa->len - 2; i >= 0; i--) {
7876557Sfr41279 		rem = ((rem << (BIG_CHUNK_SIZE / 2)) |
7886557Sfr41279 		    (aa->value[i] >> (BIG_CHUNK_SIZE / 2))) % b;
7896557Sfr41279 		rem = ((rem << (BIG_CHUNK_SIZE / 2)) |
7906557Sfr41279 		    (aa->value[i] & BIG_CHUNK_LOWHALFBITS)) % b;
7910Sstevel@tonic-gate 	}
7926557Sfr41279 
7936557Sfr41279 	return ((uint32_t)rem);
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate /*
7986557Sfr41279  * result = aa - (2^BIG_CHUNK_SIZE)^lendiff * bb
7990Sstevel@tonic-gate  * result->size should be at least aa->len at entry
8000Sstevel@tonic-gate  * aa, bb, and result should be positive
8010Sstevel@tonic-gate  */
8020Sstevel@tonic-gate void
8030Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
8040Sstevel@tonic-gate {
8050Sstevel@tonic-gate 	int i, lendiff;
8060Sstevel@tonic-gate 	BIGNUM res1, aa1;
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
8090Sstevel@tonic-gate 	res1.size = result->size - lendiff;
8100Sstevel@tonic-gate 	res1.malloced = 0;
8110Sstevel@tonic-gate 	res1.value = result->value + lendiff;
8120Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
8130Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
8140Sstevel@tonic-gate 	aa1.len = bb->len;
8150Sstevel@tonic-gate 	aa1.sign = 1;
8160Sstevel@tonic-gate 	(void) big_sub_pos(&res1, &aa1, bb);
8170Sstevel@tonic-gate 	if (result->value != aa->value) {
8180Sstevel@tonic-gate 		for (i = 0; i < lendiff; i++) {
8190Sstevel@tonic-gate 			result->value[i] = aa->value[i];
8200Sstevel@tonic-gate 		}
8210Sstevel@tonic-gate 	}
8220Sstevel@tonic-gate 	result->len = aa->len;
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate /*
8270Sstevel@tonic-gate  * returns 1, 0, or -1 depending on whether |aa| > , ==, or <
8286557Sfr41279  *					(2^BIG_CHUNK_SIZE)^lendiff * |bb|
8290Sstevel@tonic-gate  * aa->len should be >= bb->len
8300Sstevel@tonic-gate  */
8310Sstevel@tonic-gate int
8320Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb)
8330Sstevel@tonic-gate {
834*8933Sopensolaris@drydog.com 	int		lendiff;
835*8933Sopensolaris@drydog.com 	BIGNUM		aa1;
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
8380Sstevel@tonic-gate 	aa1.len = bb->len;
8390Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
8400Sstevel@tonic-gate 	aa1.malloced = 0;
8410Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
8420Sstevel@tonic-gate 	return (big_cmp_abs(&aa1, bb));
8430Sstevel@tonic-gate }
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate /*
8476557Sfr41279  * result = aa * b where b is a max. (BIG_CHUNK_SIZE / 2)-bit positive integer.
8480Sstevel@tonic-gate  * result should have enough space allocated.
8490Sstevel@tonic-gate  */
8506557Sfr41279 static void
8516557Sfr41279 big_mulhalf_low(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b)
8520Sstevel@tonic-gate {
8536557Sfr41279 	int		i;
8546557Sfr41279 	BIG_CHUNK_TYPE	t1, t2, ai, cy;
8556557Sfr41279 	BIG_CHUNK_TYPE	*a, *r;
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	a = aa->value;
8580Sstevel@tonic-gate 	r = result->value;
8590Sstevel@tonic-gate 	cy = 0;
8600Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
8610Sstevel@tonic-gate 		ai = a[i];
8626557Sfr41279 		t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy;
8636557Sfr41279 		t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b +
8646557Sfr41279 		    (t1 >> (BIG_CHUNK_SIZE / 2));
8656557Sfr41279 		r[i] = (t1 & BIG_CHUNK_LOWHALFBITS) |
8666557Sfr41279 		    (t2 << (BIG_CHUNK_SIZE / 2));
8676557Sfr41279 		cy = t2 >> (BIG_CHUNK_SIZE / 2);
8680Sstevel@tonic-gate 	}
8690Sstevel@tonic-gate 	r[i] = cy;
8700Sstevel@tonic-gate 	result->len = aa->len + 1;
8710Sstevel@tonic-gate 	result->sign = aa->sign;
8720Sstevel@tonic-gate }
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate /*
8766557Sfr41279  * result = aa * b * 2^(BIG_CHUNK_SIZE / 2) where b is a max.
8776557Sfr41279  * (BIG_CHUNK_SIZE / 2)-bit positive integer.
8780Sstevel@tonic-gate  * result should have enough space allocated.
8790Sstevel@tonic-gate  */
8806557Sfr41279 static void
8816557Sfr41279 big_mulhalf_high(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b)
8820Sstevel@tonic-gate {
8836557Sfr41279 	int		i;
8846557Sfr41279 	BIG_CHUNK_TYPE	t1, t2, ai, cy, ri;
8856557Sfr41279 	BIG_CHUNK_TYPE	*a, *r;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	a = aa->value;
8880Sstevel@tonic-gate 	r = result->value;
8890Sstevel@tonic-gate 	cy = 0;
8900Sstevel@tonic-gate 	ri = 0;
8910Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
8920Sstevel@tonic-gate 		ai = a[i];
8936557Sfr41279 		t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy;
8946557Sfr41279 		t2 = (ai >>  (BIG_CHUNK_SIZE / 2)) * b +
8956557Sfr41279 		    (t1 >>  (BIG_CHUNK_SIZE / 2));
8966557Sfr41279 		r[i] = (t1 <<  (BIG_CHUNK_SIZE / 2)) + ri;
8976557Sfr41279 		ri = t2 & BIG_CHUNK_LOWHALFBITS;
8986557Sfr41279 		cy = t2 >> (BIG_CHUNK_SIZE / 2);
8990Sstevel@tonic-gate 	}
9006557Sfr41279 	r[i] = (cy <<  (BIG_CHUNK_SIZE / 2)) + ri;
9010Sstevel@tonic-gate 	result->len = aa->len + 1;
9020Sstevel@tonic-gate 	result->sign = aa->sign;
9030Sstevel@tonic-gate }
9040Sstevel@tonic-gate 
9056557Sfr41279 
9060Sstevel@tonic-gate /* it is assumed that result->size is big enough */
9070Sstevel@tonic-gate void
9080Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs)
9090Sstevel@tonic-gate {
9106557Sfr41279 	int		i;
9116557Sfr41279 	BIG_CHUNK_TYPE	cy, ai;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	if (offs == 0) {
9140Sstevel@tonic-gate 		if (result != aa) {
9150Sstevel@tonic-gate 			(void) big_copy(result, aa);
9160Sstevel@tonic-gate 		}
9170Sstevel@tonic-gate 		return;
9180Sstevel@tonic-gate 	}
9190Sstevel@tonic-gate 	cy = 0;
9200Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
9210Sstevel@tonic-gate 		ai = aa->value[i];
9220Sstevel@tonic-gate 		result->value[i] = (ai << offs) | cy;
9236557Sfr41279 		cy = ai >> (BIG_CHUNK_SIZE - offs);
9240Sstevel@tonic-gate 	}
9250Sstevel@tonic-gate 	if (cy != 0) {
9260Sstevel@tonic-gate 		result->len = aa->len + 1;
9270Sstevel@tonic-gate 		result->value[result->len - 1] = cy;
9280Sstevel@tonic-gate 	} else {
9290Sstevel@tonic-gate 		result->len = aa->len;
9300Sstevel@tonic-gate 	}
9310Sstevel@tonic-gate 	result->sign = aa->sign;
9320Sstevel@tonic-gate }
9330Sstevel@tonic-gate 
9346557Sfr41279 
9350Sstevel@tonic-gate /* it is assumed that result->size is big enough */
9360Sstevel@tonic-gate void
9370Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs)
9380Sstevel@tonic-gate {
9396557Sfr41279 	int		 i;
9406557Sfr41279 	BIG_CHUNK_TYPE	cy, ai;
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	if (offs == 0) {
9430Sstevel@tonic-gate 		if (result != aa) {
9440Sstevel@tonic-gate 			(void) big_copy(result, aa);
9450Sstevel@tonic-gate 		}
9460Sstevel@tonic-gate 		return;
9470Sstevel@tonic-gate 	}
9480Sstevel@tonic-gate 	cy = aa->value[0] >> offs;
9490Sstevel@tonic-gate 	for (i = 1; i < aa->len; i++) {
9500Sstevel@tonic-gate 		ai = aa->value[i];
951*8933Sopensolaris@drydog.com 		result->value[i - 1] = (ai << (BIG_CHUNK_SIZE - offs)) | cy;
9520Sstevel@tonic-gate 		cy = ai >> offs;
9530Sstevel@tonic-gate 	}
9540Sstevel@tonic-gate 	result->len = aa->len;
9550Sstevel@tonic-gate 	result->value[result->len - 1] = cy;
9560Sstevel@tonic-gate 	result->sign = aa->sign;
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate /*
9610Sstevel@tonic-gate  * result = aa/bb   remainder = aa mod bb
9620Sstevel@tonic-gate  * it is assumed that aa and bb are positive
9630Sstevel@tonic-gate  */
9640Sstevel@tonic-gate BIG_ERR_CODE
965*8933Sopensolaris@drydog.com big_div_pos(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb)
9660Sstevel@tonic-gate {
9676557Sfr41279 	BIG_ERR_CODE	err = BIG_OK;
9686557Sfr41279 	int		i, alen, blen, tlen, rlen, offs;
9696557Sfr41279 	BIG_CHUNK_TYPE	higha, highb, coeff;
9706557Sfr41279 	BIG_CHUNK_TYPE	*a, *b;
9716557Sfr41279 	BIGNUM		bbhigh, bblow, tresult, tmp1, tmp2;
9726557Sfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
9736557Sfr41279 	BIG_CHUNK_TYPE	tmp2value[BIGTMPSIZE];
9746557Sfr41279 	BIG_CHUNK_TYPE	tresultvalue[BIGTMPSIZE];
9756557Sfr41279 	BIG_CHUNK_TYPE	bblowvalue[BIGTMPSIZE];
9766557Sfr41279 	BIG_CHUNK_TYPE	bbhighvalue[BIGTMPSIZE];
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	a = aa->value;
9790Sstevel@tonic-gate 	b = bb->value;
9800Sstevel@tonic-gate 	alen = aa->len;
9810Sstevel@tonic-gate 	blen = bb->len;
9826557Sfr41279 	while ((alen > 1) && (a[alen - 1] == 0)) {
9836557Sfr41279 		alen = alen - 1;
9846557Sfr41279 	}
9850Sstevel@tonic-gate 	aa->len = alen;
9866557Sfr41279 	while ((blen > 1) && (b[blen - 1] == 0)) {
9876557Sfr41279 		blen = blen - 1;
9886557Sfr41279 	}
9890Sstevel@tonic-gate 	bb->len = blen;
9906557Sfr41279 	if ((blen == 1) && (b[0] == 0)) {
9910Sstevel@tonic-gate 		return (BIG_DIV_BY_0);
9926557Sfr41279 	}
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	if (big_cmp_abs(aa, bb) < 0) {
9950Sstevel@tonic-gate 		if ((remainder != NULL) &&
9966557Sfr41279 		    ((err = big_copy(remainder, aa)) != BIG_OK)) {
9970Sstevel@tonic-gate 			return (err);
9986557Sfr41279 		}
9990Sstevel@tonic-gate 		if (result != NULL) {
10000Sstevel@tonic-gate 			result->len = 1;
10010Sstevel@tonic-gate 			result->sign = 1;
10020Sstevel@tonic-gate 			result->value[0] = 0;
10030Sstevel@tonic-gate 		}
10040Sstevel@tonic-gate 		return (BIG_OK);
10050Sstevel@tonic-gate 	}
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	if ((err = big_init1(&bblow, blen + 1,
10080Sstevel@tonic-gate 	    bblowvalue, arraysize(bblowvalue))) != BIG_OK)
10090Sstevel@tonic-gate 		return (err);
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	if ((err = big_init1(&bbhigh, blen + 1,
10120Sstevel@tonic-gate 	    bbhighvalue, arraysize(bbhighvalue))) != BIG_OK)
10130Sstevel@tonic-gate 		goto ret1;
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	if ((err = big_init1(&tmp1, alen + 2,
10160Sstevel@tonic-gate 	    tmp1value, arraysize(tmp1value))) != BIG_OK)
10170Sstevel@tonic-gate 		goto ret2;
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, blen + 2,
10200Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
10210Sstevel@tonic-gate 		goto ret3;
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	if ((err = big_init1(&tresult, alen - blen + 2,
10240Sstevel@tonic-gate 	    tresultvalue, arraysize(tresultvalue))) != BIG_OK)
10250Sstevel@tonic-gate 		goto ret4;
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	offs = 0;
10286557Sfr41279 	highb = b[blen - 1];
10296557Sfr41279 	if (highb >= (BIG_CHUNK_HALF_HIGHBIT << 1)) {
10306557Sfr41279 		highb = highb >> (BIG_CHUNK_SIZE / 2);
10316557Sfr41279 		offs = (BIG_CHUNK_SIZE / 2);
10320Sstevel@tonic-gate 	}
10336557Sfr41279 	while ((highb & BIG_CHUNK_HALF_HIGHBIT) == 0) {
10346557Sfr41279 		highb = highb << 1;
10350Sstevel@tonic-gate 		offs++;
10360Sstevel@tonic-gate 	}
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	big_shiftleft(&bblow, bb, offs);
10396557Sfr41279 
10406557Sfr41279 	if (offs <= (BIG_CHUNK_SIZE / 2 - 1)) {
10416557Sfr41279 		big_shiftleft(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2);
10420Sstevel@tonic-gate 	} else {
10436557Sfr41279 		big_shiftright(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2);
10440Sstevel@tonic-gate 	}
10450Sstevel@tonic-gate 	if (bbhigh.value[bbhigh.len - 1] == 0) {
10460Sstevel@tonic-gate 		bbhigh.len--;
10470Sstevel@tonic-gate 	} else {
10480Sstevel@tonic-gate 		bbhigh.value[bbhigh.len] = 0;
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10516557Sfr41279 	highb = bblow.value[bblow.len - 1];
10526557Sfr41279 
10530Sstevel@tonic-gate 	big_shiftleft(&tmp1, aa, offs);
10540Sstevel@tonic-gate 	rlen = tmp1.len - bblow.len + 1;
10550Sstevel@tonic-gate 	tresult.len = rlen;
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	tmp1.len++;
10580Sstevel@tonic-gate 	tlen = tmp1.len;
10590Sstevel@tonic-gate 	tmp1.value[tmp1.len - 1] = 0;
10600Sstevel@tonic-gate 	for (i = 0; i < rlen; i++) {
10616557Sfr41279 		higha = (tmp1.value[tlen - 1] << (BIG_CHUNK_SIZE / 2)) +
10626557Sfr41279 		    (tmp1.value[tlen - 2] >> (BIG_CHUNK_SIZE / 2));
10630Sstevel@tonic-gate 		coeff = higha / (highb + 1);
10646557Sfr41279 		big_mulhalf_high(&tmp2, &bblow, coeff);
10650Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
10660Sstevel@tonic-gate 		bbhigh.len++;
10670Sstevel@tonic-gate 		while (tmp1.value[tlen - 1] > 0) {
10680Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
10690Sstevel@tonic-gate 			coeff++;
10700Sstevel@tonic-gate 		}
10710Sstevel@tonic-gate 		bbhigh.len--;
10720Sstevel@tonic-gate 		tlen--;
10730Sstevel@tonic-gate 		tmp1.len--;
10740Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) {
10750Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
10760Sstevel@tonic-gate 			coeff++;
10770Sstevel@tonic-gate 		}
10786557Sfr41279 		tresult.value[rlen - i - 1] = coeff << (BIG_CHUNK_SIZE / 2);
10790Sstevel@tonic-gate 		higha = tmp1.value[tlen - 1];
10800Sstevel@tonic-gate 		coeff = higha / (highb + 1);
10816557Sfr41279 		big_mulhalf_low(&tmp2, &bblow, coeff);
10820Sstevel@tonic-gate 		tmp2.len--;
10830Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
10840Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bblow) >= 0) {
10850Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bblow);
10860Sstevel@tonic-gate 			coeff++;
10870Sstevel@tonic-gate 		}
10880Sstevel@tonic-gate 		tresult.value[rlen - i - 1] =
10890Sstevel@tonic-gate 		    tresult.value[rlen - i - 1] + coeff;
10900Sstevel@tonic-gate 	}
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	big_shiftright(&tmp1, &tmp1, offs);
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	err = BIG_OK;
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	if ((remainder != NULL) &&
10970Sstevel@tonic-gate 	    ((err = big_copy(remainder, &tmp1)) != BIG_OK))
10980Sstevel@tonic-gate 		goto ret;
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	if (result != NULL)
11010Sstevel@tonic-gate 		err = big_copy(result, &tresult);
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate ret:
11040Sstevel@tonic-gate 	big_finish(&tresult);
11050Sstevel@tonic-gate ret4:
11060Sstevel@tonic-gate 	big_finish(&tmp1);
11070Sstevel@tonic-gate ret3:
11080Sstevel@tonic-gate 	big_finish(&tmp2);
11090Sstevel@tonic-gate ret2:
11100Sstevel@tonic-gate 	big_finish(&bbhigh);
11110Sstevel@tonic-gate ret1:
11120Sstevel@tonic-gate 	big_finish(&bblow);
11130Sstevel@tonic-gate 	return (err);
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate 
1116*8933Sopensolaris@drydog.com 
11170Sstevel@tonic-gate /*
11180Sstevel@tonic-gate  * If there is no processor-specific integer implementation of
11190Sstevel@tonic-gate  * the lower level multiply functions, then this code is provided
11200Sstevel@tonic-gate  * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and
11210Sstevel@tonic-gate  * big_sqr_vec().
11220Sstevel@tonic-gate  *
11230Sstevel@tonic-gate  * There are two generic implementations.  One that assumes that
11240Sstevel@tonic-gate  * there is hardware and C compiler support for a 32 x 32 --> 64
11250Sstevel@tonic-gate  * bit unsigned multiply, but otherwise is not specific to any
11260Sstevel@tonic-gate  * processor, platform, or ISA.
11270Sstevel@tonic-gate  *
11280Sstevel@tonic-gate  * The other makes very few assumptions about hardware capabilities.
11290Sstevel@tonic-gate  * It does not even assume that there is any implementation of a
11300Sstevel@tonic-gate  * 32 x 32 --> 64 bit multiply that is accessible to C code and
11310Sstevel@tonic-gate  * appropriate to use.  It falls constructs 32 x 32 --> 64 bit
11320Sstevel@tonic-gate  * multiplies from 16 x 16 --> 32 bit multiplies.
11330Sstevel@tonic-gate  *
11340Sstevel@tonic-gate  */
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate #if !defined(PSR_MUL)
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate #ifdef UMUL64
11390Sstevel@tonic-gate 
11406557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
11416557Sfr41279 
11420Sstevel@tonic-gate #define	UNROLL8
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_PREFETCH(R) \
11450Sstevel@tonic-gate 	p = pf * d; \
1146*8933Sopensolaris@drydog.com 	pf = (uint64_t)a[R + 1]; \
11470Sstevel@tonic-gate 	t = p + cy; \
11480Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11490Sstevel@tonic-gate 	cy = t >> 32
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_NOPREFETCH(R) \
11520Sstevel@tonic-gate 	p = pf * d; \
11530Sstevel@tonic-gate 	t = p + cy; \
11540Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11550Sstevel@tonic-gate 	cy = t >> 32
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_PREFETCH(R) \
11580Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
11590Sstevel@tonic-gate 	p = pf * d; \
1160*8933Sopensolaris@drydog.com 	pf = (uint64_t)a[R + 1]; \
11610Sstevel@tonic-gate 	t = p + t + cy; \
11620Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11630Sstevel@tonic-gate 	cy = t >> 32
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_NOPREFETCH(R) \
11660Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
11670Sstevel@tonic-gate 	p = pf * d; \
11680Sstevel@tonic-gate 	t = p + t + cy; \
11690Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11700Sstevel@tonic-gate 	cy = t >> 32
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate #ifdef UNROLL8
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate #define	UNROLL 8
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate /*
11770Sstevel@tonic-gate  * r = a * b
11780Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
11790Sstevel@tonic-gate  */
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate uint32_t
11820Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
11830Sstevel@tonic-gate {
11840Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	if (len == 0)
11870Sstevel@tonic-gate 		return (0);
11880Sstevel@tonic-gate 	cy = 0;
11890Sstevel@tonic-gate 	d = (uint64_t)b;
11900Sstevel@tonic-gate 	pf = (uint64_t)a[0];
11910Sstevel@tonic-gate 	while (len > UNROLL) {
11920Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
11930Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
11940Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
11950Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
11960Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
11970Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
11980Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
11990Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(7);
12000Sstevel@tonic-gate 		r += UNROLL;
12010Sstevel@tonic-gate 		a += UNROLL;
12020Sstevel@tonic-gate 		len -= UNROLL;
12030Sstevel@tonic-gate 	}
12040Sstevel@tonic-gate 	if (len == UNROLL) {
12050Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
12060Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
12070Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
12080Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
12090Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
12100Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
12110Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
12120Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(7);
12130Sstevel@tonic-gate 		return ((uint32_t)cy);
12140Sstevel@tonic-gate 	}
12150Sstevel@tonic-gate 	while (len > 1) {
12160Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
12170Sstevel@tonic-gate 		++r;
12180Sstevel@tonic-gate 		++a;
12190Sstevel@tonic-gate 		--len;
12200Sstevel@tonic-gate 	}
12210Sstevel@tonic-gate 	if (len > 0) {
12220Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(0);
12230Sstevel@tonic-gate 	}
12240Sstevel@tonic-gate 	return ((uint32_t)cy);
12250Sstevel@tonic-gate }
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate /*
12280Sstevel@tonic-gate  * r += a * b
12290Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
12300Sstevel@tonic-gate  */
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate uint32_t
12330Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
12340Sstevel@tonic-gate {
12350Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 	if (len == 0)
12380Sstevel@tonic-gate 		return (0);
12390Sstevel@tonic-gate 	cy = 0;
12400Sstevel@tonic-gate 	d = (uint64_t)b;
12410Sstevel@tonic-gate 	pf = (uint64_t)a[0];
12420Sstevel@tonic-gate 	while (len > 8) {
12430Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12440Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
12450Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
12460Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
12470Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
12480Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
12490Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
12500Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(7);
12510Sstevel@tonic-gate 		r += 8;
12520Sstevel@tonic-gate 		a += 8;
12530Sstevel@tonic-gate 		len -= 8;
12540Sstevel@tonic-gate 	}
12550Sstevel@tonic-gate 	if (len == 8) {
12560Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12570Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
12580Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
12590Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
12600Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
12610Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
12620Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
12630Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(7);
12640Sstevel@tonic-gate 		return ((uint32_t)cy);
12650Sstevel@tonic-gate 	}
12660Sstevel@tonic-gate 	while (len > 1) {
12670Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12680Sstevel@tonic-gate 		++r;
12690Sstevel@tonic-gate 		++a;
12700Sstevel@tonic-gate 		--len;
12710Sstevel@tonic-gate 	}
12720Sstevel@tonic-gate 	if (len > 0) {
12730Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(0);
12740Sstevel@tonic-gate 	}
12750Sstevel@tonic-gate 	return ((uint32_t)cy);
12760Sstevel@tonic-gate }
12770Sstevel@tonic-gate #endif /* UNROLL8 */
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate void
12800Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
12810Sstevel@tonic-gate {
1282*8933Sopensolaris@drydog.com 	uint32_t	*tr, *ta;
1283*8933Sopensolaris@drydog.com 	int		tlen, row, col;
1284*8933Sopensolaris@drydog.com 	uint64_t	p, s, t, t2, cy;
1285*8933Sopensolaris@drydog.com 	uint32_t	d;
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	tr = r + 1;
12880Sstevel@tonic-gate 	ta = a;
12890Sstevel@tonic-gate 	tlen = len - 1;
12900Sstevel@tonic-gate 	tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]);
12910Sstevel@tonic-gate 	while (--tlen > 0) {
12920Sstevel@tonic-gate 		tr += 2;
12930Sstevel@tonic-gate 		++ta;
12940Sstevel@tonic-gate 		tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]);
12950Sstevel@tonic-gate 	}
12960Sstevel@tonic-gate 	s = (uint64_t)a[0];
12970Sstevel@tonic-gate 	s = s * s;
12980Sstevel@tonic-gate 	r[0] = (uint32_t)s;
12990Sstevel@tonic-gate 	cy = s >> 32;
13000Sstevel@tonic-gate 	p = ((uint64_t)r[1] << 1) + cy;
13010Sstevel@tonic-gate 	r[1] = (uint32_t)p;
13020Sstevel@tonic-gate 	cy = p >> 32;
13030Sstevel@tonic-gate 	row = 1;
13040Sstevel@tonic-gate 	col = 2;
13050Sstevel@tonic-gate 	while (row < len) {
13060Sstevel@tonic-gate 		s = (uint64_t)a[row];
13070Sstevel@tonic-gate 		s = s * s;
13080Sstevel@tonic-gate 		p = (uint64_t)r[col] << 1;
13090Sstevel@tonic-gate 		t = p + s;
13100Sstevel@tonic-gate 		d = (uint32_t)t;
13110Sstevel@tonic-gate 		t2 = (uint64_t)d + cy;
13120Sstevel@tonic-gate 		r[col] = (uint32_t)t2;
13130Sstevel@tonic-gate 		cy = (t >> 32) + (t2 >> 32);
13140Sstevel@tonic-gate 		if (row == len - 1)
13150Sstevel@tonic-gate 			break;
1316*8933Sopensolaris@drydog.com 		p = ((uint64_t)r[col + 1] << 1) + cy;
1317*8933Sopensolaris@drydog.com 		r[col + 1] = (uint32_t)p;
13180Sstevel@tonic-gate 		cy = p >> 32;
13190Sstevel@tonic-gate 		++row;
13200Sstevel@tonic-gate 		col += 2;
13210Sstevel@tonic-gate 	}
1322*8933Sopensolaris@drydog.com 	r[col + 1] = (uint32_t)cy;
13230Sstevel@tonic-gate }
13240Sstevel@tonic-gate 
13256557Sfr41279 #else /* BIG_CHUNK_SIZE == 64 */
13266557Sfr41279 
13276557Sfr41279 /*
13286557Sfr41279  * r = r + a * digit, r and a are vectors of length len
13296557Sfr41279  * returns the carry digit
13306557Sfr41279  */
13316557Sfr41279 BIG_CHUNK_TYPE
13326557Sfr41279 big_mul_add_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len,
13336557Sfr41279     BIG_CHUNK_TYPE digit)
13346557Sfr41279 {
13356557Sfr41279 	BIG_CHUNK_TYPE	cy, cy1, retcy, dlow, dhigh;
13366557Sfr41279 	int		i;
13376557Sfr41279 
13386557Sfr41279 	cy1 = 0;
13396557Sfr41279 	dlow = digit & BIG_CHUNK_LOWHALFBITS;
13406557Sfr41279 	dhigh = digit >> (BIG_CHUNK_SIZE / 2);
13416557Sfr41279 	for (i = 0; i < len; i++) {
13426557Sfr41279 		cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
13436557Sfr41279 		    dlow * (a[i] & BIG_CHUNK_LOWHALFBITS) +
13446557Sfr41279 		    (r[i] & BIG_CHUNK_LOWHALFBITS);
13456557Sfr41279 		cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) +
13466557Sfr41279 		    dlow * (a[i] >> (BIG_CHUNK_SIZE / 2)) +
13476557Sfr41279 		    (r[i] >> (BIG_CHUNK_SIZE / 2));
13486557Sfr41279 		r[i] = (cy & BIG_CHUNK_LOWHALFBITS) |
13496557Sfr41279 		    (cy1 << (BIG_CHUNK_SIZE / 2));
13506557Sfr41279 	}
13516557Sfr41279 	retcy = cy1 >> (BIG_CHUNK_SIZE / 2);
13526557Sfr41279 
13536557Sfr41279 	cy1 = r[0] & BIG_CHUNK_LOWHALFBITS;
13546557Sfr41279 	for (i = 0; i < len - 1; i++) {
13556557Sfr41279 		cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
13566557Sfr41279 		    dhigh * (a[i] & BIG_CHUNK_LOWHALFBITS) +
13576557Sfr41279 		    (r[i] >> (BIG_CHUNK_SIZE / 2));
13586557Sfr41279 		r[i] = (cy1 & BIG_CHUNK_LOWHALFBITS) |
13596557Sfr41279 		    (cy << (BIG_CHUNK_SIZE / 2));
13606557Sfr41279 		cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) +
13616557Sfr41279 		    dhigh * (a[i] >> (BIG_CHUNK_SIZE / 2)) +
13626557Sfr41279 		    (r[i + 1] & BIG_CHUNK_LOWHALFBITS);
13636557Sfr41279 	}
13646557Sfr41279 	cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
13656557Sfr41279 	    dhigh * (a[len - 1] & BIG_CHUNK_LOWHALFBITS) +
13666557Sfr41279 	    (r[len - 1] >> (BIG_CHUNK_SIZE / 2));
13676557Sfr41279 	r[len - 1] = (cy1 & BIG_CHUNK_LOWHALFBITS) |
13686557Sfr41279 	    (cy << (BIG_CHUNK_SIZE / 2));
13696557Sfr41279 	retcy = (cy >> (BIG_CHUNK_SIZE / 2)) +
13706557Sfr41279 	    dhigh * (a[len - 1] >> (BIG_CHUNK_SIZE / 2)) + retcy;
13716557Sfr41279 
13726557Sfr41279 	return (retcy);
13736557Sfr41279 }
13746557Sfr41279 
13756557Sfr41279 
13766557Sfr41279 /*
13776557Sfr41279  * r = a * digit, r and a are vectors of length len
13786557Sfr41279  * returns the carry digit
13796557Sfr41279  */
13806557Sfr41279 BIG_CHUNK_TYPE
13816557Sfr41279 big_mul_set_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len,
13826557Sfr41279     BIG_CHUNK_TYPE digit)
13836557Sfr41279 {
13846557Sfr41279 	int	i;
13856557Sfr41279 
13866557Sfr41279 	ASSERT(r != a);
13876557Sfr41279 	for (i = 0; i < len; i++) {
13886557Sfr41279 		r[i] = 0;
13896557Sfr41279 	}
13906557Sfr41279 	return (big_mul_add_vec(r, a, len, digit));
13916557Sfr41279 }
13926557Sfr41279 
13936557Sfr41279 void
13946557Sfr41279 big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len)
13956557Sfr41279 {
13966557Sfr41279 	int i;
13976557Sfr41279 
13986557Sfr41279 	ASSERT(r != a);
13996557Sfr41279 	r[len] = big_mul_set_vec(r, a, len, a[0]);
14006557Sfr41279 	for (i = 1; i < len; ++i)
1401*8933Sopensolaris@drydog.com 		r[len + i] = big_mul_add_vec(r + i, a, len, a[i]);
14026557Sfr41279 }
14036557Sfr41279 
14046557Sfr41279 #endif /* BIG_CHUNK_SIZE == 32/64 */
14056557Sfr41279 
1406*8933Sopensolaris@drydog.com 
14070Sstevel@tonic-gate #else /* ! UMUL64 */
14080Sstevel@tonic-gate 
14096557Sfr41279 #if (BIG_CHUNK_SIZE != 32)
14106557Sfr41279 #error Don't use 64-bit chunks without defining UMUL64
14116557Sfr41279 #endif
14126557Sfr41279 
14136557Sfr41279 
14140Sstevel@tonic-gate /*
14150Sstevel@tonic-gate  * r = r + a * digit, r and a are vectors of length len
14160Sstevel@tonic-gate  * returns the carry digit
14170Sstevel@tonic-gate  */
14180Sstevel@tonic-gate uint32_t
14190Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
14200Sstevel@tonic-gate {
14210Sstevel@tonic-gate 	uint32_t cy, cy1, retcy, dlow, dhigh;
14220Sstevel@tonic-gate 	int i;
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 	cy1 = 0;
14250Sstevel@tonic-gate 	dlow = digit & 0xffff;
14260Sstevel@tonic-gate 	dhigh = digit >> 16;
14270Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
14280Sstevel@tonic-gate 		cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff);
14290Sstevel@tonic-gate 		cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16);
14300Sstevel@tonic-gate 		r[i] = (cy & 0xffff) | (cy1 << 16);
14310Sstevel@tonic-gate 	}
14320Sstevel@tonic-gate 	retcy = cy1 >> 16;
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 	cy1 = r[0] & 0xffff;
14350Sstevel@tonic-gate 	for (i = 0; i < len - 1; i++) {
14360Sstevel@tonic-gate 		cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16);
14370Sstevel@tonic-gate 		r[i] = (cy1 & 0xffff) | (cy << 16);
14380Sstevel@tonic-gate 		cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff);
14390Sstevel@tonic-gate 	}
14400Sstevel@tonic-gate 	cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16);
14410Sstevel@tonic-gate 	r[len - 1] = (cy1 & 0xffff) | (cy << 16);
14420Sstevel@tonic-gate 	retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy;
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	return (retcy);
14450Sstevel@tonic-gate }
14460Sstevel@tonic-gate 
14476557Sfr41279 
14480Sstevel@tonic-gate /*
14490Sstevel@tonic-gate  * r = a * digit, r and a are vectors of length len
14500Sstevel@tonic-gate  * returns the carry digit
14510Sstevel@tonic-gate  */
14520Sstevel@tonic-gate uint32_t
14530Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
14540Sstevel@tonic-gate {
14556557Sfr41279 	int	i;
14566557Sfr41279 
14576557Sfr41279 	ASSERT(r != a);
14586557Sfr41279 	for (i = 0; i < len; i++) {
14596557Sfr41279 		r[i] = 0;
14606557Sfr41279 	}
14616557Sfr41279 
14620Sstevel@tonic-gate 	return (big_mul_add_vec(r, a, len, digit));
14630Sstevel@tonic-gate }
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate void
14660Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
14670Sstevel@tonic-gate {
14680Sstevel@tonic-gate 	int i;
14690Sstevel@tonic-gate 
14706557Sfr41279 	ASSERT(r != a);
14710Sstevel@tonic-gate 	r[len] = big_mul_set_vec(r, a, len, a[0]);
14720Sstevel@tonic-gate 	for (i = 1; i < len; ++i)
1473*8933Sopensolaris@drydog.com 		r[len + i] = big_mul_add_vec(r + i, a, len, a[i]);
14740Sstevel@tonic-gate }
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate #endif /* UMUL64 */
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate void
14796557Sfr41279 big_mul_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int alen,
14806557Sfr41279     BIG_CHUNK_TYPE *b, int blen)
14810Sstevel@tonic-gate {
14820Sstevel@tonic-gate 	int i;
14830Sstevel@tonic-gate 
14840Sstevel@tonic-gate 	r[alen] = big_mul_set_vec(r, a, alen, b[0]);
14850Sstevel@tonic-gate 	for (i = 1; i < blen; ++i)
1486*8933Sopensolaris@drydog.com 		r[alen + i] = big_mul_add_vec(r + i, a, alen, b[i]);
14870Sstevel@tonic-gate }
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate #endif /* ! PSR_MUL */
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate /*
14940Sstevel@tonic-gate  * result = aa * bb  result->value should be big enough to hold the result
14950Sstevel@tonic-gate  *
14960Sstevel@tonic-gate  * Implementation: Standard grammar school algorithm
14970Sstevel@tonic-gate  *
14980Sstevel@tonic-gate  */
14990Sstevel@tonic-gate BIG_ERR_CODE
15000Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
15010Sstevel@tonic-gate {
15026557Sfr41279 	BIGNUM		tmp1;
15036557Sfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
15046557Sfr41279 	BIG_CHUNK_TYPE	*r, *t, *a, *b;
15056557Sfr41279 	BIG_ERR_CODE	err;
15066557Sfr41279 	int		i, alen, blen, rsize, sign, diff;
15070Sstevel@tonic-gate 
15080Sstevel@tonic-gate 	if (aa == bb) {
15090Sstevel@tonic-gate 		diff = 0;
15100Sstevel@tonic-gate 	} else {
15110Sstevel@tonic-gate 		diff = big_cmp_abs(aa, bb);
15120Sstevel@tonic-gate 		if (diff < 0) {
15130Sstevel@tonic-gate 			BIGNUM *tt;
15140Sstevel@tonic-gate 			tt = aa;
15150Sstevel@tonic-gate 			aa = bb;
15160Sstevel@tonic-gate 			bb = tt;
15170Sstevel@tonic-gate 		}
15180Sstevel@tonic-gate 	}
15190Sstevel@tonic-gate 	a = aa->value;
15200Sstevel@tonic-gate 	b = bb->value;
15210Sstevel@tonic-gate 	alen = aa->len;
15220Sstevel@tonic-gate 	blen = bb->len;
15236557Sfr41279 	while ((alen > 1) && (a[alen - 1] == 0)) {
15246557Sfr41279 		alen--;
15256557Sfr41279 	}
15260Sstevel@tonic-gate 	aa->len = alen;
15276557Sfr41279 	while ((blen > 1) && (b[blen - 1] == 0)) {
15286557Sfr41279 		blen--;
15296557Sfr41279 	}
15300Sstevel@tonic-gate 	bb->len = blen;
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 	rsize = alen + blen;
1533*8933Sopensolaris@drydog.com 	ASSERT(rsize > 0);
15340Sstevel@tonic-gate 	if (result->size < rsize) {
15350Sstevel@tonic-gate 		err = big_extend(result, rsize);
15366557Sfr41279 		if (err != BIG_OK) {
15370Sstevel@tonic-gate 			return (err);
15386557Sfr41279 		}
15390Sstevel@tonic-gate 		/* aa or bb might be an alias to result */
15400Sstevel@tonic-gate 		a = aa->value;
15410Sstevel@tonic-gate 		b = bb->value;
15420Sstevel@tonic-gate 	}
15430Sstevel@tonic-gate 	r = result->value;
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) {
15460Sstevel@tonic-gate 		result->len = 1;
15470Sstevel@tonic-gate 		result->sign = 1;
15480Sstevel@tonic-gate 		r[0] = 0;
15490Sstevel@tonic-gate 		return (BIG_OK);
15500Sstevel@tonic-gate 	}
15510Sstevel@tonic-gate 	sign = aa->sign * bb->sign;
15520Sstevel@tonic-gate 	if ((alen == 1) && (a[0] == 1)) {
15536557Sfr41279 		for (i = 0; i < blen; i++) {
15546557Sfr41279 			r[i] = b[i];
15556557Sfr41279 		}
15560Sstevel@tonic-gate 		result->len = blen;
15570Sstevel@tonic-gate 		result->sign = sign;
15580Sstevel@tonic-gate 		return (BIG_OK);
15590Sstevel@tonic-gate 	}
15600Sstevel@tonic-gate 	if ((blen == 1) && (b[0] == 1)) {
15616557Sfr41279 		for (i = 0; i < alen; i++) {
15626557Sfr41279 			r[i] = a[i];
15636557Sfr41279 		}
15640Sstevel@tonic-gate 		result->len = alen;
15650Sstevel@tonic-gate 		result->sign = sign;
15660Sstevel@tonic-gate 		return (BIG_OK);
15670Sstevel@tonic-gate 	}
15680Sstevel@tonic-gate 
15696557Sfr41279 	if ((err = big_init1(&tmp1, rsize,
15706557Sfr41279 	    tmp1value, arraysize(tmp1value))) != BIG_OK) {
15710Sstevel@tonic-gate 		return (err);
15726557Sfr41279 	}
15736557Sfr41279 	(void) big_copy(&tmp1, aa);
15740Sstevel@tonic-gate 	t = tmp1.value;
15756557Sfr41279 
15766557Sfr41279 	for (i = 0; i < rsize; i++) {
15776557Sfr41279 		t[i] = 0;
15786557Sfr41279 	}
15796557Sfr41279 
15806557Sfr41279 	if (diff == 0 && alen > 2) {
15810Sstevel@tonic-gate 		BIG_SQR_VEC(t, a, alen);
15826557Sfr41279 	} else if (blen > 0) {
15830Sstevel@tonic-gate 		BIG_MUL_VEC(t, a, alen, b, blen);
15846557Sfr41279 	}
15856557Sfr41279 
15866557Sfr41279 	if (t[rsize - 1] == 0) {
15876557Sfr41279 		tmp1.len = rsize - 1;
15886557Sfr41279 	} else {
15896557Sfr41279 		tmp1.len = rsize;
15906557Sfr41279 	}
1591*8933Sopensolaris@drydog.com 
1592*8933Sopensolaris@drydog.com 	err = big_copy(result, &tmp1);
1593*8933Sopensolaris@drydog.com 
15940Sstevel@tonic-gate 	result->sign = sign;
15950Sstevel@tonic-gate 
15966557Sfr41279 	big_finish(&tmp1);
15970Sstevel@tonic-gate 
1598*8933Sopensolaris@drydog.com 	return (err);
15990Sstevel@tonic-gate }
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate /*
16030Sstevel@tonic-gate  * caller must ensure that  a < n,  b < n  and  ret->size >=  2 * n->len + 1
16040Sstevel@tonic-gate  * and that ret is not n
16050Sstevel@tonic-gate  */
16060Sstevel@tonic-gate BIG_ERR_CODE
16076557Sfr41279 big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, BIG_CHUNK_TYPE n0)
16080Sstevel@tonic-gate {
16096557Sfr41279 	int	i, j, nlen, needsubtract;
16106557Sfr41279 	BIG_CHUNK_TYPE	*nn, *rr;
16116557Sfr41279 	BIG_CHUNK_TYPE	digit, c;
16126557Sfr41279 	BIG_ERR_CODE	err;
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 	nlen = n->len;
16150Sstevel@tonic-gate 	nn = n->value;
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 	rr = ret->value;
16180Sstevel@tonic-gate 
16196557Sfr41279 	if ((err = big_mul(ret, a, b)) != BIG_OK) {
16200Sstevel@tonic-gate 		return (err);
16216557Sfr41279 	}
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate 	rr = ret->value;
16246557Sfr41279 	for (i = ret->len; i < 2 * nlen + 1; i++) {
16256557Sfr41279 		rr[i] = 0;
16266557Sfr41279 	}
16270Sstevel@tonic-gate 	for (i = 0; i < nlen; i++) {
16280Sstevel@tonic-gate 		digit = rr[i];
16290Sstevel@tonic-gate 		digit = digit * n0;
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 		c = BIG_MUL_ADD_VEC(rr + i, nn, nlen, digit);
16320Sstevel@tonic-gate 		j = i + nlen;
16330Sstevel@tonic-gate 		rr[j] += c;
16340Sstevel@tonic-gate 		while (rr[j] < c) {
16350Sstevel@tonic-gate 			rr[j + 1] += 1;
16360Sstevel@tonic-gate 			j++;
16370Sstevel@tonic-gate 			c = 1;
16380Sstevel@tonic-gate 		}
16390Sstevel@tonic-gate 	}
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	needsubtract = 0;
16420Sstevel@tonic-gate 	if ((rr[2 * nlen]  != 0))
16430Sstevel@tonic-gate 		needsubtract = 1;
16440Sstevel@tonic-gate 	else {
16450Sstevel@tonic-gate 		for (i = 2 * nlen - 1; i >= nlen; i--) {
16460Sstevel@tonic-gate 			if (rr[i] > nn[i - nlen]) {
16470Sstevel@tonic-gate 				needsubtract = 1;
16480Sstevel@tonic-gate 				break;
16496557Sfr41279 			} else if (rr[i] < nn[i - nlen]) {
16506557Sfr41279 				break;
16516557Sfr41279 			}
16520Sstevel@tonic-gate 		}
16530Sstevel@tonic-gate 	}
16540Sstevel@tonic-gate 	if (needsubtract)
16550Sstevel@tonic-gate 		big_sub_vec(rr, rr + nlen, nn, nlen);
16560Sstevel@tonic-gate 	else {
16576557Sfr41279 		for (i = 0; i < nlen; i++) {
16580Sstevel@tonic-gate 			rr[i] = rr[i + nlen];
16596557Sfr41279 		}
16600Sstevel@tonic-gate 	}
1661*8933Sopensolaris@drydog.com 
1662*8933Sopensolaris@drydog.com 	/* Remove leading zeros, but keep at least 1 digit: */
1663*8933Sopensolaris@drydog.com 	for (i = nlen - 1; (i > 0) && (rr[i] == 0); i--)
16646557Sfr41279 		;
1665*8933Sopensolaris@drydog.com 	ret->len = i + 1;
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate 	return (BIG_OK);
16680Sstevel@tonic-gate }
16690Sstevel@tonic-gate 
16706557Sfr41279 
16716557Sfr41279 BIG_CHUNK_TYPE
16726557Sfr41279 big_n0(BIG_CHUNK_TYPE n)
16730Sstevel@tonic-gate {
16746557Sfr41279 	int		i;
16756557Sfr41279 	BIG_CHUNK_TYPE	result, tmp;
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate 	result = 0;
16786557Sfr41279 	tmp = BIG_CHUNK_ALLBITS;
16796557Sfr41279 	for (i = 0; i < BIG_CHUNK_SIZE; i++) {
16800Sstevel@tonic-gate 		if ((tmp & 1) == 1) {
16816557Sfr41279 			result = (result >> 1) | BIG_CHUNK_HIGHBIT;
16820Sstevel@tonic-gate 			tmp = tmp - n;
16836557Sfr41279 		} else {
16846557Sfr41279 			result = (result >> 1);
16856557Sfr41279 		}
16860Sstevel@tonic-gate 		tmp = tmp >> 1;
16870Sstevel@tonic-gate 	}
16880Sstevel@tonic-gate 
16890Sstevel@tonic-gate 	return (result);
16900Sstevel@tonic-gate }
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate int
16940Sstevel@tonic-gate big_numbits(BIGNUM *n)
16950Sstevel@tonic-gate {
16966557Sfr41279 	int		i, j;
16976557Sfr41279 	BIG_CHUNK_TYPE	t;
16986557Sfr41279 
16996557Sfr41279 	for (i = n->len - 1; i > 0; i--) {
17006557Sfr41279 		if (n->value[i] != 0) {
17016557Sfr41279 			break;
17026557Sfr41279 		}
17036557Sfr41279 	}
17040Sstevel@tonic-gate 	t = n->value[i];
17056557Sfr41279 	for (j = BIG_CHUNK_SIZE; j > 0; j--) {
17066557Sfr41279 		if ((t & BIG_CHUNK_HIGHBIT) == 0) {
17070Sstevel@tonic-gate 			t = t << 1;
17086557Sfr41279 		} else {
17096557Sfr41279 			return (BIG_CHUNK_SIZE * i + j);
17106557Sfr41279 		}
17110Sstevel@tonic-gate 	}
17120Sstevel@tonic-gate 	return (0);
17130Sstevel@tonic-gate }
17140Sstevel@tonic-gate 
17156557Sfr41279 
17160Sstevel@tonic-gate /* caller must make sure that a < n */
17170Sstevel@tonic-gate BIG_ERR_CODE
17180Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n)
17190Sstevel@tonic-gate {
17206557Sfr41279 	BIGNUM		rr;
17216557Sfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
17226557Sfr41279 	int		len, i;
17236557Sfr41279 	BIG_ERR_CODE	err;
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 	rr.malloced = 0;
17260Sstevel@tonic-gate 	len = n->len;
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1,
17296557Sfr41279 	    rrvalue, arraysize(rrvalue))) != BIG_OK) {
17300Sstevel@tonic-gate 		return (err);
17316557Sfr41279 	}
17326557Sfr41279 
17336557Sfr41279 	for (i = 0; i < 2 * len; i++) {
17346557Sfr41279 		rr.value[i] = 0;
17356557Sfr41279 	}
17360Sstevel@tonic-gate 	rr.value[2 * len] = 1;
17370Sstevel@tonic-gate 	rr.len = 2 * len + 1;
17386557Sfr41279 	if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) {
17390Sstevel@tonic-gate 		goto ret;
17406557Sfr41279 	}
17410Sstevel@tonic-gate 	err = big_copy(result, &rr);
17420Sstevel@tonic-gate ret:
17436557Sfr41279 	big_finish(&rr);
17440Sstevel@tonic-gate 	return (err);
17450Sstevel@tonic-gate }
17460Sstevel@tonic-gate 
17476557Sfr41279 
17480Sstevel@tonic-gate /* caller must make sure that a < n */
17490Sstevel@tonic-gate BIG_ERR_CODE
17506557Sfr41279 big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, BIG_CHUNK_TYPE n0,
17516557Sfr41279     BIGNUM *n_rr)
17520Sstevel@tonic-gate {
17536557Sfr41279 	BIGNUM		rr;
17546557Sfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
17556557Sfr41279 	int		len, i;
17566557Sfr41279 	BIG_ERR_CODE	err;
17570Sstevel@tonic-gate 
17580Sstevel@tonic-gate 	rr.malloced = 0;
17590Sstevel@tonic-gate 	len = n->len;
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue)))
17626557Sfr41279 	    != BIG_OK) {
17636557Sfr41279 		return (err);
17646557Sfr41279 	}
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 	if (n_rr == NULL) {
17676557Sfr41279 		for (i = 0; i < 2 * len; i++) {
17686557Sfr41279 			rr.value[i] = 0;
17696557Sfr41279 		}
17700Sstevel@tonic-gate 		rr.value[2 * len] = 1;
17710Sstevel@tonic-gate 		rr.len = 2 * len + 1;
17726557Sfr41279 		if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) {
17730Sstevel@tonic-gate 			goto ret;
17746557Sfr41279 		}
17750Sstevel@tonic-gate 		n_rr = &rr;
17760Sstevel@tonic-gate 	}
17770Sstevel@tonic-gate 
17786557Sfr41279 	if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK) {
17790Sstevel@tonic-gate 		goto ret;
17806557Sfr41279 	}
17810Sstevel@tonic-gate 	err = big_copy(result, &rr);
17826557Sfr41279 
17830Sstevel@tonic-gate ret:
17846557Sfr41279 	big_finish(&rr);
17850Sstevel@tonic-gate 	return (err);
17860Sstevel@tonic-gate }
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 
17896557Sfr41279 #ifdef	USE_FLOATING_POINT
17906557Sfr41279 #define	big_modexp_ncp_float	big_modexp_ncp_sw
17916557Sfr41279 #else
17926557Sfr41279 #define	big_modexp_ncp_int	big_modexp_ncp_sw
17936557Sfr41279 #endif
17946557Sfr41279 
17950Sstevel@tonic-gate #define	MAX_EXP_BIT_GROUP_SIZE 6
17960Sstevel@tonic-gate #define	APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1))
17970Sstevel@tonic-gate 
17986557Sfr41279 /* ARGSUSED */
17990Sstevel@tonic-gate static BIG_ERR_CODE
18006557Sfr41279 big_modexp_ncp_int(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n,
18016557Sfr41279     BIGNUM *tmp, BIG_CHUNK_TYPE n0)
18026557Sfr41279 
18030Sstevel@tonic-gate {
18046557Sfr41279 	BIGNUM		apowers[APOWERS_MAX_SIZE];
18056557Sfr41279 	BIGNUM		tmp1;
18066557Sfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
18076557Sfr41279 	int		i, j, k, l, m, p;
1808*8933Sopensolaris@drydog.com 	uint32_t	bit, bitind, bitcount, groupbits, apowerssize;
1809*8933Sopensolaris@drydog.com 	uint32_t	nbits;
18106557Sfr41279 	BIG_ERR_CODE	err;
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate 	nbits = big_numbits(e);
18130Sstevel@tonic-gate 	if (nbits < 50) {
18140Sstevel@tonic-gate 		groupbits = 1;
18150Sstevel@tonic-gate 		apowerssize = 1;
18160Sstevel@tonic-gate 	} else {
18170Sstevel@tonic-gate 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
18180Sstevel@tonic-gate 		apowerssize = 1 << (groupbits - 1);
18190Sstevel@tonic-gate 	}
18200Sstevel@tonic-gate 
18216557Sfr41279 
18226557Sfr41279 	if ((err = big_init1(&tmp1, 2 * n->len + 1,
18236557Sfr41279 	    tmp1value, arraysize(tmp1value))) != BIG_OK) {
18240Sstevel@tonic-gate 		return (err);
18256557Sfr41279 	}
18266557Sfr41279 
1827*8933Sopensolaris@drydog.com 	/* clear the malloced bit to help cleanup */
18286557Sfr41279 	for (i = 0; i < apowerssize; i++) {
18296557Sfr41279 		apowers[i].malloced = 0;
18306557Sfr41279 	}
1831*8933Sopensolaris@drydog.com 
18326557Sfr41279 	for (i = 0; i < apowerssize; i++) {
18336557Sfr41279 		if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) !=
18346557Sfr41279 		    BIG_OK) {
18356557Sfr41279 			goto ret;
18366557Sfr41279 		}
18376557Sfr41279 	}
18386557Sfr41279 
18396557Sfr41279 	(void) big_copy(&(apowers[0]), ma);
18406557Sfr41279 
18416557Sfr41279 	if ((err = big_mont_mul(&tmp1, ma, ma, n, n0)) != BIG_OK) {
18426557Sfr41279 		goto ret;
18436557Sfr41279 	}
18446557Sfr41279 	(void) big_copy(ma, &tmp1);
18456557Sfr41279 
18466557Sfr41279 	for (i = 1; i < apowerssize; i++) {
18476557Sfr41279 		if ((err = big_mont_mul(&tmp1, ma,
1848*8933Sopensolaris@drydog.com 		    &(apowers[i - 1]), n, n0)) != BIG_OK) {
18496557Sfr41279 			goto ret;
18506557Sfr41279 		}
18516557Sfr41279 		(void) big_copy(&apowers[i], &tmp1);
18526557Sfr41279 	}
18536557Sfr41279 
18546557Sfr41279 	bitind = nbits % BIG_CHUNK_SIZE;
18556557Sfr41279 	k = 0;
18566557Sfr41279 	l = 0;
18576557Sfr41279 	p = 0;
18586557Sfr41279 	bitcount = 0;
18596557Sfr41279 	for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) {
18606557Sfr41279 		for (j = bitind - 1; j >= 0; j--) {
18616557Sfr41279 			bit = (e->value[i] >> j) & 1;
18626557Sfr41279 			if ((bitcount == 0) && (bit == 0)) {
18636557Sfr41279 				if ((err = big_mont_mul(tmp,
18646557Sfr41279 				    tmp, tmp, n, n0)) != BIG_OK) {
18656557Sfr41279 					goto ret;
18666557Sfr41279 				}
18676557Sfr41279 			} else {
18686557Sfr41279 				bitcount++;
18696557Sfr41279 				p = p * 2 + bit;
18706557Sfr41279 				if (bit == 1) {
18716557Sfr41279 					k = k + l + 1;
18726557Sfr41279 					l = 0;
18736557Sfr41279 				} else {
18746557Sfr41279 					l++;
18756557Sfr41279 				}
18766557Sfr41279 				if (bitcount == groupbits) {
18776557Sfr41279 					for (m = 0; m < k; m++) {
18786557Sfr41279 						if ((err = big_mont_mul(tmp,
18796557Sfr41279 						    tmp, tmp, n, n0)) !=
18806557Sfr41279 						    BIG_OK) {
18816557Sfr41279 							goto ret;
18826557Sfr41279 						}
18836557Sfr41279 					}
18846557Sfr41279 					if ((err = big_mont_mul(tmp, tmp,
18856557Sfr41279 					    &(apowers[p >> (l + 1)]),
18866557Sfr41279 					    n, n0)) != BIG_OK) {
18876557Sfr41279 						goto ret;
18886557Sfr41279 					}
18896557Sfr41279 					for (m = 0; m < l; m++) {
18906557Sfr41279 						if ((err = big_mont_mul(tmp,
18916557Sfr41279 						    tmp, tmp, n, n0)) !=
18926557Sfr41279 						    BIG_OK) {
18936557Sfr41279 							goto ret;
18946557Sfr41279 						}
18956557Sfr41279 					}
18966557Sfr41279 					k = 0;
18976557Sfr41279 					l = 0;
18986557Sfr41279 					p = 0;
18996557Sfr41279 					bitcount = 0;
19006557Sfr41279 				}
19016557Sfr41279 			}
19026557Sfr41279 		}
19036557Sfr41279 		bitind = BIG_CHUNK_SIZE;
19040Sstevel@tonic-gate 	}
19050Sstevel@tonic-gate 
19066557Sfr41279 	for (m = 0; m < k; m++) {
19076557Sfr41279 		if ((err = big_mont_mul(tmp, tmp, tmp, n, n0)) != BIG_OK) {
19086557Sfr41279 			goto ret;
19096557Sfr41279 		}
19106557Sfr41279 	}
19116557Sfr41279 	if (p != 0) {
19126557Sfr41279 		if ((err = big_mont_mul(tmp, tmp,
19136557Sfr41279 		    &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK) {
19146557Sfr41279 			goto ret;
19156557Sfr41279 		}
19166557Sfr41279 	}
19176557Sfr41279 	for (m = 0; m < l; m++) {
19186557Sfr41279 		if ((err = big_mont_mul(result, tmp, tmp, n, n0)) != BIG_OK) {
19196557Sfr41279 			goto ret;
19206557Sfr41279 		}
19216557Sfr41279 	}
19226557Sfr41279 
19236557Sfr41279 ret:
19246557Sfr41279 	for (i = apowerssize - 1; i >= 0; i--) {
19256557Sfr41279 		big_finish(&(apowers[i]));
19260Sstevel@tonic-gate 	}
19276557Sfr41279 	big_finish(&tmp1);
19286557Sfr41279 
19296557Sfr41279 	return (err);
19306557Sfr41279 }
19316557Sfr41279 
19326557Sfr41279 
19336557Sfr41279 #ifdef USE_FLOATING_POINT
19346557Sfr41279 
19356557Sfr41279 #ifdef _KERNEL
19366557Sfr41279 
19376557Sfr41279 #include <sys/sysmacros.h>
19386557Sfr41279 #include <sys/regset.h>
19396557Sfr41279 #include <sys/fpu/fpusystm.h>
19406557Sfr41279 
19416557Sfr41279 /* the alignment for block stores to save fp registers */
19426557Sfr41279 #define	FPR_ALIGN	(64)
19436557Sfr41279 
19446557Sfr41279 extern void big_savefp(kfpu_t *);
19456557Sfr41279 extern void big_restorefp(kfpu_t *);
19466557Sfr41279 
19476557Sfr41279 #endif /* _KERNEL */
19486557Sfr41279 
19496557Sfr41279 /*
19506557Sfr41279  * This version makes use of floating point for performance
19516557Sfr41279  */
19526557Sfr41279 static BIG_ERR_CODE
19536557Sfr41279 big_modexp_ncp_float(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n,
19546557Sfr41279     BIGNUM *tmp, BIG_CHUNK_TYPE n0)
19556557Sfr41279 {
19566557Sfr41279 
1957*8933Sopensolaris@drydog.com 	int		i, j, k, l, m, p;
1958*8933Sopensolaris@drydog.com 	uint32_t	bit, bitind, bitcount, nlen;
19596557Sfr41279 	double		dn0;
19606557Sfr41279 	double		*dn, *dt, *d16r, *d32r;
19616557Sfr41279 	uint32_t	*nint, *prod;
19626557Sfr41279 	double		*apowers[APOWERS_MAX_SIZE];
1963*8933Sopensolaris@drydog.com 	uint32_t	nbits, groupbits, apowerssize;
19646557Sfr41279 	BIG_ERR_CODE	err = BIG_OK;
19656557Sfr41279 
19666557Sfr41279 #ifdef _KERNEL
19676557Sfr41279 	uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN];
19686557Sfr41279 	kfpu_t *fpu;
19696557Sfr41279 
19706557Sfr41279 #ifdef DEBUG
19716557Sfr41279 	if (!fpu_exists)
19726557Sfr41279 		return (BIG_GENERAL_ERR);
19736557Sfr41279 #endif
19746557Sfr41279 
19756557Sfr41279 	fpu =  (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN);
19766557Sfr41279 	big_savefp(fpu);
19776557Sfr41279 
19786557Sfr41279 #endif /* _KERNEL */
19796557Sfr41279 
19806557Sfr41279 	nbits = big_numbits(e);
19816557Sfr41279 	if (nbits < 50) {
19826557Sfr41279 		groupbits = 1;
19836557Sfr41279 		apowerssize = 1;
19846557Sfr41279 	} else {
19856557Sfr41279 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
19866557Sfr41279 		apowerssize = 1 << (groupbits - 1);
19876557Sfr41279 	}
19886557Sfr41279 
19896557Sfr41279 	nlen = (BIG_CHUNK_SIZE / 32) * n->len;
19900Sstevel@tonic-gate 	dn0 = (double)(n0 & 0xffff);
19910Sstevel@tonic-gate 
19920Sstevel@tonic-gate 	dn = dt = d16r = d32r = NULL;
19930Sstevel@tonic-gate 	nint = prod = NULL;
19940Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
19950Sstevel@tonic-gate 		apowers[i] = NULL;
19960Sstevel@tonic-gate 	}
19970Sstevel@tonic-gate 
19980Sstevel@tonic-gate 	if ((dn = big_malloc(nlen * sizeof (double))) == NULL) {
19990Sstevel@tonic-gate 		err = BIG_NO_MEM;
20000Sstevel@tonic-gate 		goto ret;
20010Sstevel@tonic-gate 	}
20020Sstevel@tonic-gate 	if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) {
20030Sstevel@tonic-gate 		err = BIG_NO_MEM;
20040Sstevel@tonic-gate 		goto ret;
20050Sstevel@tonic-gate 	}
20060Sstevel@tonic-gate 	if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) {
20070Sstevel@tonic-gate 		err = BIG_NO_MEM;
20080Sstevel@tonic-gate 		goto ret;
20090Sstevel@tonic-gate 	}
20100Sstevel@tonic-gate 	if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) {
20110Sstevel@tonic-gate 		err = BIG_NO_MEM;
20120Sstevel@tonic-gate 		goto ret;
20130Sstevel@tonic-gate 	}
20140Sstevel@tonic-gate 	if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) {
20150Sstevel@tonic-gate 		err = BIG_NO_MEM;
20160Sstevel@tonic-gate 		goto ret;
20170Sstevel@tonic-gate 	}
20180Sstevel@tonic-gate 	if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) {
20190Sstevel@tonic-gate 		err = BIG_NO_MEM;
20200Sstevel@tonic-gate 		goto ret;
20210Sstevel@tonic-gate 	}
20220Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
20230Sstevel@tonic-gate 		if ((apowers[i] = big_malloc((2 * nlen + 1) *
20240Sstevel@tonic-gate 		    sizeof (double))) == NULL) {
20250Sstevel@tonic-gate 			err = BIG_NO_MEM;
20260Sstevel@tonic-gate 			goto ret;
20270Sstevel@tonic-gate 		}
20280Sstevel@tonic-gate 	}
20290Sstevel@tonic-gate 
20306557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
20316557Sfr41279 	for (i = 0; i < ma->len; i++) {
20326557Sfr41279 		nint[i] = ma->value[i];
20336557Sfr41279 	}
20346557Sfr41279 	for (; i < nlen; i++) {
20356557Sfr41279 		nint[i] = 0;
20366557Sfr41279 	}
20376557Sfr41279 #else
20386557Sfr41279 	for (i = 0; i < ma->len; i++) {
20396557Sfr41279 		nint[2 * i] = (uint32_t)(ma->value[i] & 0xffffffffULL);
20406557Sfr41279 		nint[2 * i + 1] = (uint32_t)(ma->value[i] >> 32);
20416557Sfr41279 	}
20426557Sfr41279 	for (i = ma->len * 2; i < nlen; i++) {
20436557Sfr41279 		nint[i] = 0;
20446557Sfr41279 	}
20456557Sfr41279 #endif
20460Sstevel@tonic-gate 	conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen);
20470Sstevel@tonic-gate 
20486557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
20496557Sfr41279 	for (i = 0; i < n->len; i++) {
20506557Sfr41279 		nint[i] = n->value[i];
20516557Sfr41279 	}
20526557Sfr41279 	for (; i < nlen; i++) {
20536557Sfr41279 		nint[i] = 0;
20546557Sfr41279 	}
20556557Sfr41279 #else
20566557Sfr41279 	for (i = 0; i < n->len; i++) {
20576557Sfr41279 		nint[2 * i] = (uint32_t)(n->value[i] & 0xffffffffULL);
20586557Sfr41279 		nint[2 * i + 1] = (uint32_t)(n->value[i] >> 32);
20596557Sfr41279 	}
20606557Sfr41279 	for (i = n->len * 2; i < nlen; i++) {
20616557Sfr41279 		nint[i] = 0;
20626557Sfr41279 	}
20636557Sfr41279 #endif
20640Sstevel@tonic-gate 	conv_i32_to_d32(dn, nint, nlen);
20650Sstevel@tonic-gate 
20660Sstevel@tonic-gate 	mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0);
20670Sstevel@tonic-gate 	conv_i32_to_d32(d32r, prod, nlen);
20680Sstevel@tonic-gate 	for (i = 1; i < apowerssize; i++) {
20690Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[i - 1],
20700Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
20710Sstevel@tonic-gate 		conv_i32_to_d16(apowers[i], prod, nlen);
20720Sstevel@tonic-gate 	}
20730Sstevel@tonic-gate 
20746557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
20756557Sfr41279 	for (i = 0; i < tmp->len; i++) {
20766557Sfr41279 		prod[i] = tmp->value[i];
20776557Sfr41279 	}
20786557Sfr41279 	for (; i < nlen + 1; i++) {
20796557Sfr41279 		prod[i] = 0;
20806557Sfr41279 	}
20816557Sfr41279 #else
20826557Sfr41279 	for (i = 0; i < tmp->len; i++) {
20836557Sfr41279 		prod[2 * i] = (uint32_t)(tmp->value[i] & 0xffffffffULL);
20846557Sfr41279 		prod[2 * i + 1] = (uint32_t)(tmp->value[i] >> 32);
20856557Sfr41279 	}
20866557Sfr41279 	for (i = tmp->len * 2; i < nlen + 1; i++) {
20876557Sfr41279 		prod[i] = 0;
20886557Sfr41279 	}
20896557Sfr41279 #endif
20906557Sfr41279 
20916557Sfr41279 	bitind = nbits % BIG_CHUNK_SIZE;
20920Sstevel@tonic-gate 	k = 0;
20930Sstevel@tonic-gate 	l = 0;
20940Sstevel@tonic-gate 	p = 0;
20950Sstevel@tonic-gate 	bitcount = 0;
20966557Sfr41279 	for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) {
20970Sstevel@tonic-gate 		for (j = bitind - 1; j >= 0; j--) {
20980Sstevel@tonic-gate 			bit = (e->value[i] >> j) & 1;
20990Sstevel@tonic-gate 			if ((bitcount == 0) && (bit == 0)) {
21000Sstevel@tonic-gate 				conv_i32_to_d32_and_d16(d32r, d16r,
21010Sstevel@tonic-gate 				    prod, nlen);
21020Sstevel@tonic-gate 				mont_mulf_noconv(prod, d32r, d16r,
21030Sstevel@tonic-gate 				    dt, dn, nint, nlen, dn0);
21040Sstevel@tonic-gate 			} else {
21050Sstevel@tonic-gate 				bitcount++;
21060Sstevel@tonic-gate 				p = p * 2 + bit;
21070Sstevel@tonic-gate 				if (bit == 1) {
21080Sstevel@tonic-gate 					k = k + l + 1;
21090Sstevel@tonic-gate 					l = 0;
21100Sstevel@tonic-gate 				} else {
21110Sstevel@tonic-gate 					l++;
21120Sstevel@tonic-gate 				}
21130Sstevel@tonic-gate 				if (bitcount == groupbits) {
21140Sstevel@tonic-gate 					for (m = 0; m < k; m++) {
21156557Sfr41279 						conv_i32_to_d32_and_d16(d32r,
21166557Sfr41279 						    d16r, prod, nlen);
21170Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
21180Sstevel@tonic-gate 						    d16r, dt, dn, nint,
21190Sstevel@tonic-gate 						    nlen, dn0);
21200Sstevel@tonic-gate 					}
21210Sstevel@tonic-gate 					conv_i32_to_d32(d32r, prod, nlen);
21220Sstevel@tonic-gate 					mont_mulf_noconv(prod, d32r,
2123*8933Sopensolaris@drydog.com 					    apowers[p >> (l + 1)],
21240Sstevel@tonic-gate 					    dt, dn, nint, nlen, dn0);
21250Sstevel@tonic-gate 					for (m = 0; m < l; m++) {
21266557Sfr41279 						conv_i32_to_d32_and_d16(d32r,
21276557Sfr41279 						    d16r, prod, nlen);
21280Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
21290Sstevel@tonic-gate 						    d16r, dt, dn, nint,
21300Sstevel@tonic-gate 						    nlen, dn0);
21310Sstevel@tonic-gate 					}
21320Sstevel@tonic-gate 					k = 0;
21330Sstevel@tonic-gate 					l = 0;
21340Sstevel@tonic-gate 					p = 0;
21350Sstevel@tonic-gate 					bitcount = 0;
21360Sstevel@tonic-gate 				}
21370Sstevel@tonic-gate 			}
21380Sstevel@tonic-gate 		}
21396557Sfr41279 		bitind = BIG_CHUNK_SIZE;
21400Sstevel@tonic-gate 	}
21410Sstevel@tonic-gate 
21420Sstevel@tonic-gate 	for (m = 0; m < k; m++) {
21430Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
21440Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
21450Sstevel@tonic-gate 	}
21460Sstevel@tonic-gate 	if (p != 0) {
21470Sstevel@tonic-gate 		conv_i32_to_d32(d32r, prod, nlen);
21480Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)],
21490Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
21500Sstevel@tonic-gate 	}
21510Sstevel@tonic-gate 	for (m = 0; m < l; m++) {
21520Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
21530Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
21540Sstevel@tonic-gate 	}
21550Sstevel@tonic-gate 
21566557Sfr41279 #if (BIG_CHUNK_SIZE == 32)
21576557Sfr41279 	for (i = 0; i < nlen; i++) {
21586557Sfr41279 		result->value[i] = prod[i];
21596557Sfr41279 	}
21606557Sfr41279 	for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--)
21616557Sfr41279 		;
21626557Sfr41279 #else
21636557Sfr41279 	for (i = 0; i < nlen / 2; i++) {
21646557Sfr41279 		result->value[i] = (uint64_t)(prod[2 * i]) +
21656557Sfr41279 		    (((uint64_t)(prod[2 * i + 1])) << 32);
21666557Sfr41279 	}
21676557Sfr41279 	for (i = nlen / 2 - 1; (i > 0) && (result->value[i] == 0); i--)
21686557Sfr41279 		;
21696557Sfr41279 #endif
21706557Sfr41279 	result->len = i + 1;
21716557Sfr41279 
21720Sstevel@tonic-gate ret:
21730Sstevel@tonic-gate 	for (i = apowerssize - 1; i >= 0; i--) {
21740Sstevel@tonic-gate 		if (apowers[i] != NULL)
21750Sstevel@tonic-gate 			big_free(apowers[i], (2 * nlen + 1) * sizeof (double));
21760Sstevel@tonic-gate 	}
21776557Sfr41279 	if (d32r != NULL) {
21780Sstevel@tonic-gate 		big_free(d32r, nlen * sizeof (double));
21796557Sfr41279 	}
21806557Sfr41279 	if (d16r != NULL) {
21810Sstevel@tonic-gate 		big_free(d16r, (2 * nlen + 1) * sizeof (double));
21826557Sfr41279 	}
21836557Sfr41279 	if (prod != NULL) {
21840Sstevel@tonic-gate 		big_free(prod, (nlen + 1) * sizeof (uint32_t));
21856557Sfr41279 	}
21866557Sfr41279 	if (nint != NULL) {
21870Sstevel@tonic-gate 		big_free(nint, nlen * sizeof (uint32_t));
21886557Sfr41279 	}
21896557Sfr41279 	if (dt != NULL) {
21900Sstevel@tonic-gate 		big_free(dt, (4 * nlen + 2) * sizeof (double));
21916557Sfr41279 	}
21926557Sfr41279 	if (dn != NULL) {
21930Sstevel@tonic-gate 		big_free(dn, nlen * sizeof (double));
21946557Sfr41279 	}
21950Sstevel@tonic-gate 
21960Sstevel@tonic-gate #ifdef _KERNEL
21976557Sfr41279 	big_restorefp(fpu);
21980Sstevel@tonic-gate #endif
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 	return (err);
22010Sstevel@tonic-gate }
22020Sstevel@tonic-gate 
22030Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */
22040Sstevel@tonic-gate 
22050Sstevel@tonic-gate 
22060Sstevel@tonic-gate BIG_ERR_CODE
22076557Sfr41279 big_modexp_ext(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr,
22086557Sfr41279     big_modexp_ncp_info_t *info)
22090Sstevel@tonic-gate {
22106557Sfr41279 	BIGNUM		ma, tmp, rr;
22116557Sfr41279 	BIG_CHUNK_TYPE	mavalue[BIGTMPSIZE];
22126557Sfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
22136557Sfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
22146557Sfr41279 	BIG_ERR_CODE	err;
22156557Sfr41279 	BIG_CHUNK_TYPE	n0;
22166557Sfr41279 
22176557Sfr41279 	if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue)))	!=
22186557Sfr41279 	    BIG_OK) {
22190Sstevel@tonic-gate 		return (err);
22206557Sfr41279 	}
22216557Sfr41279 	ma.len = 1;
22226557Sfr41279 	ma.value[0] = 0;
22236557Sfr41279 
22246557Sfr41279 	if ((err = big_init1(&tmp, 2 * n->len + 1,
22256557Sfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
22260Sstevel@tonic-gate 		goto ret1;
22276557Sfr41279 	}
22286557Sfr41279 
2229*8933Sopensolaris@drydog.com 	/* clear the malloced bit to help cleanup */
22306557Sfr41279 	rr.malloced = 0;
2231*8933Sopensolaris@drydog.com 
22326557Sfr41279 	if (n_rr == NULL) {
22336557Sfr41279 		if ((err = big_init1(&rr, 2 * n->len + 1,
22346557Sfr41279 		    rrvalue, arraysize(rrvalue))) != BIG_OK) {
22356557Sfr41279 			goto ret2;
22366557Sfr41279 		}
22376557Sfr41279 		if (big_mont_rr(&rr, n) != BIG_OK) {
22386557Sfr41279 			goto ret;
22396557Sfr41279 		}
22406557Sfr41279 		n_rr = &rr;
22416557Sfr41279 	}
22426557Sfr41279 
22436557Sfr41279 	n0 = big_n0(n->value[0]);
22446557Sfr41279 
22456557Sfr41279 	if (big_cmp_abs(a, n) > 0) {
22466557Sfr41279 		if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK) {
22476557Sfr41279 			goto ret;
22486557Sfr41279 		}
22496557Sfr41279 		err = big_mont_conv(&ma, &ma, n, n0, n_rr);
22506557Sfr41279 	} else {
22516557Sfr41279 		err = big_mont_conv(&ma, a, n, n0, n_rr);
22526557Sfr41279 	}
22536557Sfr41279 	if (err != BIG_OK) {
22546557Sfr41279 		goto ret;
22556557Sfr41279 	}
22566557Sfr41279 
22576557Sfr41279 	tmp.len = 1;
22586557Sfr41279 	tmp.value[0] = 1;
22596557Sfr41279 	if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK) {
22606557Sfr41279 		goto ret;
22616557Sfr41279 	}
22626557Sfr41279 
22636557Sfr41279 	if ((info != NULL) && (info->func != NULL)) {
22646557Sfr41279 		err = (*(info->func))(&tmp, &ma, e, n, &tmp, n0,
22656557Sfr41279 		    info->ncp, info->reqp);
22666557Sfr41279 	} else {
22676557Sfr41279 		err = big_modexp_ncp_sw(&tmp, &ma, e, n, &tmp, n0);
22686557Sfr41279 	}
22696557Sfr41279 	if (err != BIG_OK) {
22706557Sfr41279 		goto ret;
22716557Sfr41279 	}
22726557Sfr41279 
22736557Sfr41279 	ma.value[0] = 1;
22746557Sfr41279 	ma.len = 1;
22756557Sfr41279 	if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK) {
22766557Sfr41279 		goto ret;
22776557Sfr41279 	}
22786557Sfr41279 	err = big_copy(result, &tmp);
22796557Sfr41279 
22806557Sfr41279 ret:
22816557Sfr41279 	if (rr.malloced) {
22826557Sfr41279 		big_finish(&rr);
22836557Sfr41279 	}
22846557Sfr41279 ret2:
22856557Sfr41279 	big_finish(&tmp);
22866557Sfr41279 ret1:
22876557Sfr41279 	big_finish(&ma);
22886557Sfr41279 
22896557Sfr41279 	return (err);
22906557Sfr41279 }
22916557Sfr41279 
22926557Sfr41279 BIG_ERR_CODE
22936557Sfr41279 big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
22946557Sfr41279 {
22956557Sfr41279 	return (big_modexp_ext(result, a, e, n, n_rr, NULL));
22966557Sfr41279 }
22976557Sfr41279 
22986557Sfr41279 
22996557Sfr41279 BIG_ERR_CODE
23006557Sfr41279 big_modexp_crt_ext(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
23016557Sfr41279     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
23026557Sfr41279     BIGNUM *p_rr, BIGNUM *q_rr, big_modexp_ncp_info_t *info)
23036557Sfr41279 {
23046557Sfr41279 	BIGNUM		ap, aq, tmp;
23056557Sfr41279 	int		alen, biglen, sign;
23066557Sfr41279 	BIG_ERR_CODE	err;
23076557Sfr41279 
23086557Sfr41279 	if (p->len > q->len) {
23096557Sfr41279 		biglen = p->len;
23106557Sfr41279 	} else {
23116557Sfr41279 		biglen = q->len;
23126557Sfr41279 	}
23136557Sfr41279 
23146557Sfr41279 	if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK) {
23156557Sfr41279 		return (err);
23166557Sfr41279 	}
23176557Sfr41279 	if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK) {
23186557Sfr41279 		goto ret1;
23196557Sfr41279 	}
23206557Sfr41279 	if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK) {
23210Sstevel@tonic-gate 		goto ret2;
23226557Sfr41279 	}
23230Sstevel@tonic-gate 
23240Sstevel@tonic-gate 	/*
23250Sstevel@tonic-gate 	 * check whether a is too short - to avoid timing attacks
23260Sstevel@tonic-gate 	 */
23270Sstevel@tonic-gate 	alen = a->len;
23280Sstevel@tonic-gate 	while ((alen > p->len) && (a->value[alen - 1] == 0)) {
23290Sstevel@tonic-gate 		alen--;
23300Sstevel@tonic-gate 	}
23310Sstevel@tonic-gate 	if (alen < p->len + q->len) {
23320Sstevel@tonic-gate 		/*
23330Sstevel@tonic-gate 		 * a is too short, add p*q to it before
23340Sstevel@tonic-gate 		 * taking it modulo p and q
23350Sstevel@tonic-gate 		 * this will also affect timing, but this difference
23360Sstevel@tonic-gate 		 * does not depend on p or q, only on a
23370Sstevel@tonic-gate 		 * (in "normal" operation, this path will never be
23380Sstevel@tonic-gate 		 * taken, so it is not a performance penalty
23390Sstevel@tonic-gate 		 */
23406557Sfr41279 		if ((err = big_mul(&tmp, p, q)) != BIG_OK) {
23410Sstevel@tonic-gate 			goto ret;
23426557Sfr41279 		}
23436557Sfr41279 		if ((err = big_add(&tmp, &tmp, a)) != BIG_OK) {
23446557Sfr41279 			goto ret;
23456557Sfr41279 		}
23466557Sfr41279 		if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK) {
23470Sstevel@tonic-gate 			goto ret;
23486557Sfr41279 		}
23496557Sfr41279 		if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) {
23500Sstevel@tonic-gate 			goto ret;
23516557Sfr41279 		}
23526557Sfr41279 	} else {
23536557Sfr41279 		if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK) {
23540Sstevel@tonic-gate 			goto ret;
23556557Sfr41279 		}
23566557Sfr41279 		if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK) {
23570Sstevel@tonic-gate 			goto ret;
23586557Sfr41279 		}
23590Sstevel@tonic-gate 	}
23600Sstevel@tonic-gate 
23616557Sfr41279 	if ((err = big_modexp_ext(&ap, &ap, dmodpminus1, p, p_rr, info)) !=
23626557Sfr41279 	    BIG_OK) {
23630Sstevel@tonic-gate 		goto ret;
23646557Sfr41279 	}
23656557Sfr41279 	if ((err = big_modexp_ext(&aq, &aq, dmodqminus1, q, q_rr, info)) !=
23666557Sfr41279 	    BIG_OK) {
23670Sstevel@tonic-gate 		goto ret;
23686557Sfr41279 	}
23696557Sfr41279 	if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK) {
23700Sstevel@tonic-gate 		goto ret;
23716557Sfr41279 	}
23726557Sfr41279 	if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK) {
23730Sstevel@tonic-gate 		goto ret;
23746557Sfr41279 	}
23750Sstevel@tonic-gate 	sign = tmp.sign;
23760Sstevel@tonic-gate 	tmp.sign = 1;
23776557Sfr41279 	if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) {
23780Sstevel@tonic-gate 		goto ret;
23796557Sfr41279 	}
23800Sstevel@tonic-gate 	if ((sign == -1) && (!big_is_zero(&aq))) {
23810Sstevel@tonic-gate 		(void) big_sub_pos(&aq, q, &aq);
23820Sstevel@tonic-gate 	}
23836557Sfr41279 	if ((err = big_mul(&tmp, &aq, p)) != BIG_OK) {
23840Sstevel@tonic-gate 		goto ret;
23856557Sfr41279 	}
23860Sstevel@tonic-gate 	err = big_add_abs(result, &ap, &tmp);
23870Sstevel@tonic-gate 
23880Sstevel@tonic-gate ret:
23890Sstevel@tonic-gate 	big_finish(&tmp);
23900Sstevel@tonic-gate ret2:
23910Sstevel@tonic-gate 	big_finish(&aq);
23920Sstevel@tonic-gate ret1:
23930Sstevel@tonic-gate 	big_finish(&ap);
23940Sstevel@tonic-gate 
23950Sstevel@tonic-gate 	return (err);
23960Sstevel@tonic-gate }
23970Sstevel@tonic-gate 
23980Sstevel@tonic-gate 
23996557Sfr41279 BIG_ERR_CODE
24006557Sfr41279 big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
24016557Sfr41279     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
24026557Sfr41279     BIGNUM *p_rr, BIGNUM *q_rr)
24036557Sfr41279 {
24046557Sfr41279 	return (big_modexp_crt_ext(result, a, dmodpminus1, dmodqminus1,
24056557Sfr41279 	    p, q, pinvmodq, p_rr, q_rr, NULL));
24066557Sfr41279 }
24076557Sfr41279 
24086557Sfr41279 
24096557Sfr41279 static BIG_CHUNK_TYPE onearr[1] = {(BIG_CHUNK_TYPE)1};
24106557Sfr41279 BIGNUM big_One = {1, 1, 1, 0, onearr};
24116557Sfr41279 
24126557Sfr41279 static BIG_CHUNK_TYPE twoarr[1] = {(BIG_CHUNK_TYPE)2};
24136557Sfr41279 BIGNUM big_Two = {1, 1, 1, 0, twoarr};
24146557Sfr41279 
24156557Sfr41279 static BIG_CHUNK_TYPE fourarr[1] = {(BIG_CHUNK_TYPE)4};
24166557Sfr41279 static BIGNUM big_Four = {1, 1, 1, 0, fourarr};
24176557Sfr41279 
24180Sstevel@tonic-gate 
24190Sstevel@tonic-gate BIG_ERR_CODE
24200Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n)
24210Sstevel@tonic-gate {
24226557Sfr41279 	BIGNUM		*high, *low, *mid, *t;
24236557Sfr41279 	BIGNUM		t1, t2, t3, prod;
24246557Sfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
24256557Sfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
24266557Sfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
24276557Sfr41279 	BIG_CHUNK_TYPE	prodvalue[BIGTMPSIZE];
2428*8933Sopensolaris@drydog.com 	int		i, diff;
2429*8933Sopensolaris@drydog.com 	uint32_t	nbits, nrootbits, highbits;
24306557Sfr41279 	BIG_ERR_CODE	err;
24310Sstevel@tonic-gate 
24320Sstevel@tonic-gate 	nbits = big_numbits(n);
24330Sstevel@tonic-gate 
24340Sstevel@tonic-gate 	if ((err = big_init1(&t1, n->len + 1,
24350Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
24360Sstevel@tonic-gate 		return (err);
24370Sstevel@tonic-gate 	if ((err = big_init1(&t2, n->len + 1,
24380Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
24390Sstevel@tonic-gate 		goto ret1;
24400Sstevel@tonic-gate 	if ((err = big_init1(&t3, n->len + 1,
24410Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
24420Sstevel@tonic-gate 		goto ret2;
24430Sstevel@tonic-gate 	if ((err = big_init1(&prod, n->len + 1,
24440Sstevel@tonic-gate 	    prodvalue, arraysize(prodvalue))) != BIG_OK)
24450Sstevel@tonic-gate 		goto ret3;
24460Sstevel@tonic-gate 
24470Sstevel@tonic-gate 	nrootbits = (nbits + 1) / 2;
24486557Sfr41279 	t1.len = t2.len = t3.len = (nrootbits - 1) / BIG_CHUNK_SIZE + 1;
24490Sstevel@tonic-gate 	for (i = 0; i < t1.len; i++) {
24500Sstevel@tonic-gate 		t1.value[i] = 0;
24516557Sfr41279 		t2.value[i] = BIG_CHUNK_ALLBITS;
24520Sstevel@tonic-gate 	}
24536557Sfr41279 	highbits = nrootbits - BIG_CHUNK_SIZE * (t1.len - 1);
24546557Sfr41279 	if (highbits == BIG_CHUNK_SIZE) {
24556557Sfr41279 		t1.value[t1.len - 1] = BIG_CHUNK_HIGHBIT;
24566557Sfr41279 		t2.value[t2.len - 1] = BIG_CHUNK_ALLBITS;
24570Sstevel@tonic-gate 	} else {
24586557Sfr41279 		t1.value[t1.len - 1] = (BIG_CHUNK_TYPE)1 << (highbits - 1);
24590Sstevel@tonic-gate 		t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1;
24600Sstevel@tonic-gate 	}
24616557Sfr41279 
24620Sstevel@tonic-gate 	high = &t2;
24630Sstevel@tonic-gate 	low = &t1;
24640Sstevel@tonic-gate 	mid = &t3;
24650Sstevel@tonic-gate 
24666557Sfr41279 	if ((err = big_mul(&prod, high, high)) != BIG_OK) {
24670Sstevel@tonic-gate 		goto ret;
24686557Sfr41279 	}
24690Sstevel@tonic-gate 	diff = big_cmp_abs(&prod, n);
24700Sstevel@tonic-gate 	if (diff <= 0) {
24710Sstevel@tonic-gate 		err = big_copy(result, high);
24720Sstevel@tonic-gate 		goto ret;
24730Sstevel@tonic-gate 	}
24740Sstevel@tonic-gate 
24750Sstevel@tonic-gate 	(void) big_sub_pos(mid, high, low);
24766557Sfr41279 	while (big_cmp_abs(&big_One, mid) != 0) {
24770Sstevel@tonic-gate 		(void) big_add_abs(mid, high, low);
24780Sstevel@tonic-gate 		(void) big_half_pos(mid, mid);
24790Sstevel@tonic-gate 		if ((err = big_mul(&prod, mid, mid)) != BIG_OK)
24800Sstevel@tonic-gate 			goto ret;
24810Sstevel@tonic-gate 		diff = big_cmp_abs(&prod, n);
24820Sstevel@tonic-gate 		if (diff > 0) {
24830Sstevel@tonic-gate 			t = high;
24840Sstevel@tonic-gate 			high = mid;
24850Sstevel@tonic-gate 			mid = t;
24860Sstevel@tonic-gate 		} else if (diff < 0) {
24870Sstevel@tonic-gate 			t = low;
24880Sstevel@tonic-gate 			low = mid;
24890Sstevel@tonic-gate 			mid = t;
24900Sstevel@tonic-gate 		} else {
24910Sstevel@tonic-gate 			err = big_copy(result, low);
24920Sstevel@tonic-gate 			goto ret;
24930Sstevel@tonic-gate 		}
24940Sstevel@tonic-gate 		(void) big_sub_pos(mid, high, low);
24950Sstevel@tonic-gate 	}
24960Sstevel@tonic-gate 
24970Sstevel@tonic-gate 	err = big_copy(result, low);
24980Sstevel@tonic-gate ret:
24990Sstevel@tonic-gate 	if (prod.malloced) big_finish(&prod);
25000Sstevel@tonic-gate ret3:
25010Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
25020Sstevel@tonic-gate ret2:
25030Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
25040Sstevel@tonic-gate ret1:
25050Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
25060Sstevel@tonic-gate 
25070Sstevel@tonic-gate 	return (err);
25080Sstevel@tonic-gate }
25090Sstevel@tonic-gate 
25100Sstevel@tonic-gate 
25110Sstevel@tonic-gate BIG_ERR_CODE
25120Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm)
25130Sstevel@tonic-gate {
25146557Sfr41279 	BIGNUM		*t, *tmp2, *m, *n;
25156557Sfr41279 	BIGNUM		t1, t2, t3;
25166557Sfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
25176557Sfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
25186557Sfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
25196557Sfr41279 	int		len, err;
25200Sstevel@tonic-gate 
25210Sstevel@tonic-gate 	if (big_is_zero(nn) ||
25220Sstevel@tonic-gate 	    (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) {
25230Sstevel@tonic-gate 		*jac = 0;
25240Sstevel@tonic-gate 		return (BIG_OK);
25250Sstevel@tonic-gate 	}
25260Sstevel@tonic-gate 
25276557Sfr41279 	if (nn->len > mm->len) {
25286557Sfr41279 		len = nn->len;
25296557Sfr41279 	} else {
25306557Sfr41279 		len = mm->len;
25316557Sfr41279 	}
25320Sstevel@tonic-gate 
25330Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
25346557Sfr41279 	    t1value, arraysize(t1value))) != BIG_OK) {
25350Sstevel@tonic-gate 		return (err);
25366557Sfr41279 	}
25370Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
25386557Sfr41279 	    t2value, arraysize(t2value))) != BIG_OK) {
25390Sstevel@tonic-gate 		goto ret1;
25406557Sfr41279 	}
25410Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
25426557Sfr41279 	    t3value, arraysize(t3value))) != BIG_OK) {
25430Sstevel@tonic-gate 		goto ret2;
25446557Sfr41279 	}
25450Sstevel@tonic-gate 
25460Sstevel@tonic-gate 	n = &t1;
25470Sstevel@tonic-gate 	m = &t2;
25480Sstevel@tonic-gate 	tmp2 = &t3;
25490Sstevel@tonic-gate 
25500Sstevel@tonic-gate 	(void) big_copy(n, nn);
25510Sstevel@tonic-gate 	(void) big_copy(m, mm);
25520Sstevel@tonic-gate 
25530Sstevel@tonic-gate 	*jac = 1;
25546557Sfr41279 	while (big_cmp_abs(&big_One, m) != 0) {
25550Sstevel@tonic-gate 		if (big_is_zero(n)) {
25560Sstevel@tonic-gate 			*jac = 0;
25570Sstevel@tonic-gate 			goto ret;
25580Sstevel@tonic-gate 		}
25590Sstevel@tonic-gate 		if ((m->value[0] & 1) == 0) {
25600Sstevel@tonic-gate 			if (((n->value[0] & 7) == 3) ||
25616557Sfr41279 			    ((n->value[0] & 7) == 5))
25626557Sfr41279 				*jac = -*jac;
25630Sstevel@tonic-gate 			(void) big_half_pos(m, m);
25640Sstevel@tonic-gate 		} else if ((n->value[0] & 1) == 0) {
25650Sstevel@tonic-gate 			if (((m->value[0] & 7) == 3) ||
25666557Sfr41279 			    ((m->value[0] & 7) == 5))
25676557Sfr41279 				*jac = -*jac;
25680Sstevel@tonic-gate 			(void) big_half_pos(n, n);
25690Sstevel@tonic-gate 		} else {
25700Sstevel@tonic-gate 			if (((m->value[0] & 3) == 3) &&
25710Sstevel@tonic-gate 			    ((n->value[0] & 3) == 3)) {
25720Sstevel@tonic-gate 				*jac = -*jac;
25730Sstevel@tonic-gate 			}
25746557Sfr41279 			if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK) {
25750Sstevel@tonic-gate 				goto ret;
25766557Sfr41279 			}
25770Sstevel@tonic-gate 			t = tmp2;
25780Sstevel@tonic-gate 			tmp2 = m;
25790Sstevel@tonic-gate 			m = n;
25800Sstevel@tonic-gate 			n = t;
25810Sstevel@tonic-gate 		}
25820Sstevel@tonic-gate 	}
25830Sstevel@tonic-gate 	err = BIG_OK;
25840Sstevel@tonic-gate 
25850Sstevel@tonic-gate ret:
25860Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
25870Sstevel@tonic-gate ret2:
25880Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
25890Sstevel@tonic-gate ret1:
25900Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
25910Sstevel@tonic-gate 
25920Sstevel@tonic-gate 	return (err);
25930Sstevel@tonic-gate }
25940Sstevel@tonic-gate 
25950Sstevel@tonic-gate 
25960Sstevel@tonic-gate BIG_ERR_CODE
25970Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n)
25980Sstevel@tonic-gate {
2599*8933Sopensolaris@drydog.com 	int		i;
2600*8933Sopensolaris@drydog.com 	uint32_t	m, w;
26016557Sfr41279 	BIG_CHUNK_TYPE	bit;
26026557Sfr41279 	BIGNUM		ki, tmp, tmp2;
26036557Sfr41279 	BIG_CHUNK_TYPE	kivalue[BIGTMPSIZE];
26046557Sfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
26056557Sfr41279 	BIG_CHUNK_TYPE	tmp2value[BIGTMPSIZE];
26066557Sfr41279 	BIG_ERR_CODE	err;
26076557Sfr41279 
26086557Sfr41279 	if (big_cmp_abs(k, &big_One) == 0) {
26090Sstevel@tonic-gate 		(void) big_copy(Lk, p);
26106557Sfr41279 		(void) big_copy(Lkminus1, &big_Two);
26110Sstevel@tonic-gate 		return (BIG_OK);
26120Sstevel@tonic-gate 	}
26130Sstevel@tonic-gate 
26140Sstevel@tonic-gate 	if ((err = big_init1(&ki, k->len + 1,
26150Sstevel@tonic-gate 	    kivalue, arraysize(kivalue))) != BIG_OK)
26160Sstevel@tonic-gate 		return (err);
26170Sstevel@tonic-gate 
2618*8933Sopensolaris@drydog.com 	if ((err = big_init1(&tmp, 2 * n->len + 1,
26190Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
26200Sstevel@tonic-gate 		goto ret1;
26210Sstevel@tonic-gate 
26220Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, n->len,
26230Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
26240Sstevel@tonic-gate 		goto ret2;
26250Sstevel@tonic-gate 
26260Sstevel@tonic-gate 	m = big_numbits(k);
26276557Sfr41279 	ki.len = (m - 1) / BIG_CHUNK_SIZE + 1;
26286557Sfr41279 	w = (m - 1) / BIG_CHUNK_SIZE;
26296557Sfr41279 	bit = (BIG_CHUNK_TYPE)1 << ((m - 1) % BIG_CHUNK_SIZE);
26306557Sfr41279 	for (i = 0; i < ki.len; i++) {
26316557Sfr41279 		ki.value[i] = 0;
26326557Sfr41279 	}
26330Sstevel@tonic-gate 	ki.value[ki.len - 1] = bit;
26346557Sfr41279 	if (big_cmp_abs(k, &ki) != 0) {
26350Sstevel@tonic-gate 		(void) big_double(&ki, &ki);
26366557Sfr41279 	}
26370Sstevel@tonic-gate 	(void) big_sub_pos(&ki, &ki, k);
26380Sstevel@tonic-gate 
26390Sstevel@tonic-gate 	(void) big_copy(Lk, p);
26406557Sfr41279 	(void) big_copy(Lkminus1, &big_Two);
26410Sstevel@tonic-gate 
26420Sstevel@tonic-gate 	for (i = 0; i < m; i++) {
26436557Sfr41279 		if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK) {
26440Sstevel@tonic-gate 			goto ret;
26456557Sfr41279 		}
26460Sstevel@tonic-gate 		(void) big_add_abs(&tmp, &tmp, n);
26470Sstevel@tonic-gate 		(void) big_sub_pos(&tmp, &tmp, p);
26486557Sfr41279 		if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK) {
26490Sstevel@tonic-gate 			goto ret;
26506557Sfr41279 		}
26510Sstevel@tonic-gate 		if ((ki.value[w] & bit) != 0) {
26520Sstevel@tonic-gate 			if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) !=
26536557Sfr41279 			    BIG_OK) {
26540Sstevel@tonic-gate 				goto ret;
26556557Sfr41279 			}
26560Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
26576557Sfr41279 			(void) big_sub_pos(&tmp, &tmp, &big_Two);
26580Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) !=
26596557Sfr41279 			    BIG_OK) {
26600Sstevel@tonic-gate 				goto ret;
26616557Sfr41279 			}
26620Sstevel@tonic-gate 			(void) big_copy(Lk, &tmp2);
26630Sstevel@tonic-gate 		} else {
26646557Sfr41279 			if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK) {
26650Sstevel@tonic-gate 				goto ret;
26666557Sfr41279 			}
26670Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
26686557Sfr41279 			(void) big_sub_pos(&tmp, &tmp, &big_Two);
26696557Sfr41279 			if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK) {
26700Sstevel@tonic-gate 				goto ret;
26716557Sfr41279 			}
26720Sstevel@tonic-gate 			(void) big_copy(Lkminus1, &tmp2);
26730Sstevel@tonic-gate 		}
26740Sstevel@tonic-gate 		bit = bit >> 1;
26750Sstevel@tonic-gate 		if (bit == 0) {
26766557Sfr41279 			bit = BIG_CHUNK_HIGHBIT;
26770Sstevel@tonic-gate 			w--;
26780Sstevel@tonic-gate 		}
26790Sstevel@tonic-gate 	}
26800Sstevel@tonic-gate 
26810Sstevel@tonic-gate 	err = BIG_OK;
26820Sstevel@tonic-gate 
26830Sstevel@tonic-gate ret:
26840Sstevel@tonic-gate 	if (tmp2.malloced) big_finish(&tmp2);
26850Sstevel@tonic-gate ret2:
26860Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
26870Sstevel@tonic-gate ret1:
26880Sstevel@tonic-gate 	if (ki.malloced) big_finish(&ki);
26890Sstevel@tonic-gate 
26900Sstevel@tonic-gate 	return (err);
26910Sstevel@tonic-gate }
26920Sstevel@tonic-gate 
26930Sstevel@tonic-gate 
26940Sstevel@tonic-gate BIG_ERR_CODE
26956557Sfr41279 big_isprime_pos_ext(BIGNUM *n, big_modexp_ncp_info_t *info)
26960Sstevel@tonic-gate {
26976557Sfr41279 	BIGNUM		o, nminus1, tmp, Lkminus1, Lk;
26986557Sfr41279 	BIG_CHUNK_TYPE	ovalue[BIGTMPSIZE];
26996557Sfr41279 	BIG_CHUNK_TYPE	nminus1value[BIGTMPSIZE];
27006557Sfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
27016557Sfr41279 	BIG_CHUNK_TYPE	Lkminus1value[BIGTMPSIZE];
27026557Sfr41279 	BIG_CHUNK_TYPE	Lkvalue[BIGTMPSIZE];
27036557Sfr41279 	BIG_ERR_CODE	err;
27046557Sfr41279 	int		e, i, jac;
27056557Sfr41279 
27066557Sfr41279 	if (big_cmp_abs(n, &big_One) == 0) {
27070Sstevel@tonic-gate 		return (BIG_FALSE);
27086557Sfr41279 	}
27096557Sfr41279 	if (big_cmp_abs(n, &big_Two) == 0) {
27100Sstevel@tonic-gate 		return (BIG_TRUE);
27116557Sfr41279 	}
27126557Sfr41279 	if ((n->value[0] & 1) == 0) {
27130Sstevel@tonic-gate 		return (BIG_FALSE);
27146557Sfr41279 	}
27156557Sfr41279 
27166557Sfr41279 	if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) !=
27176557Sfr41279 	    BIG_OK) {
27180Sstevel@tonic-gate 		return (err);
27196557Sfr41279 	}
27200Sstevel@tonic-gate 
27210Sstevel@tonic-gate 	if ((err = big_init1(&nminus1, n->len,
27226557Sfr41279 	    nminus1value, arraysize(nminus1value))) != BIG_OK) {
27230Sstevel@tonic-gate 		goto ret1;
27246557Sfr41279 	}
27250Sstevel@tonic-gate 
27260Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len,
27276557Sfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
27280Sstevel@tonic-gate 		goto ret2;
27296557Sfr41279 	}
27300Sstevel@tonic-gate 
27310Sstevel@tonic-gate 	if ((err = big_init1(&Lkminus1, n->len,
27326557Sfr41279 	    Lkminus1value, arraysize(Lkminus1value))) != BIG_OK) {
27330Sstevel@tonic-gate 		goto ret3;
27346557Sfr41279 	}
27350Sstevel@tonic-gate 
27360Sstevel@tonic-gate 	if ((err = big_init1(&Lk, n->len,
27376557Sfr41279 	    Lkvalue, arraysize(Lkvalue))) != BIG_OK) {
27380Sstevel@tonic-gate 		goto ret4;
27396557Sfr41279 	}
27406557Sfr41279 
2741*8933Sopensolaris@drydog.com 	(void) big_sub_pos(&o, n, &big_One);	/* cannot fail */
27420Sstevel@tonic-gate 	(void) big_copy(&nminus1, &o);		/* cannot fail */
27430Sstevel@tonic-gate 	e = 0;
27440Sstevel@tonic-gate 	while ((o.value[0] & 1) == 0) {
27450Sstevel@tonic-gate 		e++;
27460Sstevel@tonic-gate 		(void) big_half_pos(&o, &o);  /* cannot fail */
27470Sstevel@tonic-gate 	}
27486557Sfr41279 	if ((err = big_modexp_ext(&tmp, &big_Two, &o, n, NULL, info)) !=
27496557Sfr41279 	    BIG_OK) {
27500Sstevel@tonic-gate 		goto ret;
27516557Sfr41279 	}
27526557Sfr41279 
27530Sstevel@tonic-gate 	i = 0;
27540Sstevel@tonic-gate 	while ((i < e) &&
27556557Sfr41279 	    (big_cmp_abs(&tmp, &big_One) != 0) &&
27560Sstevel@tonic-gate 	    (big_cmp_abs(&tmp, &nminus1) != 0)) {
27576557Sfr41279 		if ((err =
27586557Sfr41279 		    big_modexp_ext(&tmp, &tmp, &big_Two, n, NULL, info)) !=
27596557Sfr41279 		    BIG_OK)
27600Sstevel@tonic-gate 			goto ret;
27610Sstevel@tonic-gate 		i++;
27620Sstevel@tonic-gate 	}
27636557Sfr41279 
27640Sstevel@tonic-gate 	if (!((big_cmp_abs(&tmp, &nminus1) == 0) ||
27656557Sfr41279 	    ((i == 0) && (big_cmp_abs(&tmp, &big_One) == 0)))) {
27660Sstevel@tonic-gate 		err = BIG_FALSE;
27670Sstevel@tonic-gate 		goto ret;
27680Sstevel@tonic-gate 	}
27690Sstevel@tonic-gate 
27706557Sfr41279 	if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK) {
27710Sstevel@tonic-gate 		goto ret;
27726557Sfr41279 	}
27736557Sfr41279 
27746557Sfr41279 	if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK) {
27750Sstevel@tonic-gate 		goto ret;
27766557Sfr41279 	}
27770Sstevel@tonic-gate 	if (big_cmp_abs(&tmp, n) == 0) {
27780Sstevel@tonic-gate 		err = BIG_FALSE;
27790Sstevel@tonic-gate 		goto ret;
27800Sstevel@tonic-gate 	}
27810Sstevel@tonic-gate 
27826557Sfr41279 	(void) big_copy(&o, &big_Two);
27830Sstevel@tonic-gate 	do {
27846557Sfr41279 		(void) big_add_abs(&o, &o, &big_One);
27856557Sfr41279 		if ((err = big_mul(&tmp, &o, &o)) != BIG_OK) {
27860Sstevel@tonic-gate 			goto ret;
27876557Sfr41279 		}
27886557Sfr41279 		(void) big_sub_pos(&tmp, &tmp, &big_Four);
27896557Sfr41279 		if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK) {
27900Sstevel@tonic-gate 			goto ret;
27916557Sfr41279 		}
27920Sstevel@tonic-gate 	} while (jac != -1);
27930Sstevel@tonic-gate 
27946557Sfr41279 	(void) big_add_abs(&tmp, n, &big_One);
27956557Sfr41279 	if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK) {
27960Sstevel@tonic-gate 		goto ret;
27976557Sfr41279 	}
27986557Sfr41279 
27996557Sfr41279 	if ((big_cmp_abs(&Lkminus1, &o) == 0) &&
28006557Sfr41279 	    (big_cmp_abs(&Lk, &big_Two) == 0)) {
28010Sstevel@tonic-gate 		err = BIG_TRUE;
28026557Sfr41279 	} else {
28036557Sfr41279 		err = BIG_FALSE;
28046557Sfr41279 	}
28050Sstevel@tonic-gate 
28060Sstevel@tonic-gate ret:
28070Sstevel@tonic-gate 	if (Lk.malloced) big_finish(&Lk);
28080Sstevel@tonic-gate ret4:
28090Sstevel@tonic-gate 	if (Lkminus1.malloced) big_finish(&Lkminus1);
28100Sstevel@tonic-gate ret3:
28110Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
28120Sstevel@tonic-gate ret2:
28130Sstevel@tonic-gate 	if (nminus1.malloced) big_finish(&nminus1);
28140Sstevel@tonic-gate ret1:
28150Sstevel@tonic-gate 	if (o.malloced) big_finish(&o);
28160Sstevel@tonic-gate 
28170Sstevel@tonic-gate 	return (err);
28180Sstevel@tonic-gate }
28190Sstevel@tonic-gate 
28200Sstevel@tonic-gate 
28216557Sfr41279 BIG_ERR_CODE
28226557Sfr41279 big_isprime_pos(BIGNUM *n)
28236557Sfr41279 {
28246557Sfr41279 	return (big_isprime_pos_ext(n, NULL));
28256557Sfr41279 }
28266557Sfr41279 
28276557Sfr41279 
28280Sstevel@tonic-gate #define	SIEVESIZE 1000
28290Sstevel@tonic-gate 
28300Sstevel@tonic-gate 
28310Sstevel@tonic-gate BIG_ERR_CODE
28326557Sfr41279 big_nextprime_pos_ext(BIGNUM *result, BIGNUM *n, big_modexp_ncp_info_t *info)
28330Sstevel@tonic-gate {
2834*8933Sopensolaris@drydog.com 	static const uint32_t smallprimes[] = {
2835*8933Sopensolaris@drydog.com 	    3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
2836*8933Sopensolaris@drydog.com 	    51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97 };
28376557Sfr41279 	BIG_ERR_CODE	err;
28386557Sfr41279 	int		sieve[SIEVESIZE];
28396557Sfr41279 	int		i;
28406557Sfr41279 	uint32_t	off, p;
28416557Sfr41279 
28426557Sfr41279 	if ((err = big_copy(result, n)) != BIG_OK) {
28430Sstevel@tonic-gate 		return (err);
28446557Sfr41279 	}
28450Sstevel@tonic-gate 	result->value[0] |= 1;
28461027Srobinson 	/* CONSTCOND */
28470Sstevel@tonic-gate 	while (1) {
28480Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0;
28490Sstevel@tonic-gate 		for (i = 0;
28506557Sfr41279 		    i < sizeof (smallprimes) / sizeof (smallprimes[0]); i++) {
28510Sstevel@tonic-gate 			p = smallprimes[i];
28526557Sfr41279 			off = big_modhalf_pos(result, p);
28530Sstevel@tonic-gate 			off = p - off;
28546557Sfr41279 			if ((off % 2) == 1) {
28556557Sfr41279 				off = off + p;
28566557Sfr41279 			}
28576557Sfr41279 			off = off / 2;
28580Sstevel@tonic-gate 			while (off < SIEVESIZE) {
28590Sstevel@tonic-gate 				sieve[off] = 1;
28600Sstevel@tonic-gate 				off = off + p;
28610Sstevel@tonic-gate 			}
28620Sstevel@tonic-gate 		}
28630Sstevel@tonic-gate 
28640Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) {
28650Sstevel@tonic-gate 			if (sieve[i] == 0) {
28666557Sfr41279 				err = big_isprime_pos_ext(result, info);
28670Sstevel@tonic-gate 				if (err != BIG_FALSE) {
28686557Sfr41279 					if (err != BIG_TRUE) {
28690Sstevel@tonic-gate 						return (err);
28706557Sfr41279 					} else {
28716557Sfr41279 						goto out;
28726557Sfr41279 					}
28730Sstevel@tonic-gate 				}
28740Sstevel@tonic-gate 
28750Sstevel@tonic-gate 			}
28766557Sfr41279 			if ((err = big_add_abs(result, result, &big_Two)) !=
28776557Sfr41279 			    BIG_OK) {
28780Sstevel@tonic-gate 				return (err);
28796557Sfr41279 			}
28800Sstevel@tonic-gate 		}
28810Sstevel@tonic-gate 	}
28826557Sfr41279 
28836557Sfr41279 out:
28846557Sfr41279 	return (BIG_OK);
28856557Sfr41279 }
28866557Sfr41279 
28876557Sfr41279 
28886557Sfr41279 BIG_ERR_CODE
28896557Sfr41279 big_nextprime_pos(BIGNUM *result, BIGNUM *n)
28906557Sfr41279 {
28916557Sfr41279 	return (big_nextprime_pos_ext(result, n, NULL));
28920Sstevel@tonic-gate }
28930Sstevel@tonic-gate 
28940Sstevel@tonic-gate 
28950Sstevel@tonic-gate BIG_ERR_CODE
28960Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n)
28970Sstevel@tonic-gate {
28980Sstevel@tonic-gate 	BIG_ERR_CODE err;
28990Sstevel@tonic-gate 
29000Sstevel@tonic-gate 
29010Sstevel@tonic-gate 	if ((err = big_copy(result, n)) != BIG_OK)
29020Sstevel@tonic-gate 		return (err);
29030Sstevel@tonic-gate 	result->value[0] |= 1;
29046557Sfr41279 	while ((err = big_isprime_pos_ext(result, NULL)) != BIG_TRUE) {
29050Sstevel@tonic-gate 		if (err != BIG_FALSE)
29060Sstevel@tonic-gate 			return (err);
29076557Sfr41279 		if ((err = big_add_abs(result, result, &big_Two)) != BIG_OK)
29080Sstevel@tonic-gate 			return (err);
29090Sstevel@tonic-gate 	}
29100Sstevel@tonic-gate 	return (BIG_OK);
29110Sstevel@tonic-gate }
29120Sstevel@tonic-gate 
29130Sstevel@tonic-gate 
29140Sstevel@tonic-gate /*
29150Sstevel@tonic-gate  * given m and e, computes the rest in the equation
29160Sstevel@tonic-gate  * gcd(m, e) = cm * m + ce * e
29170Sstevel@tonic-gate  */
29180Sstevel@tonic-gate BIG_ERR_CODE
29190Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e)
29200Sstevel@tonic-gate {
29216557Sfr41279 	BIGNUM		*xi, *ri, *riminus1, *riminus2, *t;
29226557Sfr41279 	BIGNUM		*vmi, *vei, *vmiminus1, *veiminus1;
29236557Sfr41279 	BIGNUM		t1, t2, t3, t4, t5, t6, t7, t8, tmp;
29246557Sfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
29256557Sfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
29266557Sfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
29276557Sfr41279 	BIG_CHUNK_TYPE	t4value[BIGTMPSIZE];
29286557Sfr41279 	BIG_CHUNK_TYPE	t5value[BIGTMPSIZE];
29296557Sfr41279 	BIG_CHUNK_TYPE	t6value[BIGTMPSIZE];
29306557Sfr41279 	BIG_CHUNK_TYPE	t7value[BIGTMPSIZE];
29316557Sfr41279 	BIG_CHUNK_TYPE	t8value[BIGTMPSIZE];
29326557Sfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
29336557Sfr41279 	BIG_ERR_CODE	err;
29346557Sfr41279 	int		len;
29356557Sfr41279 
29366557Sfr41279 	if (big_cmp_abs(m, e) >= 0) {
29376557Sfr41279 		len = m->len;
29386557Sfr41279 	} else {
29396557Sfr41279 		len = e->len;
29406557Sfr41279 	}
29410Sstevel@tonic-gate 
29420Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
29436557Sfr41279 	    t1value, arraysize(t1value))) != BIG_OK) {
29440Sstevel@tonic-gate 		return (err);
29456557Sfr41279 	}
29460Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
29476557Sfr41279 	    t2value, arraysize(t2value))) != BIG_OK) {
29486557Sfr41279 		goto ret1;
29496557Sfr41279 	}
29500Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
29516557Sfr41279 	    t3value, arraysize(t3value))) != BIG_OK) {
29526557Sfr41279 		goto ret2;
29536557Sfr41279 	}
29540Sstevel@tonic-gate 	if ((err = big_init1(&t4, len,
29556557Sfr41279 	    t4value, arraysize(t3value))) != BIG_OK) {
29566557Sfr41279 		goto ret3;
29576557Sfr41279 	}
29580Sstevel@tonic-gate 	if ((err = big_init1(&t5, len,
29596557Sfr41279 	    t5value, arraysize(t5value))) != BIG_OK) {
29606557Sfr41279 		goto ret4;
29616557Sfr41279 	}
29620Sstevel@tonic-gate 	if ((err = big_init1(&t6, len,
29636557Sfr41279 	    t6value, arraysize(t6value))) != BIG_OK) {
29646557Sfr41279 		goto ret5;
29656557Sfr41279 	}
29660Sstevel@tonic-gate 	if ((err = big_init1(&t7, len,
29676557Sfr41279 	    t7value, arraysize(t7value))) != BIG_OK) {
29686557Sfr41279 		goto ret6;
29696557Sfr41279 	}
29700Sstevel@tonic-gate 	if ((err = big_init1(&t8, len,
29716557Sfr41279 	    t8value, arraysize(t8value))) != BIG_OK) {
29726557Sfr41279 		goto ret7;
29736557Sfr41279 	}
29740Sstevel@tonic-gate 
29750Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * len,
29766557Sfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
29770Sstevel@tonic-gate 		goto ret8;
29786557Sfr41279 	}
29790Sstevel@tonic-gate 
29800Sstevel@tonic-gate 	ri = &t1;
29810Sstevel@tonic-gate 	ri->value[0] = 1;
29820Sstevel@tonic-gate 	ri->len = 1;
29830Sstevel@tonic-gate 	xi = &t2;
29840Sstevel@tonic-gate 	riminus1 = &t3;
29850Sstevel@tonic-gate 	riminus2 = &t4;
29860Sstevel@tonic-gate 	vmi = &t5;
29870Sstevel@tonic-gate 	vei = &t6;
29880Sstevel@tonic-gate 	vmiminus1 = &t7;
29890Sstevel@tonic-gate 	veiminus1 = &t8;
29900Sstevel@tonic-gate 
29916557Sfr41279 	(void) big_copy(vmiminus1, &big_One);
29926557Sfr41279 	(void) big_copy(vmi, &big_One);
29936557Sfr41279 	(void) big_copy(veiminus1, &big_One);
29946557Sfr41279 	(void) big_copy(xi, &big_One);
29950Sstevel@tonic-gate 	vei->len = 1;
29960Sstevel@tonic-gate 	vei->value[0] = 0;
29970Sstevel@tonic-gate 
29980Sstevel@tonic-gate 	(void) big_copy(riminus1, m);
29990Sstevel@tonic-gate 	(void) big_copy(ri, e);
30000Sstevel@tonic-gate 
30010Sstevel@tonic-gate 	while (!big_is_zero(ri)) {
30020Sstevel@tonic-gate 		t = riminus2;
30030Sstevel@tonic-gate 		riminus2 = riminus1;
30040Sstevel@tonic-gate 		riminus1 = ri;
30050Sstevel@tonic-gate 		ri = t;
30066557Sfr41279 		if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK) {
30070Sstevel@tonic-gate 			goto ret;
30086557Sfr41279 		}
30096557Sfr41279 		if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK) {
30100Sstevel@tonic-gate 			goto ret;
30116557Sfr41279 		}
30120Sstevel@tonic-gate 		t = vmiminus1;
30130Sstevel@tonic-gate 		vmiminus1 = vmi;
30140Sstevel@tonic-gate 		vmi = t;
30156557Sfr41279 		if ((err = big_mul(&tmp, vei, xi)) != BIG_OK) {
30160Sstevel@tonic-gate 			goto ret;
30176557Sfr41279 		}
30186557Sfr41279 		if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK) {
30190Sstevel@tonic-gate 			goto ret;
30206557Sfr41279 		}
30210Sstevel@tonic-gate 		t = veiminus1;
30220Sstevel@tonic-gate 		veiminus1 = vei;
30230Sstevel@tonic-gate 		vei = t;
30246557Sfr41279 		if ((err = big_div_pos(xi, ri, riminus2, riminus1)) !=
30256557Sfr41279 		    BIG_OK) {
30260Sstevel@tonic-gate 			goto ret;
30276557Sfr41279 		}
30280Sstevel@tonic-gate 	}
30296557Sfr41279 	if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK)) {
30300Sstevel@tonic-gate 		goto ret;
30316557Sfr41279 	}
30326557Sfr41279 	if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK)) {
30330Sstevel@tonic-gate 		goto ret;
30346557Sfr41279 	}
30356557Sfr41279 	if (ce != NULL) {
30360Sstevel@tonic-gate 		err = big_copy(ce, vei);
30376557Sfr41279 	}
30380Sstevel@tonic-gate ret:
30390Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
30400Sstevel@tonic-gate ret8:
30410Sstevel@tonic-gate 	if (t8.malloced) big_finish(&t8);
30420Sstevel@tonic-gate ret7:
30430Sstevel@tonic-gate 	if (t7.malloced) big_finish(&t7);
30440Sstevel@tonic-gate ret6:
30450Sstevel@tonic-gate 	if (t6.malloced) big_finish(&t6);
30460Sstevel@tonic-gate ret5:
30470Sstevel@tonic-gate 	if (t5.malloced) big_finish(&t5);
30480Sstevel@tonic-gate ret4:
30490Sstevel@tonic-gate 	if (t4.malloced) big_finish(&t4);
30500Sstevel@tonic-gate ret3:
30510Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
30520Sstevel@tonic-gate ret2:
30530Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
30540Sstevel@tonic-gate ret1:
30550Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
30560Sstevel@tonic-gate 
30570Sstevel@tonic-gate 	return (err);
30580Sstevel@tonic-gate }
3059