xref: /titanic_53/usr/src/common/bignum/bignumimpl.c (revision 8475e04352e630e4bd0f59a283286ee2475a14ce)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5b60f2a0bSfr41279  * Common Development and Distribution License (the "License").
6b60f2a0bSfr41279  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*8475e043SDan OpenSolaris Anderson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Configuration guide
287c478bd9Sstevel@tonic-gate  * -------------------
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  * There are 4 preprocessor symbols used to configure the bignum
317c478bd9Sstevel@tonic-gate  * implementation.  This file contains no logic to configure based on
327c478bd9Sstevel@tonic-gate  * processor; we leave that to the Makefiles to specify.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * USE_FLOATING_POINT
357c478bd9Sstevel@tonic-gate  *   Meaning: There is support for a fast floating-point implementation of
367c478bd9Sstevel@tonic-gate  *   Montgomery multiply.
377c478bd9Sstevel@tonic-gate  *
387c478bd9Sstevel@tonic-gate  * PSR_MUL
397c478bd9Sstevel@tonic-gate  *   Meaning: There are processor-specific versions of the low level
407c478bd9Sstevel@tonic-gate  *   functions to implement big_mul.  Those functions are: big_mul_set_vec,
417c478bd9Sstevel@tonic-gate  *   big_mul_add_vec, big_mul_vec, and big_sqr_vec.  PSR_MUL implies support
427c478bd9Sstevel@tonic-gate  *   for all 4 functions.  You cannot pick and choose which subset of these
437c478bd9Sstevel@tonic-gate  *   functions to support; that would lead to a rat's nest of #ifdefs.
447c478bd9Sstevel@tonic-gate  *
457c478bd9Sstevel@tonic-gate  * HWCAP
467c478bd9Sstevel@tonic-gate  *   Meaning: Call multiply support functions through a function pointer.
47*8475e043SDan OpenSolaris Anderson  *   On x86, there are multiple implementations for different hardware
487c478bd9Sstevel@tonic-gate  *   capabilities, such as MMX, SSE2, etc.  Tests are made at run-time, when
497c478bd9Sstevel@tonic-gate  *   a function is first used.  So, the support functions are called through
507c478bd9Sstevel@tonic-gate  *   a function pointer.  There is no need for that on Sparc, because there
517c478bd9Sstevel@tonic-gate  *   is only one implementation; support functions are called directly.
527c478bd9Sstevel@tonic-gate  *   Later, if there were some new VIS instruction, or something, and a
537c478bd9Sstevel@tonic-gate  *   run-time test were needed, rather than variant kernel modules and
547c478bd9Sstevel@tonic-gate  *   libraries, then HWCAP would be defined for Sparc, as well.
557c478bd9Sstevel@tonic-gate  *
567c478bd9Sstevel@tonic-gate  * UMUL64
577c478bd9Sstevel@tonic-gate  *   Meaning: It is safe to use generic C code that assumes the existence
587c478bd9Sstevel@tonic-gate  *   of a 32 x 32 --> 64 bit unsigned multiply.  If this is not defined,
597c478bd9Sstevel@tonic-gate  *   then the generic code for big_mul_add_vec() must necessarily be very slow,
607c478bd9Sstevel@tonic-gate  *   because it must fall back to using 16 x 16 --> 32 bit multiplication.
617c478bd9Sstevel@tonic-gate  *
627c478bd9Sstevel@tonic-gate  */
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 
65*8475e043SDan OpenSolaris Anderson #include <sys/types.h>
66*8475e043SDan OpenSolaris Anderson #include "bignum.h"
67*8475e043SDan OpenSolaris Anderson 
687c478bd9Sstevel@tonic-gate #ifdef	_KERNEL
69b60f2a0bSfr41279 #include <sys/ddi.h>
70b60f2a0bSfr41279 #include <sys/mdesc.h>
71b60f2a0bSfr41279 #include <sys/crypto/common.h>
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
747c478bd9Sstevel@tonic-gate #include <sys/param.h>
757c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
767c478bd9Sstevel@tonic-gate 
77*8475e043SDan OpenSolaris Anderson #else
78*8475e043SDan OpenSolaris Anderson #include <stdlib.h>
79*8475e043SDan OpenSolaris Anderson #include <stdio.h>
80*8475e043SDan OpenSolaris Anderson #include <assert.h>
81*8475e043SDan OpenSolaris Anderson #define	ASSERT	assert
82*8475e043SDan OpenSolaris Anderson #endif	/* _KERNEL */
83*8475e043SDan OpenSolaris Anderson 
84*8475e043SDan OpenSolaris Anderson #ifdef	_LP64 /* truncate 64-bit size_t to 32-bits */
85*8475e043SDan OpenSolaris Anderson #define	UI32(ui)	((uint32_t)ui)
86*8475e043SDan OpenSolaris Anderson #else /* size_t already 32-bits */
87*8475e043SDan OpenSolaris Anderson #define	UI32(ui)	(ui)
88*8475e043SDan OpenSolaris Anderson #endif
89*8475e043SDan OpenSolaris Anderson 
90*8475e043SDan OpenSolaris Anderson 
91*8475e043SDan OpenSolaris Anderson #ifdef	_KERNEL
927c478bd9Sstevel@tonic-gate #define	big_malloc(size)	kmem_alloc(size, KM_NOSLEEP)
937c478bd9Sstevel@tonic-gate #define	big_free(ptr, size)	kmem_free(ptr, size)
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate void *
967c478bd9Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	void *rv;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	rv = kmem_alloc(newsize, KM_NOSLEEP);
1017c478bd9Sstevel@tonic-gate 	if (rv != NULL)
1027c478bd9Sstevel@tonic-gate 		bcopy(from, rv, oldsize);
1037c478bd9Sstevel@tonic-gate 	kmem_free(from, oldsize);
1047c478bd9Sstevel@tonic-gate 	return (rv);
1057c478bd9Sstevel@tonic-gate }
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate #else	/* _KERNEL */
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate #ifndef MALLOC_DEBUG
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate #define	big_malloc(size)	malloc(size)
1127c478bd9Sstevel@tonic-gate #define	big_free(ptr, size)	free(ptr)
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate #else
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate void
1177c478bd9Sstevel@tonic-gate big_free(void *ptr, size_t size)
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate 	printf("freed %d bytes at %p\n", size, ptr);
1207c478bd9Sstevel@tonic-gate 	free(ptr);
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate void *
1247c478bd9Sstevel@tonic-gate big_malloc(size_t size)
1257c478bd9Sstevel@tonic-gate {
1267c478bd9Sstevel@tonic-gate 	void *rv;
1277c478bd9Sstevel@tonic-gate 	rv = malloc(size);
1287c478bd9Sstevel@tonic-gate 	printf("malloced %d bytes, addr:%p\n", size, rv);
1297c478bd9Sstevel@tonic-gate 	return (rv);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate #endif /* MALLOC_DEBUG */
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate #define	big_realloc(x, y, z) realloc((x), (z))
1347c478bd9Sstevel@tonic-gate 
135*8475e043SDan OpenSolaris Anderson 
136*8475e043SDan OpenSolaris Anderson /*
137*8475e043SDan OpenSolaris Anderson  * printbignum()
138*8475e043SDan OpenSolaris Anderson  * Print a BIGNUM type to stdout.
139*8475e043SDan OpenSolaris Anderson  */
1407c478bd9Sstevel@tonic-gate void
1417c478bd9Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a)
1427c478bd9Sstevel@tonic-gate {
1437c478bd9Sstevel@tonic-gate 	int i;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	(void) printf("\n%s\n%d\n", aname, a->sign*a->len);
1467c478bd9Sstevel@tonic-gate 	for (i = a->len - 1; i >= 0; i--) {
147b60f2a0bSfr41279 #ifdef BIGNUM_CHUNK_32
1487c478bd9Sstevel@tonic-gate 		(void) printf("%08x ", a->value[i]);
149*8475e043SDan OpenSolaris Anderson 		if (((i & (BITSINBYTE - 1)) == 0) && (i != 0)) {
1507c478bd9Sstevel@tonic-gate 			(void) printf("\n");
1517c478bd9Sstevel@tonic-gate 		}
152b60f2a0bSfr41279 #else
153b60f2a0bSfr41279 		(void) printf("%08x %08x ", (uint32_t)((a->value[i]) >> 32),
154b60f2a0bSfr41279 		    (uint32_t)((a->value[i]) & 0xffffffff));
155*8475e043SDan OpenSolaris Anderson 		if (((i & 3) == 0) && (i != 0)) { /* end of this chunk */
156b60f2a0bSfr41279 			(void) printf("\n");
157b60f2a0bSfr41279 		}
158b60f2a0bSfr41279 #endif
159b60f2a0bSfr41279 	}
1607c478bd9Sstevel@tonic-gate 	(void) printf("\n");
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate #endif	/* _KERNEL */
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 
166*8475e043SDan OpenSolaris Anderson /*
167*8475e043SDan OpenSolaris Anderson  * big_init()
168*8475e043SDan OpenSolaris Anderson  * Initialize and allocate memory for a BIGNUM type.
169*8475e043SDan OpenSolaris Anderson  *
170*8475e043SDan OpenSolaris Anderson  * big_init(number, size) is equivalent to big_init1(number, size, NULL, 0)
171*8475e043SDan OpenSolaris Anderson  *
172*8475e043SDan OpenSolaris Anderson  * Note: call big_finish() to free memory allocated by big_init().
173*8475e043SDan OpenSolaris Anderson  *
174*8475e043SDan OpenSolaris Anderson  * Input:
175*8475e043SDan OpenSolaris Anderson  * number	Uninitialized memory for BIGNUM
176*8475e043SDan OpenSolaris Anderson  * size		Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM
177*8475e043SDan OpenSolaris Anderson  *
178*8475e043SDan OpenSolaris Anderson  * Output:
179*8475e043SDan OpenSolaris Anderson  * number	Initialized BIGNUM
180*8475e043SDan OpenSolaris Anderson  *
181*8475e043SDan OpenSolaris Anderson  * Return BIG_OK on success or BIG_NO_MEM for an allocation error.
182*8475e043SDan OpenSolaris Anderson  */
1837c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1847c478bd9Sstevel@tonic-gate big_init(BIGNUM *number, int size)
1857c478bd9Sstevel@tonic-gate {
186*8475e043SDan OpenSolaris Anderson 	number->value = big_malloc(BIGNUM_WORDSIZE * size);
1877c478bd9Sstevel@tonic-gate 	if (number->value == NULL) {
1887c478bd9Sstevel@tonic-gate 		return (BIG_NO_MEM);
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 	number->size = size;
1917c478bd9Sstevel@tonic-gate 	number->len = 0;
1927c478bd9Sstevel@tonic-gate 	number->sign = 1;
1937c478bd9Sstevel@tonic-gate 	number->malloced = 1;
1947c478bd9Sstevel@tonic-gate 	return (BIG_OK);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
197*8475e043SDan OpenSolaris Anderson 
198*8475e043SDan OpenSolaris Anderson /*
199*8475e043SDan OpenSolaris Anderson  * big_init1()
200*8475e043SDan OpenSolaris Anderson  * Initialize and, if needed, allocate memory for a BIGNUM type.
201*8475e043SDan OpenSolaris Anderson  * Use the buffer passed, buf, if any, instad of allocating memory
202*8475e043SDan OpenSolaris Anderson  * if it's at least "size" bytes.
203*8475e043SDan OpenSolaris Anderson  *
204*8475e043SDan OpenSolaris Anderson  * Note: call big_finish() to free memory allocated by big_init().
205*8475e043SDan OpenSolaris Anderson  *
206*8475e043SDan OpenSolaris Anderson  * Input:
207*8475e043SDan OpenSolaris Anderson  * number	Uninitialized memory for BIGNUM
208*8475e043SDan OpenSolaris Anderson  * size		Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM
209*8475e043SDan OpenSolaris Anderson  * buf		Buffer for storing a BIGNUM.
210*8475e043SDan OpenSolaris Anderson  *		If NULL, big_init1() will allocate a buffer
211*8475e043SDan OpenSolaris Anderson  * bufsize	Size, in BIG_CHUNK_SIZE_bit words, of buf
212*8475e043SDan OpenSolaris Anderson  *
213*8475e043SDan OpenSolaris Anderson  * Output:
214*8475e043SDan OpenSolaris Anderson  * number	Initialized BIGNUM
215*8475e043SDan OpenSolaris Anderson  *
216*8475e043SDan OpenSolaris Anderson  * Return BIG_OK on success or BIG_NO_MEM for an allocation error.
217*8475e043SDan OpenSolaris Anderson  */
2187c478bd9Sstevel@tonic-gate BIG_ERR_CODE
219b60f2a0bSfr41279 big_init1(BIGNUM *number, int size, BIG_CHUNK_TYPE *buf, int bufsize)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (size > bufsize)) {
222*8475e043SDan OpenSolaris Anderson 		number->value = big_malloc(BIGNUM_WORDSIZE * size);
2237c478bd9Sstevel@tonic-gate 		if (number->value == NULL) {
2247c478bd9Sstevel@tonic-gate 			return (BIG_NO_MEM);
2257c478bd9Sstevel@tonic-gate 		}
2267c478bd9Sstevel@tonic-gate 		number->size = size;
2277c478bd9Sstevel@tonic-gate 		number->malloced = 1;
2287c478bd9Sstevel@tonic-gate 	} else {
2297c478bd9Sstevel@tonic-gate 		number->value = buf;
2307c478bd9Sstevel@tonic-gate 		number->size = bufsize;
2317c478bd9Sstevel@tonic-gate 		number->malloced = 0;
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 	number->len = 0;
2347c478bd9Sstevel@tonic-gate 	number->sign = 1;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	return (BIG_OK);
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate 
239*8475e043SDan OpenSolaris Anderson 
240*8475e043SDan OpenSolaris Anderson /*
241*8475e043SDan OpenSolaris Anderson  * big_finish()
242*8475e043SDan OpenSolaris Anderson  * Free memory, if any, allocated by big_init() or big_init1().
243*8475e043SDan OpenSolaris Anderson  */
2447c478bd9Sstevel@tonic-gate void
2457c478bd9Sstevel@tonic-gate big_finish(BIGNUM *number)
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate 	if (number->malloced == 1) {
248*8475e043SDan OpenSolaris Anderson 		big_free(number->value, BIGNUM_WORDSIZE * number->size);
2497c478bd9Sstevel@tonic-gate 		number->malloced = 0;
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
253b60f2a0bSfr41279 
2547c478bd9Sstevel@tonic-gate /*
255b60f2a0bSfr41279  * bn->size should be at least
256*8475e043SDan OpenSolaris Anderson  * (len + BIGNUM_WORDSIZE - 1) / BIGNUM_WORDSIZE bytes
2577c478bd9Sstevel@tonic-gate  * converts from byte-big-endian format to bignum format (words in
2587c478bd9Sstevel@tonic-gate  * little endian order, but bytes within the words big endian)
2597c478bd9Sstevel@tonic-gate  */
2607c478bd9Sstevel@tonic-gate void
2617c478bd9Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len)
2627c478bd9Sstevel@tonic-gate {
263*8475e043SDan OpenSolaris Anderson 	int		i, j;
264*8475e043SDan OpenSolaris Anderson 	uint32_t	offs;
265*8475e043SDan OpenSolaris Anderson 	const uint32_t	slen = UI32(len);
266b60f2a0bSfr41279 	BIG_CHUNK_TYPE	word;
2677c478bd9Sstevel@tonic-gate 	uchar_t		*knwordp;
2687c478bd9Sstevel@tonic-gate 
269*8475e043SDan OpenSolaris Anderson 	if (slen == 0) {
270*8475e043SDan OpenSolaris Anderson 		bn->len = 1;
271*8475e043SDan OpenSolaris Anderson 		bn->value[0] = 0;
272*8475e043SDan OpenSolaris Anderson 		return;
273*8475e043SDan OpenSolaris Anderson 	}
274b60f2a0bSfr41279 
275*8475e043SDan OpenSolaris Anderson 	offs = slen % BIGNUM_WORDSIZE;
276*8475e043SDan OpenSolaris Anderson 	bn->len = slen / BIGNUM_WORDSIZE;
277*8475e043SDan OpenSolaris Anderson 
278*8475e043SDan OpenSolaris Anderson 	for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) {
279*8475e043SDan OpenSolaris Anderson 		knwordp = &(kn[slen - BIGNUM_WORDSIZE * (i + 1)]);
2807c478bd9Sstevel@tonic-gate 		word = knwordp[0];
281*8475e043SDan OpenSolaris Anderson 		for (j = 1; j < BIGNUM_WORDSIZE; j++) {
282*8475e043SDan OpenSolaris Anderson 			word = (word << BITSINBYTE) + knwordp[j];
2837c478bd9Sstevel@tonic-gate 		}
2847c478bd9Sstevel@tonic-gate 		bn->value[i] = word;
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 	if (offs > 0) {
2877c478bd9Sstevel@tonic-gate 		word = kn[0];
288*8475e043SDan OpenSolaris Anderson 		for (i = 1; i < offs; i++) word = (word << BITSINBYTE) + kn[i];
2897c478bd9Sstevel@tonic-gate 		bn->value[bn->len++] = word;
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 	while ((bn->len > 1) && (bn->value[bn->len - 1] == 0)) {
2927c478bd9Sstevel@tonic-gate 		bn->len --;
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
296*8475e043SDan OpenSolaris Anderson 
2977c478bd9Sstevel@tonic-gate /*
2987c478bd9Sstevel@tonic-gate  * copies the least significant len bytes if
299*8475e043SDan OpenSolaris Anderson  * len < bn->len * BIGNUM_WORDSIZE
3007c478bd9Sstevel@tonic-gate  * converts from bignum format to byte-big-endian format.
301b60f2a0bSfr41279  * bignum format is words of type  BIG_CHUNK_TYPE in little endian order.
3027c478bd9Sstevel@tonic-gate  */
3037c478bd9Sstevel@tonic-gate void
3047c478bd9Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len)
3057c478bd9Sstevel@tonic-gate {
306*8475e043SDan OpenSolaris Anderson 	int		i, j;
307*8475e043SDan OpenSolaris Anderson 	uint32_t	offs;
308*8475e043SDan OpenSolaris Anderson 	const uint32_t	slen = UI32(len);
309b60f2a0bSfr41279 	BIG_CHUNK_TYPE	word;
3107c478bd9Sstevel@tonic-gate 
311*8475e043SDan OpenSolaris Anderson 	if (len < BIGNUM_WORDSIZE * bn->len) {
312*8475e043SDan OpenSolaris Anderson 		for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) {
3137c478bd9Sstevel@tonic-gate 			word = bn->value[i];
314*8475e043SDan OpenSolaris Anderson 			for (j = 0; j < BIGNUM_WORDSIZE; j++) {
315*8475e043SDan OpenSolaris Anderson 				kn[slen - BIGNUM_WORDSIZE * i - j - 1] =
3167c478bd9Sstevel@tonic-gate 				    word & 0xff;
317*8475e043SDan OpenSolaris Anderson 				word = word >> BITSINBYTE;
3187c478bd9Sstevel@tonic-gate 			}
3197c478bd9Sstevel@tonic-gate 		}
320*8475e043SDan OpenSolaris Anderson 		offs = slen % BIGNUM_WORDSIZE;
3217c478bd9Sstevel@tonic-gate 		if (offs > 0) {
322*8475e043SDan OpenSolaris Anderson 			word = bn->value[slen / BIGNUM_WORDSIZE];
323*8475e043SDan OpenSolaris Anderson 			for (i =  slen % BIGNUM_WORDSIZE; i > 0; i --) {
3247c478bd9Sstevel@tonic-gate 				kn[i - 1] = word & 0xff;
325*8475e043SDan OpenSolaris Anderson 				word = word >> BITSINBYTE;
3267c478bd9Sstevel@tonic-gate 			}
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 	} else {
3297c478bd9Sstevel@tonic-gate 		for (i = 0; i < bn->len; i++) {
3307c478bd9Sstevel@tonic-gate 			word = bn->value[i];
331*8475e043SDan OpenSolaris Anderson 			for (j = 0; j < BIGNUM_WORDSIZE; j++) {
332*8475e043SDan OpenSolaris Anderson 				kn[slen - BIGNUM_WORDSIZE * i - j - 1] =
3337c478bd9Sstevel@tonic-gate 				    word & 0xff;
334*8475e043SDan OpenSolaris Anderson 				word = word >> BITSINBYTE;
3357c478bd9Sstevel@tonic-gate 			}
3367c478bd9Sstevel@tonic-gate 		}
337*8475e043SDan OpenSolaris Anderson 		for (i = 0; i < slen - BIGNUM_WORDSIZE * bn->len; i++) {
3387c478bd9Sstevel@tonic-gate 			kn[i] = 0;
3397c478bd9Sstevel@tonic-gate 		}
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate int
3457c478bd9Sstevel@tonic-gate big_bitlength(BIGNUM *a)
3467c478bd9Sstevel@tonic-gate {
347b60f2a0bSfr41279 	int		l = 0, b = 0;
348b60f2a0bSfr41279 	BIG_CHUNK_TYPE	c;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	l = a->len - 1;
3517c478bd9Sstevel@tonic-gate 	while ((l > 0) && (a->value[l] == 0)) {
3527c478bd9Sstevel@tonic-gate 		l--;
3537c478bd9Sstevel@tonic-gate 	}
354*8475e043SDan OpenSolaris Anderson 	b = BIG_CHUNK_SIZE;
3557c478bd9Sstevel@tonic-gate 	c = a->value[l];
356b60f2a0bSfr41279 	while ((b > 1) && ((c & BIG_CHUNK_HIGHBIT) == 0)) {
3577c478bd9Sstevel@tonic-gate 		c = c << 1;
3587c478bd9Sstevel@tonic-gate 		b--;
3597c478bd9Sstevel@tonic-gate 	}
360b60f2a0bSfr41279 
361*8475e043SDan OpenSolaris Anderson 	return (l * BIG_CHUNK_SIZE + b);
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate BIG_ERR_CODE
3667c478bd9Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src)
3677c478bd9Sstevel@tonic-gate {
368b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*newptr;
3697c478bd9Sstevel@tonic-gate 	int		i, len;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	len = src->len;
372b60f2a0bSfr41279 	while ((len > 1) && (src->value[len - 1] == 0)) {
3737c478bd9Sstevel@tonic-gate 		len--;
374b60f2a0bSfr41279 	}
3757c478bd9Sstevel@tonic-gate 	src->len = len;
3767c478bd9Sstevel@tonic-gate 	if (dest->size < len) {
3777c478bd9Sstevel@tonic-gate 		if (dest->malloced == 1) {
378b60f2a0bSfr41279 			newptr = (BIG_CHUNK_TYPE *)big_realloc(dest->value,
379*8475e043SDan OpenSolaris Anderson 			    BIGNUM_WORDSIZE * dest->size,
380*8475e043SDan OpenSolaris Anderson 			    BIGNUM_WORDSIZE * len);
3817c478bd9Sstevel@tonic-gate 		} else {
382b60f2a0bSfr41279 			newptr = (BIG_CHUNK_TYPE *)
383*8475e043SDan OpenSolaris Anderson 			    big_malloc(BIGNUM_WORDSIZE * len);
384b60f2a0bSfr41279 			if (newptr != NULL) {
385b60f2a0bSfr41279 				dest->malloced = 1;
3867c478bd9Sstevel@tonic-gate 			}
387b60f2a0bSfr41279 		}
388b60f2a0bSfr41279 		if (newptr == NULL) {
3897c478bd9Sstevel@tonic-gate 			return (BIG_NO_MEM);
390b60f2a0bSfr41279 		}
3917c478bd9Sstevel@tonic-gate 		dest->value = newptr;
3927c478bd9Sstevel@tonic-gate 		dest->size = len;
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 	dest->len = len;
3957c478bd9Sstevel@tonic-gate 	dest->sign = src->sign;
396b60f2a0bSfr41279 	for (i = 0; i < len; i++) {
397b60f2a0bSfr41279 		dest->value[i] = src->value[i];
398b60f2a0bSfr41279 	}
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	return (BIG_OK);
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate BIG_ERR_CODE
4057c478bd9Sstevel@tonic-gate big_extend(BIGNUM *number, int size)
4067c478bd9Sstevel@tonic-gate {
407b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*newptr;
4087c478bd9Sstevel@tonic-gate 	int		i;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	if (number->size >= size)
4117c478bd9Sstevel@tonic-gate 		return (BIG_OK);
4127c478bd9Sstevel@tonic-gate 	if (number->malloced) {
413b60f2a0bSfr41279 		number->value = big_realloc(number->value,
414*8475e043SDan OpenSolaris Anderson 		    BIGNUM_WORDSIZE * number->size,
415*8475e043SDan OpenSolaris Anderson 		    BIGNUM_WORDSIZE * size);
4167c478bd9Sstevel@tonic-gate 	} else {
417*8475e043SDan OpenSolaris Anderson 		newptr = big_malloc(BIGNUM_WORDSIZE * size);
4187c478bd9Sstevel@tonic-gate 		if (newptr != NULL) {
4197c478bd9Sstevel@tonic-gate 			for (i = 0; i < number->size; i++) {
4207c478bd9Sstevel@tonic-gate 				newptr[i] = number->value[i];
4217c478bd9Sstevel@tonic-gate 			}
4227c478bd9Sstevel@tonic-gate 		}
4237c478bd9Sstevel@tonic-gate 		number->value = newptr;
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 
426b60f2a0bSfr41279 	if (number->value == NULL) {
4277c478bd9Sstevel@tonic-gate 		return (BIG_NO_MEM);
428b60f2a0bSfr41279 	}
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	number->size = size;
4317c478bd9Sstevel@tonic-gate 	number->malloced = 1;
4327c478bd9Sstevel@tonic-gate 	return (BIG_OK);
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 
436b60f2a0bSfr41279 /* returns 1 if n == 0 */
4377c478bd9Sstevel@tonic-gate int
4387c478bd9Sstevel@tonic-gate big_is_zero(BIGNUM *n)
4397c478bd9Sstevel@tonic-gate {
4407c478bd9Sstevel@tonic-gate 	int	i, result;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	result = 1;
443b60f2a0bSfr41279 	for (i = 0; i < n->len; i++) {
444b60f2a0bSfr41279 		if (n->value[i] != 0) {
445b60f2a0bSfr41279 			result = 0;
446b60f2a0bSfr41279 		}
447b60f2a0bSfr41279 	}
4487c478bd9Sstevel@tonic-gate 	return (result);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate BIG_ERR_CODE
4537c478bd9Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
4547c478bd9Sstevel@tonic-gate {
4557c478bd9Sstevel@tonic-gate 	int		i, shorter, longer;
456b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, ai;
457b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*r, *a, *b, *c;
4587c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
459b60f2a0bSfr41279 	BIGNUM		*longerarg;
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	if (aa->len > bb->len) {
4627c478bd9Sstevel@tonic-gate 		shorter = bb->len;
4637c478bd9Sstevel@tonic-gate 		longer = aa->len;
464b60f2a0bSfr41279 		longerarg = aa;
4657c478bd9Sstevel@tonic-gate 	} else {
4667c478bd9Sstevel@tonic-gate 		shorter = aa->len;
4677c478bd9Sstevel@tonic-gate 		longer = bb->len;
468b60f2a0bSfr41279 		longerarg = bb;
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 	if (result->size < longer + 1) {
4717c478bd9Sstevel@tonic-gate 		err = big_extend(result, longer + 1);
472b60f2a0bSfr41279 		if (err != BIG_OK) {
4737c478bd9Sstevel@tonic-gate 			return (err);
4747c478bd9Sstevel@tonic-gate 		}
475b60f2a0bSfr41279 	}
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	r = result->value;
4787c478bd9Sstevel@tonic-gate 	a = aa->value;
4797c478bd9Sstevel@tonic-gate 	b = bb->value;
480b60f2a0bSfr41279 	c = longerarg->value;
4817c478bd9Sstevel@tonic-gate 	cy = 0;
4827c478bd9Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
4837c478bd9Sstevel@tonic-gate 		ai = a[i];
4847c478bd9Sstevel@tonic-gate 		r[i] = ai + b[i] + cy;
485b60f2a0bSfr41279 		if (r[i] > ai) {
486b60f2a0bSfr41279 			cy = 0;
487b60f2a0bSfr41279 		} else if (r[i] < ai) {
488b60f2a0bSfr41279 			cy = 1;
489b60f2a0bSfr41279 		}
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate 	for (; i < longer; i++) {
4927c478bd9Sstevel@tonic-gate 		ai = c[i];
4937c478bd9Sstevel@tonic-gate 		r[i] = ai + cy;
494b60f2a0bSfr41279 		if (r[i] >= ai) {
495b60f2a0bSfr41279 			cy = 0;
496b60f2a0bSfr41279 		}
4977c478bd9Sstevel@tonic-gate 	}
4987c478bd9Sstevel@tonic-gate 	if (cy == 1) {
4997c478bd9Sstevel@tonic-gate 		r[i] = cy;
5007c478bd9Sstevel@tonic-gate 		result->len = longer + 1;
5017c478bd9Sstevel@tonic-gate 	} else {
5027c478bd9Sstevel@tonic-gate 		result->len = longer;
5037c478bd9Sstevel@tonic-gate 	}
5047c478bd9Sstevel@tonic-gate 	result->sign = 1;
5057c478bd9Sstevel@tonic-gate 	return (BIG_OK);
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */
5107c478bd9Sstevel@tonic-gate void
511b60f2a0bSfr41279 big_sub_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, BIG_CHUNK_TYPE *b, int len)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate 	int		i;
514b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, ai;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	cy = 1;
5177c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
5187c478bd9Sstevel@tonic-gate 		ai = a[i];
5197c478bd9Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
520b60f2a0bSfr41279 		if (r[i] > ai) {
521b60f2a0bSfr41279 			cy = 0;
522b60f2a0bSfr41279 		} else if (r[i] < ai) {
523b60f2a0bSfr41279 			cy = 1;
524b60f2a0bSfr41279 		}
5257c478bd9Sstevel@tonic-gate 	}
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate /* result=aa-bb  it is assumed that aa>=bb */
5307c478bd9Sstevel@tonic-gate BIG_ERR_CODE
5317c478bd9Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate 	int		i, shorter;
534b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy = 1, ai;
535b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*r, *a, *b;
536b60f2a0bSfr41279 	BIG_ERR_CODE	err = BIG_OK;
5377c478bd9Sstevel@tonic-gate 
538b60f2a0bSfr41279 	if (aa->len > bb->len) {
539b60f2a0bSfr41279 		shorter = bb->len;
540b60f2a0bSfr41279 	} else {
541b60f2a0bSfr41279 		shorter = aa->len;
542b60f2a0bSfr41279 	}
5437c478bd9Sstevel@tonic-gate 	if (result->size < aa->len) {
5447c478bd9Sstevel@tonic-gate 		err = big_extend(result, aa->len);
545b60f2a0bSfr41279 		if (err != BIG_OK) {
5467c478bd9Sstevel@tonic-gate 			return (err);
5477c478bd9Sstevel@tonic-gate 		}
548b60f2a0bSfr41279 	}
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	r = result->value;
5517c478bd9Sstevel@tonic-gate 	a = aa->value;
5527c478bd9Sstevel@tonic-gate 	b = bb->value;
5537c478bd9Sstevel@tonic-gate 	result->len = aa->len;
5547c478bd9Sstevel@tonic-gate 	cy = 1;
5557c478bd9Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
5567c478bd9Sstevel@tonic-gate 		ai = a[i];
5577c478bd9Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
558b60f2a0bSfr41279 		if (r[i] > ai) {
559b60f2a0bSfr41279 			cy = 0;
560b60f2a0bSfr41279 		} else if (r[i] < ai) {
561b60f2a0bSfr41279 			cy = 1;
562b60f2a0bSfr41279 		}
5637c478bd9Sstevel@tonic-gate 	}
5647c478bd9Sstevel@tonic-gate 	for (; i < aa->len; i++) {
5657c478bd9Sstevel@tonic-gate 		ai = a[i];
5667c478bd9Sstevel@tonic-gate 		r[i] = ai + (~0) + cy;
567b60f2a0bSfr41279 		if (r[i] < ai) {
568b60f2a0bSfr41279 			cy = 1;
569b60f2a0bSfr41279 		}
5707c478bd9Sstevel@tonic-gate 	}
5717c478bd9Sstevel@tonic-gate 	result->sign = 1;
572b60f2a0bSfr41279 
573b60f2a0bSfr41279 	if (cy == 0) {
5747c478bd9Sstevel@tonic-gate 		return (BIG_INVALID_ARGS);
575b60f2a0bSfr41279 	} else {
5767c478bd9Sstevel@tonic-gate 		return (BIG_OK);
5777c478bd9Sstevel@tonic-gate 	}
578b60f2a0bSfr41279 }
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */
5827c478bd9Sstevel@tonic-gate int
5837c478bd9Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb)
5847c478bd9Sstevel@tonic-gate {
5857c478bd9Sstevel@tonic-gate 	int	i;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	if (aa->len > bb->len) {
5887c478bd9Sstevel@tonic-gate 		for (i = aa->len - 1; i > bb->len - 1; i--) {
589b60f2a0bSfr41279 			if (aa->value[i] > 0) {
5907c478bd9Sstevel@tonic-gate 				return (1);
5917c478bd9Sstevel@tonic-gate 			}
592b60f2a0bSfr41279 		}
5937c478bd9Sstevel@tonic-gate 	} else if (aa->len < bb->len) {
5947c478bd9Sstevel@tonic-gate 		for (i = bb->len - 1; i > aa->len - 1; i--) {
595b60f2a0bSfr41279 			if (bb->value[i] > 0) {
5967c478bd9Sstevel@tonic-gate 				return (-1);
5977c478bd9Sstevel@tonic-gate 			}
598b60f2a0bSfr41279 		}
599b60f2a0bSfr41279 	} else {
600b60f2a0bSfr41279 		i = aa->len - 1;
601b60f2a0bSfr41279 	}
6027c478bd9Sstevel@tonic-gate 	for (; i >= 0; i--) {
603b60f2a0bSfr41279 		if (aa->value[i] > bb->value[i]) {
6047c478bd9Sstevel@tonic-gate 			return (1);
605b60f2a0bSfr41279 		} else if (aa->value[i] < bb->value[i]) {
6067c478bd9Sstevel@tonic-gate 			return (-1);
6077c478bd9Sstevel@tonic-gate 		}
608b60f2a0bSfr41279 	}
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	return (0);
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate BIG_ERR_CODE
6157c478bd9Sstevel@tonic-gate big_sub(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == 1)) {
620b60f2a0bSfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
6217c478bd9Sstevel@tonic-gate 			return (err);
622b60f2a0bSfr41279 		}
6237c478bd9Sstevel@tonic-gate 		result->sign = 1;
6247c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == -1) && (bb->sign == 1)) {
625b60f2a0bSfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
6267c478bd9Sstevel@tonic-gate 			return (err);
627b60f2a0bSfr41279 		}
6287c478bd9Sstevel@tonic-gate 		result->sign = -1;
6297c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
6307c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
631b60f2a0bSfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6327c478bd9Sstevel@tonic-gate 				return (err);
633b60f2a0bSfr41279 			}
6347c478bd9Sstevel@tonic-gate 			result->sign = 1;
6357c478bd9Sstevel@tonic-gate 		} else {
636b60f2a0bSfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6377c478bd9Sstevel@tonic-gate 				return (err);
638b60f2a0bSfr41279 			}
6397c478bd9Sstevel@tonic-gate 			result->sign = -1;
6407c478bd9Sstevel@tonic-gate 		}
6417c478bd9Sstevel@tonic-gate 	} else {
6427c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
643b60f2a0bSfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6447c478bd9Sstevel@tonic-gate 				return (err);
645b60f2a0bSfr41279 			}
6467c478bd9Sstevel@tonic-gate 			result->sign = -1;
6477c478bd9Sstevel@tonic-gate 		} else {
648b60f2a0bSfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6497c478bd9Sstevel@tonic-gate 				return (err);
650b60f2a0bSfr41279 			}
6517c478bd9Sstevel@tonic-gate 			result->sign = 1;
6527c478bd9Sstevel@tonic-gate 		}
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 	return (BIG_OK);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate BIG_ERR_CODE
6597c478bd9Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
6607c478bd9Sstevel@tonic-gate {
6617c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == -1)) {
664b60f2a0bSfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
6657c478bd9Sstevel@tonic-gate 			return (err);
666b60f2a0bSfr41279 		}
6677c478bd9Sstevel@tonic-gate 		result->sign = -1;
6687c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
669b60f2a0bSfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
6707c478bd9Sstevel@tonic-gate 			return (err);
671b60f2a0bSfr41279 		}
6727c478bd9Sstevel@tonic-gate 		result->sign = 1;
6737c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == -1)) {
6747c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
675b60f2a0bSfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6767c478bd9Sstevel@tonic-gate 				return (err);
677b60f2a0bSfr41279 			}
6787c478bd9Sstevel@tonic-gate 			result->sign = 1;
6797c478bd9Sstevel@tonic-gate 		} else {
680b60f2a0bSfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6817c478bd9Sstevel@tonic-gate 				return (err);
682b60f2a0bSfr41279 			}
6837c478bd9Sstevel@tonic-gate 			result->sign = -1;
6847c478bd9Sstevel@tonic-gate 		}
6857c478bd9Sstevel@tonic-gate 	} else {
6867c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
687b60f2a0bSfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6887c478bd9Sstevel@tonic-gate 				return (err);
689b60f2a0bSfr41279 			}
6907c478bd9Sstevel@tonic-gate 			result->sign = -1;
6917c478bd9Sstevel@tonic-gate 		} else {
692b60f2a0bSfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6937c478bd9Sstevel@tonic-gate 				return (err);
694b60f2a0bSfr41279 			}
6957c478bd9Sstevel@tonic-gate 			result->sign = 1;
6967c478bd9Sstevel@tonic-gate 		}
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 	return (BIG_OK);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 
702b60f2a0bSfr41279 /* result = aa/2 */
7037c478bd9Sstevel@tonic-gate BIG_ERR_CODE
7047c478bd9Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa)
7057c478bd9Sstevel@tonic-gate {
7067c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
7077c478bd9Sstevel@tonic-gate 	int		i;
708b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, cy1;
709b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *r;
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	if (result->size < aa->len) {
7127c478bd9Sstevel@tonic-gate 		err = big_extend(result, aa->len);
713b60f2a0bSfr41279 		if (err != BIG_OK) {
7147c478bd9Sstevel@tonic-gate 			return (err);
7157c478bd9Sstevel@tonic-gate 		}
716b60f2a0bSfr41279 	}
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	result->len = aa->len;
7197c478bd9Sstevel@tonic-gate 	a = aa->value;
7207c478bd9Sstevel@tonic-gate 	r = result->value;
7217c478bd9Sstevel@tonic-gate 	cy = 0;
7227c478bd9Sstevel@tonic-gate 	for (i = aa->len - 1; i >= 0; i--) {
723b60f2a0bSfr41279 		cy1 = a[i] << (BIG_CHUNK_SIZE - 1);
7247c478bd9Sstevel@tonic-gate 		r[i] = (cy | (a[i] >> 1));
7257c478bd9Sstevel@tonic-gate 		cy = cy1;
7267c478bd9Sstevel@tonic-gate 	}
727b60f2a0bSfr41279 	if (r[result->len - 1] == 0) {
728b60f2a0bSfr41279 		result->len--;
729b60f2a0bSfr41279 	}
730b60f2a0bSfr41279 
7317c478bd9Sstevel@tonic-gate 	return (BIG_OK);
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate 
734b60f2a0bSfr41279 /* result  =  aa*2 */
7357c478bd9Sstevel@tonic-gate BIG_ERR_CODE
7367c478bd9Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa)
7377c478bd9Sstevel@tonic-gate {
7387c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
7397c478bd9Sstevel@tonic-gate 	int		i, rsize;
740b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, cy1;
741b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *r;
7427c478bd9Sstevel@tonic-gate 
743b60f2a0bSfr41279 	if ((aa->len > 0) &&
744b60f2a0bSfr41279 	    ((aa->value[aa->len - 1] & BIG_CHUNK_HIGHBIT) != 0)) {
7457c478bd9Sstevel@tonic-gate 		rsize = aa->len + 1;
746b60f2a0bSfr41279 	} else {
747b60f2a0bSfr41279 		rsize = aa->len;
748b60f2a0bSfr41279 	}
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	if (result->size < rsize) {
7517c478bd9Sstevel@tonic-gate 		err = big_extend(result, rsize);
7527c478bd9Sstevel@tonic-gate 		if (err != BIG_OK)
7537c478bd9Sstevel@tonic-gate 			return (err);
7547c478bd9Sstevel@tonic-gate 	}
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	a = aa->value;
7577c478bd9Sstevel@tonic-gate 	r = result->value;
758b60f2a0bSfr41279 	if (rsize == aa->len + 1) {
759b60f2a0bSfr41279 		r[rsize - 1] = 1;
760b60f2a0bSfr41279 	}
7617c478bd9Sstevel@tonic-gate 	cy = 0;
7627c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
763b60f2a0bSfr41279 		cy1 = a[i] >> (BIG_CHUNK_SIZE - 1);
7647c478bd9Sstevel@tonic-gate 		r[i] = (cy | (a[i] << 1));
7657c478bd9Sstevel@tonic-gate 		cy = cy1;
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate 	result->len = rsize;
7687c478bd9Sstevel@tonic-gate 	return (BIG_OK);
7697c478bd9Sstevel@tonic-gate }
7707c478bd9Sstevel@tonic-gate 
771b60f2a0bSfr41279 
772b60f2a0bSfr41279 /*
773b60f2a0bSfr41279  * returns aa mod b, aa must be nonneg, b must be a max
774b60f2a0bSfr41279  * (BIG_CHUNK_SIZE / 2)-bit integer
775b60f2a0bSfr41279  */
776b60f2a0bSfr41279 static uint32_t
777b60f2a0bSfr41279 big_modhalf_pos(BIGNUM *aa, uint32_t b)
7787c478bd9Sstevel@tonic-gate {
7797c478bd9Sstevel@tonic-gate 	int		i;
780b60f2a0bSfr41279 	BIG_CHUNK_TYPE	rem;
7817c478bd9Sstevel@tonic-gate 
782b60f2a0bSfr41279 	if (aa->len == 0) {
7837c478bd9Sstevel@tonic-gate 		return (0);
784b60f2a0bSfr41279 	}
7857c478bd9Sstevel@tonic-gate 	rem = aa->value[aa->len - 1] % b;
7867c478bd9Sstevel@tonic-gate 	for (i = aa->len - 2; i >= 0; i--) {
787b60f2a0bSfr41279 		rem = ((rem << (BIG_CHUNK_SIZE / 2)) |
788b60f2a0bSfr41279 		    (aa->value[i] >> (BIG_CHUNK_SIZE / 2))) % b;
789b60f2a0bSfr41279 		rem = ((rem << (BIG_CHUNK_SIZE / 2)) |
790b60f2a0bSfr41279 		    (aa->value[i] & BIG_CHUNK_LOWHALFBITS)) % b;
7917c478bd9Sstevel@tonic-gate 	}
792b60f2a0bSfr41279 
793b60f2a0bSfr41279 	return ((uint32_t)rem);
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate /*
798b60f2a0bSfr41279  * result = aa - (2^BIG_CHUNK_SIZE)^lendiff * bb
7997c478bd9Sstevel@tonic-gate  * result->size should be at least aa->len at entry
8007c478bd9Sstevel@tonic-gate  * aa, bb, and result should be positive
8017c478bd9Sstevel@tonic-gate  */
8027c478bd9Sstevel@tonic-gate void
8037c478bd9Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
8047c478bd9Sstevel@tonic-gate {
8057c478bd9Sstevel@tonic-gate 	int i, lendiff;
8067c478bd9Sstevel@tonic-gate 	BIGNUM res1, aa1;
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
8097c478bd9Sstevel@tonic-gate 	res1.size = result->size - lendiff;
8107c478bd9Sstevel@tonic-gate 	res1.malloced = 0;
8117c478bd9Sstevel@tonic-gate 	res1.value = result->value + lendiff;
8127c478bd9Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
8137c478bd9Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
8147c478bd9Sstevel@tonic-gate 	aa1.len = bb->len;
8157c478bd9Sstevel@tonic-gate 	aa1.sign = 1;
8167c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(&res1, &aa1, bb);
8177c478bd9Sstevel@tonic-gate 	if (result->value != aa->value) {
8187c478bd9Sstevel@tonic-gate 		for (i = 0; i < lendiff; i++) {
8197c478bd9Sstevel@tonic-gate 			result->value[i] = aa->value[i];
8207c478bd9Sstevel@tonic-gate 		}
8217c478bd9Sstevel@tonic-gate 	}
8227c478bd9Sstevel@tonic-gate 	result->len = aa->len;
8237c478bd9Sstevel@tonic-gate }
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate /*
8277c478bd9Sstevel@tonic-gate  * returns 1, 0, or -1 depending on whether |aa| > , ==, or <
828b60f2a0bSfr41279  *					(2^BIG_CHUNK_SIZE)^lendiff * |bb|
8297c478bd9Sstevel@tonic-gate  * aa->len should be >= bb->len
8307c478bd9Sstevel@tonic-gate  */
8317c478bd9Sstevel@tonic-gate int
8327c478bd9Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb)
8337c478bd9Sstevel@tonic-gate {
8347c478bd9Sstevel@tonic-gate 	int		lendiff;
8357c478bd9Sstevel@tonic-gate 	BIGNUM		aa1;
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
8387c478bd9Sstevel@tonic-gate 	aa1.len = bb->len;
8397c478bd9Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
8407c478bd9Sstevel@tonic-gate 	aa1.malloced = 0;
8417c478bd9Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
8427c478bd9Sstevel@tonic-gate 	return (big_cmp_abs(&aa1, bb));
8437c478bd9Sstevel@tonic-gate }
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate /*
847b60f2a0bSfr41279  * result = aa * b where b is a max. (BIG_CHUNK_SIZE / 2)-bit positive integer.
8487c478bd9Sstevel@tonic-gate  * result should have enough space allocated.
8497c478bd9Sstevel@tonic-gate  */
850b60f2a0bSfr41279 static void
851b60f2a0bSfr41279 big_mulhalf_low(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b)
8527c478bd9Sstevel@tonic-gate {
8537c478bd9Sstevel@tonic-gate 	int		i;
854b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1, t2, ai, cy;
855b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *r;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	a = aa->value;
8587c478bd9Sstevel@tonic-gate 	r = result->value;
8597c478bd9Sstevel@tonic-gate 	cy = 0;
8607c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
8617c478bd9Sstevel@tonic-gate 		ai = a[i];
862b60f2a0bSfr41279 		t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy;
863b60f2a0bSfr41279 		t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b +
864b60f2a0bSfr41279 		    (t1 >> (BIG_CHUNK_SIZE / 2));
865b60f2a0bSfr41279 		r[i] = (t1 & BIG_CHUNK_LOWHALFBITS) |
866b60f2a0bSfr41279 		    (t2 << (BIG_CHUNK_SIZE / 2));
867b60f2a0bSfr41279 		cy = t2 >> (BIG_CHUNK_SIZE / 2);
8687c478bd9Sstevel@tonic-gate 	}
8697c478bd9Sstevel@tonic-gate 	r[i] = cy;
8707c478bd9Sstevel@tonic-gate 	result->len = aa->len + 1;
8717c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate /*
876b60f2a0bSfr41279  * result = aa * b * 2^(BIG_CHUNK_SIZE / 2) where b is a max.
877b60f2a0bSfr41279  * (BIG_CHUNK_SIZE / 2)-bit positive integer.
8787c478bd9Sstevel@tonic-gate  * result should have enough space allocated.
8797c478bd9Sstevel@tonic-gate  */
880b60f2a0bSfr41279 static void
881b60f2a0bSfr41279 big_mulhalf_high(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b)
8827c478bd9Sstevel@tonic-gate {
8837c478bd9Sstevel@tonic-gate 	int		i;
884b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1, t2, ai, cy, ri;
885b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *r;
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	a = aa->value;
8887c478bd9Sstevel@tonic-gate 	r = result->value;
8897c478bd9Sstevel@tonic-gate 	cy = 0;
8907c478bd9Sstevel@tonic-gate 	ri = 0;
8917c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
8927c478bd9Sstevel@tonic-gate 		ai = a[i];
893b60f2a0bSfr41279 		t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy;
894b60f2a0bSfr41279 		t2 = (ai >>  (BIG_CHUNK_SIZE / 2)) * b +
895b60f2a0bSfr41279 		    (t1 >>  (BIG_CHUNK_SIZE / 2));
896b60f2a0bSfr41279 		r[i] = (t1 <<  (BIG_CHUNK_SIZE / 2)) + ri;
897b60f2a0bSfr41279 		ri = t2 & BIG_CHUNK_LOWHALFBITS;
898b60f2a0bSfr41279 		cy = t2 >> (BIG_CHUNK_SIZE / 2);
8997c478bd9Sstevel@tonic-gate 	}
900b60f2a0bSfr41279 	r[i] = (cy <<  (BIG_CHUNK_SIZE / 2)) + ri;
9017c478bd9Sstevel@tonic-gate 	result->len = aa->len + 1;
9027c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
9037c478bd9Sstevel@tonic-gate }
9047c478bd9Sstevel@tonic-gate 
905b60f2a0bSfr41279 
9067c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */
9077c478bd9Sstevel@tonic-gate void
9087c478bd9Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs)
9097c478bd9Sstevel@tonic-gate {
9107c478bd9Sstevel@tonic-gate 	int		i;
911b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, ai;
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	if (offs == 0) {
9147c478bd9Sstevel@tonic-gate 		if (result != aa) {
9157c478bd9Sstevel@tonic-gate 			(void) big_copy(result, aa);
9167c478bd9Sstevel@tonic-gate 		}
9177c478bd9Sstevel@tonic-gate 		return;
9187c478bd9Sstevel@tonic-gate 	}
9197c478bd9Sstevel@tonic-gate 	cy = 0;
9207c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
9217c478bd9Sstevel@tonic-gate 		ai = aa->value[i];
9227c478bd9Sstevel@tonic-gate 		result->value[i] = (ai << offs) | cy;
923b60f2a0bSfr41279 		cy = ai >> (BIG_CHUNK_SIZE - offs);
9247c478bd9Sstevel@tonic-gate 	}
9257c478bd9Sstevel@tonic-gate 	if (cy != 0) {
9267c478bd9Sstevel@tonic-gate 		result->len = aa->len + 1;
9277c478bd9Sstevel@tonic-gate 		result->value[result->len - 1] = cy;
9287c478bd9Sstevel@tonic-gate 	} else {
9297c478bd9Sstevel@tonic-gate 		result->len = aa->len;
9307c478bd9Sstevel@tonic-gate 	}
9317c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
9327c478bd9Sstevel@tonic-gate }
9337c478bd9Sstevel@tonic-gate 
934b60f2a0bSfr41279 
9357c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */
9367c478bd9Sstevel@tonic-gate void
9377c478bd9Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs)
9387c478bd9Sstevel@tonic-gate {
9397c478bd9Sstevel@tonic-gate 	int		 i;
940b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, ai;
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	if (offs == 0) {
9437c478bd9Sstevel@tonic-gate 		if (result != aa) {
9447c478bd9Sstevel@tonic-gate 			(void) big_copy(result, aa);
9457c478bd9Sstevel@tonic-gate 		}
9467c478bd9Sstevel@tonic-gate 		return;
9477c478bd9Sstevel@tonic-gate 	}
9487c478bd9Sstevel@tonic-gate 	cy = aa->value[0] >> offs;
9497c478bd9Sstevel@tonic-gate 	for (i = 1; i < aa->len; i++) {
9507c478bd9Sstevel@tonic-gate 		ai = aa->value[i];
951b60f2a0bSfr41279 		result->value[i - 1] = (ai << (BIG_CHUNK_SIZE - offs)) | cy;
9527c478bd9Sstevel@tonic-gate 		cy = ai >> offs;
9537c478bd9Sstevel@tonic-gate 	}
9547c478bd9Sstevel@tonic-gate 	result->len = aa->len;
9557c478bd9Sstevel@tonic-gate 	result->value[result->len - 1] = cy;
9567c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate /*
9617c478bd9Sstevel@tonic-gate  * result = aa/bb   remainder = aa mod bb
9627c478bd9Sstevel@tonic-gate  * it is assumed that aa and bb are positive
9637c478bd9Sstevel@tonic-gate  */
9647c478bd9Sstevel@tonic-gate BIG_ERR_CODE
965*8475e043SDan OpenSolaris Anderson big_div_pos(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb)
9667c478bd9Sstevel@tonic-gate {
967b60f2a0bSfr41279 	BIG_ERR_CODE	err = BIG_OK;
9687c478bd9Sstevel@tonic-gate 	int		i, alen, blen, tlen, rlen, offs;
969b60f2a0bSfr41279 	BIG_CHUNK_TYPE	higha, highb, coeff;
970b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *b;
9717c478bd9Sstevel@tonic-gate 	BIGNUM		bbhigh, bblow, tresult, tmp1, tmp2;
972b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
973b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp2value[BIGTMPSIZE];
974b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tresultvalue[BIGTMPSIZE];
975b60f2a0bSfr41279 	BIG_CHUNK_TYPE	bblowvalue[BIGTMPSIZE];
976b60f2a0bSfr41279 	BIG_CHUNK_TYPE	bbhighvalue[BIGTMPSIZE];
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	a = aa->value;
9797c478bd9Sstevel@tonic-gate 	b = bb->value;
9807c478bd9Sstevel@tonic-gate 	alen = aa->len;
9817c478bd9Sstevel@tonic-gate 	blen = bb->len;
982b60f2a0bSfr41279 	while ((alen > 1) && (a[alen - 1] == 0)) {
983b60f2a0bSfr41279 		alen = alen - 1;
984b60f2a0bSfr41279 	}
9857c478bd9Sstevel@tonic-gate 	aa->len = alen;
986b60f2a0bSfr41279 	while ((blen > 1) && (b[blen - 1] == 0)) {
987b60f2a0bSfr41279 		blen = blen - 1;
988b60f2a0bSfr41279 	}
9897c478bd9Sstevel@tonic-gate 	bb->len = blen;
990b60f2a0bSfr41279 	if ((blen == 1) && (b[0] == 0)) {
9917c478bd9Sstevel@tonic-gate 		return (BIG_DIV_BY_0);
992b60f2a0bSfr41279 	}
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(aa, bb) < 0) {
9957c478bd9Sstevel@tonic-gate 		if ((remainder != NULL) &&
996b60f2a0bSfr41279 		    ((err = big_copy(remainder, aa)) != BIG_OK)) {
9977c478bd9Sstevel@tonic-gate 			return (err);
998b60f2a0bSfr41279 		}
9997c478bd9Sstevel@tonic-gate 		if (result != NULL) {
10007c478bd9Sstevel@tonic-gate 			result->len = 1;
10017c478bd9Sstevel@tonic-gate 			result->sign = 1;
10027c478bd9Sstevel@tonic-gate 			result->value[0] = 0;
10037c478bd9Sstevel@tonic-gate 		}
10047c478bd9Sstevel@tonic-gate 		return (BIG_OK);
10057c478bd9Sstevel@tonic-gate 	}
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&bblow, blen + 1,
10087c478bd9Sstevel@tonic-gate 	    bblowvalue, arraysize(bblowvalue))) != BIG_OK)
10097c478bd9Sstevel@tonic-gate 		return (err);
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&bbhigh, blen + 1,
10127c478bd9Sstevel@tonic-gate 	    bbhighvalue, arraysize(bbhighvalue))) != BIG_OK)
10137c478bd9Sstevel@tonic-gate 		goto ret1;
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp1, alen + 2,
10167c478bd9Sstevel@tonic-gate 	    tmp1value, arraysize(tmp1value))) != BIG_OK)
10177c478bd9Sstevel@tonic-gate 		goto ret2;
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, blen + 2,
10207c478bd9Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
10217c478bd9Sstevel@tonic-gate 		goto ret3;
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tresult, alen - blen + 2,
10247c478bd9Sstevel@tonic-gate 	    tresultvalue, arraysize(tresultvalue))) != BIG_OK)
10257c478bd9Sstevel@tonic-gate 		goto ret4;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	offs = 0;
1028b60f2a0bSfr41279 	highb = b[blen - 1];
1029b60f2a0bSfr41279 	if (highb >= (BIG_CHUNK_HALF_HIGHBIT << 1)) {
1030b60f2a0bSfr41279 		highb = highb >> (BIG_CHUNK_SIZE / 2);
1031b60f2a0bSfr41279 		offs = (BIG_CHUNK_SIZE / 2);
10327c478bd9Sstevel@tonic-gate 	}
1033b60f2a0bSfr41279 	while ((highb & BIG_CHUNK_HALF_HIGHBIT) == 0) {
1034b60f2a0bSfr41279 		highb = highb << 1;
10357c478bd9Sstevel@tonic-gate 		offs++;
10367c478bd9Sstevel@tonic-gate 	}
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	big_shiftleft(&bblow, bb, offs);
1039b60f2a0bSfr41279 
1040b60f2a0bSfr41279 	if (offs <= (BIG_CHUNK_SIZE / 2 - 1)) {
1041b60f2a0bSfr41279 		big_shiftleft(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2);
10427c478bd9Sstevel@tonic-gate 	} else {
1043b60f2a0bSfr41279 		big_shiftright(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2);
10447c478bd9Sstevel@tonic-gate 	}
10457c478bd9Sstevel@tonic-gate 	if (bbhigh.value[bbhigh.len - 1] == 0) {
10467c478bd9Sstevel@tonic-gate 		bbhigh.len--;
10477c478bd9Sstevel@tonic-gate 	} else {
10487c478bd9Sstevel@tonic-gate 		bbhigh.value[bbhigh.len] = 0;
10497c478bd9Sstevel@tonic-gate 	}
10507c478bd9Sstevel@tonic-gate 
1051b60f2a0bSfr41279 	highb = bblow.value[bblow.len - 1];
1052b60f2a0bSfr41279 
10537c478bd9Sstevel@tonic-gate 	big_shiftleft(&tmp1, aa, offs);
10547c478bd9Sstevel@tonic-gate 	rlen = tmp1.len - bblow.len + 1;
10557c478bd9Sstevel@tonic-gate 	tresult.len = rlen;
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	tmp1.len++;
10587c478bd9Sstevel@tonic-gate 	tlen = tmp1.len;
10597c478bd9Sstevel@tonic-gate 	tmp1.value[tmp1.len - 1] = 0;
10607c478bd9Sstevel@tonic-gate 	for (i = 0; i < rlen; i++) {
1061b60f2a0bSfr41279 		higha = (tmp1.value[tlen - 1] << (BIG_CHUNK_SIZE / 2)) +
1062b60f2a0bSfr41279 		    (tmp1.value[tlen - 2] >> (BIG_CHUNK_SIZE / 2));
10637c478bd9Sstevel@tonic-gate 		coeff = higha / (highb + 1);
1064b60f2a0bSfr41279 		big_mulhalf_high(&tmp2, &bblow, coeff);
10657c478bd9Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
10667c478bd9Sstevel@tonic-gate 		bbhigh.len++;
10677c478bd9Sstevel@tonic-gate 		while (tmp1.value[tlen - 1] > 0) {
10687c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
10697c478bd9Sstevel@tonic-gate 			coeff++;
10707c478bd9Sstevel@tonic-gate 		}
10717c478bd9Sstevel@tonic-gate 		bbhigh.len--;
10727c478bd9Sstevel@tonic-gate 		tlen--;
10737c478bd9Sstevel@tonic-gate 		tmp1.len--;
10747c478bd9Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) {
10757c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
10767c478bd9Sstevel@tonic-gate 			coeff++;
10777c478bd9Sstevel@tonic-gate 		}
1078b60f2a0bSfr41279 		tresult.value[rlen - i - 1] = coeff << (BIG_CHUNK_SIZE / 2);
10797c478bd9Sstevel@tonic-gate 		higha = tmp1.value[tlen - 1];
10807c478bd9Sstevel@tonic-gate 		coeff = higha / (highb + 1);
1081b60f2a0bSfr41279 		big_mulhalf_low(&tmp2, &bblow, coeff);
10827c478bd9Sstevel@tonic-gate 		tmp2.len--;
10837c478bd9Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
10847c478bd9Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bblow) >= 0) {
10857c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bblow);
10867c478bd9Sstevel@tonic-gate 			coeff++;
10877c478bd9Sstevel@tonic-gate 		}
10887c478bd9Sstevel@tonic-gate 		tresult.value[rlen - i - 1] =
10897c478bd9Sstevel@tonic-gate 		    tresult.value[rlen - i - 1] + coeff;
10907c478bd9Sstevel@tonic-gate 	}
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	big_shiftright(&tmp1, &tmp1, offs);
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	err = BIG_OK;
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	if ((remainder != NULL) &&
10977c478bd9Sstevel@tonic-gate 	    ((err = big_copy(remainder, &tmp1)) != BIG_OK))
10987c478bd9Sstevel@tonic-gate 		goto ret;
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	if (result != NULL)
11017c478bd9Sstevel@tonic-gate 		err = big_copy(result, &tresult);
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate ret:
11047c478bd9Sstevel@tonic-gate 	big_finish(&tresult);
11057c478bd9Sstevel@tonic-gate ret4:
11067c478bd9Sstevel@tonic-gate 	big_finish(&tmp1);
11077c478bd9Sstevel@tonic-gate ret3:
11087c478bd9Sstevel@tonic-gate 	big_finish(&tmp2);
11097c478bd9Sstevel@tonic-gate ret2:
11107c478bd9Sstevel@tonic-gate 	big_finish(&bbhigh);
11117c478bd9Sstevel@tonic-gate ret1:
11127c478bd9Sstevel@tonic-gate 	big_finish(&bblow);
11137c478bd9Sstevel@tonic-gate 	return (err);
11147c478bd9Sstevel@tonic-gate }
11157c478bd9Sstevel@tonic-gate 
1116*8475e043SDan OpenSolaris Anderson 
11177c478bd9Sstevel@tonic-gate /*
11187c478bd9Sstevel@tonic-gate  * If there is no processor-specific integer implementation of
11197c478bd9Sstevel@tonic-gate  * the lower level multiply functions, then this code is provided
11207c478bd9Sstevel@tonic-gate  * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and
11217c478bd9Sstevel@tonic-gate  * big_sqr_vec().
11227c478bd9Sstevel@tonic-gate  *
11237c478bd9Sstevel@tonic-gate  * There are two generic implementations.  One that assumes that
11247c478bd9Sstevel@tonic-gate  * there is hardware and C compiler support for a 32 x 32 --> 64
11257c478bd9Sstevel@tonic-gate  * bit unsigned multiply, but otherwise is not specific to any
11267c478bd9Sstevel@tonic-gate  * processor, platform, or ISA.
11277c478bd9Sstevel@tonic-gate  *
11287c478bd9Sstevel@tonic-gate  * The other makes very few assumptions about hardware capabilities.
11297c478bd9Sstevel@tonic-gate  * It does not even assume that there is any implementation of a
11307c478bd9Sstevel@tonic-gate  * 32 x 32 --> 64 bit multiply that is accessible to C code and
11317c478bd9Sstevel@tonic-gate  * appropriate to use.  It falls constructs 32 x 32 --> 64 bit
11327c478bd9Sstevel@tonic-gate  * multiplies from 16 x 16 --> 32 bit multiplies.
11337c478bd9Sstevel@tonic-gate  *
11347c478bd9Sstevel@tonic-gate  */
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate #if !defined(PSR_MUL)
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate #ifdef UMUL64
11397c478bd9Sstevel@tonic-gate 
1140b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
1141b60f2a0bSfr41279 
11427c478bd9Sstevel@tonic-gate #define	UNROLL8
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_PREFETCH(R) \
11457c478bd9Sstevel@tonic-gate 	p = pf * d; \
11467c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[R + 1]; \
11477c478bd9Sstevel@tonic-gate 	t = p + cy; \
11487c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11497c478bd9Sstevel@tonic-gate 	cy = t >> 32
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_NOPREFETCH(R) \
11527c478bd9Sstevel@tonic-gate 	p = pf * d; \
11537c478bd9Sstevel@tonic-gate 	t = p + cy; \
11547c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11557c478bd9Sstevel@tonic-gate 	cy = t >> 32
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_PREFETCH(R) \
11587c478bd9Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
11597c478bd9Sstevel@tonic-gate 	p = pf * d; \
11607c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[R + 1]; \
11617c478bd9Sstevel@tonic-gate 	t = p + t + cy; \
11627c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11637c478bd9Sstevel@tonic-gate 	cy = t >> 32
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_NOPREFETCH(R) \
11667c478bd9Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
11677c478bd9Sstevel@tonic-gate 	p = pf * d; \
11687c478bd9Sstevel@tonic-gate 	t = p + t + cy; \
11697c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11707c478bd9Sstevel@tonic-gate 	cy = t >> 32
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate #ifdef UNROLL8
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate #define	UNROLL 8
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate /*
11777c478bd9Sstevel@tonic-gate  * r = a * b
11787c478bd9Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
11797c478bd9Sstevel@tonic-gate  */
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate uint32_t
11827c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
11837c478bd9Sstevel@tonic-gate {
11847c478bd9Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	if (len == 0)
11877c478bd9Sstevel@tonic-gate 		return (0);
11887c478bd9Sstevel@tonic-gate 	cy = 0;
11897c478bd9Sstevel@tonic-gate 	d = (uint64_t)b;
11907c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[0];
11917c478bd9Sstevel@tonic-gate 	while (len > UNROLL) {
11927c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
11937c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
11947c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
11957c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
11967c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
11977c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
11987c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
11997c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(7);
12007c478bd9Sstevel@tonic-gate 		r += UNROLL;
12017c478bd9Sstevel@tonic-gate 		a += UNROLL;
12027c478bd9Sstevel@tonic-gate 		len -= UNROLL;
12037c478bd9Sstevel@tonic-gate 	}
12047c478bd9Sstevel@tonic-gate 	if (len == UNROLL) {
12057c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
12067c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
12077c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
12087c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
12097c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
12107c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
12117c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
12127c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(7);
12137c478bd9Sstevel@tonic-gate 		return ((uint32_t)cy);
12147c478bd9Sstevel@tonic-gate 	}
12157c478bd9Sstevel@tonic-gate 	while (len > 1) {
12167c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
12177c478bd9Sstevel@tonic-gate 		++r;
12187c478bd9Sstevel@tonic-gate 		++a;
12197c478bd9Sstevel@tonic-gate 		--len;
12207c478bd9Sstevel@tonic-gate 	}
12217c478bd9Sstevel@tonic-gate 	if (len > 0) {
12227c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(0);
12237c478bd9Sstevel@tonic-gate 	}
12247c478bd9Sstevel@tonic-gate 	return ((uint32_t)cy);
12257c478bd9Sstevel@tonic-gate }
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate /*
12287c478bd9Sstevel@tonic-gate  * r += a * b
12297c478bd9Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
12307c478bd9Sstevel@tonic-gate  */
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate uint32_t
12337c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
12347c478bd9Sstevel@tonic-gate {
12357c478bd9Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 	if (len == 0)
12387c478bd9Sstevel@tonic-gate 		return (0);
12397c478bd9Sstevel@tonic-gate 	cy = 0;
12407c478bd9Sstevel@tonic-gate 	d = (uint64_t)b;
12417c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[0];
12427c478bd9Sstevel@tonic-gate 	while (len > 8) {
12437c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12447c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
12457c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
12467c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
12477c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
12487c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
12497c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
12507c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(7);
12517c478bd9Sstevel@tonic-gate 		r += 8;
12527c478bd9Sstevel@tonic-gate 		a += 8;
12537c478bd9Sstevel@tonic-gate 		len -= 8;
12547c478bd9Sstevel@tonic-gate 	}
12557c478bd9Sstevel@tonic-gate 	if (len == 8) {
12567c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12577c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
12587c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
12597c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
12607c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
12617c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
12627c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
12637c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(7);
12647c478bd9Sstevel@tonic-gate 		return ((uint32_t)cy);
12657c478bd9Sstevel@tonic-gate 	}
12667c478bd9Sstevel@tonic-gate 	while (len > 1) {
12677c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12687c478bd9Sstevel@tonic-gate 		++r;
12697c478bd9Sstevel@tonic-gate 		++a;
12707c478bd9Sstevel@tonic-gate 		--len;
12717c478bd9Sstevel@tonic-gate 	}
12727c478bd9Sstevel@tonic-gate 	if (len > 0) {
12737c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(0);
12747c478bd9Sstevel@tonic-gate 	}
12757c478bd9Sstevel@tonic-gate 	return ((uint32_t)cy);
12767c478bd9Sstevel@tonic-gate }
12777c478bd9Sstevel@tonic-gate #endif /* UNROLL8 */
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate void
12807c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
12817c478bd9Sstevel@tonic-gate {
12827c478bd9Sstevel@tonic-gate 	uint32_t	*tr, *ta;
12837c478bd9Sstevel@tonic-gate 	int		tlen, row, col;
12847c478bd9Sstevel@tonic-gate 	uint64_t	p, s, t, t2, cy;
12857c478bd9Sstevel@tonic-gate 	uint32_t	d;
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	tr = r + 1;
12887c478bd9Sstevel@tonic-gate 	ta = a;
12897c478bd9Sstevel@tonic-gate 	tlen = len - 1;
12907c478bd9Sstevel@tonic-gate 	tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]);
12917c478bd9Sstevel@tonic-gate 	while (--tlen > 0) {
12927c478bd9Sstevel@tonic-gate 		tr += 2;
12937c478bd9Sstevel@tonic-gate 		++ta;
12947c478bd9Sstevel@tonic-gate 		tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]);
12957c478bd9Sstevel@tonic-gate 	}
12967c478bd9Sstevel@tonic-gate 	s = (uint64_t)a[0];
12977c478bd9Sstevel@tonic-gate 	s = s * s;
12987c478bd9Sstevel@tonic-gate 	r[0] = (uint32_t)s;
12997c478bd9Sstevel@tonic-gate 	cy = s >> 32;
13007c478bd9Sstevel@tonic-gate 	p = ((uint64_t)r[1] << 1) + cy;
13017c478bd9Sstevel@tonic-gate 	r[1] = (uint32_t)p;
13027c478bd9Sstevel@tonic-gate 	cy = p >> 32;
13037c478bd9Sstevel@tonic-gate 	row = 1;
13047c478bd9Sstevel@tonic-gate 	col = 2;
13057c478bd9Sstevel@tonic-gate 	while (row < len) {
13067c478bd9Sstevel@tonic-gate 		s = (uint64_t)a[row];
13077c478bd9Sstevel@tonic-gate 		s = s * s;
13087c478bd9Sstevel@tonic-gate 		p = (uint64_t)r[col] << 1;
13097c478bd9Sstevel@tonic-gate 		t = p + s;
13107c478bd9Sstevel@tonic-gate 		d = (uint32_t)t;
13117c478bd9Sstevel@tonic-gate 		t2 = (uint64_t)d + cy;
13127c478bd9Sstevel@tonic-gate 		r[col] = (uint32_t)t2;
13137c478bd9Sstevel@tonic-gate 		cy = (t >> 32) + (t2 >> 32);
13147c478bd9Sstevel@tonic-gate 		if (row == len - 1)
13157c478bd9Sstevel@tonic-gate 			break;
13167c478bd9Sstevel@tonic-gate 		p = ((uint64_t)r[col + 1] << 1) + cy;
13177c478bd9Sstevel@tonic-gate 		r[col + 1] = (uint32_t)p;
13187c478bd9Sstevel@tonic-gate 		cy = p >> 32;
13197c478bd9Sstevel@tonic-gate 		++row;
13207c478bd9Sstevel@tonic-gate 		col += 2;
13217c478bd9Sstevel@tonic-gate 	}
13227c478bd9Sstevel@tonic-gate 	r[col + 1] = (uint32_t)cy;
13237c478bd9Sstevel@tonic-gate }
13247c478bd9Sstevel@tonic-gate 
1325b60f2a0bSfr41279 #else /* BIG_CHUNK_SIZE == 64 */
1326b60f2a0bSfr41279 
1327b60f2a0bSfr41279 /*
1328b60f2a0bSfr41279  * r = r + a * digit, r and a are vectors of length len
1329b60f2a0bSfr41279  * returns the carry digit
1330b60f2a0bSfr41279  */
1331b60f2a0bSfr41279 BIG_CHUNK_TYPE
1332b60f2a0bSfr41279 big_mul_add_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len,
1333b60f2a0bSfr41279     BIG_CHUNK_TYPE digit)
1334b60f2a0bSfr41279 {
1335b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, cy1, retcy, dlow, dhigh;
1336b60f2a0bSfr41279 	int		i;
1337b60f2a0bSfr41279 
1338b60f2a0bSfr41279 	cy1 = 0;
1339b60f2a0bSfr41279 	dlow = digit & BIG_CHUNK_LOWHALFBITS;
1340b60f2a0bSfr41279 	dhigh = digit >> (BIG_CHUNK_SIZE / 2);
1341b60f2a0bSfr41279 	for (i = 0; i < len; i++) {
1342b60f2a0bSfr41279 		cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
1343b60f2a0bSfr41279 		    dlow * (a[i] & BIG_CHUNK_LOWHALFBITS) +
1344b60f2a0bSfr41279 		    (r[i] & BIG_CHUNK_LOWHALFBITS);
1345b60f2a0bSfr41279 		cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) +
1346b60f2a0bSfr41279 		    dlow * (a[i] >> (BIG_CHUNK_SIZE / 2)) +
1347b60f2a0bSfr41279 		    (r[i] >> (BIG_CHUNK_SIZE / 2));
1348b60f2a0bSfr41279 		r[i] = (cy & BIG_CHUNK_LOWHALFBITS) |
1349b60f2a0bSfr41279 		    (cy1 << (BIG_CHUNK_SIZE / 2));
1350b60f2a0bSfr41279 	}
1351b60f2a0bSfr41279 	retcy = cy1 >> (BIG_CHUNK_SIZE / 2);
1352b60f2a0bSfr41279 
1353b60f2a0bSfr41279 	cy1 = r[0] & BIG_CHUNK_LOWHALFBITS;
1354b60f2a0bSfr41279 	for (i = 0; i < len - 1; i++) {
1355b60f2a0bSfr41279 		cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
1356b60f2a0bSfr41279 		    dhigh * (a[i] & BIG_CHUNK_LOWHALFBITS) +
1357b60f2a0bSfr41279 		    (r[i] >> (BIG_CHUNK_SIZE / 2));
1358b60f2a0bSfr41279 		r[i] = (cy1 & BIG_CHUNK_LOWHALFBITS) |
1359b60f2a0bSfr41279 		    (cy << (BIG_CHUNK_SIZE / 2));
1360b60f2a0bSfr41279 		cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) +
1361b60f2a0bSfr41279 		    dhigh * (a[i] >> (BIG_CHUNK_SIZE / 2)) +
1362b60f2a0bSfr41279 		    (r[i + 1] & BIG_CHUNK_LOWHALFBITS);
1363b60f2a0bSfr41279 	}
1364b60f2a0bSfr41279 	cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
1365b60f2a0bSfr41279 	    dhigh * (a[len - 1] & BIG_CHUNK_LOWHALFBITS) +
1366b60f2a0bSfr41279 	    (r[len - 1] >> (BIG_CHUNK_SIZE / 2));
1367b60f2a0bSfr41279 	r[len - 1] = (cy1 & BIG_CHUNK_LOWHALFBITS) |
1368b60f2a0bSfr41279 	    (cy << (BIG_CHUNK_SIZE / 2));
1369b60f2a0bSfr41279 	retcy = (cy >> (BIG_CHUNK_SIZE / 2)) +
1370b60f2a0bSfr41279 	    dhigh * (a[len - 1] >> (BIG_CHUNK_SIZE / 2)) + retcy;
1371b60f2a0bSfr41279 
1372b60f2a0bSfr41279 	return (retcy);
1373b60f2a0bSfr41279 }
1374b60f2a0bSfr41279 
1375b60f2a0bSfr41279 
1376b60f2a0bSfr41279 /*
1377b60f2a0bSfr41279  * r = a * digit, r and a are vectors of length len
1378b60f2a0bSfr41279  * returns the carry digit
1379b60f2a0bSfr41279  */
1380b60f2a0bSfr41279 BIG_CHUNK_TYPE
1381b60f2a0bSfr41279 big_mul_set_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len,
1382b60f2a0bSfr41279     BIG_CHUNK_TYPE digit)
1383b60f2a0bSfr41279 {
1384b60f2a0bSfr41279 	int	i;
1385b60f2a0bSfr41279 
1386b60f2a0bSfr41279 	ASSERT(r != a);
1387b60f2a0bSfr41279 	for (i = 0; i < len; i++) {
1388b60f2a0bSfr41279 		r[i] = 0;
1389b60f2a0bSfr41279 	}
1390b60f2a0bSfr41279 	return (big_mul_add_vec(r, a, len, digit));
1391b60f2a0bSfr41279 }
1392b60f2a0bSfr41279 
1393b60f2a0bSfr41279 void
1394b60f2a0bSfr41279 big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len)
1395b60f2a0bSfr41279 {
1396b60f2a0bSfr41279 	int i;
1397b60f2a0bSfr41279 
1398b60f2a0bSfr41279 	ASSERT(r != a);
1399b60f2a0bSfr41279 	r[len] = big_mul_set_vec(r, a, len, a[0]);
1400b60f2a0bSfr41279 	for (i = 1; i < len; ++i)
1401b60f2a0bSfr41279 		r[len + i] = big_mul_add_vec(r + i, a, len, a[i]);
1402b60f2a0bSfr41279 }
1403b60f2a0bSfr41279 
1404b60f2a0bSfr41279 #endif /* BIG_CHUNK_SIZE == 32/64 */
1405b60f2a0bSfr41279 
1406*8475e043SDan OpenSolaris Anderson 
14077c478bd9Sstevel@tonic-gate #else /* ! UMUL64 */
14087c478bd9Sstevel@tonic-gate 
1409b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE != 32)
1410b60f2a0bSfr41279 #error Don't use 64-bit chunks without defining UMUL64
1411b60f2a0bSfr41279 #endif
1412b60f2a0bSfr41279 
1413b60f2a0bSfr41279 
14147c478bd9Sstevel@tonic-gate /*
14157c478bd9Sstevel@tonic-gate  * r = r + a * digit, r and a are vectors of length len
14167c478bd9Sstevel@tonic-gate  * returns the carry digit
14177c478bd9Sstevel@tonic-gate  */
14187c478bd9Sstevel@tonic-gate uint32_t
14197c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
14207c478bd9Sstevel@tonic-gate {
14217c478bd9Sstevel@tonic-gate 	uint32_t cy, cy1, retcy, dlow, dhigh;
14227c478bd9Sstevel@tonic-gate 	int i;
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 	cy1 = 0;
14257c478bd9Sstevel@tonic-gate 	dlow = digit & 0xffff;
14267c478bd9Sstevel@tonic-gate 	dhigh = digit >> 16;
14277c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
14287c478bd9Sstevel@tonic-gate 		cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff);
14297c478bd9Sstevel@tonic-gate 		cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16);
14307c478bd9Sstevel@tonic-gate 		r[i] = (cy & 0xffff) | (cy1 << 16);
14317c478bd9Sstevel@tonic-gate 	}
14327c478bd9Sstevel@tonic-gate 	retcy = cy1 >> 16;
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 	cy1 = r[0] & 0xffff;
14357c478bd9Sstevel@tonic-gate 	for (i = 0; i < len - 1; i++) {
14367c478bd9Sstevel@tonic-gate 		cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16);
14377c478bd9Sstevel@tonic-gate 		r[i] = (cy1 & 0xffff) | (cy << 16);
14387c478bd9Sstevel@tonic-gate 		cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff);
14397c478bd9Sstevel@tonic-gate 	}
14407c478bd9Sstevel@tonic-gate 	cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16);
14417c478bd9Sstevel@tonic-gate 	r[len - 1] = (cy1 & 0xffff) | (cy << 16);
14427c478bd9Sstevel@tonic-gate 	retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy;
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	return (retcy);
14457c478bd9Sstevel@tonic-gate }
14467c478bd9Sstevel@tonic-gate 
1447b60f2a0bSfr41279 
14487c478bd9Sstevel@tonic-gate /*
14497c478bd9Sstevel@tonic-gate  * r = a * digit, r and a are vectors of length len
14507c478bd9Sstevel@tonic-gate  * returns the carry digit
14517c478bd9Sstevel@tonic-gate  */
14527c478bd9Sstevel@tonic-gate uint32_t
14537c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
14547c478bd9Sstevel@tonic-gate {
1455b60f2a0bSfr41279 	int	i;
1456b60f2a0bSfr41279 
1457b60f2a0bSfr41279 	ASSERT(r != a);
1458b60f2a0bSfr41279 	for (i = 0; i < len; i++) {
1459b60f2a0bSfr41279 		r[i] = 0;
1460b60f2a0bSfr41279 	}
1461b60f2a0bSfr41279 
14627c478bd9Sstevel@tonic-gate 	return (big_mul_add_vec(r, a, len, digit));
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate void
14667c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
14677c478bd9Sstevel@tonic-gate {
14687c478bd9Sstevel@tonic-gate 	int i;
14697c478bd9Sstevel@tonic-gate 
1470b60f2a0bSfr41279 	ASSERT(r != a);
14717c478bd9Sstevel@tonic-gate 	r[len] = big_mul_set_vec(r, a, len, a[0]);
14727c478bd9Sstevel@tonic-gate 	for (i = 1; i < len; ++i)
14737c478bd9Sstevel@tonic-gate 		r[len + i] = big_mul_add_vec(r + i, a, len, a[i]);
14747c478bd9Sstevel@tonic-gate }
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate #endif /* UMUL64 */
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate void
1479b60f2a0bSfr41279 big_mul_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int alen,
1480b60f2a0bSfr41279     BIG_CHUNK_TYPE *b, int blen)
14817c478bd9Sstevel@tonic-gate {
14827c478bd9Sstevel@tonic-gate 	int i;
14837c478bd9Sstevel@tonic-gate 
14847c478bd9Sstevel@tonic-gate 	r[alen] = big_mul_set_vec(r, a, alen, b[0]);
14857c478bd9Sstevel@tonic-gate 	for (i = 1; i < blen; ++i)
14867c478bd9Sstevel@tonic-gate 		r[alen + i] = big_mul_add_vec(r + i, a, alen, b[i]);
14877c478bd9Sstevel@tonic-gate }
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate #endif /* ! PSR_MUL */
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate /*
14947c478bd9Sstevel@tonic-gate  * result = aa * bb  result->value should be big enough to hold the result
14957c478bd9Sstevel@tonic-gate  *
14967c478bd9Sstevel@tonic-gate  * Implementation: Standard grammar school algorithm
14977c478bd9Sstevel@tonic-gate  *
14987c478bd9Sstevel@tonic-gate  */
14997c478bd9Sstevel@tonic-gate BIG_ERR_CODE
15007c478bd9Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
15017c478bd9Sstevel@tonic-gate {
15027c478bd9Sstevel@tonic-gate 	BIGNUM		tmp1;
1503b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
1504b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*r, *t, *a, *b;
15057c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
15067c478bd9Sstevel@tonic-gate 	int		i, alen, blen, rsize, sign, diff;
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 	if (aa == bb) {
15097c478bd9Sstevel@tonic-gate 		diff = 0;
15107c478bd9Sstevel@tonic-gate 	} else {
15117c478bd9Sstevel@tonic-gate 		diff = big_cmp_abs(aa, bb);
15127c478bd9Sstevel@tonic-gate 		if (diff < 0) {
15137c478bd9Sstevel@tonic-gate 			BIGNUM *tt;
15147c478bd9Sstevel@tonic-gate 			tt = aa;
15157c478bd9Sstevel@tonic-gate 			aa = bb;
15167c478bd9Sstevel@tonic-gate 			bb = tt;
15177c478bd9Sstevel@tonic-gate 		}
15187c478bd9Sstevel@tonic-gate 	}
15197c478bd9Sstevel@tonic-gate 	a = aa->value;
15207c478bd9Sstevel@tonic-gate 	b = bb->value;
15217c478bd9Sstevel@tonic-gate 	alen = aa->len;
15227c478bd9Sstevel@tonic-gate 	blen = bb->len;
1523b60f2a0bSfr41279 	while ((alen > 1) && (a[alen - 1] == 0)) {
1524b60f2a0bSfr41279 		alen--;
1525b60f2a0bSfr41279 	}
15267c478bd9Sstevel@tonic-gate 	aa->len = alen;
1527b60f2a0bSfr41279 	while ((blen > 1) && (b[blen - 1] == 0)) {
1528b60f2a0bSfr41279 		blen--;
1529b60f2a0bSfr41279 	}
15307c478bd9Sstevel@tonic-gate 	bb->len = blen;
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate 	rsize = alen + blen;
1533*8475e043SDan OpenSolaris Anderson 	ASSERT(rsize > 0);
15347c478bd9Sstevel@tonic-gate 	if (result->size < rsize) {
15357c478bd9Sstevel@tonic-gate 		err = big_extend(result, rsize);
1536b60f2a0bSfr41279 		if (err != BIG_OK) {
15377c478bd9Sstevel@tonic-gate 			return (err);
1538b60f2a0bSfr41279 		}
15397c478bd9Sstevel@tonic-gate 		/* aa or bb might be an alias to result */
15407c478bd9Sstevel@tonic-gate 		a = aa->value;
15417c478bd9Sstevel@tonic-gate 		b = bb->value;
15427c478bd9Sstevel@tonic-gate 	}
15437c478bd9Sstevel@tonic-gate 	r = result->value;
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate 	if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) {
15467c478bd9Sstevel@tonic-gate 		result->len = 1;
15477c478bd9Sstevel@tonic-gate 		result->sign = 1;
15487c478bd9Sstevel@tonic-gate 		r[0] = 0;
15497c478bd9Sstevel@tonic-gate 		return (BIG_OK);
15507c478bd9Sstevel@tonic-gate 	}
15517c478bd9Sstevel@tonic-gate 	sign = aa->sign * bb->sign;
15527c478bd9Sstevel@tonic-gate 	if ((alen == 1) && (a[0] == 1)) {
1553b60f2a0bSfr41279 		for (i = 0; i < blen; i++) {
1554b60f2a0bSfr41279 			r[i] = b[i];
1555b60f2a0bSfr41279 		}
15567c478bd9Sstevel@tonic-gate 		result->len = blen;
15577c478bd9Sstevel@tonic-gate 		result->sign = sign;
15587c478bd9Sstevel@tonic-gate 		return (BIG_OK);
15597c478bd9Sstevel@tonic-gate 	}
15607c478bd9Sstevel@tonic-gate 	if ((blen == 1) && (b[0] == 1)) {
1561b60f2a0bSfr41279 		for (i = 0; i < alen; i++) {
1562b60f2a0bSfr41279 			r[i] = a[i];
1563b60f2a0bSfr41279 		}
15647c478bd9Sstevel@tonic-gate 		result->len = alen;
15657c478bd9Sstevel@tonic-gate 		result->sign = sign;
15667c478bd9Sstevel@tonic-gate 		return (BIG_OK);
15677c478bd9Sstevel@tonic-gate 	}
15687c478bd9Sstevel@tonic-gate 
1569b60f2a0bSfr41279 	if ((err = big_init1(&tmp1, rsize,
1570b60f2a0bSfr41279 	    tmp1value, arraysize(tmp1value))) != BIG_OK) {
15717c478bd9Sstevel@tonic-gate 		return (err);
1572b60f2a0bSfr41279 	}
1573b60f2a0bSfr41279 	(void) big_copy(&tmp1, aa);
15747c478bd9Sstevel@tonic-gate 	t = tmp1.value;
15757c478bd9Sstevel@tonic-gate 
1576b60f2a0bSfr41279 	for (i = 0; i < rsize; i++) {
1577b60f2a0bSfr41279 		t[i] = 0;
1578b60f2a0bSfr41279 	}
1579b60f2a0bSfr41279 
1580b60f2a0bSfr41279 	if (diff == 0 && alen > 2) {
15817c478bd9Sstevel@tonic-gate 		BIG_SQR_VEC(t, a, alen);
1582b60f2a0bSfr41279 	} else if (blen > 0) {
15837c478bd9Sstevel@tonic-gate 		BIG_MUL_VEC(t, a, alen, b, blen);
1584b60f2a0bSfr41279 	}
15857c478bd9Sstevel@tonic-gate 
1586b60f2a0bSfr41279 	if (t[rsize - 1] == 0) {
1587b60f2a0bSfr41279 		tmp1.len = rsize - 1;
1588b60f2a0bSfr41279 	} else {
1589b60f2a0bSfr41279 		tmp1.len = rsize;
1590b60f2a0bSfr41279 	}
1591*8475e043SDan OpenSolaris Anderson 
1592*8475e043SDan OpenSolaris Anderson 	err = big_copy(result, &tmp1);
1593*8475e043SDan OpenSolaris Anderson 
15947c478bd9Sstevel@tonic-gate 	result->sign = sign;
15957c478bd9Sstevel@tonic-gate 
1596b60f2a0bSfr41279 	big_finish(&tmp1);
15977c478bd9Sstevel@tonic-gate 
1598*8475e043SDan OpenSolaris Anderson 	return (err);
15997c478bd9Sstevel@tonic-gate }
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate /*
16037c478bd9Sstevel@tonic-gate  * caller must ensure that  a < n,  b < n  and  ret->size >=  2 * n->len + 1
16047c478bd9Sstevel@tonic-gate  * and that ret is not n
16057c478bd9Sstevel@tonic-gate  */
16067c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1607b60f2a0bSfr41279 big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, BIG_CHUNK_TYPE n0)
16087c478bd9Sstevel@tonic-gate {
16097c478bd9Sstevel@tonic-gate 	int	i, j, nlen, needsubtract;
1610b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*nn, *rr;
1611b60f2a0bSfr41279 	BIG_CHUNK_TYPE	digit, c;
16127c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 	nlen = n->len;
16157c478bd9Sstevel@tonic-gate 	nn = n->value;
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	rr = ret->value;
16187c478bd9Sstevel@tonic-gate 
1619b60f2a0bSfr41279 	if ((err = big_mul(ret, a, b)) != BIG_OK) {
16207c478bd9Sstevel@tonic-gate 		return (err);
1621b60f2a0bSfr41279 	}
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 	rr = ret->value;
1624b60f2a0bSfr41279 	for (i = ret->len; i < 2 * nlen + 1; i++) {
1625b60f2a0bSfr41279 		rr[i] = 0;
1626b60f2a0bSfr41279 	}
16277c478bd9Sstevel@tonic-gate 	for (i = 0; i < nlen; i++) {
16287c478bd9Sstevel@tonic-gate 		digit = rr[i];
16297c478bd9Sstevel@tonic-gate 		digit = digit * n0;
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 		c = BIG_MUL_ADD_VEC(rr + i, nn, nlen, digit);
16327c478bd9Sstevel@tonic-gate 		j = i + nlen;
16337c478bd9Sstevel@tonic-gate 		rr[j] += c;
16347c478bd9Sstevel@tonic-gate 		while (rr[j] < c) {
16357c478bd9Sstevel@tonic-gate 			rr[j + 1] += 1;
16367c478bd9Sstevel@tonic-gate 			j++;
16377c478bd9Sstevel@tonic-gate 			c = 1;
16387c478bd9Sstevel@tonic-gate 		}
16397c478bd9Sstevel@tonic-gate 	}
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate 	needsubtract = 0;
16427c478bd9Sstevel@tonic-gate 	if ((rr[2 * nlen]  != 0))
16437c478bd9Sstevel@tonic-gate 		needsubtract = 1;
16447c478bd9Sstevel@tonic-gate 	else {
16457c478bd9Sstevel@tonic-gate 		for (i = 2 * nlen - 1; i >= nlen; i--) {
16467c478bd9Sstevel@tonic-gate 			if (rr[i] > nn[i - nlen]) {
16477c478bd9Sstevel@tonic-gate 				needsubtract = 1;
16487c478bd9Sstevel@tonic-gate 				break;
1649b60f2a0bSfr41279 			} else if (rr[i] < nn[i - nlen]) {
1650b60f2a0bSfr41279 				break;
1651b60f2a0bSfr41279 			}
16527c478bd9Sstevel@tonic-gate 		}
16537c478bd9Sstevel@tonic-gate 	}
16547c478bd9Sstevel@tonic-gate 	if (needsubtract)
16557c478bd9Sstevel@tonic-gate 		big_sub_vec(rr, rr + nlen, nn, nlen);
16567c478bd9Sstevel@tonic-gate 	else {
1657b60f2a0bSfr41279 		for (i = 0; i < nlen; i++) {
16587c478bd9Sstevel@tonic-gate 			rr[i] = rr[i + nlen];
16597c478bd9Sstevel@tonic-gate 		}
1660b60f2a0bSfr41279 	}
1661*8475e043SDan OpenSolaris Anderson 
1662*8475e043SDan OpenSolaris Anderson 	/* Remove leading zeros, but keep at least 1 digit: */
1663*8475e043SDan OpenSolaris Anderson 	for (i = nlen - 1; (i > 0) && (rr[i] == 0); i--)
1664b60f2a0bSfr41279 		;
16657c478bd9Sstevel@tonic-gate 	ret->len = i + 1;
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate 	return (BIG_OK);
16687c478bd9Sstevel@tonic-gate }
16697c478bd9Sstevel@tonic-gate 
1670b60f2a0bSfr41279 
1671b60f2a0bSfr41279 BIG_CHUNK_TYPE
1672b60f2a0bSfr41279 big_n0(BIG_CHUNK_TYPE n)
16737c478bd9Sstevel@tonic-gate {
16747c478bd9Sstevel@tonic-gate 	int		i;
1675b60f2a0bSfr41279 	BIG_CHUNK_TYPE	result, tmp;
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate 	result = 0;
1678b60f2a0bSfr41279 	tmp = BIG_CHUNK_ALLBITS;
1679b60f2a0bSfr41279 	for (i = 0; i < BIG_CHUNK_SIZE; i++) {
16807c478bd9Sstevel@tonic-gate 		if ((tmp & 1) == 1) {
1681b60f2a0bSfr41279 			result = (result >> 1) | BIG_CHUNK_HIGHBIT;
16827c478bd9Sstevel@tonic-gate 			tmp = tmp - n;
1683b60f2a0bSfr41279 		} else {
1684b60f2a0bSfr41279 			result = (result >> 1);
1685b60f2a0bSfr41279 		}
16867c478bd9Sstevel@tonic-gate 		tmp = tmp >> 1;
16877c478bd9Sstevel@tonic-gate 	}
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate 	return (result);
16907c478bd9Sstevel@tonic-gate }
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate int
16947c478bd9Sstevel@tonic-gate big_numbits(BIGNUM *n)
16957c478bd9Sstevel@tonic-gate {
16967c478bd9Sstevel@tonic-gate 	int		i, j;
1697b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t;
16987c478bd9Sstevel@tonic-gate 
1699b60f2a0bSfr41279 	for (i = n->len - 1; i > 0; i--) {
1700b60f2a0bSfr41279 		if (n->value[i] != 0) {
1701b60f2a0bSfr41279 			break;
1702b60f2a0bSfr41279 		}
1703b60f2a0bSfr41279 	}
17047c478bd9Sstevel@tonic-gate 	t = n->value[i];
1705b60f2a0bSfr41279 	for (j = BIG_CHUNK_SIZE; j > 0; j--) {
1706b60f2a0bSfr41279 		if ((t & BIG_CHUNK_HIGHBIT) == 0) {
17077c478bd9Sstevel@tonic-gate 			t = t << 1;
1708b60f2a0bSfr41279 		} else {
1709b60f2a0bSfr41279 			return (BIG_CHUNK_SIZE * i + j);
1710b60f2a0bSfr41279 		}
17117c478bd9Sstevel@tonic-gate 	}
17127c478bd9Sstevel@tonic-gate 	return (0);
17137c478bd9Sstevel@tonic-gate }
17147c478bd9Sstevel@tonic-gate 
1715b60f2a0bSfr41279 
17167c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */
17177c478bd9Sstevel@tonic-gate BIG_ERR_CODE
17187c478bd9Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n)
17197c478bd9Sstevel@tonic-gate {
17207c478bd9Sstevel@tonic-gate 	BIGNUM		rr;
1721b60f2a0bSfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
17227c478bd9Sstevel@tonic-gate 	int		len, i;
17237c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
17267c478bd9Sstevel@tonic-gate 	len = n->len;
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1,
1729b60f2a0bSfr41279 	    rrvalue, arraysize(rrvalue))) != BIG_OK) {
17307c478bd9Sstevel@tonic-gate 		return (err);
17317c478bd9Sstevel@tonic-gate 	}
17327c478bd9Sstevel@tonic-gate 
1733b60f2a0bSfr41279 	for (i = 0; i < 2 * len; i++) {
1734b60f2a0bSfr41279 		rr.value[i] = 0;
1735b60f2a0bSfr41279 	}
1736b60f2a0bSfr41279 	rr.value[2 * len] = 1;
1737b60f2a0bSfr41279 	rr.len = 2 * len + 1;
1738b60f2a0bSfr41279 	if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) {
1739b60f2a0bSfr41279 		goto ret;
1740b60f2a0bSfr41279 	}
1741b60f2a0bSfr41279 	err = big_copy(result, &rr);
1742b60f2a0bSfr41279 ret:
1743b60f2a0bSfr41279 	big_finish(&rr);
1744b60f2a0bSfr41279 	return (err);
1745b60f2a0bSfr41279 }
1746b60f2a0bSfr41279 
1747b60f2a0bSfr41279 
17487c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */
17497c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1750b60f2a0bSfr41279 big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, BIG_CHUNK_TYPE n0,
1751b60f2a0bSfr41279     BIGNUM *n_rr)
17527c478bd9Sstevel@tonic-gate {
17537c478bd9Sstevel@tonic-gate 	BIGNUM		rr;
1754b60f2a0bSfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
17557c478bd9Sstevel@tonic-gate 	int		len, i;
17567c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
17597c478bd9Sstevel@tonic-gate 	len = n->len;
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue)))
1762b60f2a0bSfr41279 	    != BIG_OK) {
17637c478bd9Sstevel@tonic-gate 		return (err);
1764b60f2a0bSfr41279 	}
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 	if (n_rr == NULL) {
1767b60f2a0bSfr41279 		for (i = 0; i < 2 * len; i++) {
1768b60f2a0bSfr41279 			rr.value[i] = 0;
1769b60f2a0bSfr41279 		}
17707c478bd9Sstevel@tonic-gate 		rr.value[2 * len] = 1;
17717c478bd9Sstevel@tonic-gate 		rr.len = 2 * len + 1;
1772b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) {
17737c478bd9Sstevel@tonic-gate 			goto ret;
1774b60f2a0bSfr41279 		}
17757c478bd9Sstevel@tonic-gate 		n_rr = &rr;
17767c478bd9Sstevel@tonic-gate 	}
17777c478bd9Sstevel@tonic-gate 
1778b60f2a0bSfr41279 	if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK) {
17797c478bd9Sstevel@tonic-gate 		goto ret;
1780b60f2a0bSfr41279 	}
17817c478bd9Sstevel@tonic-gate 	err = big_copy(result, &rr);
1782b60f2a0bSfr41279 
17837c478bd9Sstevel@tonic-gate ret:
1784b60f2a0bSfr41279 	big_finish(&rr);
17857c478bd9Sstevel@tonic-gate 	return (err);
17867c478bd9Sstevel@tonic-gate }
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate 
1789b60f2a0bSfr41279 #ifdef	USE_FLOATING_POINT
1790b60f2a0bSfr41279 #define	big_modexp_ncp_float	big_modexp_ncp_sw
1791b60f2a0bSfr41279 #else
1792b60f2a0bSfr41279 #define	big_modexp_ncp_int	big_modexp_ncp_sw
1793b60f2a0bSfr41279 #endif
1794b60f2a0bSfr41279 
17957c478bd9Sstevel@tonic-gate #define	MAX_EXP_BIT_GROUP_SIZE 6
17967c478bd9Sstevel@tonic-gate #define	APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1))
17977c478bd9Sstevel@tonic-gate 
1798b60f2a0bSfr41279 /* ARGSUSED */
17997c478bd9Sstevel@tonic-gate static BIG_ERR_CODE
1800b60f2a0bSfr41279 big_modexp_ncp_int(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n,
1801b60f2a0bSfr41279     BIGNUM *tmp, BIG_CHUNK_TYPE n0)
1802b60f2a0bSfr41279 
18037c478bd9Sstevel@tonic-gate {
1804b60f2a0bSfr41279 	BIGNUM		apowers[APOWERS_MAX_SIZE];
1805b60f2a0bSfr41279 	BIGNUM		tmp1;
1806b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
1807b60f2a0bSfr41279 	int		i, j, k, l, m, p;
1808*8475e043SDan OpenSolaris Anderson 	uint32_t	bit, bitind, bitcount, groupbits, apowerssize;
1809*8475e043SDan OpenSolaris Anderson 	uint32_t	nbits;
18107c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 	nbits = big_numbits(e);
18137c478bd9Sstevel@tonic-gate 	if (nbits < 50) {
18147c478bd9Sstevel@tonic-gate 		groupbits = 1;
18157c478bd9Sstevel@tonic-gate 		apowerssize = 1;
18167c478bd9Sstevel@tonic-gate 	} else {
18177c478bd9Sstevel@tonic-gate 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
18187c478bd9Sstevel@tonic-gate 		apowerssize = 1 << (groupbits - 1);
18197c478bd9Sstevel@tonic-gate 	}
18207c478bd9Sstevel@tonic-gate 
1821b60f2a0bSfr41279 
1822b60f2a0bSfr41279 	if ((err = big_init1(&tmp1, 2 * n->len + 1,
1823b60f2a0bSfr41279 	    tmp1value, arraysize(tmp1value))) != BIG_OK) {
18247c478bd9Sstevel@tonic-gate 		return (err);
18257c478bd9Sstevel@tonic-gate 	}
18267c478bd9Sstevel@tonic-gate 
1827*8475e043SDan OpenSolaris Anderson 	/* clear the malloced bit to help cleanup */
1828b60f2a0bSfr41279 	for (i = 0; i < apowerssize; i++) {
1829b60f2a0bSfr41279 		apowers[i].malloced = 0;
1830b60f2a0bSfr41279 	}
1831*8475e043SDan OpenSolaris Anderson 
1832b60f2a0bSfr41279 	for (i = 0; i < apowerssize; i++) {
1833b60f2a0bSfr41279 		if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) !=
1834b60f2a0bSfr41279 		    BIG_OK) {
1835b60f2a0bSfr41279 			goto ret;
1836b60f2a0bSfr41279 		}
1837b60f2a0bSfr41279 	}
18387c478bd9Sstevel@tonic-gate 
1839b60f2a0bSfr41279 	(void) big_copy(&(apowers[0]), ma);
1840b60f2a0bSfr41279 
1841b60f2a0bSfr41279 	if ((err = big_mont_mul(&tmp1, ma, ma, n, n0)) != BIG_OK) {
1842b60f2a0bSfr41279 		goto ret;
1843b60f2a0bSfr41279 	}
1844b60f2a0bSfr41279 	(void) big_copy(ma, &tmp1);
1845b60f2a0bSfr41279 
1846b60f2a0bSfr41279 	for (i = 1; i < apowerssize; i++) {
1847b60f2a0bSfr41279 		if ((err = big_mont_mul(&tmp1, ma,
1848b60f2a0bSfr41279 		    &(apowers[i - 1]), n, n0)) != BIG_OK) {
1849b60f2a0bSfr41279 			goto ret;
1850b60f2a0bSfr41279 		}
1851b60f2a0bSfr41279 		(void) big_copy(&apowers[i], &tmp1);
1852b60f2a0bSfr41279 	}
1853b60f2a0bSfr41279 
1854b60f2a0bSfr41279 	bitind = nbits % BIG_CHUNK_SIZE;
1855b60f2a0bSfr41279 	k = 0;
1856b60f2a0bSfr41279 	l = 0;
1857b60f2a0bSfr41279 	p = 0;
1858b60f2a0bSfr41279 	bitcount = 0;
1859b60f2a0bSfr41279 	for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) {
1860b60f2a0bSfr41279 		for (j = bitind - 1; j >= 0; j--) {
1861b60f2a0bSfr41279 			bit = (e->value[i] >> j) & 1;
1862b60f2a0bSfr41279 			if ((bitcount == 0) && (bit == 0)) {
1863b60f2a0bSfr41279 				if ((err = big_mont_mul(tmp,
1864b60f2a0bSfr41279 				    tmp, tmp, n, n0)) != BIG_OK) {
1865b60f2a0bSfr41279 					goto ret;
1866b60f2a0bSfr41279 				}
18677c478bd9Sstevel@tonic-gate 			} else {
1868b60f2a0bSfr41279 				bitcount++;
1869b60f2a0bSfr41279 				p = p * 2 + bit;
1870b60f2a0bSfr41279 				if (bit == 1) {
1871b60f2a0bSfr41279 					k = k + l + 1;
1872b60f2a0bSfr41279 					l = 0;
1873b60f2a0bSfr41279 				} else {
1874b60f2a0bSfr41279 					l++;
18757c478bd9Sstevel@tonic-gate 				}
1876b60f2a0bSfr41279 				if (bitcount == groupbits) {
1877b60f2a0bSfr41279 					for (m = 0; m < k; m++) {
1878b60f2a0bSfr41279 						if ((err = big_mont_mul(tmp,
1879b60f2a0bSfr41279 						    tmp, tmp, n, n0)) !=
1880b60f2a0bSfr41279 						    BIG_OK) {
1881b60f2a0bSfr41279 							goto ret;
1882b60f2a0bSfr41279 						}
1883b60f2a0bSfr41279 					}
1884b60f2a0bSfr41279 					if ((err = big_mont_mul(tmp, tmp,
1885b60f2a0bSfr41279 					    &(apowers[p >> (l + 1)]),
1886b60f2a0bSfr41279 					    n, n0)) != BIG_OK) {
1887b60f2a0bSfr41279 						goto ret;
1888b60f2a0bSfr41279 					}
1889b60f2a0bSfr41279 					for (m = 0; m < l; m++) {
1890b60f2a0bSfr41279 						if ((err = big_mont_mul(tmp,
1891b60f2a0bSfr41279 						    tmp, tmp, n, n0)) !=
1892b60f2a0bSfr41279 						    BIG_OK) {
1893b60f2a0bSfr41279 							goto ret;
1894b60f2a0bSfr41279 						}
1895b60f2a0bSfr41279 					}
1896b60f2a0bSfr41279 					k = 0;
1897b60f2a0bSfr41279 					l = 0;
1898b60f2a0bSfr41279 					p = 0;
1899b60f2a0bSfr41279 					bitcount = 0;
1900b60f2a0bSfr41279 				}
1901b60f2a0bSfr41279 			}
1902b60f2a0bSfr41279 		}
1903b60f2a0bSfr41279 		bitind = BIG_CHUNK_SIZE;
1904b60f2a0bSfr41279 	}
19057c478bd9Sstevel@tonic-gate 
1906b60f2a0bSfr41279 	for (m = 0; m < k; m++) {
1907b60f2a0bSfr41279 		if ((err = big_mont_mul(tmp, tmp, tmp, n, n0)) != BIG_OK) {
1908b60f2a0bSfr41279 			goto ret;
1909b60f2a0bSfr41279 		}
1910b60f2a0bSfr41279 	}
1911b60f2a0bSfr41279 	if (p != 0) {
1912b60f2a0bSfr41279 		if ((err = big_mont_mul(tmp, tmp,
1913b60f2a0bSfr41279 		    &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK) {
1914b60f2a0bSfr41279 			goto ret;
1915b60f2a0bSfr41279 		}
1916b60f2a0bSfr41279 	}
1917b60f2a0bSfr41279 	for (m = 0; m < l; m++) {
1918b60f2a0bSfr41279 		if ((err = big_mont_mul(result, tmp, tmp, n, n0)) != BIG_OK) {
1919b60f2a0bSfr41279 			goto ret;
1920b60f2a0bSfr41279 		}
1921b60f2a0bSfr41279 	}
19227c478bd9Sstevel@tonic-gate 
1923b60f2a0bSfr41279 ret:
1924b60f2a0bSfr41279 	for (i = apowerssize - 1; i >= 0; i--) {
1925b60f2a0bSfr41279 		big_finish(&(apowers[i]));
1926b60f2a0bSfr41279 	}
1927b60f2a0bSfr41279 	big_finish(&tmp1);
1928b60f2a0bSfr41279 
1929b60f2a0bSfr41279 	return (err);
1930b60f2a0bSfr41279 }
1931b60f2a0bSfr41279 
1932b60f2a0bSfr41279 
1933b60f2a0bSfr41279 #ifdef USE_FLOATING_POINT
1934b60f2a0bSfr41279 
1935b60f2a0bSfr41279 #ifdef _KERNEL
1936b60f2a0bSfr41279 
1937b60f2a0bSfr41279 #include <sys/sysmacros.h>
1938b60f2a0bSfr41279 #include <sys/regset.h>
1939b60f2a0bSfr41279 #include <sys/fpu/fpusystm.h>
1940b60f2a0bSfr41279 
1941b60f2a0bSfr41279 /* the alignment for block stores to save fp registers */
1942b60f2a0bSfr41279 #define	FPR_ALIGN	(64)
1943b60f2a0bSfr41279 
1944b60f2a0bSfr41279 extern void big_savefp(kfpu_t *);
1945b60f2a0bSfr41279 extern void big_restorefp(kfpu_t *);
1946b60f2a0bSfr41279 
1947b60f2a0bSfr41279 #endif /* _KERNEL */
1948b60f2a0bSfr41279 
1949b60f2a0bSfr41279 /*
1950b60f2a0bSfr41279  * This version makes use of floating point for performance
1951b60f2a0bSfr41279  */
1952b60f2a0bSfr41279 static BIG_ERR_CODE
1953b60f2a0bSfr41279 big_modexp_ncp_float(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n,
1954b60f2a0bSfr41279     BIGNUM *tmp, BIG_CHUNK_TYPE n0)
1955b60f2a0bSfr41279 {
1956b60f2a0bSfr41279 
1957*8475e043SDan OpenSolaris Anderson 	int		i, j, k, l, m, p;
1958*8475e043SDan OpenSolaris Anderson 	uint32_t	bit, bitind, bitcount, nlen;
1959b60f2a0bSfr41279 	double		dn0;
1960b60f2a0bSfr41279 	double		*dn, *dt, *d16r, *d32r;
1961b60f2a0bSfr41279 	uint32_t	*nint, *prod;
1962b60f2a0bSfr41279 	double		*apowers[APOWERS_MAX_SIZE];
1963*8475e043SDan OpenSolaris Anderson 	uint32_t	nbits, groupbits, apowerssize;
1964b60f2a0bSfr41279 	BIG_ERR_CODE	err = BIG_OK;
1965b60f2a0bSfr41279 
1966b60f2a0bSfr41279 #ifdef _KERNEL
1967b60f2a0bSfr41279 	uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN];
1968b60f2a0bSfr41279 	kfpu_t *fpu;
1969b60f2a0bSfr41279 
1970b60f2a0bSfr41279 #ifdef DEBUG
1971b60f2a0bSfr41279 	if (!fpu_exists)
1972b60f2a0bSfr41279 		return (BIG_GENERAL_ERR);
1973b60f2a0bSfr41279 #endif
1974b60f2a0bSfr41279 
1975b60f2a0bSfr41279 	fpu =  (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN);
1976b60f2a0bSfr41279 	big_savefp(fpu);
1977b60f2a0bSfr41279 
1978b60f2a0bSfr41279 #endif /* _KERNEL */
1979b60f2a0bSfr41279 
1980b60f2a0bSfr41279 	nbits = big_numbits(e);
1981b60f2a0bSfr41279 	if (nbits < 50) {
1982b60f2a0bSfr41279 		groupbits = 1;
1983b60f2a0bSfr41279 		apowerssize = 1;
1984b60f2a0bSfr41279 	} else {
1985b60f2a0bSfr41279 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
1986b60f2a0bSfr41279 		apowerssize = 1 << (groupbits - 1);
1987b60f2a0bSfr41279 	}
1988b60f2a0bSfr41279 
1989b60f2a0bSfr41279 	nlen = (BIG_CHUNK_SIZE / 32) * n->len;
19907c478bd9Sstevel@tonic-gate 	dn0 = (double)(n0 & 0xffff);
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate 	dn = dt = d16r = d32r = NULL;
19937c478bd9Sstevel@tonic-gate 	nint = prod = NULL;
19947c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
19957c478bd9Sstevel@tonic-gate 		apowers[i] = NULL;
19967c478bd9Sstevel@tonic-gate 	}
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate 	if ((dn = big_malloc(nlen * sizeof (double))) == NULL) {
19997c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
20007c478bd9Sstevel@tonic-gate 		goto ret;
20017c478bd9Sstevel@tonic-gate 	}
20027c478bd9Sstevel@tonic-gate 	if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) {
20037c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
20047c478bd9Sstevel@tonic-gate 		goto ret;
20057c478bd9Sstevel@tonic-gate 	}
20067c478bd9Sstevel@tonic-gate 	if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) {
20077c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
20087c478bd9Sstevel@tonic-gate 		goto ret;
20097c478bd9Sstevel@tonic-gate 	}
20107c478bd9Sstevel@tonic-gate 	if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) {
20117c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
20127c478bd9Sstevel@tonic-gate 		goto ret;
20137c478bd9Sstevel@tonic-gate 	}
20147c478bd9Sstevel@tonic-gate 	if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) {
20157c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
20167c478bd9Sstevel@tonic-gate 		goto ret;
20177c478bd9Sstevel@tonic-gate 	}
20187c478bd9Sstevel@tonic-gate 	if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) {
20197c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
20207c478bd9Sstevel@tonic-gate 		goto ret;
20217c478bd9Sstevel@tonic-gate 	}
20227c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
20237c478bd9Sstevel@tonic-gate 		if ((apowers[i] = big_malloc((2 * nlen + 1) *
20247c478bd9Sstevel@tonic-gate 		    sizeof (double))) == NULL) {
20257c478bd9Sstevel@tonic-gate 			err = BIG_NO_MEM;
20267c478bd9Sstevel@tonic-gate 			goto ret;
20277c478bd9Sstevel@tonic-gate 		}
20287c478bd9Sstevel@tonic-gate 	}
20297c478bd9Sstevel@tonic-gate 
2030b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
2031b60f2a0bSfr41279 	for (i = 0; i < ma->len; i++) {
2032b60f2a0bSfr41279 		nint[i] = ma->value[i];
2033b60f2a0bSfr41279 	}
2034b60f2a0bSfr41279 	for (; i < nlen; i++) {
2035b60f2a0bSfr41279 		nint[i] = 0;
2036b60f2a0bSfr41279 	}
2037b60f2a0bSfr41279 #else
2038b60f2a0bSfr41279 	for (i = 0; i < ma->len; i++) {
2039b60f2a0bSfr41279 		nint[2 * i] = (uint32_t)(ma->value[i] & 0xffffffffULL);
2040b60f2a0bSfr41279 		nint[2 * i + 1] = (uint32_t)(ma->value[i] >> 32);
2041b60f2a0bSfr41279 	}
2042b60f2a0bSfr41279 	for (i = ma->len * 2; i < nlen; i++) {
2043b60f2a0bSfr41279 		nint[i] = 0;
2044b60f2a0bSfr41279 	}
2045b60f2a0bSfr41279 #endif
20467c478bd9Sstevel@tonic-gate 	conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen);
20477c478bd9Sstevel@tonic-gate 
2048b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
2049b60f2a0bSfr41279 	for (i = 0; i < n->len; i++) {
2050b60f2a0bSfr41279 		nint[i] = n->value[i];
2051b60f2a0bSfr41279 	}
2052b60f2a0bSfr41279 	for (; i < nlen; i++) {
2053b60f2a0bSfr41279 		nint[i] = 0;
2054b60f2a0bSfr41279 	}
2055b60f2a0bSfr41279 #else
2056b60f2a0bSfr41279 	for (i = 0; i < n->len; i++) {
2057b60f2a0bSfr41279 		nint[2 * i] = (uint32_t)(n->value[i] & 0xffffffffULL);
2058b60f2a0bSfr41279 		nint[2 * i + 1] = (uint32_t)(n->value[i] >> 32);
2059b60f2a0bSfr41279 	}
2060b60f2a0bSfr41279 	for (i = n->len * 2; i < nlen; i++) {
2061b60f2a0bSfr41279 		nint[i] = 0;
2062b60f2a0bSfr41279 	}
2063b60f2a0bSfr41279 #endif
20647c478bd9Sstevel@tonic-gate 	conv_i32_to_d32(dn, nint, nlen);
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate 	mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0);
20677c478bd9Sstevel@tonic-gate 	conv_i32_to_d32(d32r, prod, nlen);
20687c478bd9Sstevel@tonic-gate 	for (i = 1; i < apowerssize; i++) {
20697c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[i - 1],
20707c478bd9Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
20717c478bd9Sstevel@tonic-gate 		conv_i32_to_d16(apowers[i], prod, nlen);
20727c478bd9Sstevel@tonic-gate 	}
20737c478bd9Sstevel@tonic-gate 
2074b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
2075b60f2a0bSfr41279 	for (i = 0; i < tmp->len; i++) {
2076b60f2a0bSfr41279 		prod[i] = tmp->value[i];
2077b60f2a0bSfr41279 	}
2078b60f2a0bSfr41279 	for (; i < nlen + 1; i++) {
2079b60f2a0bSfr41279 		prod[i] = 0;
2080b60f2a0bSfr41279 	}
2081b60f2a0bSfr41279 #else
2082b60f2a0bSfr41279 	for (i = 0; i < tmp->len; i++) {
2083b60f2a0bSfr41279 		prod[2 * i] = (uint32_t)(tmp->value[i] & 0xffffffffULL);
2084b60f2a0bSfr41279 		prod[2 * i + 1] = (uint32_t)(tmp->value[i] >> 32);
2085b60f2a0bSfr41279 	}
2086b60f2a0bSfr41279 	for (i = tmp->len * 2; i < nlen + 1; i++) {
2087b60f2a0bSfr41279 		prod[i] = 0;
2088b60f2a0bSfr41279 	}
2089b60f2a0bSfr41279 #endif
20907c478bd9Sstevel@tonic-gate 
2091b60f2a0bSfr41279 	bitind = nbits % BIG_CHUNK_SIZE;
20927c478bd9Sstevel@tonic-gate 	k = 0;
20937c478bd9Sstevel@tonic-gate 	l = 0;
20947c478bd9Sstevel@tonic-gate 	p = 0;
20957c478bd9Sstevel@tonic-gate 	bitcount = 0;
2096b60f2a0bSfr41279 	for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) {
20977c478bd9Sstevel@tonic-gate 		for (j = bitind - 1; j >= 0; j--) {
20987c478bd9Sstevel@tonic-gate 			bit = (e->value[i] >> j) & 1;
20997c478bd9Sstevel@tonic-gate 			if ((bitcount == 0) && (bit == 0)) {
21007c478bd9Sstevel@tonic-gate 				conv_i32_to_d32_and_d16(d32r, d16r,
21017c478bd9Sstevel@tonic-gate 				    prod, nlen);
21027c478bd9Sstevel@tonic-gate 				mont_mulf_noconv(prod, d32r, d16r,
21037c478bd9Sstevel@tonic-gate 				    dt, dn, nint, nlen, dn0);
21047c478bd9Sstevel@tonic-gate 			} else {
21057c478bd9Sstevel@tonic-gate 				bitcount++;
21067c478bd9Sstevel@tonic-gate 				p = p * 2 + bit;
21077c478bd9Sstevel@tonic-gate 				if (bit == 1) {
21087c478bd9Sstevel@tonic-gate 					k = k + l + 1;
21097c478bd9Sstevel@tonic-gate 					l = 0;
21107c478bd9Sstevel@tonic-gate 				} else {
21117c478bd9Sstevel@tonic-gate 					l++;
21127c478bd9Sstevel@tonic-gate 				}
21137c478bd9Sstevel@tonic-gate 				if (bitcount == groupbits) {
21147c478bd9Sstevel@tonic-gate 					for (m = 0; m < k; m++) {
2115b60f2a0bSfr41279 						conv_i32_to_d32_and_d16(d32r,
2116b60f2a0bSfr41279 						    d16r, prod, nlen);
21177c478bd9Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
21187c478bd9Sstevel@tonic-gate 						    d16r, dt, dn, nint,
21197c478bd9Sstevel@tonic-gate 						    nlen, dn0);
21207c478bd9Sstevel@tonic-gate 					}
21217c478bd9Sstevel@tonic-gate 					conv_i32_to_d32(d32r, prod, nlen);
21227c478bd9Sstevel@tonic-gate 					mont_mulf_noconv(prod, d32r,
21237c478bd9Sstevel@tonic-gate 					    apowers[p >> (l + 1)],
21247c478bd9Sstevel@tonic-gate 					    dt, dn, nint, nlen, dn0);
21257c478bd9Sstevel@tonic-gate 					for (m = 0; m < l; m++) {
2126b60f2a0bSfr41279 						conv_i32_to_d32_and_d16(d32r,
2127b60f2a0bSfr41279 						    d16r, prod, nlen);
21287c478bd9Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
21297c478bd9Sstevel@tonic-gate 						    d16r, dt, dn, nint,
21307c478bd9Sstevel@tonic-gate 						    nlen, dn0);
21317c478bd9Sstevel@tonic-gate 					}
21327c478bd9Sstevel@tonic-gate 					k = 0;
21337c478bd9Sstevel@tonic-gate 					l = 0;
21347c478bd9Sstevel@tonic-gate 					p = 0;
21357c478bd9Sstevel@tonic-gate 					bitcount = 0;
21367c478bd9Sstevel@tonic-gate 				}
21377c478bd9Sstevel@tonic-gate 			}
21387c478bd9Sstevel@tonic-gate 		}
2139b60f2a0bSfr41279 		bitind = BIG_CHUNK_SIZE;
21407c478bd9Sstevel@tonic-gate 	}
21417c478bd9Sstevel@tonic-gate 
21427c478bd9Sstevel@tonic-gate 	for (m = 0; m < k; m++) {
21437c478bd9Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
21447c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
21457c478bd9Sstevel@tonic-gate 	}
21467c478bd9Sstevel@tonic-gate 	if (p != 0) {
21477c478bd9Sstevel@tonic-gate 		conv_i32_to_d32(d32r, prod, nlen);
21487c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)],
21497c478bd9Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
21507c478bd9Sstevel@tonic-gate 	}
21517c478bd9Sstevel@tonic-gate 	for (m = 0; m < l; m++) {
21527c478bd9Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
21537c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
21547c478bd9Sstevel@tonic-gate 	}
21557c478bd9Sstevel@tonic-gate 
2156b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
2157b60f2a0bSfr41279 	for (i = 0; i < nlen; i++) {
2158b60f2a0bSfr41279 		result->value[i] = prod[i];
2159b60f2a0bSfr41279 	}
2160b60f2a0bSfr41279 	for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--)
2161b60f2a0bSfr41279 		;
2162b60f2a0bSfr41279 #else
2163b60f2a0bSfr41279 	for (i = 0; i < nlen / 2; i++) {
2164b60f2a0bSfr41279 		result->value[i] = (uint64_t)(prod[2 * i]) +
2165b60f2a0bSfr41279 		    (((uint64_t)(prod[2 * i + 1])) << 32);
2166b60f2a0bSfr41279 	}
2167b60f2a0bSfr41279 	for (i = nlen / 2 - 1; (i > 0) && (result->value[i] == 0); i--)
2168b60f2a0bSfr41279 		;
2169b60f2a0bSfr41279 #endif
2170b60f2a0bSfr41279 	result->len = i + 1;
2171b60f2a0bSfr41279 
21727c478bd9Sstevel@tonic-gate ret:
21737c478bd9Sstevel@tonic-gate 	for (i = apowerssize - 1; i >= 0; i--) {
21747c478bd9Sstevel@tonic-gate 		if (apowers[i] != NULL)
21757c478bd9Sstevel@tonic-gate 			big_free(apowers[i], (2 * nlen + 1) * sizeof (double));
21767c478bd9Sstevel@tonic-gate 	}
2177b60f2a0bSfr41279 	if (d32r != NULL) {
21787c478bd9Sstevel@tonic-gate 		big_free(d32r, nlen * sizeof (double));
2179b60f2a0bSfr41279 	}
2180b60f2a0bSfr41279 	if (d16r != NULL) {
21817c478bd9Sstevel@tonic-gate 		big_free(d16r, (2 * nlen + 1) * sizeof (double));
2182b60f2a0bSfr41279 	}
2183b60f2a0bSfr41279 	if (prod != NULL) {
21847c478bd9Sstevel@tonic-gate 		big_free(prod, (nlen + 1) * sizeof (uint32_t));
2185b60f2a0bSfr41279 	}
2186b60f2a0bSfr41279 	if (nint != NULL) {
21877c478bd9Sstevel@tonic-gate 		big_free(nint, nlen * sizeof (uint32_t));
2188b60f2a0bSfr41279 	}
2189b60f2a0bSfr41279 	if (dt != NULL) {
21907c478bd9Sstevel@tonic-gate 		big_free(dt, (4 * nlen + 2) * sizeof (double));
2191b60f2a0bSfr41279 	}
2192b60f2a0bSfr41279 	if (dn != NULL) {
21937c478bd9Sstevel@tonic-gate 		big_free(dn, nlen * sizeof (double));
21947c478bd9Sstevel@tonic-gate 	}
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate #ifdef _KERNEL
2197b60f2a0bSfr41279 	big_restorefp(fpu);
21987c478bd9Sstevel@tonic-gate #endif
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 	return (err);
22017c478bd9Sstevel@tonic-gate }
22027c478bd9Sstevel@tonic-gate 
22037c478bd9Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */
22047c478bd9Sstevel@tonic-gate 
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2207b60f2a0bSfr41279 big_modexp_ext(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr,
2208b60f2a0bSfr41279     big_modexp_ncp_info_t *info)
2209b60f2a0bSfr41279 {
2210b60f2a0bSfr41279 	BIGNUM		ma, tmp, rr;
2211b60f2a0bSfr41279 	BIG_CHUNK_TYPE	mavalue[BIGTMPSIZE];
2212b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
2213b60f2a0bSfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
2214b60f2a0bSfr41279 	BIG_ERR_CODE	err;
2215b60f2a0bSfr41279 	BIG_CHUNK_TYPE	n0;
2216b60f2a0bSfr41279 
2217b60f2a0bSfr41279 	if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue)))	!=
2218b60f2a0bSfr41279 	    BIG_OK) {
2219b60f2a0bSfr41279 		return (err);
2220b60f2a0bSfr41279 	}
2221b60f2a0bSfr41279 	ma.len = 1;
2222b60f2a0bSfr41279 	ma.value[0] = 0;
2223b60f2a0bSfr41279 
2224b60f2a0bSfr41279 	if ((err = big_init1(&tmp, 2 * n->len + 1,
2225b60f2a0bSfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
2226b60f2a0bSfr41279 		goto ret1;
2227b60f2a0bSfr41279 	}
2228b60f2a0bSfr41279 
2229*8475e043SDan OpenSolaris Anderson 	/* clear the malloced bit to help cleanup */
2230b60f2a0bSfr41279 	rr.malloced = 0;
2231*8475e043SDan OpenSolaris Anderson 
2232b60f2a0bSfr41279 	if (n_rr == NULL) {
2233b60f2a0bSfr41279 		if ((err = big_init1(&rr, 2 * n->len + 1,
2234b60f2a0bSfr41279 		    rrvalue, arraysize(rrvalue))) != BIG_OK) {
2235b60f2a0bSfr41279 			goto ret2;
2236b60f2a0bSfr41279 		}
2237b60f2a0bSfr41279 		if (big_mont_rr(&rr, n) != BIG_OK) {
2238b60f2a0bSfr41279 			goto ret;
2239b60f2a0bSfr41279 		}
2240b60f2a0bSfr41279 		n_rr = &rr;
2241b60f2a0bSfr41279 	}
2242b60f2a0bSfr41279 
2243b60f2a0bSfr41279 	n0 = big_n0(n->value[0]);
2244b60f2a0bSfr41279 
2245b60f2a0bSfr41279 	if (big_cmp_abs(a, n) > 0) {
2246b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK) {
2247b60f2a0bSfr41279 			goto ret;
2248b60f2a0bSfr41279 		}
2249b60f2a0bSfr41279 		err = big_mont_conv(&ma, &ma, n, n0, n_rr);
2250b60f2a0bSfr41279 	} else {
2251b60f2a0bSfr41279 		err = big_mont_conv(&ma, a, n, n0, n_rr);
2252b60f2a0bSfr41279 	}
2253b60f2a0bSfr41279 	if (err != BIG_OK) {
2254b60f2a0bSfr41279 		goto ret;
2255b60f2a0bSfr41279 	}
2256b60f2a0bSfr41279 
2257b60f2a0bSfr41279 	tmp.len = 1;
2258b60f2a0bSfr41279 	tmp.value[0] = 1;
2259b60f2a0bSfr41279 	if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK) {
2260b60f2a0bSfr41279 		goto ret;
2261b60f2a0bSfr41279 	}
2262b60f2a0bSfr41279 
2263b60f2a0bSfr41279 	if ((info != NULL) && (info->func != NULL)) {
2264b60f2a0bSfr41279 		err = (*(info->func))(&tmp, &ma, e, n, &tmp, n0,
2265b60f2a0bSfr41279 		    info->ncp, info->reqp);
2266b60f2a0bSfr41279 	} else {
2267b60f2a0bSfr41279 		err = big_modexp_ncp_sw(&tmp, &ma, e, n, &tmp, n0);
2268b60f2a0bSfr41279 	}
2269b60f2a0bSfr41279 	if (err != BIG_OK) {
2270b60f2a0bSfr41279 		goto ret;
2271b60f2a0bSfr41279 	}
2272b60f2a0bSfr41279 
2273b60f2a0bSfr41279 	ma.value[0] = 1;
2274b60f2a0bSfr41279 	ma.len = 1;
2275b60f2a0bSfr41279 	if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK) {
2276b60f2a0bSfr41279 		goto ret;
2277b60f2a0bSfr41279 	}
2278b60f2a0bSfr41279 	err = big_copy(result, &tmp);
2279b60f2a0bSfr41279 
2280b60f2a0bSfr41279 ret:
2281b60f2a0bSfr41279 	if (rr.malloced) {
2282b60f2a0bSfr41279 		big_finish(&rr);
2283b60f2a0bSfr41279 	}
2284b60f2a0bSfr41279 ret2:
2285b60f2a0bSfr41279 	big_finish(&tmp);
2286b60f2a0bSfr41279 ret1:
2287b60f2a0bSfr41279 	big_finish(&ma);
2288b60f2a0bSfr41279 
2289b60f2a0bSfr41279 	return (err);
2290b60f2a0bSfr41279 }
2291b60f2a0bSfr41279 
2292b60f2a0bSfr41279 BIG_ERR_CODE
2293b60f2a0bSfr41279 big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
2294b60f2a0bSfr41279 {
2295b60f2a0bSfr41279 	return (big_modexp_ext(result, a, e, n, n_rr, NULL));
2296b60f2a0bSfr41279 }
2297b60f2a0bSfr41279 
2298b60f2a0bSfr41279 
2299b60f2a0bSfr41279 BIG_ERR_CODE
2300b60f2a0bSfr41279 big_modexp_crt_ext(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
23017c478bd9Sstevel@tonic-gate     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
2302b60f2a0bSfr41279     BIGNUM *p_rr, BIGNUM *q_rr, big_modexp_ncp_info_t *info)
23037c478bd9Sstevel@tonic-gate {
23047c478bd9Sstevel@tonic-gate 	BIGNUM		ap, aq, tmp;
23057c478bd9Sstevel@tonic-gate 	int		alen, biglen, sign;
23067c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
23077c478bd9Sstevel@tonic-gate 
2308b60f2a0bSfr41279 	if (p->len > q->len) {
2309b60f2a0bSfr41279 		biglen = p->len;
2310b60f2a0bSfr41279 	} else {
2311b60f2a0bSfr41279 		biglen = q->len;
2312b60f2a0bSfr41279 	}
23137c478bd9Sstevel@tonic-gate 
2314b60f2a0bSfr41279 	if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK) {
23157c478bd9Sstevel@tonic-gate 		return (err);
2316b60f2a0bSfr41279 	}
2317b60f2a0bSfr41279 	if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK) {
23187c478bd9Sstevel@tonic-gate 		goto ret1;
2319b60f2a0bSfr41279 	}
2320b60f2a0bSfr41279 	if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK) {
23217c478bd9Sstevel@tonic-gate 		goto ret2;
2322b60f2a0bSfr41279 	}
23237c478bd9Sstevel@tonic-gate 
23247c478bd9Sstevel@tonic-gate 	/*
23257c478bd9Sstevel@tonic-gate 	 * check whether a is too short - to avoid timing attacks
23267c478bd9Sstevel@tonic-gate 	 */
23277c478bd9Sstevel@tonic-gate 	alen = a->len;
23287c478bd9Sstevel@tonic-gate 	while ((alen > p->len) && (a->value[alen - 1] == 0)) {
23297c478bd9Sstevel@tonic-gate 		alen--;
23307c478bd9Sstevel@tonic-gate 	}
23317c478bd9Sstevel@tonic-gate 	if (alen < p->len + q->len) {
23327c478bd9Sstevel@tonic-gate 		/*
23337c478bd9Sstevel@tonic-gate 		 * a is too short, add p*q to it before
23347c478bd9Sstevel@tonic-gate 		 * taking it modulo p and q
23357c478bd9Sstevel@tonic-gate 		 * this will also affect timing, but this difference
23367c478bd9Sstevel@tonic-gate 		 * does not depend on p or q, only on a
23377c478bd9Sstevel@tonic-gate 		 * (in "normal" operation, this path will never be
23387c478bd9Sstevel@tonic-gate 		 * taken, so it is not a performance penalty
23397c478bd9Sstevel@tonic-gate 		 */
2340b60f2a0bSfr41279 		if ((err = big_mul(&tmp, p, q)) != BIG_OK) {
23417c478bd9Sstevel@tonic-gate 			goto ret;
23427c478bd9Sstevel@tonic-gate 		}
2343b60f2a0bSfr41279 		if ((err = big_add(&tmp, &tmp, a)) != BIG_OK) {
2344b60f2a0bSfr41279 			goto ret;
2345b60f2a0bSfr41279 		}
2346b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK) {
2347b60f2a0bSfr41279 			goto ret;
2348b60f2a0bSfr41279 		}
2349b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) {
2350b60f2a0bSfr41279 			goto ret;
2351b60f2a0bSfr41279 		}
2352b60f2a0bSfr41279 	} else {
2353b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK) {
2354b60f2a0bSfr41279 			goto ret;
2355b60f2a0bSfr41279 		}
2356b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK) {
2357b60f2a0bSfr41279 			goto ret;
2358b60f2a0bSfr41279 		}
2359b60f2a0bSfr41279 	}
23607c478bd9Sstevel@tonic-gate 
2361b60f2a0bSfr41279 	if ((err = big_modexp_ext(&ap, &ap, dmodpminus1, p, p_rr, info)) !=
2362b60f2a0bSfr41279 	    BIG_OK) {
23637c478bd9Sstevel@tonic-gate 		goto ret;
2364b60f2a0bSfr41279 	}
2365b60f2a0bSfr41279 	if ((err = big_modexp_ext(&aq, &aq, dmodqminus1, q, q_rr, info)) !=
2366b60f2a0bSfr41279 	    BIG_OK) {
23677c478bd9Sstevel@tonic-gate 		goto ret;
2368b60f2a0bSfr41279 	}
2369b60f2a0bSfr41279 	if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK) {
23707c478bd9Sstevel@tonic-gate 		goto ret;
2371b60f2a0bSfr41279 	}
2372b60f2a0bSfr41279 	if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK) {
23737c478bd9Sstevel@tonic-gate 		goto ret;
2374b60f2a0bSfr41279 	}
23757c478bd9Sstevel@tonic-gate 	sign = tmp.sign;
23767c478bd9Sstevel@tonic-gate 	tmp.sign = 1;
2377b60f2a0bSfr41279 	if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) {
23787c478bd9Sstevel@tonic-gate 		goto ret;
2379b60f2a0bSfr41279 	}
23807c478bd9Sstevel@tonic-gate 	if ((sign == -1) && (!big_is_zero(&aq))) {
23817c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(&aq, q, &aq);
23827c478bd9Sstevel@tonic-gate 	}
2383b60f2a0bSfr41279 	if ((err = big_mul(&tmp, &aq, p)) != BIG_OK) {
23847c478bd9Sstevel@tonic-gate 		goto ret;
2385b60f2a0bSfr41279 	}
23867c478bd9Sstevel@tonic-gate 	err = big_add_abs(result, &ap, &tmp);
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate ret:
23897c478bd9Sstevel@tonic-gate 	big_finish(&tmp);
23907c478bd9Sstevel@tonic-gate ret2:
23917c478bd9Sstevel@tonic-gate 	big_finish(&aq);
23927c478bd9Sstevel@tonic-gate ret1:
23937c478bd9Sstevel@tonic-gate 	big_finish(&ap);
23947c478bd9Sstevel@tonic-gate 
23957c478bd9Sstevel@tonic-gate 	return (err);
23967c478bd9Sstevel@tonic-gate }
23977c478bd9Sstevel@tonic-gate 
23987c478bd9Sstevel@tonic-gate 
2399b60f2a0bSfr41279 BIG_ERR_CODE
2400b60f2a0bSfr41279 big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
2401b60f2a0bSfr41279     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
2402b60f2a0bSfr41279     BIGNUM *p_rr, BIGNUM *q_rr)
2403b60f2a0bSfr41279 {
2404b60f2a0bSfr41279 	return (big_modexp_crt_ext(result, a, dmodpminus1, dmodqminus1,
2405b60f2a0bSfr41279 	    p, q, pinvmodq, p_rr, q_rr, NULL));
2406b60f2a0bSfr41279 }
24077c478bd9Sstevel@tonic-gate 
24087c478bd9Sstevel@tonic-gate 
2409b60f2a0bSfr41279 static BIG_CHUNK_TYPE onearr[1] = {(BIG_CHUNK_TYPE)1};
2410b60f2a0bSfr41279 BIGNUM big_One = {1, 1, 1, 0, onearr};
2411b60f2a0bSfr41279 
2412b60f2a0bSfr41279 static BIG_CHUNK_TYPE twoarr[1] = {(BIG_CHUNK_TYPE)2};
2413b60f2a0bSfr41279 BIGNUM big_Two = {1, 1, 1, 0, twoarr};
2414b60f2a0bSfr41279 
2415b60f2a0bSfr41279 static BIG_CHUNK_TYPE fourarr[1] = {(BIG_CHUNK_TYPE)4};
2416b60f2a0bSfr41279 static BIGNUM big_Four = {1, 1, 1, 0, fourarr};
2417b60f2a0bSfr41279 
24187c478bd9Sstevel@tonic-gate 
24197c478bd9Sstevel@tonic-gate BIG_ERR_CODE
24207c478bd9Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n)
24217c478bd9Sstevel@tonic-gate {
24227c478bd9Sstevel@tonic-gate 	BIGNUM		*high, *low, *mid, *t;
24237c478bd9Sstevel@tonic-gate 	BIGNUM		t1, t2, t3, prod;
2424b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
2425b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
2426b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
2427b60f2a0bSfr41279 	BIG_CHUNK_TYPE	prodvalue[BIGTMPSIZE];
2428*8475e043SDan OpenSolaris Anderson 	int		i, diff;
2429*8475e043SDan OpenSolaris Anderson 	uint32_t	nbits, nrootbits, highbits;
24307c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
24317c478bd9Sstevel@tonic-gate 
24327c478bd9Sstevel@tonic-gate 	nbits = big_numbits(n);
24337c478bd9Sstevel@tonic-gate 
24347c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, n->len + 1,
24357c478bd9Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
24367c478bd9Sstevel@tonic-gate 		return (err);
24377c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, n->len + 1,
24387c478bd9Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
24397c478bd9Sstevel@tonic-gate 		goto ret1;
24407c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, n->len + 1,
24417c478bd9Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
24427c478bd9Sstevel@tonic-gate 		goto ret2;
24437c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&prod, n->len + 1,
24447c478bd9Sstevel@tonic-gate 	    prodvalue, arraysize(prodvalue))) != BIG_OK)
24457c478bd9Sstevel@tonic-gate 		goto ret3;
24467c478bd9Sstevel@tonic-gate 
24477c478bd9Sstevel@tonic-gate 	nrootbits = (nbits + 1) / 2;
2448b60f2a0bSfr41279 	t1.len = t2.len = t3.len = (nrootbits - 1) / BIG_CHUNK_SIZE + 1;
24497c478bd9Sstevel@tonic-gate 	for (i = 0; i < t1.len; i++) {
24507c478bd9Sstevel@tonic-gate 		t1.value[i] = 0;
2451b60f2a0bSfr41279 		t2.value[i] = BIG_CHUNK_ALLBITS;
24527c478bd9Sstevel@tonic-gate 	}
2453b60f2a0bSfr41279 	highbits = nrootbits - BIG_CHUNK_SIZE * (t1.len - 1);
2454b60f2a0bSfr41279 	if (highbits == BIG_CHUNK_SIZE) {
2455b60f2a0bSfr41279 		t1.value[t1.len - 1] = BIG_CHUNK_HIGHBIT;
2456b60f2a0bSfr41279 		t2.value[t2.len - 1] = BIG_CHUNK_ALLBITS;
24577c478bd9Sstevel@tonic-gate 	} else {
2458b60f2a0bSfr41279 		t1.value[t1.len - 1] = (BIG_CHUNK_TYPE)1 << (highbits - 1);
24597c478bd9Sstevel@tonic-gate 		t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1;
24607c478bd9Sstevel@tonic-gate 	}
2461b60f2a0bSfr41279 
24627c478bd9Sstevel@tonic-gate 	high = &t2;
24637c478bd9Sstevel@tonic-gate 	low = &t1;
24647c478bd9Sstevel@tonic-gate 	mid = &t3;
24657c478bd9Sstevel@tonic-gate 
2466b60f2a0bSfr41279 	if ((err = big_mul(&prod, high, high)) != BIG_OK) {
24677c478bd9Sstevel@tonic-gate 		goto ret;
2468b60f2a0bSfr41279 	}
24697c478bd9Sstevel@tonic-gate 	diff = big_cmp_abs(&prod, n);
24707c478bd9Sstevel@tonic-gate 	if (diff <= 0) {
24717c478bd9Sstevel@tonic-gate 		err = big_copy(result, high);
24727c478bd9Sstevel@tonic-gate 		goto ret;
24737c478bd9Sstevel@tonic-gate 	}
24747c478bd9Sstevel@tonic-gate 
24757c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(mid, high, low);
2476b60f2a0bSfr41279 	while (big_cmp_abs(&big_One, mid) != 0) {
24777c478bd9Sstevel@tonic-gate 		(void) big_add_abs(mid, high, low);
24787c478bd9Sstevel@tonic-gate 		(void) big_half_pos(mid, mid);
24797c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&prod, mid, mid)) != BIG_OK)
24807c478bd9Sstevel@tonic-gate 			goto ret;
24817c478bd9Sstevel@tonic-gate 		diff = big_cmp_abs(&prod, n);
24827c478bd9Sstevel@tonic-gate 		if (diff > 0) {
24837c478bd9Sstevel@tonic-gate 			t = high;
24847c478bd9Sstevel@tonic-gate 			high = mid;
24857c478bd9Sstevel@tonic-gate 			mid = t;
24867c478bd9Sstevel@tonic-gate 		} else if (diff < 0) {
24877c478bd9Sstevel@tonic-gate 			t = low;
24887c478bd9Sstevel@tonic-gate 			low = mid;
24897c478bd9Sstevel@tonic-gate 			mid = t;
24907c478bd9Sstevel@tonic-gate 		} else {
24917c478bd9Sstevel@tonic-gate 			err = big_copy(result, low);
24927c478bd9Sstevel@tonic-gate 			goto ret;
24937c478bd9Sstevel@tonic-gate 		}
24947c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(mid, high, low);
24957c478bd9Sstevel@tonic-gate 	}
24967c478bd9Sstevel@tonic-gate 
24977c478bd9Sstevel@tonic-gate 	err = big_copy(result, low);
24987c478bd9Sstevel@tonic-gate ret:
24997c478bd9Sstevel@tonic-gate 	if (prod.malloced) big_finish(&prod);
25007c478bd9Sstevel@tonic-gate ret3:
25017c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
25027c478bd9Sstevel@tonic-gate ret2:
25037c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
25047c478bd9Sstevel@tonic-gate ret1:
25057c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
25067c478bd9Sstevel@tonic-gate 
25077c478bd9Sstevel@tonic-gate 	return (err);
25087c478bd9Sstevel@tonic-gate }
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate 
25117c478bd9Sstevel@tonic-gate BIG_ERR_CODE
25127c478bd9Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm)
25137c478bd9Sstevel@tonic-gate {
25147c478bd9Sstevel@tonic-gate 	BIGNUM		*t, *tmp2, *m, *n;
25157c478bd9Sstevel@tonic-gate 	BIGNUM		t1, t2, t3;
2516b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
2517b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
2518b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
25197c478bd9Sstevel@tonic-gate 	int		len, err;
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate 	if (big_is_zero(nn) ||
25227c478bd9Sstevel@tonic-gate 	    (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) {
25237c478bd9Sstevel@tonic-gate 		*jac = 0;
25247c478bd9Sstevel@tonic-gate 		return (BIG_OK);
25257c478bd9Sstevel@tonic-gate 	}
25267c478bd9Sstevel@tonic-gate 
2527b60f2a0bSfr41279 	if (nn->len > mm->len) {
2528b60f2a0bSfr41279 		len = nn->len;
2529b60f2a0bSfr41279 	} else {
2530b60f2a0bSfr41279 		len = mm->len;
2531b60f2a0bSfr41279 	}
25327c478bd9Sstevel@tonic-gate 
25337c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
2534b60f2a0bSfr41279 	    t1value, arraysize(t1value))) != BIG_OK) {
25357c478bd9Sstevel@tonic-gate 		return (err);
2536b60f2a0bSfr41279 	}
25377c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
2538b60f2a0bSfr41279 	    t2value, arraysize(t2value))) != BIG_OK) {
25397c478bd9Sstevel@tonic-gate 		goto ret1;
2540b60f2a0bSfr41279 	}
25417c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
2542b60f2a0bSfr41279 	    t3value, arraysize(t3value))) != BIG_OK) {
25437c478bd9Sstevel@tonic-gate 		goto ret2;
2544b60f2a0bSfr41279 	}
25457c478bd9Sstevel@tonic-gate 
25467c478bd9Sstevel@tonic-gate 	n = &t1;
25477c478bd9Sstevel@tonic-gate 	m = &t2;
25487c478bd9Sstevel@tonic-gate 	tmp2 = &t3;
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate 	(void) big_copy(n, nn);
25517c478bd9Sstevel@tonic-gate 	(void) big_copy(m, mm);
25527c478bd9Sstevel@tonic-gate 
25537c478bd9Sstevel@tonic-gate 	*jac = 1;
2554b60f2a0bSfr41279 	while (big_cmp_abs(&big_One, m) != 0) {
25557c478bd9Sstevel@tonic-gate 		if (big_is_zero(n)) {
25567c478bd9Sstevel@tonic-gate 			*jac = 0;
25577c478bd9Sstevel@tonic-gate 			goto ret;
25587c478bd9Sstevel@tonic-gate 		}
25597c478bd9Sstevel@tonic-gate 		if ((m->value[0] & 1) == 0) {
25607c478bd9Sstevel@tonic-gate 			if (((n->value[0] & 7) == 3) ||
2561b60f2a0bSfr41279 			    ((n->value[0] & 7) == 5))
2562b60f2a0bSfr41279 				*jac = -*jac;
25637c478bd9Sstevel@tonic-gate 			(void) big_half_pos(m, m);
25647c478bd9Sstevel@tonic-gate 		} else if ((n->value[0] & 1) == 0) {
25657c478bd9Sstevel@tonic-gate 			if (((m->value[0] & 7) == 3) ||
2566b60f2a0bSfr41279 			    ((m->value[0] & 7) == 5))
2567b60f2a0bSfr41279 				*jac = -*jac;
25687c478bd9Sstevel@tonic-gate 			(void) big_half_pos(n, n);
25697c478bd9Sstevel@tonic-gate 		} else {
25707c478bd9Sstevel@tonic-gate 			if (((m->value[0] & 3) == 3) &&
25717c478bd9Sstevel@tonic-gate 			    ((n->value[0] & 3) == 3)) {
25727c478bd9Sstevel@tonic-gate 				*jac = -*jac;
25737c478bd9Sstevel@tonic-gate 			}
2574b60f2a0bSfr41279 			if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK) {
25757c478bd9Sstevel@tonic-gate 				goto ret;
2576b60f2a0bSfr41279 			}
25777c478bd9Sstevel@tonic-gate 			t = tmp2;
25787c478bd9Sstevel@tonic-gate 			tmp2 = m;
25797c478bd9Sstevel@tonic-gate 			m = n;
25807c478bd9Sstevel@tonic-gate 			n = t;
25817c478bd9Sstevel@tonic-gate 		}
25827c478bd9Sstevel@tonic-gate 	}
25837c478bd9Sstevel@tonic-gate 	err = BIG_OK;
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate ret:
25867c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
25877c478bd9Sstevel@tonic-gate ret2:
25887c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
25897c478bd9Sstevel@tonic-gate ret1:
25907c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate 	return (err);
25937c478bd9Sstevel@tonic-gate }
25947c478bd9Sstevel@tonic-gate 
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate BIG_ERR_CODE
25977c478bd9Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n)
25987c478bd9Sstevel@tonic-gate {
2599*8475e043SDan OpenSolaris Anderson 	int		i;
2600*8475e043SDan OpenSolaris Anderson 	uint32_t	m, w;
2601b60f2a0bSfr41279 	BIG_CHUNK_TYPE	bit;
26027c478bd9Sstevel@tonic-gate 	BIGNUM		ki, tmp, tmp2;
2603b60f2a0bSfr41279 	BIG_CHUNK_TYPE	kivalue[BIGTMPSIZE];
2604b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
2605b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp2value[BIGTMPSIZE];
26067c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
26077c478bd9Sstevel@tonic-gate 
2608b60f2a0bSfr41279 	if (big_cmp_abs(k, &big_One) == 0) {
26097c478bd9Sstevel@tonic-gate 		(void) big_copy(Lk, p);
2610b60f2a0bSfr41279 		(void) big_copy(Lkminus1, &big_Two);
26117c478bd9Sstevel@tonic-gate 		return (BIG_OK);
26127c478bd9Sstevel@tonic-gate 	}
26137c478bd9Sstevel@tonic-gate 
26147c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&ki, k->len + 1,
26157c478bd9Sstevel@tonic-gate 	    kivalue, arraysize(kivalue))) != BIG_OK)
26167c478bd9Sstevel@tonic-gate 		return (err);
26177c478bd9Sstevel@tonic-gate 
26187c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len + 1,
26197c478bd9Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
26207c478bd9Sstevel@tonic-gate 		goto ret1;
26217c478bd9Sstevel@tonic-gate 
26227c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, n->len,
26237c478bd9Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
26247c478bd9Sstevel@tonic-gate 		goto ret2;
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	m = big_numbits(k);
2627b60f2a0bSfr41279 	ki.len = (m - 1) / BIG_CHUNK_SIZE + 1;
2628b60f2a0bSfr41279 	w = (m - 1) / BIG_CHUNK_SIZE;
2629b60f2a0bSfr41279 	bit = (BIG_CHUNK_TYPE)1 << ((m - 1) % BIG_CHUNK_SIZE);
2630b60f2a0bSfr41279 	for (i = 0; i < ki.len; i++) {
2631b60f2a0bSfr41279 		ki.value[i] = 0;
2632b60f2a0bSfr41279 	}
26337c478bd9Sstevel@tonic-gate 	ki.value[ki.len - 1] = bit;
2634b60f2a0bSfr41279 	if (big_cmp_abs(k, &ki) != 0) {
26357c478bd9Sstevel@tonic-gate 		(void) big_double(&ki, &ki);
2636b60f2a0bSfr41279 	}
26377c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(&ki, &ki, k);
26387c478bd9Sstevel@tonic-gate 
26397c478bd9Sstevel@tonic-gate 	(void) big_copy(Lk, p);
2640b60f2a0bSfr41279 	(void) big_copy(Lkminus1, &big_Two);
26417c478bd9Sstevel@tonic-gate 
26427c478bd9Sstevel@tonic-gate 	for (i = 0; i < m; i++) {
2643b60f2a0bSfr41279 		if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK) {
26447c478bd9Sstevel@tonic-gate 			goto ret;
2645b60f2a0bSfr41279 		}
26467c478bd9Sstevel@tonic-gate 		(void) big_add_abs(&tmp, &tmp, n);
26477c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(&tmp, &tmp, p);
2648b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK) {
26497c478bd9Sstevel@tonic-gate 			goto ret;
2650b60f2a0bSfr41279 		}
26517c478bd9Sstevel@tonic-gate 		if ((ki.value[w] & bit) != 0) {
26527c478bd9Sstevel@tonic-gate 			if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) !=
2653b60f2a0bSfr41279 			    BIG_OK) {
26547c478bd9Sstevel@tonic-gate 				goto ret;
2655b60f2a0bSfr41279 			}
26567c478bd9Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
2657b60f2a0bSfr41279 			(void) big_sub_pos(&tmp, &tmp, &big_Two);
26587c478bd9Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) !=
2659b60f2a0bSfr41279 			    BIG_OK) {
26607c478bd9Sstevel@tonic-gate 				goto ret;
2661b60f2a0bSfr41279 			}
26627c478bd9Sstevel@tonic-gate 			(void) big_copy(Lk, &tmp2);
26637c478bd9Sstevel@tonic-gate 		} else {
2664b60f2a0bSfr41279 			if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK) {
26657c478bd9Sstevel@tonic-gate 				goto ret;
2666b60f2a0bSfr41279 			}
26677c478bd9Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
2668b60f2a0bSfr41279 			(void) big_sub_pos(&tmp, &tmp, &big_Two);
2669b60f2a0bSfr41279 			if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK) {
26707c478bd9Sstevel@tonic-gate 				goto ret;
2671b60f2a0bSfr41279 			}
26727c478bd9Sstevel@tonic-gate 			(void) big_copy(Lkminus1, &tmp2);
26737c478bd9Sstevel@tonic-gate 		}
26747c478bd9Sstevel@tonic-gate 		bit = bit >> 1;
26757c478bd9Sstevel@tonic-gate 		if (bit == 0) {
2676b60f2a0bSfr41279 			bit = BIG_CHUNK_HIGHBIT;
26777c478bd9Sstevel@tonic-gate 			w--;
26787c478bd9Sstevel@tonic-gate 		}
26797c478bd9Sstevel@tonic-gate 	}
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate 	err = BIG_OK;
26827c478bd9Sstevel@tonic-gate 
26837c478bd9Sstevel@tonic-gate ret:
26847c478bd9Sstevel@tonic-gate 	if (tmp2.malloced) big_finish(&tmp2);
26857c478bd9Sstevel@tonic-gate ret2:
26867c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
26877c478bd9Sstevel@tonic-gate ret1:
26887c478bd9Sstevel@tonic-gate 	if (ki.malloced) big_finish(&ki);
26897c478bd9Sstevel@tonic-gate 
26907c478bd9Sstevel@tonic-gate 	return (err);
26917c478bd9Sstevel@tonic-gate }
26927c478bd9Sstevel@tonic-gate 
26937c478bd9Sstevel@tonic-gate 
26947c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2695b60f2a0bSfr41279 big_isprime_pos_ext(BIGNUM *n, big_modexp_ncp_info_t *info)
26967c478bd9Sstevel@tonic-gate {
26977c478bd9Sstevel@tonic-gate 	BIGNUM		o, nminus1, tmp, Lkminus1, Lk;
2698b60f2a0bSfr41279 	BIG_CHUNK_TYPE	ovalue[BIGTMPSIZE];
2699b60f2a0bSfr41279 	BIG_CHUNK_TYPE	nminus1value[BIGTMPSIZE];
2700b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
2701b60f2a0bSfr41279 	BIG_CHUNK_TYPE	Lkminus1value[BIGTMPSIZE];
2702b60f2a0bSfr41279 	BIG_CHUNK_TYPE	Lkvalue[BIGTMPSIZE];
27037c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
27047c478bd9Sstevel@tonic-gate 	int		e, i, jac;
27057c478bd9Sstevel@tonic-gate 
2706b60f2a0bSfr41279 	if (big_cmp_abs(n, &big_One) == 0) {
27077c478bd9Sstevel@tonic-gate 		return (BIG_FALSE);
2708b60f2a0bSfr41279 	}
2709b60f2a0bSfr41279 	if (big_cmp_abs(n, &big_Two) == 0) {
27107c478bd9Sstevel@tonic-gate 		return (BIG_TRUE);
2711b60f2a0bSfr41279 	}
2712b60f2a0bSfr41279 	if ((n->value[0] & 1) == 0) {
27137c478bd9Sstevel@tonic-gate 		return (BIG_FALSE);
2714b60f2a0bSfr41279 	}
27157c478bd9Sstevel@tonic-gate 
2716b60f2a0bSfr41279 	if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) !=
2717b60f2a0bSfr41279 	    BIG_OK) {
27187c478bd9Sstevel@tonic-gate 		return (err);
2719b60f2a0bSfr41279 	}
27207c478bd9Sstevel@tonic-gate 
27217c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&nminus1, n->len,
2722b60f2a0bSfr41279 	    nminus1value, arraysize(nminus1value))) != BIG_OK) {
27237c478bd9Sstevel@tonic-gate 		goto ret1;
2724b60f2a0bSfr41279 	}
27257c478bd9Sstevel@tonic-gate 
27267c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len,
2727b60f2a0bSfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
27287c478bd9Sstevel@tonic-gate 		goto ret2;
2729b60f2a0bSfr41279 	}
27307c478bd9Sstevel@tonic-gate 
27317c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&Lkminus1, n->len,
2732b60f2a0bSfr41279 	    Lkminus1value, arraysize(Lkminus1value))) != BIG_OK) {
27337c478bd9Sstevel@tonic-gate 		goto ret3;
2734b60f2a0bSfr41279 	}
27357c478bd9Sstevel@tonic-gate 
27367c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&Lk, n->len,
2737b60f2a0bSfr41279 	    Lkvalue, arraysize(Lkvalue))) != BIG_OK) {
27387c478bd9Sstevel@tonic-gate 		goto ret4;
2739b60f2a0bSfr41279 	}
27407c478bd9Sstevel@tonic-gate 
2741b60f2a0bSfr41279 	(void) big_sub_pos(&o, n, &big_One);	/* cannot fail */
27427c478bd9Sstevel@tonic-gate 	(void) big_copy(&nminus1, &o);		/* cannot fail */
27437c478bd9Sstevel@tonic-gate 	e = 0;
27447c478bd9Sstevel@tonic-gate 	while ((o.value[0] & 1) == 0) {
27457c478bd9Sstevel@tonic-gate 		e++;
27467c478bd9Sstevel@tonic-gate 		(void) big_half_pos(&o, &o);  /* cannot fail */
27477c478bd9Sstevel@tonic-gate 	}
2748b60f2a0bSfr41279 	if ((err = big_modexp_ext(&tmp, &big_Two, &o, n, NULL, info)) !=
2749b60f2a0bSfr41279 	    BIG_OK) {
27507c478bd9Sstevel@tonic-gate 		goto ret;
2751b60f2a0bSfr41279 	}
2752b60f2a0bSfr41279 
27537c478bd9Sstevel@tonic-gate 	i = 0;
27547c478bd9Sstevel@tonic-gate 	while ((i < e) &&
2755b60f2a0bSfr41279 	    (big_cmp_abs(&tmp, &big_One) != 0) &&
27567c478bd9Sstevel@tonic-gate 	    (big_cmp_abs(&tmp, &nminus1) != 0)) {
2757b60f2a0bSfr41279 		if ((err =
2758b60f2a0bSfr41279 		    big_modexp_ext(&tmp, &tmp, &big_Two, n, NULL, info)) !=
2759b60f2a0bSfr41279 		    BIG_OK)
27607c478bd9Sstevel@tonic-gate 			goto ret;
27617c478bd9Sstevel@tonic-gate 		i++;
27627c478bd9Sstevel@tonic-gate 	}
2763b60f2a0bSfr41279 
27647c478bd9Sstevel@tonic-gate 	if (!((big_cmp_abs(&tmp, &nminus1) == 0) ||
2765b60f2a0bSfr41279 	    ((i == 0) && (big_cmp_abs(&tmp, &big_One) == 0)))) {
27667c478bd9Sstevel@tonic-gate 		err = BIG_FALSE;
27677c478bd9Sstevel@tonic-gate 		goto ret;
27687c478bd9Sstevel@tonic-gate 	}
27697c478bd9Sstevel@tonic-gate 
2770b60f2a0bSfr41279 	if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK) {
27717c478bd9Sstevel@tonic-gate 		goto ret;
2772b60f2a0bSfr41279 	}
2773b60f2a0bSfr41279 
2774b60f2a0bSfr41279 	if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK) {
27757c478bd9Sstevel@tonic-gate 		goto ret;
2776b60f2a0bSfr41279 	}
27777c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(&tmp, n) == 0) {
27787c478bd9Sstevel@tonic-gate 		err = BIG_FALSE;
27797c478bd9Sstevel@tonic-gate 		goto ret;
27807c478bd9Sstevel@tonic-gate 	}
27817c478bd9Sstevel@tonic-gate 
2782b60f2a0bSfr41279 	(void) big_copy(&o, &big_Two);
27837c478bd9Sstevel@tonic-gate 	do {
2784b60f2a0bSfr41279 		(void) big_add_abs(&o, &o, &big_One);
2785b60f2a0bSfr41279 		if ((err = big_mul(&tmp, &o, &o)) != BIG_OK) {
27867c478bd9Sstevel@tonic-gate 			goto ret;
2787b60f2a0bSfr41279 		}
2788b60f2a0bSfr41279 		(void) big_sub_pos(&tmp, &tmp, &big_Four);
2789b60f2a0bSfr41279 		if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK) {
27907c478bd9Sstevel@tonic-gate 			goto ret;
2791b60f2a0bSfr41279 		}
27927c478bd9Sstevel@tonic-gate 	} while (jac != -1);
27937c478bd9Sstevel@tonic-gate 
2794b60f2a0bSfr41279 	(void) big_add_abs(&tmp, n, &big_One);
2795b60f2a0bSfr41279 	if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK) {
27967c478bd9Sstevel@tonic-gate 		goto ret;
2797b60f2a0bSfr41279 	}
2798b60f2a0bSfr41279 
2799b60f2a0bSfr41279 	if ((big_cmp_abs(&Lkminus1, &o) == 0) &&
2800b60f2a0bSfr41279 	    (big_cmp_abs(&Lk, &big_Two) == 0)) {
28017c478bd9Sstevel@tonic-gate 		err = BIG_TRUE;
2802b60f2a0bSfr41279 	} else {
2803b60f2a0bSfr41279 		err = BIG_FALSE;
2804b60f2a0bSfr41279 	}
28057c478bd9Sstevel@tonic-gate 
28067c478bd9Sstevel@tonic-gate ret:
28077c478bd9Sstevel@tonic-gate 	if (Lk.malloced) big_finish(&Lk);
28087c478bd9Sstevel@tonic-gate ret4:
28097c478bd9Sstevel@tonic-gate 	if (Lkminus1.malloced) big_finish(&Lkminus1);
28107c478bd9Sstevel@tonic-gate ret3:
28117c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
28127c478bd9Sstevel@tonic-gate ret2:
28137c478bd9Sstevel@tonic-gate 	if (nminus1.malloced) big_finish(&nminus1);
28147c478bd9Sstevel@tonic-gate ret1:
28157c478bd9Sstevel@tonic-gate 	if (o.malloced) big_finish(&o);
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate 	return (err);
28187c478bd9Sstevel@tonic-gate }
28197c478bd9Sstevel@tonic-gate 
28207c478bd9Sstevel@tonic-gate 
2821b60f2a0bSfr41279 BIG_ERR_CODE
2822b60f2a0bSfr41279 big_isprime_pos(BIGNUM *n)
2823b60f2a0bSfr41279 {
2824b60f2a0bSfr41279 	return (big_isprime_pos_ext(n, NULL));
2825b60f2a0bSfr41279 }
2826b60f2a0bSfr41279 
2827b60f2a0bSfr41279 
28287c478bd9Sstevel@tonic-gate #define	SIEVESIZE 1000
28297c478bd9Sstevel@tonic-gate 
28307c478bd9Sstevel@tonic-gate 
28317c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2832b60f2a0bSfr41279 big_nextprime_pos_ext(BIGNUM *result, BIGNUM *n, big_modexp_ncp_info_t *info)
28337c478bd9Sstevel@tonic-gate {
2834*8475e043SDan OpenSolaris Anderson 	static const uint32_t smallprimes[] = {
2835*8475e043SDan OpenSolaris Anderson 	    3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
2836*8475e043SDan OpenSolaris Anderson 	    51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97 };
28377c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
28387c478bd9Sstevel@tonic-gate 	int		sieve[SIEVESIZE];
28397c478bd9Sstevel@tonic-gate 	int		i;
28407c478bd9Sstevel@tonic-gate 	uint32_t	off, p;
28417c478bd9Sstevel@tonic-gate 
2842b60f2a0bSfr41279 	if ((err = big_copy(result, n)) != BIG_OK) {
28437c478bd9Sstevel@tonic-gate 		return (err);
2844b60f2a0bSfr41279 	}
28457c478bd9Sstevel@tonic-gate 	result->value[0] |= 1;
2846f56c1286Srobinson 	/* CONSTCOND */
28477c478bd9Sstevel@tonic-gate 	while (1) {
28487c478bd9Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0;
28497c478bd9Sstevel@tonic-gate 		for (i = 0;
2850b60f2a0bSfr41279 		    i < sizeof (smallprimes) / sizeof (smallprimes[0]); i++) {
28517c478bd9Sstevel@tonic-gate 			p = smallprimes[i];
2852b60f2a0bSfr41279 			off = big_modhalf_pos(result, p);
28537c478bd9Sstevel@tonic-gate 			off = p - off;
2854b60f2a0bSfr41279 			if ((off % 2) == 1) {
2855b60f2a0bSfr41279 				off = off + p;
2856b60f2a0bSfr41279 			}
28577c478bd9Sstevel@tonic-gate 			off = off / 2;
28587c478bd9Sstevel@tonic-gate 			while (off < SIEVESIZE) {
28597c478bd9Sstevel@tonic-gate 				sieve[off] = 1;
28607c478bd9Sstevel@tonic-gate 				off = off + p;
28617c478bd9Sstevel@tonic-gate 			}
28627c478bd9Sstevel@tonic-gate 		}
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) {
28657c478bd9Sstevel@tonic-gate 			if (sieve[i] == 0) {
2866b60f2a0bSfr41279 				err = big_isprime_pos_ext(result, info);
28677c478bd9Sstevel@tonic-gate 				if (err != BIG_FALSE) {
2868b60f2a0bSfr41279 					if (err != BIG_TRUE) {
28697c478bd9Sstevel@tonic-gate 						return (err);
2870b60f2a0bSfr41279 					} else {
2871b60f2a0bSfr41279 						goto out;
2872b60f2a0bSfr41279 					}
28737c478bd9Sstevel@tonic-gate 				}
28747c478bd9Sstevel@tonic-gate 
28757c478bd9Sstevel@tonic-gate 			}
2876b60f2a0bSfr41279 			if ((err = big_add_abs(result, result, &big_Two)) !=
2877b60f2a0bSfr41279 			    BIG_OK) {
28787c478bd9Sstevel@tonic-gate 				return (err);
28797c478bd9Sstevel@tonic-gate 			}
28807c478bd9Sstevel@tonic-gate 		}
2881b60f2a0bSfr41279 	}
2882b60f2a0bSfr41279 
2883b60f2a0bSfr41279 out:
2884b60f2a0bSfr41279 	return (BIG_OK);
2885b60f2a0bSfr41279 }
2886b60f2a0bSfr41279 
2887b60f2a0bSfr41279 
2888b60f2a0bSfr41279 BIG_ERR_CODE
2889b60f2a0bSfr41279 big_nextprime_pos(BIGNUM *result, BIGNUM *n)
2890b60f2a0bSfr41279 {
2891b60f2a0bSfr41279 	return (big_nextprime_pos_ext(result, n, NULL));
28927c478bd9Sstevel@tonic-gate }
28937c478bd9Sstevel@tonic-gate 
28947c478bd9Sstevel@tonic-gate 
28957c478bd9Sstevel@tonic-gate BIG_ERR_CODE
28967c478bd9Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n)
28977c478bd9Sstevel@tonic-gate {
28987c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
28997c478bd9Sstevel@tonic-gate 
29007c478bd9Sstevel@tonic-gate 
29017c478bd9Sstevel@tonic-gate 	if ((err = big_copy(result, n)) != BIG_OK)
29027c478bd9Sstevel@tonic-gate 		return (err);
29037c478bd9Sstevel@tonic-gate 	result->value[0] |= 1;
2904b60f2a0bSfr41279 	while ((err = big_isprime_pos_ext(result, NULL)) != BIG_TRUE) {
29057c478bd9Sstevel@tonic-gate 		if (err != BIG_FALSE)
29067c478bd9Sstevel@tonic-gate 			return (err);
2907b60f2a0bSfr41279 		if ((err = big_add_abs(result, result, &big_Two)) != BIG_OK)
29087c478bd9Sstevel@tonic-gate 			return (err);
29097c478bd9Sstevel@tonic-gate 	}
29107c478bd9Sstevel@tonic-gate 	return (BIG_OK);
29117c478bd9Sstevel@tonic-gate }
29127c478bd9Sstevel@tonic-gate 
29137c478bd9Sstevel@tonic-gate 
29147c478bd9Sstevel@tonic-gate /*
29157c478bd9Sstevel@tonic-gate  * given m and e, computes the rest in the equation
29167c478bd9Sstevel@tonic-gate  * gcd(m, e) = cm * m + ce * e
29177c478bd9Sstevel@tonic-gate  */
29187c478bd9Sstevel@tonic-gate BIG_ERR_CODE
29197c478bd9Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e)
29207c478bd9Sstevel@tonic-gate {
2921b60f2a0bSfr41279 	BIGNUM		*xi, *ri, *riminus1, *riminus2, *t;
2922b60f2a0bSfr41279 	BIGNUM		*vmi, *vei, *vmiminus1, *veiminus1;
29237c478bd9Sstevel@tonic-gate 	BIGNUM		t1, t2, t3, t4, t5, t6, t7, t8, tmp;
2924b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
2925b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
2926b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
2927b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t4value[BIGTMPSIZE];
2928b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t5value[BIGTMPSIZE];
2929b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t6value[BIGTMPSIZE];
2930b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t7value[BIGTMPSIZE];
2931b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t8value[BIGTMPSIZE];
2932b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
29337c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
29347c478bd9Sstevel@tonic-gate 	int		len;
29357c478bd9Sstevel@tonic-gate 
2936b60f2a0bSfr41279 	if (big_cmp_abs(m, e) >= 0) {
2937b60f2a0bSfr41279 		len = m->len;
2938b60f2a0bSfr41279 	} else {
2939b60f2a0bSfr41279 		len = e->len;
2940b60f2a0bSfr41279 	}
29417c478bd9Sstevel@tonic-gate 
29427c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
2943b60f2a0bSfr41279 	    t1value, arraysize(t1value))) != BIG_OK) {
29447c478bd9Sstevel@tonic-gate 		return (err);
2945b60f2a0bSfr41279 	}
29467c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
2947b60f2a0bSfr41279 	    t2value, arraysize(t2value))) != BIG_OK) {
29487c478bd9Sstevel@tonic-gate 		goto ret1;
2949b60f2a0bSfr41279 	}
29507c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
2951b60f2a0bSfr41279 	    t3value, arraysize(t3value))) != BIG_OK) {
29527c478bd9Sstevel@tonic-gate 		goto ret2;
2953b60f2a0bSfr41279 	}
29547c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t4, len,
2955b60f2a0bSfr41279 	    t4value, arraysize(t3value))) != BIG_OK) {
29567c478bd9Sstevel@tonic-gate 		goto ret3;
2957b60f2a0bSfr41279 	}
29587c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t5, len,
2959b60f2a0bSfr41279 	    t5value, arraysize(t5value))) != BIG_OK) {
29607c478bd9Sstevel@tonic-gate 		goto ret4;
2961b60f2a0bSfr41279 	}
29627c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t6, len,
2963b60f2a0bSfr41279 	    t6value, arraysize(t6value))) != BIG_OK) {
29647c478bd9Sstevel@tonic-gate 		goto ret5;
2965b60f2a0bSfr41279 	}
29667c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t7, len,
2967b60f2a0bSfr41279 	    t7value, arraysize(t7value))) != BIG_OK) {
29687c478bd9Sstevel@tonic-gate 		goto ret6;
2969b60f2a0bSfr41279 	}
29707c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t8, len,
2971b60f2a0bSfr41279 	    t8value, arraysize(t8value))) != BIG_OK) {
29727c478bd9Sstevel@tonic-gate 		goto ret7;
2973b60f2a0bSfr41279 	}
29747c478bd9Sstevel@tonic-gate 
29757c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * len,
2976b60f2a0bSfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
29777c478bd9Sstevel@tonic-gate 		goto ret8;
2978b60f2a0bSfr41279 	}
29797c478bd9Sstevel@tonic-gate 
29807c478bd9Sstevel@tonic-gate 	ri = &t1;
29817c478bd9Sstevel@tonic-gate 	ri->value[0] = 1;
29827c478bd9Sstevel@tonic-gate 	ri->len = 1;
29837c478bd9Sstevel@tonic-gate 	xi = &t2;
29847c478bd9Sstevel@tonic-gate 	riminus1 = &t3;
29857c478bd9Sstevel@tonic-gate 	riminus2 = &t4;
29867c478bd9Sstevel@tonic-gate 	vmi = &t5;
29877c478bd9Sstevel@tonic-gate 	vei = &t6;
29887c478bd9Sstevel@tonic-gate 	vmiminus1 = &t7;
29897c478bd9Sstevel@tonic-gate 	veiminus1 = &t8;
29907c478bd9Sstevel@tonic-gate 
2991b60f2a0bSfr41279 	(void) big_copy(vmiminus1, &big_One);
2992b60f2a0bSfr41279 	(void) big_copy(vmi, &big_One);
2993b60f2a0bSfr41279 	(void) big_copy(veiminus1, &big_One);
2994b60f2a0bSfr41279 	(void) big_copy(xi, &big_One);
29957c478bd9Sstevel@tonic-gate 	vei->len = 1;
29967c478bd9Sstevel@tonic-gate 	vei->value[0] = 0;
29977c478bd9Sstevel@tonic-gate 
29987c478bd9Sstevel@tonic-gate 	(void) big_copy(riminus1, m);
29997c478bd9Sstevel@tonic-gate 	(void) big_copy(ri, e);
30007c478bd9Sstevel@tonic-gate 
30017c478bd9Sstevel@tonic-gate 	while (!big_is_zero(ri)) {
30027c478bd9Sstevel@tonic-gate 		t = riminus2;
30037c478bd9Sstevel@tonic-gate 		riminus2 = riminus1;
30047c478bd9Sstevel@tonic-gate 		riminus1 = ri;
30057c478bd9Sstevel@tonic-gate 		ri = t;
3006b60f2a0bSfr41279 		if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK) {
30077c478bd9Sstevel@tonic-gate 			goto ret;
3008b60f2a0bSfr41279 		}
3009b60f2a0bSfr41279 		if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK) {
30107c478bd9Sstevel@tonic-gate 			goto ret;
3011b60f2a0bSfr41279 		}
30127c478bd9Sstevel@tonic-gate 		t = vmiminus1;
30137c478bd9Sstevel@tonic-gate 		vmiminus1 = vmi;
30147c478bd9Sstevel@tonic-gate 		vmi = t;
3015b60f2a0bSfr41279 		if ((err = big_mul(&tmp, vei, xi)) != BIG_OK) {
30167c478bd9Sstevel@tonic-gate 			goto ret;
3017b60f2a0bSfr41279 		}
3018b60f2a0bSfr41279 		if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK) {
30197c478bd9Sstevel@tonic-gate 			goto ret;
3020b60f2a0bSfr41279 		}
30217c478bd9Sstevel@tonic-gate 		t = veiminus1;
30227c478bd9Sstevel@tonic-gate 		veiminus1 = vei;
30237c478bd9Sstevel@tonic-gate 		vei = t;
3024b60f2a0bSfr41279 		if ((err = big_div_pos(xi, ri, riminus2, riminus1)) !=
3025b60f2a0bSfr41279 		    BIG_OK) {
30267c478bd9Sstevel@tonic-gate 			goto ret;
30277c478bd9Sstevel@tonic-gate 		}
3028b60f2a0bSfr41279 	}
3029b60f2a0bSfr41279 	if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK)) {
30307c478bd9Sstevel@tonic-gate 		goto ret;
3031b60f2a0bSfr41279 	}
3032b60f2a0bSfr41279 	if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK)) {
30337c478bd9Sstevel@tonic-gate 		goto ret;
3034b60f2a0bSfr41279 	}
3035b60f2a0bSfr41279 	if (ce != NULL) {
30367c478bd9Sstevel@tonic-gate 		err = big_copy(ce, vei);
3037b60f2a0bSfr41279 	}
30387c478bd9Sstevel@tonic-gate ret:
30397c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
30407c478bd9Sstevel@tonic-gate ret8:
30417c478bd9Sstevel@tonic-gate 	if (t8.malloced) big_finish(&t8);
30427c478bd9Sstevel@tonic-gate ret7:
30437c478bd9Sstevel@tonic-gate 	if (t7.malloced) big_finish(&t7);
30447c478bd9Sstevel@tonic-gate ret6:
30457c478bd9Sstevel@tonic-gate 	if (t6.malloced) big_finish(&t6);
30467c478bd9Sstevel@tonic-gate ret5:
30477c478bd9Sstevel@tonic-gate 	if (t5.malloced) big_finish(&t5);
30487c478bd9Sstevel@tonic-gate ret4:
30497c478bd9Sstevel@tonic-gate 	if (t4.malloced) big_finish(&t4);
30507c478bd9Sstevel@tonic-gate ret3:
30517c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
30527c478bd9Sstevel@tonic-gate ret2:
30537c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
30547c478bd9Sstevel@tonic-gate ret1:
30557c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
30567c478bd9Sstevel@tonic-gate 
30577c478bd9Sstevel@tonic-gate 	return (err);
30587c478bd9Sstevel@tonic-gate }
3059