xref: /titanic_54/usr/src/common/bignum/bignumimpl.c (revision 0a1ad920531b37f01f4aa8084737026621c76bdb)
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 /*
228475e043SDan 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.
478475e043SDan 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 
658475e043SDan OpenSolaris Anderson #include <sys/types.h>
668475e043SDan OpenSolaris Anderson #include "bignum.h"
678475e043SDan 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 
778475e043SDan OpenSolaris Anderson #else
788475e043SDan OpenSolaris Anderson #include <stdlib.h>
798475e043SDan OpenSolaris Anderson #include <stdio.h>
808475e043SDan OpenSolaris Anderson #include <assert.h>
818475e043SDan OpenSolaris Anderson #define	ASSERT	assert
828475e043SDan OpenSolaris Anderson #endif	/* _KERNEL */
838475e043SDan OpenSolaris Anderson 
84*0a1ad920SDan OpenSolaris Anderson #ifdef __amd64
85*0a1ad920SDan OpenSolaris Anderson #ifdef _KERNEL
86*0a1ad920SDan OpenSolaris Anderson #include <sys/x86_archext.h>	/* cpuid_getvendor() */
87*0a1ad920SDan OpenSolaris Anderson #include <sys/cpuvar.h>
88*0a1ad920SDan OpenSolaris Anderson #else
89*0a1ad920SDan OpenSolaris Anderson #include <sys/auxv.h>		/* getisax() */
90*0a1ad920SDan OpenSolaris Anderson #endif  /* _KERNEL */
91*0a1ad920SDan OpenSolaris Anderson #endif  /* __amd64 */
92*0a1ad920SDan OpenSolaris Anderson 
93*0a1ad920SDan OpenSolaris Anderson 
948475e043SDan OpenSolaris Anderson #ifdef	_LP64 /* truncate 64-bit size_t to 32-bits */
958475e043SDan OpenSolaris Anderson #define	UI32(ui)	((uint32_t)ui)
968475e043SDan OpenSolaris Anderson #else /* size_t already 32-bits */
978475e043SDan OpenSolaris Anderson #define	UI32(ui)	(ui)
988475e043SDan OpenSolaris Anderson #endif
998475e043SDan OpenSolaris Anderson 
1008475e043SDan OpenSolaris Anderson 
1018475e043SDan OpenSolaris Anderson #ifdef	_KERNEL
1027c478bd9Sstevel@tonic-gate #define	big_malloc(size)	kmem_alloc(size, KM_NOSLEEP)
1037c478bd9Sstevel@tonic-gate #define	big_free(ptr, size)	kmem_free(ptr, size)
1047c478bd9Sstevel@tonic-gate 
105*0a1ad920SDan OpenSolaris Anderson /*
106*0a1ad920SDan OpenSolaris Anderson  * big_realloc()
107*0a1ad920SDan OpenSolaris Anderson  * Allocate memory of newsize bytes and copy oldsize bytes
108*0a1ad920SDan OpenSolaris Anderson  * to the newly-allocated memory, then free the
109*0a1ad920SDan OpenSolaris Anderson  * previously-allocated memory.
110*0a1ad920SDan OpenSolaris Anderson  * Note: newsize must be > oldsize
111*0a1ad920SDan OpenSolaris Anderson  */
1127c478bd9Sstevel@tonic-gate void *
1137c478bd9Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize)
1147c478bd9Sstevel@tonic-gate {
1157c478bd9Sstevel@tonic-gate 	void *rv;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	rv = kmem_alloc(newsize, KM_NOSLEEP);
1187c478bd9Sstevel@tonic-gate 	if (rv != NULL)
1197c478bd9Sstevel@tonic-gate 		bcopy(from, rv, oldsize);
1207c478bd9Sstevel@tonic-gate 	kmem_free(from, oldsize);
1217c478bd9Sstevel@tonic-gate 	return (rv);
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate #else	/* _KERNEL */
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate #ifndef MALLOC_DEBUG
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate #define	big_malloc(size)	malloc(size)
1297c478bd9Sstevel@tonic-gate #define	big_free(ptr, size)	free(ptr)
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate #else
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate void
1347c478bd9Sstevel@tonic-gate big_free(void *ptr, size_t size)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	printf("freed %d bytes at %p\n", size, ptr);
1377c478bd9Sstevel@tonic-gate 	free(ptr);
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate void *
1417c478bd9Sstevel@tonic-gate big_malloc(size_t size)
1427c478bd9Sstevel@tonic-gate {
1437c478bd9Sstevel@tonic-gate 	void *rv;
1447c478bd9Sstevel@tonic-gate 	rv = malloc(size);
1457c478bd9Sstevel@tonic-gate 	printf("malloced %d bytes, addr:%p\n", size, rv);
1467c478bd9Sstevel@tonic-gate 	return (rv);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate #endif /* MALLOC_DEBUG */
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate #define	big_realloc(x, y, z) realloc((x), (z))
1517c478bd9Sstevel@tonic-gate 
1528475e043SDan OpenSolaris Anderson 
1538475e043SDan OpenSolaris Anderson /*
1548475e043SDan OpenSolaris Anderson  * printbignum()
1558475e043SDan OpenSolaris Anderson  * Print a BIGNUM type to stdout.
1568475e043SDan OpenSolaris Anderson  */
1577c478bd9Sstevel@tonic-gate void
1587c478bd9Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a)
1597c478bd9Sstevel@tonic-gate {
1607c478bd9Sstevel@tonic-gate 	int i;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	(void) printf("\n%s\n%d\n", aname, a->sign*a->len);
1637c478bd9Sstevel@tonic-gate 	for (i = a->len - 1; i >= 0; i--) {
164b60f2a0bSfr41279 #ifdef BIGNUM_CHUNK_32
1657c478bd9Sstevel@tonic-gate 		(void) printf("%08x ", a->value[i]);
1668475e043SDan OpenSolaris Anderson 		if (((i & (BITSINBYTE - 1)) == 0) && (i != 0)) {
1677c478bd9Sstevel@tonic-gate 			(void) printf("\n");
1687c478bd9Sstevel@tonic-gate 		}
169b60f2a0bSfr41279 #else
170b60f2a0bSfr41279 		(void) printf("%08x %08x ", (uint32_t)((a->value[i]) >> 32),
171b60f2a0bSfr41279 		    (uint32_t)((a->value[i]) & 0xffffffff));
1728475e043SDan OpenSolaris Anderson 		if (((i & 3) == 0) && (i != 0)) { /* end of this chunk */
173b60f2a0bSfr41279 			(void) printf("\n");
174b60f2a0bSfr41279 		}
175b60f2a0bSfr41279 #endif
176b60f2a0bSfr41279 	}
1777c478bd9Sstevel@tonic-gate 	(void) printf("\n");
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate #endif	/* _KERNEL */
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 
183*0a1ad920SDan OpenSolaris Anderson #ifdef  __amd64
184*0a1ad920SDan OpenSolaris Anderson /*
185*0a1ad920SDan OpenSolaris Anderson  * Return 1 if executing on Intel, otherwise 0 (e.g., AMD64).
186*0a1ad920SDan OpenSolaris Anderson  */
187*0a1ad920SDan OpenSolaris Anderson static int
188*0a1ad920SDan OpenSolaris Anderson bignum_on_intel(void)
189*0a1ad920SDan OpenSolaris Anderson {
190*0a1ad920SDan OpenSolaris Anderson #ifdef _KERNEL
191*0a1ad920SDan OpenSolaris Anderson 	return (cpuid_getvendor(CPU) == X86_VENDOR_Intel);
192*0a1ad920SDan OpenSolaris Anderson #else
193*0a1ad920SDan OpenSolaris Anderson 	uint_t  ui;
194*0a1ad920SDan OpenSolaris Anderson 	(void) getisax(&ui, 1);
195*0a1ad920SDan OpenSolaris Anderson 	return ((ui & AV_386_AMD_MMX) == 0);
196*0a1ad920SDan OpenSolaris Anderson #endif  /* _KERNEL */
197*0a1ad920SDan OpenSolaris Anderson }
198*0a1ad920SDan OpenSolaris Anderson #endif  /* __amd64 */
199*0a1ad920SDan OpenSolaris Anderson 
200*0a1ad920SDan OpenSolaris Anderson 
2018475e043SDan OpenSolaris Anderson /*
2028475e043SDan OpenSolaris Anderson  * big_init()
2038475e043SDan OpenSolaris Anderson  * Initialize and allocate memory for a BIGNUM type.
2048475e043SDan OpenSolaris Anderson  *
2058475e043SDan OpenSolaris Anderson  * big_init(number, size) is equivalent to big_init1(number, size, NULL, 0)
2068475e043SDan OpenSolaris Anderson  *
2078475e043SDan OpenSolaris Anderson  * Note: call big_finish() to free memory allocated by big_init().
2088475e043SDan OpenSolaris Anderson  *
2098475e043SDan OpenSolaris Anderson  * Input:
2108475e043SDan OpenSolaris Anderson  * number	Uninitialized memory for BIGNUM
2118475e043SDan OpenSolaris Anderson  * size		Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM
2128475e043SDan OpenSolaris Anderson  *
2138475e043SDan OpenSolaris Anderson  * Output:
2148475e043SDan OpenSolaris Anderson  * number	Initialized BIGNUM
2158475e043SDan OpenSolaris Anderson  *
2168475e043SDan OpenSolaris Anderson  * Return BIG_OK on success or BIG_NO_MEM for an allocation error.
2178475e043SDan OpenSolaris Anderson  */
2187c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2197c478bd9Sstevel@tonic-gate big_init(BIGNUM *number, int size)
2207c478bd9Sstevel@tonic-gate {
2218475e043SDan OpenSolaris Anderson 	number->value = big_malloc(BIGNUM_WORDSIZE * size);
2227c478bd9Sstevel@tonic-gate 	if (number->value == NULL) {
2237c478bd9Sstevel@tonic-gate 		return (BIG_NO_MEM);
2247c478bd9Sstevel@tonic-gate 	}
2257c478bd9Sstevel@tonic-gate 	number->size = size;
2267c478bd9Sstevel@tonic-gate 	number->len = 0;
2277c478bd9Sstevel@tonic-gate 	number->sign = 1;
2287c478bd9Sstevel@tonic-gate 	number->malloced = 1;
2297c478bd9Sstevel@tonic-gate 	return (BIG_OK);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate 
2328475e043SDan OpenSolaris Anderson 
2338475e043SDan OpenSolaris Anderson /*
2348475e043SDan OpenSolaris Anderson  * big_init1()
2358475e043SDan OpenSolaris Anderson  * Initialize and, if needed, allocate memory for a BIGNUM type.
2368475e043SDan OpenSolaris Anderson  * Use the buffer passed, buf, if any, instad of allocating memory
2378475e043SDan OpenSolaris Anderson  * if it's at least "size" bytes.
2388475e043SDan OpenSolaris Anderson  *
2398475e043SDan OpenSolaris Anderson  * Note: call big_finish() to free memory allocated by big_init().
2408475e043SDan OpenSolaris Anderson  *
2418475e043SDan OpenSolaris Anderson  * Input:
2428475e043SDan OpenSolaris Anderson  * number	Uninitialized memory for BIGNUM
2438475e043SDan OpenSolaris Anderson  * size		Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM
2448475e043SDan OpenSolaris Anderson  * buf		Buffer for storing a BIGNUM.
2458475e043SDan OpenSolaris Anderson  *		If NULL, big_init1() will allocate a buffer
2468475e043SDan OpenSolaris Anderson  * bufsize	Size, in BIG_CHUNK_SIZE_bit words, of buf
2478475e043SDan OpenSolaris Anderson  *
2488475e043SDan OpenSolaris Anderson  * Output:
2498475e043SDan OpenSolaris Anderson  * number	Initialized BIGNUM
2508475e043SDan OpenSolaris Anderson  *
2518475e043SDan OpenSolaris Anderson  * Return BIG_OK on success or BIG_NO_MEM for an allocation error.
2528475e043SDan OpenSolaris Anderson  */
2537c478bd9Sstevel@tonic-gate BIG_ERR_CODE
254b60f2a0bSfr41279 big_init1(BIGNUM *number, int size, BIG_CHUNK_TYPE *buf, int bufsize)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (size > bufsize)) {
2578475e043SDan OpenSolaris Anderson 		number->value = big_malloc(BIGNUM_WORDSIZE * size);
2587c478bd9Sstevel@tonic-gate 		if (number->value == NULL) {
2597c478bd9Sstevel@tonic-gate 			return (BIG_NO_MEM);
2607c478bd9Sstevel@tonic-gate 		}
2617c478bd9Sstevel@tonic-gate 		number->size = size;
2627c478bd9Sstevel@tonic-gate 		number->malloced = 1;
2637c478bd9Sstevel@tonic-gate 	} else {
2647c478bd9Sstevel@tonic-gate 		number->value = buf;
2657c478bd9Sstevel@tonic-gate 		number->size = bufsize;
2667c478bd9Sstevel@tonic-gate 		number->malloced = 0;
2677c478bd9Sstevel@tonic-gate 	}
2687c478bd9Sstevel@tonic-gate 	number->len = 0;
2697c478bd9Sstevel@tonic-gate 	number->sign = 1;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	return (BIG_OK);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate 
2748475e043SDan OpenSolaris Anderson 
2758475e043SDan OpenSolaris Anderson /*
2768475e043SDan OpenSolaris Anderson  * big_finish()
2778475e043SDan OpenSolaris Anderson  * Free memory, if any, allocated by big_init() or big_init1().
2788475e043SDan OpenSolaris Anderson  */
2797c478bd9Sstevel@tonic-gate void
2807c478bd9Sstevel@tonic-gate big_finish(BIGNUM *number)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 	if (number->malloced == 1) {
2838475e043SDan OpenSolaris Anderson 		big_free(number->value, BIGNUM_WORDSIZE * number->size);
2847c478bd9Sstevel@tonic-gate 		number->malloced = 0;
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate 
288b60f2a0bSfr41279 
2897c478bd9Sstevel@tonic-gate /*
290b60f2a0bSfr41279  * bn->size should be at least
2918475e043SDan OpenSolaris Anderson  * (len + BIGNUM_WORDSIZE - 1) / BIGNUM_WORDSIZE bytes
2927c478bd9Sstevel@tonic-gate  * converts from byte-big-endian format to bignum format (words in
2937c478bd9Sstevel@tonic-gate  * little endian order, but bytes within the words big endian)
2947c478bd9Sstevel@tonic-gate  */
2957c478bd9Sstevel@tonic-gate void
2967c478bd9Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len)
2977c478bd9Sstevel@tonic-gate {
2988475e043SDan OpenSolaris Anderson 	int		i, j;
2998475e043SDan OpenSolaris Anderson 	uint32_t	offs;
3008475e043SDan OpenSolaris Anderson 	const uint32_t	slen = UI32(len);
301b60f2a0bSfr41279 	BIG_CHUNK_TYPE	word;
3027c478bd9Sstevel@tonic-gate 	uchar_t		*knwordp;
3037c478bd9Sstevel@tonic-gate 
3048475e043SDan OpenSolaris Anderson 	if (slen == 0) {
3058475e043SDan OpenSolaris Anderson 		bn->len = 1;
3068475e043SDan OpenSolaris Anderson 		bn->value[0] = 0;
3078475e043SDan OpenSolaris Anderson 		return;
3088475e043SDan OpenSolaris Anderson 	}
309b60f2a0bSfr41279 
3108475e043SDan OpenSolaris Anderson 	offs = slen % BIGNUM_WORDSIZE;
3118475e043SDan OpenSolaris Anderson 	bn->len = slen / BIGNUM_WORDSIZE;
3128475e043SDan OpenSolaris Anderson 
3138475e043SDan OpenSolaris Anderson 	for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) {
3148475e043SDan OpenSolaris Anderson 		knwordp = &(kn[slen - BIGNUM_WORDSIZE * (i + 1)]);
3157c478bd9Sstevel@tonic-gate 		word = knwordp[0];
3168475e043SDan OpenSolaris Anderson 		for (j = 1; j < BIGNUM_WORDSIZE; j++) {
3178475e043SDan OpenSolaris Anderson 			word = (word << BITSINBYTE) + knwordp[j];
3187c478bd9Sstevel@tonic-gate 		}
3197c478bd9Sstevel@tonic-gate 		bn->value[i] = word;
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 	if (offs > 0) {
3227c478bd9Sstevel@tonic-gate 		word = kn[0];
3238475e043SDan OpenSolaris Anderson 		for (i = 1; i < offs; i++) word = (word << BITSINBYTE) + kn[i];
3247c478bd9Sstevel@tonic-gate 		bn->value[bn->len++] = word;
3257c478bd9Sstevel@tonic-gate 	}
3267c478bd9Sstevel@tonic-gate 	while ((bn->len > 1) && (bn->value[bn->len - 1] == 0)) {
3277c478bd9Sstevel@tonic-gate 		bn->len --;
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate 
3318475e043SDan OpenSolaris Anderson 
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate  * copies the least significant len bytes if
3348475e043SDan OpenSolaris Anderson  * len < bn->len * BIGNUM_WORDSIZE
3357c478bd9Sstevel@tonic-gate  * converts from bignum format to byte-big-endian format.
336b60f2a0bSfr41279  * bignum format is words of type  BIG_CHUNK_TYPE in little endian order.
3377c478bd9Sstevel@tonic-gate  */
3387c478bd9Sstevel@tonic-gate void
3397c478bd9Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len)
3407c478bd9Sstevel@tonic-gate {
3418475e043SDan OpenSolaris Anderson 	int		i, j;
3428475e043SDan OpenSolaris Anderson 	uint32_t	offs;
3438475e043SDan OpenSolaris Anderson 	const uint32_t	slen = UI32(len);
344b60f2a0bSfr41279 	BIG_CHUNK_TYPE	word;
3457c478bd9Sstevel@tonic-gate 
3468475e043SDan OpenSolaris Anderson 	if (len < BIGNUM_WORDSIZE * bn->len) {
3478475e043SDan OpenSolaris Anderson 		for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) {
3487c478bd9Sstevel@tonic-gate 			word = bn->value[i];
3498475e043SDan OpenSolaris Anderson 			for (j = 0; j < BIGNUM_WORDSIZE; j++) {
3508475e043SDan OpenSolaris Anderson 				kn[slen - BIGNUM_WORDSIZE * i - j - 1] =
3517c478bd9Sstevel@tonic-gate 				    word & 0xff;
3528475e043SDan OpenSolaris Anderson 				word = word >> BITSINBYTE;
3537c478bd9Sstevel@tonic-gate 			}
3547c478bd9Sstevel@tonic-gate 		}
3558475e043SDan OpenSolaris Anderson 		offs = slen % BIGNUM_WORDSIZE;
3567c478bd9Sstevel@tonic-gate 		if (offs > 0) {
3578475e043SDan OpenSolaris Anderson 			word = bn->value[slen / BIGNUM_WORDSIZE];
3588475e043SDan OpenSolaris Anderson 			for (i =  slen % BIGNUM_WORDSIZE; i > 0; i --) {
3597c478bd9Sstevel@tonic-gate 				kn[i - 1] = word & 0xff;
3608475e043SDan OpenSolaris Anderson 				word = word >> BITSINBYTE;
3617c478bd9Sstevel@tonic-gate 			}
3627c478bd9Sstevel@tonic-gate 		}
3637c478bd9Sstevel@tonic-gate 	} else {
3647c478bd9Sstevel@tonic-gate 		for (i = 0; i < bn->len; i++) {
3657c478bd9Sstevel@tonic-gate 			word = bn->value[i];
3668475e043SDan OpenSolaris Anderson 			for (j = 0; j < BIGNUM_WORDSIZE; j++) {
3678475e043SDan OpenSolaris Anderson 				kn[slen - BIGNUM_WORDSIZE * i - j - 1] =
3687c478bd9Sstevel@tonic-gate 				    word & 0xff;
3698475e043SDan OpenSolaris Anderson 				word = word >> BITSINBYTE;
3707c478bd9Sstevel@tonic-gate 			}
3717c478bd9Sstevel@tonic-gate 		}
3728475e043SDan OpenSolaris Anderson 		for (i = 0; i < slen - BIGNUM_WORDSIZE * bn->len; i++) {
3737c478bd9Sstevel@tonic-gate 			kn[i] = 0;
3747c478bd9Sstevel@tonic-gate 		}
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate int
3807c478bd9Sstevel@tonic-gate big_bitlength(BIGNUM *a)
3817c478bd9Sstevel@tonic-gate {
382b60f2a0bSfr41279 	int		l = 0, b = 0;
383b60f2a0bSfr41279 	BIG_CHUNK_TYPE	c;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	l = a->len - 1;
3867c478bd9Sstevel@tonic-gate 	while ((l > 0) && (a->value[l] == 0)) {
3877c478bd9Sstevel@tonic-gate 		l--;
3887c478bd9Sstevel@tonic-gate 	}
3898475e043SDan OpenSolaris Anderson 	b = BIG_CHUNK_SIZE;
3907c478bd9Sstevel@tonic-gate 	c = a->value[l];
391b60f2a0bSfr41279 	while ((b > 1) && ((c & BIG_CHUNK_HIGHBIT) == 0)) {
3927c478bd9Sstevel@tonic-gate 		c = c << 1;
3937c478bd9Sstevel@tonic-gate 		b--;
3947c478bd9Sstevel@tonic-gate 	}
395b60f2a0bSfr41279 
3968475e043SDan OpenSolaris Anderson 	return (l * BIG_CHUNK_SIZE + b);
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 
400*0a1ad920SDan OpenSolaris Anderson /*
401*0a1ad920SDan OpenSolaris Anderson  * big_copy()
402*0a1ad920SDan OpenSolaris Anderson  * Copy BIGNUM src to dest, allocating memory if needed.
403*0a1ad920SDan OpenSolaris Anderson  */
4047c478bd9Sstevel@tonic-gate BIG_ERR_CODE
4057c478bd9Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src)
4067c478bd9Sstevel@tonic-gate {
407b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*newptr;
4087c478bd9Sstevel@tonic-gate 	int		i, len;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	len = src->len;
411b60f2a0bSfr41279 	while ((len > 1) && (src->value[len - 1] == 0)) {
4127c478bd9Sstevel@tonic-gate 		len--;
413b60f2a0bSfr41279 	}
4147c478bd9Sstevel@tonic-gate 	src->len = len;
4157c478bd9Sstevel@tonic-gate 	if (dest->size < len) {
4167c478bd9Sstevel@tonic-gate 		if (dest->malloced == 1) {
417b60f2a0bSfr41279 			newptr = (BIG_CHUNK_TYPE *)big_realloc(dest->value,
4188475e043SDan OpenSolaris Anderson 			    BIGNUM_WORDSIZE * dest->size,
4198475e043SDan OpenSolaris Anderson 			    BIGNUM_WORDSIZE * len);
4207c478bd9Sstevel@tonic-gate 		} else {
421b60f2a0bSfr41279 			newptr = (BIG_CHUNK_TYPE *)
4228475e043SDan OpenSolaris Anderson 			    big_malloc(BIGNUM_WORDSIZE * len);
423b60f2a0bSfr41279 			if (newptr != NULL) {
424b60f2a0bSfr41279 				dest->malloced = 1;
4257c478bd9Sstevel@tonic-gate 			}
426b60f2a0bSfr41279 		}
427b60f2a0bSfr41279 		if (newptr == NULL) {
4287c478bd9Sstevel@tonic-gate 			return (BIG_NO_MEM);
429b60f2a0bSfr41279 		}
4307c478bd9Sstevel@tonic-gate 		dest->value = newptr;
4317c478bd9Sstevel@tonic-gate 		dest->size = len;
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate 	dest->len = len;
4347c478bd9Sstevel@tonic-gate 	dest->sign = src->sign;
435b60f2a0bSfr41279 	for (i = 0; i < len; i++) {
436b60f2a0bSfr41279 		dest->value[i] = src->value[i];
437b60f2a0bSfr41279 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	return (BIG_OK);
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 
443*0a1ad920SDan OpenSolaris Anderson /*
444*0a1ad920SDan OpenSolaris Anderson  * big_extend()
445*0a1ad920SDan OpenSolaris Anderson  * Allocate memory to extend BIGNUM number to size bignum chunks,
446*0a1ad920SDan OpenSolaris Anderson  * if not at least that size already.
447*0a1ad920SDan OpenSolaris Anderson  */
4487c478bd9Sstevel@tonic-gate BIG_ERR_CODE
4497c478bd9Sstevel@tonic-gate big_extend(BIGNUM *number, int size)
4507c478bd9Sstevel@tonic-gate {
451b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*newptr;
4527c478bd9Sstevel@tonic-gate 	int		i;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	if (number->size >= size)
4557c478bd9Sstevel@tonic-gate 		return (BIG_OK);
4567c478bd9Sstevel@tonic-gate 	if (number->malloced) {
457b60f2a0bSfr41279 		number->value = big_realloc(number->value,
4588475e043SDan OpenSolaris Anderson 		    BIGNUM_WORDSIZE * number->size,
4598475e043SDan OpenSolaris Anderson 		    BIGNUM_WORDSIZE * size);
4607c478bd9Sstevel@tonic-gate 	} else {
4618475e043SDan OpenSolaris Anderson 		newptr = big_malloc(BIGNUM_WORDSIZE * size);
4627c478bd9Sstevel@tonic-gate 		if (newptr != NULL) {
4637c478bd9Sstevel@tonic-gate 			for (i = 0; i < number->size; i++) {
4647c478bd9Sstevel@tonic-gate 				newptr[i] = number->value[i];
4657c478bd9Sstevel@tonic-gate 			}
4667c478bd9Sstevel@tonic-gate 		}
4677c478bd9Sstevel@tonic-gate 		number->value = newptr;
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate 
470b60f2a0bSfr41279 	if (number->value == NULL) {
4717c478bd9Sstevel@tonic-gate 		return (BIG_NO_MEM);
472b60f2a0bSfr41279 	}
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	number->size = size;
4757c478bd9Sstevel@tonic-gate 	number->malloced = 1;
4767c478bd9Sstevel@tonic-gate 	return (BIG_OK);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 
480b60f2a0bSfr41279 /* returns 1 if n == 0 */
4817c478bd9Sstevel@tonic-gate int
4827c478bd9Sstevel@tonic-gate big_is_zero(BIGNUM *n)
4837c478bd9Sstevel@tonic-gate {
4847c478bd9Sstevel@tonic-gate 	int	i, result;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	result = 1;
487b60f2a0bSfr41279 	for (i = 0; i < n->len; i++) {
488b60f2a0bSfr41279 		if (n->value[i] != 0) {
489b60f2a0bSfr41279 			result = 0;
490b60f2a0bSfr41279 		}
491b60f2a0bSfr41279 	}
4927c478bd9Sstevel@tonic-gate 	return (result);
4937c478bd9Sstevel@tonic-gate }
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate BIG_ERR_CODE
4977c478bd9Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
4987c478bd9Sstevel@tonic-gate {
4997c478bd9Sstevel@tonic-gate 	int		i, shorter, longer;
500b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, ai;
501b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*r, *a, *b, *c;
5027c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
503b60f2a0bSfr41279 	BIGNUM		*longerarg;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	if (aa->len > bb->len) {
5067c478bd9Sstevel@tonic-gate 		shorter = bb->len;
5077c478bd9Sstevel@tonic-gate 		longer = aa->len;
508b60f2a0bSfr41279 		longerarg = aa;
5097c478bd9Sstevel@tonic-gate 	} else {
5107c478bd9Sstevel@tonic-gate 		shorter = aa->len;
5117c478bd9Sstevel@tonic-gate 		longer = bb->len;
512b60f2a0bSfr41279 		longerarg = bb;
5137c478bd9Sstevel@tonic-gate 	}
5147c478bd9Sstevel@tonic-gate 	if (result->size < longer + 1) {
5157c478bd9Sstevel@tonic-gate 		err = big_extend(result, longer + 1);
516b60f2a0bSfr41279 		if (err != BIG_OK) {
5177c478bd9Sstevel@tonic-gate 			return (err);
5187c478bd9Sstevel@tonic-gate 		}
519b60f2a0bSfr41279 	}
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	r = result->value;
5227c478bd9Sstevel@tonic-gate 	a = aa->value;
5237c478bd9Sstevel@tonic-gate 	b = bb->value;
524b60f2a0bSfr41279 	c = longerarg->value;
5257c478bd9Sstevel@tonic-gate 	cy = 0;
5267c478bd9Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
5277c478bd9Sstevel@tonic-gate 		ai = a[i];
5287c478bd9Sstevel@tonic-gate 		r[i] = ai + b[i] + cy;
529b60f2a0bSfr41279 		if (r[i] > ai) {
530b60f2a0bSfr41279 			cy = 0;
531b60f2a0bSfr41279 		} else if (r[i] < ai) {
532b60f2a0bSfr41279 			cy = 1;
533b60f2a0bSfr41279 		}
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 	for (; i < longer; i++) {
5367c478bd9Sstevel@tonic-gate 		ai = c[i];
5377c478bd9Sstevel@tonic-gate 		r[i] = ai + cy;
538b60f2a0bSfr41279 		if (r[i] >= ai) {
539b60f2a0bSfr41279 			cy = 0;
540b60f2a0bSfr41279 		}
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate 	if (cy == 1) {
5437c478bd9Sstevel@tonic-gate 		r[i] = cy;
5447c478bd9Sstevel@tonic-gate 		result->len = longer + 1;
5457c478bd9Sstevel@tonic-gate 	} else {
5467c478bd9Sstevel@tonic-gate 		result->len = longer;
5477c478bd9Sstevel@tonic-gate 	}
5487c478bd9Sstevel@tonic-gate 	result->sign = 1;
5497c478bd9Sstevel@tonic-gate 	return (BIG_OK);
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */
5547c478bd9Sstevel@tonic-gate void
555b60f2a0bSfr41279 big_sub_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, BIG_CHUNK_TYPE *b, int len)
5567c478bd9Sstevel@tonic-gate {
5577c478bd9Sstevel@tonic-gate 	int		i;
558b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, ai;
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	cy = 1;
5617c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
5627c478bd9Sstevel@tonic-gate 		ai = a[i];
5637c478bd9Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
564b60f2a0bSfr41279 		if (r[i] > ai) {
565b60f2a0bSfr41279 			cy = 0;
566b60f2a0bSfr41279 		} else if (r[i] < ai) {
567b60f2a0bSfr41279 			cy = 1;
568b60f2a0bSfr41279 		}
5697c478bd9Sstevel@tonic-gate 	}
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate /* result=aa-bb  it is assumed that aa>=bb */
5747c478bd9Sstevel@tonic-gate BIG_ERR_CODE
5757c478bd9Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
5767c478bd9Sstevel@tonic-gate {
5777c478bd9Sstevel@tonic-gate 	int		i, shorter;
578b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy = 1, ai;
579b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*r, *a, *b;
580b60f2a0bSfr41279 	BIG_ERR_CODE	err = BIG_OK;
5817c478bd9Sstevel@tonic-gate 
582b60f2a0bSfr41279 	if (aa->len > bb->len) {
583b60f2a0bSfr41279 		shorter = bb->len;
584b60f2a0bSfr41279 	} else {
585b60f2a0bSfr41279 		shorter = aa->len;
586b60f2a0bSfr41279 	}
5877c478bd9Sstevel@tonic-gate 	if (result->size < aa->len) {
5887c478bd9Sstevel@tonic-gate 		err = big_extend(result, aa->len);
589b60f2a0bSfr41279 		if (err != BIG_OK) {
5907c478bd9Sstevel@tonic-gate 			return (err);
5917c478bd9Sstevel@tonic-gate 		}
592b60f2a0bSfr41279 	}
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	r = result->value;
5957c478bd9Sstevel@tonic-gate 	a = aa->value;
5967c478bd9Sstevel@tonic-gate 	b = bb->value;
5977c478bd9Sstevel@tonic-gate 	result->len = aa->len;
5987c478bd9Sstevel@tonic-gate 	cy = 1;
5997c478bd9Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
6007c478bd9Sstevel@tonic-gate 		ai = a[i];
6017c478bd9Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
602b60f2a0bSfr41279 		if (r[i] > ai) {
603b60f2a0bSfr41279 			cy = 0;
604b60f2a0bSfr41279 		} else if (r[i] < ai) {
605b60f2a0bSfr41279 			cy = 1;
606b60f2a0bSfr41279 		}
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 	for (; i < aa->len; i++) {
6097c478bd9Sstevel@tonic-gate 		ai = a[i];
6107c478bd9Sstevel@tonic-gate 		r[i] = ai + (~0) + cy;
611b60f2a0bSfr41279 		if (r[i] < ai) {
612b60f2a0bSfr41279 			cy = 1;
613b60f2a0bSfr41279 		}
6147c478bd9Sstevel@tonic-gate 	}
6157c478bd9Sstevel@tonic-gate 	result->sign = 1;
616b60f2a0bSfr41279 
617b60f2a0bSfr41279 	if (cy == 0) {
6187c478bd9Sstevel@tonic-gate 		return (BIG_INVALID_ARGS);
619b60f2a0bSfr41279 	} else {
6207c478bd9Sstevel@tonic-gate 		return (BIG_OK);
6217c478bd9Sstevel@tonic-gate 	}
622b60f2a0bSfr41279 }
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */
6267c478bd9Sstevel@tonic-gate int
6277c478bd9Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb)
6287c478bd9Sstevel@tonic-gate {
6297c478bd9Sstevel@tonic-gate 	int	i;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	if (aa->len > bb->len) {
6327c478bd9Sstevel@tonic-gate 		for (i = aa->len - 1; i > bb->len - 1; i--) {
633b60f2a0bSfr41279 			if (aa->value[i] > 0) {
6347c478bd9Sstevel@tonic-gate 				return (1);
6357c478bd9Sstevel@tonic-gate 			}
636b60f2a0bSfr41279 		}
6377c478bd9Sstevel@tonic-gate 	} else if (aa->len < bb->len) {
6387c478bd9Sstevel@tonic-gate 		for (i = bb->len - 1; i > aa->len - 1; i--) {
639b60f2a0bSfr41279 			if (bb->value[i] > 0) {
6407c478bd9Sstevel@tonic-gate 				return (-1);
6417c478bd9Sstevel@tonic-gate 			}
642b60f2a0bSfr41279 		}
643b60f2a0bSfr41279 	} else {
644b60f2a0bSfr41279 		i = aa->len - 1;
645b60f2a0bSfr41279 	}
6467c478bd9Sstevel@tonic-gate 	for (; i >= 0; i--) {
647b60f2a0bSfr41279 		if (aa->value[i] > bb->value[i]) {
6487c478bd9Sstevel@tonic-gate 			return (1);
649b60f2a0bSfr41279 		} else if (aa->value[i] < bb->value[i]) {
6507c478bd9Sstevel@tonic-gate 			return (-1);
6517c478bd9Sstevel@tonic-gate 		}
652b60f2a0bSfr41279 	}
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	return (0);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate BIG_ERR_CODE
6597c478bd9Sstevel@tonic-gate big_sub(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 
7027c478bd9Sstevel@tonic-gate BIG_ERR_CODE
7037c478bd9Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
7047c478bd9Sstevel@tonic-gate {
7057c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == -1)) {
708b60f2a0bSfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
7097c478bd9Sstevel@tonic-gate 			return (err);
710b60f2a0bSfr41279 		}
7117c478bd9Sstevel@tonic-gate 		result->sign = -1;
7127c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
713b60f2a0bSfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
7147c478bd9Sstevel@tonic-gate 			return (err);
715b60f2a0bSfr41279 		}
7167c478bd9Sstevel@tonic-gate 		result->sign = 1;
7177c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == -1)) {
7187c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
719b60f2a0bSfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
7207c478bd9Sstevel@tonic-gate 				return (err);
721b60f2a0bSfr41279 			}
7227c478bd9Sstevel@tonic-gate 			result->sign = 1;
7237c478bd9Sstevel@tonic-gate 		} else {
724b60f2a0bSfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
7257c478bd9Sstevel@tonic-gate 				return (err);
726b60f2a0bSfr41279 			}
7277c478bd9Sstevel@tonic-gate 			result->sign = -1;
7287c478bd9Sstevel@tonic-gate 		}
7297c478bd9Sstevel@tonic-gate 	} else {
7307c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
731b60f2a0bSfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
7327c478bd9Sstevel@tonic-gate 				return (err);
733b60f2a0bSfr41279 			}
7347c478bd9Sstevel@tonic-gate 			result->sign = -1;
7357c478bd9Sstevel@tonic-gate 		} else {
736b60f2a0bSfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
7377c478bd9Sstevel@tonic-gate 				return (err);
738b60f2a0bSfr41279 			}
7397c478bd9Sstevel@tonic-gate 			result->sign = 1;
7407c478bd9Sstevel@tonic-gate 		}
7417c478bd9Sstevel@tonic-gate 	}
7427c478bd9Sstevel@tonic-gate 	return (BIG_OK);
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 
746b60f2a0bSfr41279 /* result = aa/2 */
7477c478bd9Sstevel@tonic-gate BIG_ERR_CODE
7487c478bd9Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa)
7497c478bd9Sstevel@tonic-gate {
7507c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
7517c478bd9Sstevel@tonic-gate 	int		i;
752b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, cy1;
753b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *r;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	if (result->size < aa->len) {
7567c478bd9Sstevel@tonic-gate 		err = big_extend(result, aa->len);
757b60f2a0bSfr41279 		if (err != BIG_OK) {
7587c478bd9Sstevel@tonic-gate 			return (err);
7597c478bd9Sstevel@tonic-gate 		}
760b60f2a0bSfr41279 	}
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	result->len = aa->len;
7637c478bd9Sstevel@tonic-gate 	a = aa->value;
7647c478bd9Sstevel@tonic-gate 	r = result->value;
7657c478bd9Sstevel@tonic-gate 	cy = 0;
7667c478bd9Sstevel@tonic-gate 	for (i = aa->len - 1; i >= 0; i--) {
767b60f2a0bSfr41279 		cy1 = a[i] << (BIG_CHUNK_SIZE - 1);
7687c478bd9Sstevel@tonic-gate 		r[i] = (cy | (a[i] >> 1));
7697c478bd9Sstevel@tonic-gate 		cy = cy1;
7707c478bd9Sstevel@tonic-gate 	}
771b60f2a0bSfr41279 	if (r[result->len - 1] == 0) {
772b60f2a0bSfr41279 		result->len--;
773b60f2a0bSfr41279 	}
774b60f2a0bSfr41279 
7757c478bd9Sstevel@tonic-gate 	return (BIG_OK);
7767c478bd9Sstevel@tonic-gate }
7777c478bd9Sstevel@tonic-gate 
778b60f2a0bSfr41279 /* result  =  aa*2 */
7797c478bd9Sstevel@tonic-gate BIG_ERR_CODE
7807c478bd9Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa)
7817c478bd9Sstevel@tonic-gate {
7827c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
7837c478bd9Sstevel@tonic-gate 	int		i, rsize;
784b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, cy1;
785b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *r;
7867c478bd9Sstevel@tonic-gate 
787b60f2a0bSfr41279 	if ((aa->len > 0) &&
788b60f2a0bSfr41279 	    ((aa->value[aa->len - 1] & BIG_CHUNK_HIGHBIT) != 0)) {
7897c478bd9Sstevel@tonic-gate 		rsize = aa->len + 1;
790b60f2a0bSfr41279 	} else {
791b60f2a0bSfr41279 		rsize = aa->len;
792b60f2a0bSfr41279 	}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	if (result->size < rsize) {
7957c478bd9Sstevel@tonic-gate 		err = big_extend(result, rsize);
7967c478bd9Sstevel@tonic-gate 		if (err != BIG_OK)
7977c478bd9Sstevel@tonic-gate 			return (err);
7987c478bd9Sstevel@tonic-gate 	}
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	a = aa->value;
8017c478bd9Sstevel@tonic-gate 	r = result->value;
802b60f2a0bSfr41279 	if (rsize == aa->len + 1) {
803b60f2a0bSfr41279 		r[rsize - 1] = 1;
804b60f2a0bSfr41279 	}
8057c478bd9Sstevel@tonic-gate 	cy = 0;
8067c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
807b60f2a0bSfr41279 		cy1 = a[i] >> (BIG_CHUNK_SIZE - 1);
8087c478bd9Sstevel@tonic-gate 		r[i] = (cy | (a[i] << 1));
8097c478bd9Sstevel@tonic-gate 		cy = cy1;
8107c478bd9Sstevel@tonic-gate 	}
8117c478bd9Sstevel@tonic-gate 	result->len = rsize;
8127c478bd9Sstevel@tonic-gate 	return (BIG_OK);
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate 
815b60f2a0bSfr41279 
816b60f2a0bSfr41279 /*
817b60f2a0bSfr41279  * returns aa mod b, aa must be nonneg, b must be a max
818b60f2a0bSfr41279  * (BIG_CHUNK_SIZE / 2)-bit integer
819b60f2a0bSfr41279  */
820b60f2a0bSfr41279 static uint32_t
821b60f2a0bSfr41279 big_modhalf_pos(BIGNUM *aa, uint32_t b)
8227c478bd9Sstevel@tonic-gate {
8237c478bd9Sstevel@tonic-gate 	int		i;
824b60f2a0bSfr41279 	BIG_CHUNK_TYPE	rem;
8257c478bd9Sstevel@tonic-gate 
826b60f2a0bSfr41279 	if (aa->len == 0) {
8277c478bd9Sstevel@tonic-gate 		return (0);
828b60f2a0bSfr41279 	}
8297c478bd9Sstevel@tonic-gate 	rem = aa->value[aa->len - 1] % b;
8307c478bd9Sstevel@tonic-gate 	for (i = aa->len - 2; i >= 0; i--) {
831b60f2a0bSfr41279 		rem = ((rem << (BIG_CHUNK_SIZE / 2)) |
832b60f2a0bSfr41279 		    (aa->value[i] >> (BIG_CHUNK_SIZE / 2))) % b;
833b60f2a0bSfr41279 		rem = ((rem << (BIG_CHUNK_SIZE / 2)) |
834b60f2a0bSfr41279 		    (aa->value[i] & BIG_CHUNK_LOWHALFBITS)) % b;
8357c478bd9Sstevel@tonic-gate 	}
836b60f2a0bSfr41279 
837b60f2a0bSfr41279 	return ((uint32_t)rem);
8387c478bd9Sstevel@tonic-gate }
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate /*
842b60f2a0bSfr41279  * result = aa - (2^BIG_CHUNK_SIZE)^lendiff * bb
8437c478bd9Sstevel@tonic-gate  * result->size should be at least aa->len at entry
8447c478bd9Sstevel@tonic-gate  * aa, bb, and result should be positive
8457c478bd9Sstevel@tonic-gate  */
8467c478bd9Sstevel@tonic-gate void
8477c478bd9Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
8487c478bd9Sstevel@tonic-gate {
8497c478bd9Sstevel@tonic-gate 	int i, lendiff;
8507c478bd9Sstevel@tonic-gate 	BIGNUM res1, aa1;
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
8537c478bd9Sstevel@tonic-gate 	res1.size = result->size - lendiff;
8547c478bd9Sstevel@tonic-gate 	res1.malloced = 0;
8557c478bd9Sstevel@tonic-gate 	res1.value = result->value + lendiff;
8567c478bd9Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
8577c478bd9Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
8587c478bd9Sstevel@tonic-gate 	aa1.len = bb->len;
8597c478bd9Sstevel@tonic-gate 	aa1.sign = 1;
8607c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(&res1, &aa1, bb);
8617c478bd9Sstevel@tonic-gate 	if (result->value != aa->value) {
8627c478bd9Sstevel@tonic-gate 		for (i = 0; i < lendiff; i++) {
8637c478bd9Sstevel@tonic-gate 			result->value[i] = aa->value[i];
8647c478bd9Sstevel@tonic-gate 		}
8657c478bd9Sstevel@tonic-gate 	}
8667c478bd9Sstevel@tonic-gate 	result->len = aa->len;
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate /*
8717c478bd9Sstevel@tonic-gate  * returns 1, 0, or -1 depending on whether |aa| > , ==, or <
872b60f2a0bSfr41279  *					(2^BIG_CHUNK_SIZE)^lendiff * |bb|
8737c478bd9Sstevel@tonic-gate  * aa->len should be >= bb->len
8747c478bd9Sstevel@tonic-gate  */
8757c478bd9Sstevel@tonic-gate int
8767c478bd9Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb)
8777c478bd9Sstevel@tonic-gate {
8787c478bd9Sstevel@tonic-gate 	int		lendiff;
8797c478bd9Sstevel@tonic-gate 	BIGNUM		aa1;
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
8827c478bd9Sstevel@tonic-gate 	aa1.len = bb->len;
8837c478bd9Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
8847c478bd9Sstevel@tonic-gate 	aa1.malloced = 0;
8857c478bd9Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
8867c478bd9Sstevel@tonic-gate 	return (big_cmp_abs(&aa1, bb));
8877c478bd9Sstevel@tonic-gate }
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate /*
891b60f2a0bSfr41279  * result = aa * b where b is a max. (BIG_CHUNK_SIZE / 2)-bit positive integer.
8927c478bd9Sstevel@tonic-gate  * result should have enough space allocated.
8937c478bd9Sstevel@tonic-gate  */
894b60f2a0bSfr41279 static void
895b60f2a0bSfr41279 big_mulhalf_low(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b)
8967c478bd9Sstevel@tonic-gate {
8977c478bd9Sstevel@tonic-gate 	int		i;
898b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1, t2, ai, cy;
899b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *r;
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	a = aa->value;
9027c478bd9Sstevel@tonic-gate 	r = result->value;
9037c478bd9Sstevel@tonic-gate 	cy = 0;
9047c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
9057c478bd9Sstevel@tonic-gate 		ai = a[i];
906b60f2a0bSfr41279 		t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy;
907b60f2a0bSfr41279 		t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b +
908b60f2a0bSfr41279 		    (t1 >> (BIG_CHUNK_SIZE / 2));
909b60f2a0bSfr41279 		r[i] = (t1 & BIG_CHUNK_LOWHALFBITS) |
910b60f2a0bSfr41279 		    (t2 << (BIG_CHUNK_SIZE / 2));
911b60f2a0bSfr41279 		cy = t2 >> (BIG_CHUNK_SIZE / 2);
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 	r[i] = cy;
9147c478bd9Sstevel@tonic-gate 	result->len = aa->len + 1;
9157c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
9167c478bd9Sstevel@tonic-gate }
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate /*
920b60f2a0bSfr41279  * result = aa * b * 2^(BIG_CHUNK_SIZE / 2) where b is a max.
921b60f2a0bSfr41279  * (BIG_CHUNK_SIZE / 2)-bit positive integer.
9227c478bd9Sstevel@tonic-gate  * result should have enough space allocated.
9237c478bd9Sstevel@tonic-gate  */
924b60f2a0bSfr41279 static void
925b60f2a0bSfr41279 big_mulhalf_high(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b)
9267c478bd9Sstevel@tonic-gate {
9277c478bd9Sstevel@tonic-gate 	int		i;
928b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1, t2, ai, cy, ri;
929b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *r;
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	a = aa->value;
9327c478bd9Sstevel@tonic-gate 	r = result->value;
9337c478bd9Sstevel@tonic-gate 	cy = 0;
9347c478bd9Sstevel@tonic-gate 	ri = 0;
9357c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
9367c478bd9Sstevel@tonic-gate 		ai = a[i];
937b60f2a0bSfr41279 		t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy;
938b60f2a0bSfr41279 		t2 = (ai >>  (BIG_CHUNK_SIZE / 2)) * b +
939b60f2a0bSfr41279 		    (t1 >>  (BIG_CHUNK_SIZE / 2));
940b60f2a0bSfr41279 		r[i] = (t1 <<  (BIG_CHUNK_SIZE / 2)) + ri;
941b60f2a0bSfr41279 		ri = t2 & BIG_CHUNK_LOWHALFBITS;
942b60f2a0bSfr41279 		cy = t2 >> (BIG_CHUNK_SIZE / 2);
9437c478bd9Sstevel@tonic-gate 	}
944b60f2a0bSfr41279 	r[i] = (cy <<  (BIG_CHUNK_SIZE / 2)) + ri;
9457c478bd9Sstevel@tonic-gate 	result->len = aa->len + 1;
9467c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
9477c478bd9Sstevel@tonic-gate }
9487c478bd9Sstevel@tonic-gate 
949b60f2a0bSfr41279 
9507c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */
9517c478bd9Sstevel@tonic-gate void
9527c478bd9Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs)
9537c478bd9Sstevel@tonic-gate {
9547c478bd9Sstevel@tonic-gate 	int		i;
955b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, ai;
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	if (offs == 0) {
9587c478bd9Sstevel@tonic-gate 		if (result != aa) {
9597c478bd9Sstevel@tonic-gate 			(void) big_copy(result, aa);
9607c478bd9Sstevel@tonic-gate 		}
9617c478bd9Sstevel@tonic-gate 		return;
9627c478bd9Sstevel@tonic-gate 	}
9637c478bd9Sstevel@tonic-gate 	cy = 0;
9647c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
9657c478bd9Sstevel@tonic-gate 		ai = aa->value[i];
9667c478bd9Sstevel@tonic-gate 		result->value[i] = (ai << offs) | cy;
967b60f2a0bSfr41279 		cy = ai >> (BIG_CHUNK_SIZE - offs);
9687c478bd9Sstevel@tonic-gate 	}
9697c478bd9Sstevel@tonic-gate 	if (cy != 0) {
9707c478bd9Sstevel@tonic-gate 		result->len = aa->len + 1;
9717c478bd9Sstevel@tonic-gate 		result->value[result->len - 1] = cy;
9727c478bd9Sstevel@tonic-gate 	} else {
9737c478bd9Sstevel@tonic-gate 		result->len = aa->len;
9747c478bd9Sstevel@tonic-gate 	}
9757c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
9767c478bd9Sstevel@tonic-gate }
9777c478bd9Sstevel@tonic-gate 
978b60f2a0bSfr41279 
9797c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */
9807c478bd9Sstevel@tonic-gate void
9817c478bd9Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs)
9827c478bd9Sstevel@tonic-gate {
9837c478bd9Sstevel@tonic-gate 	int		 i;
984b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, ai;
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	if (offs == 0) {
9877c478bd9Sstevel@tonic-gate 		if (result != aa) {
9887c478bd9Sstevel@tonic-gate 			(void) big_copy(result, aa);
9897c478bd9Sstevel@tonic-gate 		}
9907c478bd9Sstevel@tonic-gate 		return;
9917c478bd9Sstevel@tonic-gate 	}
9927c478bd9Sstevel@tonic-gate 	cy = aa->value[0] >> offs;
9937c478bd9Sstevel@tonic-gate 	for (i = 1; i < aa->len; i++) {
9947c478bd9Sstevel@tonic-gate 		ai = aa->value[i];
995b60f2a0bSfr41279 		result->value[i - 1] = (ai << (BIG_CHUNK_SIZE - offs)) | cy;
9967c478bd9Sstevel@tonic-gate 		cy = ai >> offs;
9977c478bd9Sstevel@tonic-gate 	}
9987c478bd9Sstevel@tonic-gate 	result->len = aa->len;
9997c478bd9Sstevel@tonic-gate 	result->value[result->len - 1] = cy;
10007c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate /*
10057c478bd9Sstevel@tonic-gate  * result = aa/bb   remainder = aa mod bb
10067c478bd9Sstevel@tonic-gate  * it is assumed that aa and bb are positive
10077c478bd9Sstevel@tonic-gate  */
10087c478bd9Sstevel@tonic-gate BIG_ERR_CODE
10098475e043SDan OpenSolaris Anderson big_div_pos(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb)
10107c478bd9Sstevel@tonic-gate {
1011b60f2a0bSfr41279 	BIG_ERR_CODE	err = BIG_OK;
10127c478bd9Sstevel@tonic-gate 	int		i, alen, blen, tlen, rlen, offs;
1013b60f2a0bSfr41279 	BIG_CHUNK_TYPE	higha, highb, coeff;
1014b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *b;
10157c478bd9Sstevel@tonic-gate 	BIGNUM		bbhigh, bblow, tresult, tmp1, tmp2;
1016b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
1017b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp2value[BIGTMPSIZE];
1018b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tresultvalue[BIGTMPSIZE];
1019b60f2a0bSfr41279 	BIG_CHUNK_TYPE	bblowvalue[BIGTMPSIZE];
1020b60f2a0bSfr41279 	BIG_CHUNK_TYPE	bbhighvalue[BIGTMPSIZE];
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	a = aa->value;
10237c478bd9Sstevel@tonic-gate 	b = bb->value;
10247c478bd9Sstevel@tonic-gate 	alen = aa->len;
10257c478bd9Sstevel@tonic-gate 	blen = bb->len;
1026b60f2a0bSfr41279 	while ((alen > 1) && (a[alen - 1] == 0)) {
1027b60f2a0bSfr41279 		alen = alen - 1;
1028b60f2a0bSfr41279 	}
10297c478bd9Sstevel@tonic-gate 	aa->len = alen;
1030b60f2a0bSfr41279 	while ((blen > 1) && (b[blen - 1] == 0)) {
1031b60f2a0bSfr41279 		blen = blen - 1;
1032b60f2a0bSfr41279 	}
10337c478bd9Sstevel@tonic-gate 	bb->len = blen;
1034b60f2a0bSfr41279 	if ((blen == 1) && (b[0] == 0)) {
10357c478bd9Sstevel@tonic-gate 		return (BIG_DIV_BY_0);
1036b60f2a0bSfr41279 	}
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(aa, bb) < 0) {
10397c478bd9Sstevel@tonic-gate 		if ((remainder != NULL) &&
1040b60f2a0bSfr41279 		    ((err = big_copy(remainder, aa)) != BIG_OK)) {
10417c478bd9Sstevel@tonic-gate 			return (err);
1042b60f2a0bSfr41279 		}
10437c478bd9Sstevel@tonic-gate 		if (result != NULL) {
10447c478bd9Sstevel@tonic-gate 			result->len = 1;
10457c478bd9Sstevel@tonic-gate 			result->sign = 1;
10467c478bd9Sstevel@tonic-gate 			result->value[0] = 0;
10477c478bd9Sstevel@tonic-gate 		}
10487c478bd9Sstevel@tonic-gate 		return (BIG_OK);
10497c478bd9Sstevel@tonic-gate 	}
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&bblow, blen + 1,
10527c478bd9Sstevel@tonic-gate 	    bblowvalue, arraysize(bblowvalue))) != BIG_OK)
10537c478bd9Sstevel@tonic-gate 		return (err);
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&bbhigh, blen + 1,
10567c478bd9Sstevel@tonic-gate 	    bbhighvalue, arraysize(bbhighvalue))) != BIG_OK)
10577c478bd9Sstevel@tonic-gate 		goto ret1;
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp1, alen + 2,
10607c478bd9Sstevel@tonic-gate 	    tmp1value, arraysize(tmp1value))) != BIG_OK)
10617c478bd9Sstevel@tonic-gate 		goto ret2;
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, blen + 2,
10647c478bd9Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
10657c478bd9Sstevel@tonic-gate 		goto ret3;
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tresult, alen - blen + 2,
10687c478bd9Sstevel@tonic-gate 	    tresultvalue, arraysize(tresultvalue))) != BIG_OK)
10697c478bd9Sstevel@tonic-gate 		goto ret4;
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	offs = 0;
1072b60f2a0bSfr41279 	highb = b[blen - 1];
1073b60f2a0bSfr41279 	if (highb >= (BIG_CHUNK_HALF_HIGHBIT << 1)) {
1074b60f2a0bSfr41279 		highb = highb >> (BIG_CHUNK_SIZE / 2);
1075b60f2a0bSfr41279 		offs = (BIG_CHUNK_SIZE / 2);
10767c478bd9Sstevel@tonic-gate 	}
1077b60f2a0bSfr41279 	while ((highb & BIG_CHUNK_HALF_HIGHBIT) == 0) {
1078b60f2a0bSfr41279 		highb = highb << 1;
10797c478bd9Sstevel@tonic-gate 		offs++;
10807c478bd9Sstevel@tonic-gate 	}
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	big_shiftleft(&bblow, bb, offs);
1083b60f2a0bSfr41279 
1084b60f2a0bSfr41279 	if (offs <= (BIG_CHUNK_SIZE / 2 - 1)) {
1085b60f2a0bSfr41279 		big_shiftleft(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2);
10867c478bd9Sstevel@tonic-gate 	} else {
1087b60f2a0bSfr41279 		big_shiftright(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2);
10887c478bd9Sstevel@tonic-gate 	}
10897c478bd9Sstevel@tonic-gate 	if (bbhigh.value[bbhigh.len - 1] == 0) {
10907c478bd9Sstevel@tonic-gate 		bbhigh.len--;
10917c478bd9Sstevel@tonic-gate 	} else {
10927c478bd9Sstevel@tonic-gate 		bbhigh.value[bbhigh.len] = 0;
10937c478bd9Sstevel@tonic-gate 	}
10947c478bd9Sstevel@tonic-gate 
1095b60f2a0bSfr41279 	highb = bblow.value[bblow.len - 1];
1096b60f2a0bSfr41279 
10977c478bd9Sstevel@tonic-gate 	big_shiftleft(&tmp1, aa, offs);
10987c478bd9Sstevel@tonic-gate 	rlen = tmp1.len - bblow.len + 1;
10997c478bd9Sstevel@tonic-gate 	tresult.len = rlen;
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 	tmp1.len++;
11027c478bd9Sstevel@tonic-gate 	tlen = tmp1.len;
11037c478bd9Sstevel@tonic-gate 	tmp1.value[tmp1.len - 1] = 0;
11047c478bd9Sstevel@tonic-gate 	for (i = 0; i < rlen; i++) {
1105b60f2a0bSfr41279 		higha = (tmp1.value[tlen - 1] << (BIG_CHUNK_SIZE / 2)) +
1106b60f2a0bSfr41279 		    (tmp1.value[tlen - 2] >> (BIG_CHUNK_SIZE / 2));
11077c478bd9Sstevel@tonic-gate 		coeff = higha / (highb + 1);
1108b60f2a0bSfr41279 		big_mulhalf_high(&tmp2, &bblow, coeff);
11097c478bd9Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
11107c478bd9Sstevel@tonic-gate 		bbhigh.len++;
11117c478bd9Sstevel@tonic-gate 		while (tmp1.value[tlen - 1] > 0) {
11127c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
11137c478bd9Sstevel@tonic-gate 			coeff++;
11147c478bd9Sstevel@tonic-gate 		}
11157c478bd9Sstevel@tonic-gate 		bbhigh.len--;
11167c478bd9Sstevel@tonic-gate 		tlen--;
11177c478bd9Sstevel@tonic-gate 		tmp1.len--;
11187c478bd9Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) {
11197c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
11207c478bd9Sstevel@tonic-gate 			coeff++;
11217c478bd9Sstevel@tonic-gate 		}
1122b60f2a0bSfr41279 		tresult.value[rlen - i - 1] = coeff << (BIG_CHUNK_SIZE / 2);
11237c478bd9Sstevel@tonic-gate 		higha = tmp1.value[tlen - 1];
11247c478bd9Sstevel@tonic-gate 		coeff = higha / (highb + 1);
1125b60f2a0bSfr41279 		big_mulhalf_low(&tmp2, &bblow, coeff);
11267c478bd9Sstevel@tonic-gate 		tmp2.len--;
11277c478bd9Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
11287c478bd9Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bblow) >= 0) {
11297c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bblow);
11307c478bd9Sstevel@tonic-gate 			coeff++;
11317c478bd9Sstevel@tonic-gate 		}
11327c478bd9Sstevel@tonic-gate 		tresult.value[rlen - i - 1] =
11337c478bd9Sstevel@tonic-gate 		    tresult.value[rlen - i - 1] + coeff;
11347c478bd9Sstevel@tonic-gate 	}
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	big_shiftright(&tmp1, &tmp1, offs);
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 	err = BIG_OK;
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate 	if ((remainder != NULL) &&
11417c478bd9Sstevel@tonic-gate 	    ((err = big_copy(remainder, &tmp1)) != BIG_OK))
11427c478bd9Sstevel@tonic-gate 		goto ret;
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	if (result != NULL)
11457c478bd9Sstevel@tonic-gate 		err = big_copy(result, &tresult);
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate ret:
11487c478bd9Sstevel@tonic-gate 	big_finish(&tresult);
11497c478bd9Sstevel@tonic-gate ret4:
11507c478bd9Sstevel@tonic-gate 	big_finish(&tmp1);
11517c478bd9Sstevel@tonic-gate ret3:
11527c478bd9Sstevel@tonic-gate 	big_finish(&tmp2);
11537c478bd9Sstevel@tonic-gate ret2:
11547c478bd9Sstevel@tonic-gate 	big_finish(&bbhigh);
11557c478bd9Sstevel@tonic-gate ret1:
11567c478bd9Sstevel@tonic-gate 	big_finish(&bblow);
11577c478bd9Sstevel@tonic-gate 	return (err);
11587c478bd9Sstevel@tonic-gate }
11597c478bd9Sstevel@tonic-gate 
11608475e043SDan OpenSolaris Anderson 
11617c478bd9Sstevel@tonic-gate /*
11627c478bd9Sstevel@tonic-gate  * If there is no processor-specific integer implementation of
11637c478bd9Sstevel@tonic-gate  * the lower level multiply functions, then this code is provided
11647c478bd9Sstevel@tonic-gate  * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and
11657c478bd9Sstevel@tonic-gate  * big_sqr_vec().
11667c478bd9Sstevel@tonic-gate  *
11677c478bd9Sstevel@tonic-gate  * There are two generic implementations.  One that assumes that
11687c478bd9Sstevel@tonic-gate  * there is hardware and C compiler support for a 32 x 32 --> 64
11697c478bd9Sstevel@tonic-gate  * bit unsigned multiply, but otherwise is not specific to any
11707c478bd9Sstevel@tonic-gate  * processor, platform, or ISA.
11717c478bd9Sstevel@tonic-gate  *
11727c478bd9Sstevel@tonic-gate  * The other makes very few assumptions about hardware capabilities.
11737c478bd9Sstevel@tonic-gate  * It does not even assume that there is any implementation of a
11747c478bd9Sstevel@tonic-gate  * 32 x 32 --> 64 bit multiply that is accessible to C code and
11757c478bd9Sstevel@tonic-gate  * appropriate to use.  It falls constructs 32 x 32 --> 64 bit
11767c478bd9Sstevel@tonic-gate  * multiplies from 16 x 16 --> 32 bit multiplies.
11777c478bd9Sstevel@tonic-gate  *
11787c478bd9Sstevel@tonic-gate  */
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate #if !defined(PSR_MUL)
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate #ifdef UMUL64
11837c478bd9Sstevel@tonic-gate 
1184b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
1185b60f2a0bSfr41279 
11867c478bd9Sstevel@tonic-gate #define	UNROLL8
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_PREFETCH(R) \
11897c478bd9Sstevel@tonic-gate 	p = pf * d; \
11907c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[R + 1]; \
11917c478bd9Sstevel@tonic-gate 	t = p + cy; \
11927c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11937c478bd9Sstevel@tonic-gate 	cy = t >> 32
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_NOPREFETCH(R) \
11967c478bd9Sstevel@tonic-gate 	p = pf * d; \
11977c478bd9Sstevel@tonic-gate 	t = p + cy; \
11987c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11997c478bd9Sstevel@tonic-gate 	cy = t >> 32
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_PREFETCH(R) \
12027c478bd9Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
12037c478bd9Sstevel@tonic-gate 	p = pf * d; \
12047c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[R + 1]; \
12057c478bd9Sstevel@tonic-gate 	t = p + t + cy; \
12067c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
12077c478bd9Sstevel@tonic-gate 	cy = t >> 32
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_NOPREFETCH(R) \
12107c478bd9Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
12117c478bd9Sstevel@tonic-gate 	p = pf * d; \
12127c478bd9Sstevel@tonic-gate 	t = p + t + cy; \
12137c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
12147c478bd9Sstevel@tonic-gate 	cy = t >> 32
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate #ifdef UNROLL8
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate #define	UNROLL 8
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate /*
12217c478bd9Sstevel@tonic-gate  * r = a * b
12227c478bd9Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
12237c478bd9Sstevel@tonic-gate  */
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate uint32_t
12267c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
12277c478bd9Sstevel@tonic-gate {
12287c478bd9Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	if (len == 0)
12317c478bd9Sstevel@tonic-gate 		return (0);
12327c478bd9Sstevel@tonic-gate 	cy = 0;
12337c478bd9Sstevel@tonic-gate 	d = (uint64_t)b;
12347c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[0];
12357c478bd9Sstevel@tonic-gate 	while (len > UNROLL) {
12367c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
12377c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
12387c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
12397c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
12407c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
12417c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
12427c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
12437c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(7);
12447c478bd9Sstevel@tonic-gate 		r += UNROLL;
12457c478bd9Sstevel@tonic-gate 		a += UNROLL;
12467c478bd9Sstevel@tonic-gate 		len -= UNROLL;
12477c478bd9Sstevel@tonic-gate 	}
12487c478bd9Sstevel@tonic-gate 	if (len == UNROLL) {
12497c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
12507c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
12517c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
12527c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
12537c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
12547c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
12557c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
12567c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(7);
12577c478bd9Sstevel@tonic-gate 		return ((uint32_t)cy);
12587c478bd9Sstevel@tonic-gate 	}
12597c478bd9Sstevel@tonic-gate 	while (len > 1) {
12607c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
12617c478bd9Sstevel@tonic-gate 		++r;
12627c478bd9Sstevel@tonic-gate 		++a;
12637c478bd9Sstevel@tonic-gate 		--len;
12647c478bd9Sstevel@tonic-gate 	}
12657c478bd9Sstevel@tonic-gate 	if (len > 0) {
12667c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(0);
12677c478bd9Sstevel@tonic-gate 	}
12687c478bd9Sstevel@tonic-gate 	return ((uint32_t)cy);
12697c478bd9Sstevel@tonic-gate }
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate /*
12727c478bd9Sstevel@tonic-gate  * r += a * b
12737c478bd9Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
12747c478bd9Sstevel@tonic-gate  */
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate uint32_t
12777c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
12787c478bd9Sstevel@tonic-gate {
12797c478bd9Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 	if (len == 0)
12827c478bd9Sstevel@tonic-gate 		return (0);
12837c478bd9Sstevel@tonic-gate 	cy = 0;
12847c478bd9Sstevel@tonic-gate 	d = (uint64_t)b;
12857c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[0];
12867c478bd9Sstevel@tonic-gate 	while (len > 8) {
12877c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12887c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
12897c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
12907c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
12917c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
12927c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
12937c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
12947c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(7);
12957c478bd9Sstevel@tonic-gate 		r += 8;
12967c478bd9Sstevel@tonic-gate 		a += 8;
12977c478bd9Sstevel@tonic-gate 		len -= 8;
12987c478bd9Sstevel@tonic-gate 	}
12997c478bd9Sstevel@tonic-gate 	if (len == 8) {
13007c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
13017c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
13027c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
13037c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
13047c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
13057c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
13067c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
13077c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(7);
13087c478bd9Sstevel@tonic-gate 		return ((uint32_t)cy);
13097c478bd9Sstevel@tonic-gate 	}
13107c478bd9Sstevel@tonic-gate 	while (len > 1) {
13117c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
13127c478bd9Sstevel@tonic-gate 		++r;
13137c478bd9Sstevel@tonic-gate 		++a;
13147c478bd9Sstevel@tonic-gate 		--len;
13157c478bd9Sstevel@tonic-gate 	}
13167c478bd9Sstevel@tonic-gate 	if (len > 0) {
13177c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(0);
13187c478bd9Sstevel@tonic-gate 	}
13197c478bd9Sstevel@tonic-gate 	return ((uint32_t)cy);
13207c478bd9Sstevel@tonic-gate }
13217c478bd9Sstevel@tonic-gate #endif /* UNROLL8 */
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate void
13247c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
13257c478bd9Sstevel@tonic-gate {
13267c478bd9Sstevel@tonic-gate 	uint32_t	*tr, *ta;
13277c478bd9Sstevel@tonic-gate 	int		tlen, row, col;
13287c478bd9Sstevel@tonic-gate 	uint64_t	p, s, t, t2, cy;
13297c478bd9Sstevel@tonic-gate 	uint32_t	d;
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	tr = r + 1;
13327c478bd9Sstevel@tonic-gate 	ta = a;
13337c478bd9Sstevel@tonic-gate 	tlen = len - 1;
13347c478bd9Sstevel@tonic-gate 	tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]);
13357c478bd9Sstevel@tonic-gate 	while (--tlen > 0) {
13367c478bd9Sstevel@tonic-gate 		tr += 2;
13377c478bd9Sstevel@tonic-gate 		++ta;
13387c478bd9Sstevel@tonic-gate 		tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]);
13397c478bd9Sstevel@tonic-gate 	}
13407c478bd9Sstevel@tonic-gate 	s = (uint64_t)a[0];
13417c478bd9Sstevel@tonic-gate 	s = s * s;
13427c478bd9Sstevel@tonic-gate 	r[0] = (uint32_t)s;
13437c478bd9Sstevel@tonic-gate 	cy = s >> 32;
13447c478bd9Sstevel@tonic-gate 	p = ((uint64_t)r[1] << 1) + cy;
13457c478bd9Sstevel@tonic-gate 	r[1] = (uint32_t)p;
13467c478bd9Sstevel@tonic-gate 	cy = p >> 32;
13477c478bd9Sstevel@tonic-gate 	row = 1;
13487c478bd9Sstevel@tonic-gate 	col = 2;
13497c478bd9Sstevel@tonic-gate 	while (row < len) {
13507c478bd9Sstevel@tonic-gate 		s = (uint64_t)a[row];
13517c478bd9Sstevel@tonic-gate 		s = s * s;
13527c478bd9Sstevel@tonic-gate 		p = (uint64_t)r[col] << 1;
13537c478bd9Sstevel@tonic-gate 		t = p + s;
13547c478bd9Sstevel@tonic-gate 		d = (uint32_t)t;
13557c478bd9Sstevel@tonic-gate 		t2 = (uint64_t)d + cy;
13567c478bd9Sstevel@tonic-gate 		r[col] = (uint32_t)t2;
13577c478bd9Sstevel@tonic-gate 		cy = (t >> 32) + (t2 >> 32);
13587c478bd9Sstevel@tonic-gate 		if (row == len - 1)
13597c478bd9Sstevel@tonic-gate 			break;
13607c478bd9Sstevel@tonic-gate 		p = ((uint64_t)r[col + 1] << 1) + cy;
13617c478bd9Sstevel@tonic-gate 		r[col + 1] = (uint32_t)p;
13627c478bd9Sstevel@tonic-gate 		cy = p >> 32;
13637c478bd9Sstevel@tonic-gate 		++row;
13647c478bd9Sstevel@tonic-gate 		col += 2;
13657c478bd9Sstevel@tonic-gate 	}
13667c478bd9Sstevel@tonic-gate 	r[col + 1] = (uint32_t)cy;
13677c478bd9Sstevel@tonic-gate }
13687c478bd9Sstevel@tonic-gate 
1369b60f2a0bSfr41279 #else /* BIG_CHUNK_SIZE == 64 */
1370b60f2a0bSfr41279 
1371b60f2a0bSfr41279 /*
1372b60f2a0bSfr41279  * r = r + a * digit, r and a are vectors of length len
1373b60f2a0bSfr41279  * returns the carry digit
1374b60f2a0bSfr41279  */
1375b60f2a0bSfr41279 BIG_CHUNK_TYPE
1376b60f2a0bSfr41279 big_mul_add_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len,
1377b60f2a0bSfr41279     BIG_CHUNK_TYPE digit)
1378b60f2a0bSfr41279 {
1379b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, cy1, retcy, dlow, dhigh;
1380b60f2a0bSfr41279 	int		i;
1381b60f2a0bSfr41279 
1382b60f2a0bSfr41279 	cy1 = 0;
1383b60f2a0bSfr41279 	dlow = digit & BIG_CHUNK_LOWHALFBITS;
1384b60f2a0bSfr41279 	dhigh = digit >> (BIG_CHUNK_SIZE / 2);
1385b60f2a0bSfr41279 	for (i = 0; i < len; i++) {
1386b60f2a0bSfr41279 		cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
1387b60f2a0bSfr41279 		    dlow * (a[i] & BIG_CHUNK_LOWHALFBITS) +
1388b60f2a0bSfr41279 		    (r[i] & BIG_CHUNK_LOWHALFBITS);
1389b60f2a0bSfr41279 		cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) +
1390b60f2a0bSfr41279 		    dlow * (a[i] >> (BIG_CHUNK_SIZE / 2)) +
1391b60f2a0bSfr41279 		    (r[i] >> (BIG_CHUNK_SIZE / 2));
1392b60f2a0bSfr41279 		r[i] = (cy & BIG_CHUNK_LOWHALFBITS) |
1393b60f2a0bSfr41279 		    (cy1 << (BIG_CHUNK_SIZE / 2));
1394b60f2a0bSfr41279 	}
1395b60f2a0bSfr41279 	retcy = cy1 >> (BIG_CHUNK_SIZE / 2);
1396b60f2a0bSfr41279 
1397b60f2a0bSfr41279 	cy1 = r[0] & BIG_CHUNK_LOWHALFBITS;
1398b60f2a0bSfr41279 	for (i = 0; i < len - 1; i++) {
1399b60f2a0bSfr41279 		cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
1400b60f2a0bSfr41279 		    dhigh * (a[i] & BIG_CHUNK_LOWHALFBITS) +
1401b60f2a0bSfr41279 		    (r[i] >> (BIG_CHUNK_SIZE / 2));
1402b60f2a0bSfr41279 		r[i] = (cy1 & BIG_CHUNK_LOWHALFBITS) |
1403b60f2a0bSfr41279 		    (cy << (BIG_CHUNK_SIZE / 2));
1404b60f2a0bSfr41279 		cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) +
1405b60f2a0bSfr41279 		    dhigh * (a[i] >> (BIG_CHUNK_SIZE / 2)) +
1406b60f2a0bSfr41279 		    (r[i + 1] & BIG_CHUNK_LOWHALFBITS);
1407b60f2a0bSfr41279 	}
1408b60f2a0bSfr41279 	cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
1409b60f2a0bSfr41279 	    dhigh * (a[len - 1] & BIG_CHUNK_LOWHALFBITS) +
1410b60f2a0bSfr41279 	    (r[len - 1] >> (BIG_CHUNK_SIZE / 2));
1411b60f2a0bSfr41279 	r[len - 1] = (cy1 & BIG_CHUNK_LOWHALFBITS) |
1412b60f2a0bSfr41279 	    (cy << (BIG_CHUNK_SIZE / 2));
1413b60f2a0bSfr41279 	retcy = (cy >> (BIG_CHUNK_SIZE / 2)) +
1414b60f2a0bSfr41279 	    dhigh * (a[len - 1] >> (BIG_CHUNK_SIZE / 2)) + retcy;
1415b60f2a0bSfr41279 
1416b60f2a0bSfr41279 	return (retcy);
1417b60f2a0bSfr41279 }
1418b60f2a0bSfr41279 
1419b60f2a0bSfr41279 
1420b60f2a0bSfr41279 /*
1421b60f2a0bSfr41279  * r = a * digit, r and a are vectors of length len
1422b60f2a0bSfr41279  * returns the carry digit
1423b60f2a0bSfr41279  */
1424b60f2a0bSfr41279 BIG_CHUNK_TYPE
1425b60f2a0bSfr41279 big_mul_set_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len,
1426b60f2a0bSfr41279     BIG_CHUNK_TYPE digit)
1427b60f2a0bSfr41279 {
1428b60f2a0bSfr41279 	int	i;
1429b60f2a0bSfr41279 
1430b60f2a0bSfr41279 	ASSERT(r != a);
1431b60f2a0bSfr41279 	for (i = 0; i < len; i++) {
1432b60f2a0bSfr41279 		r[i] = 0;
1433b60f2a0bSfr41279 	}
1434b60f2a0bSfr41279 	return (big_mul_add_vec(r, a, len, digit));
1435b60f2a0bSfr41279 }
1436b60f2a0bSfr41279 
1437b60f2a0bSfr41279 void
1438b60f2a0bSfr41279 big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len)
1439b60f2a0bSfr41279 {
1440b60f2a0bSfr41279 	int i;
1441b60f2a0bSfr41279 
1442b60f2a0bSfr41279 	ASSERT(r != a);
1443b60f2a0bSfr41279 	r[len] = big_mul_set_vec(r, a, len, a[0]);
1444b60f2a0bSfr41279 	for (i = 1; i < len; ++i)
1445b60f2a0bSfr41279 		r[len + i] = big_mul_add_vec(r + i, a, len, a[i]);
1446b60f2a0bSfr41279 }
1447b60f2a0bSfr41279 
1448b60f2a0bSfr41279 #endif /* BIG_CHUNK_SIZE == 32/64 */
1449b60f2a0bSfr41279 
14508475e043SDan OpenSolaris Anderson 
14517c478bd9Sstevel@tonic-gate #else /* ! UMUL64 */
14527c478bd9Sstevel@tonic-gate 
1453b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE != 32)
1454b60f2a0bSfr41279 #error Don't use 64-bit chunks without defining UMUL64
1455b60f2a0bSfr41279 #endif
1456b60f2a0bSfr41279 
1457b60f2a0bSfr41279 
14587c478bd9Sstevel@tonic-gate /*
14597c478bd9Sstevel@tonic-gate  * r = r + a * digit, r and a are vectors of length len
14607c478bd9Sstevel@tonic-gate  * returns the carry digit
14617c478bd9Sstevel@tonic-gate  */
14627c478bd9Sstevel@tonic-gate uint32_t
14637c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
14647c478bd9Sstevel@tonic-gate {
14657c478bd9Sstevel@tonic-gate 	uint32_t cy, cy1, retcy, dlow, dhigh;
14667c478bd9Sstevel@tonic-gate 	int i;
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	cy1 = 0;
14697c478bd9Sstevel@tonic-gate 	dlow = digit & 0xffff;
14707c478bd9Sstevel@tonic-gate 	dhigh = digit >> 16;
14717c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
14727c478bd9Sstevel@tonic-gate 		cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff);
14737c478bd9Sstevel@tonic-gate 		cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16);
14747c478bd9Sstevel@tonic-gate 		r[i] = (cy & 0xffff) | (cy1 << 16);
14757c478bd9Sstevel@tonic-gate 	}
14767c478bd9Sstevel@tonic-gate 	retcy = cy1 >> 16;
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 	cy1 = r[0] & 0xffff;
14797c478bd9Sstevel@tonic-gate 	for (i = 0; i < len - 1; i++) {
14807c478bd9Sstevel@tonic-gate 		cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16);
14817c478bd9Sstevel@tonic-gate 		r[i] = (cy1 & 0xffff) | (cy << 16);
14827c478bd9Sstevel@tonic-gate 		cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff);
14837c478bd9Sstevel@tonic-gate 	}
14847c478bd9Sstevel@tonic-gate 	cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16);
14857c478bd9Sstevel@tonic-gate 	r[len - 1] = (cy1 & 0xffff) | (cy << 16);
14867c478bd9Sstevel@tonic-gate 	retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy;
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 	return (retcy);
14897c478bd9Sstevel@tonic-gate }
14907c478bd9Sstevel@tonic-gate 
1491b60f2a0bSfr41279 
14927c478bd9Sstevel@tonic-gate /*
14937c478bd9Sstevel@tonic-gate  * r = a * digit, r and a are vectors of length len
14947c478bd9Sstevel@tonic-gate  * returns the carry digit
14957c478bd9Sstevel@tonic-gate  */
14967c478bd9Sstevel@tonic-gate uint32_t
14977c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
14987c478bd9Sstevel@tonic-gate {
1499b60f2a0bSfr41279 	int	i;
1500b60f2a0bSfr41279 
1501b60f2a0bSfr41279 	ASSERT(r != a);
1502b60f2a0bSfr41279 	for (i = 0; i < len; i++) {
1503b60f2a0bSfr41279 		r[i] = 0;
1504b60f2a0bSfr41279 	}
1505b60f2a0bSfr41279 
15067c478bd9Sstevel@tonic-gate 	return (big_mul_add_vec(r, a, len, digit));
15077c478bd9Sstevel@tonic-gate }
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate void
15107c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
15117c478bd9Sstevel@tonic-gate {
15127c478bd9Sstevel@tonic-gate 	int i;
15137c478bd9Sstevel@tonic-gate 
1514b60f2a0bSfr41279 	ASSERT(r != a);
15157c478bd9Sstevel@tonic-gate 	r[len] = big_mul_set_vec(r, a, len, a[0]);
15167c478bd9Sstevel@tonic-gate 	for (i = 1; i < len; ++i)
15177c478bd9Sstevel@tonic-gate 		r[len + i] = big_mul_add_vec(r + i, a, len, a[i]);
15187c478bd9Sstevel@tonic-gate }
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate #endif /* UMUL64 */
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate void
1523b60f2a0bSfr41279 big_mul_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int alen,
1524b60f2a0bSfr41279     BIG_CHUNK_TYPE *b, int blen)
15257c478bd9Sstevel@tonic-gate {
15267c478bd9Sstevel@tonic-gate 	int i;
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 	r[alen] = big_mul_set_vec(r, a, alen, b[0]);
15297c478bd9Sstevel@tonic-gate 	for (i = 1; i < blen; ++i)
15307c478bd9Sstevel@tonic-gate 		r[alen + i] = big_mul_add_vec(r + i, a, alen, b[i]);
15317c478bd9Sstevel@tonic-gate }
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate #endif /* ! PSR_MUL */
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate /*
15387c478bd9Sstevel@tonic-gate  * result = aa * bb  result->value should be big enough to hold the result
15397c478bd9Sstevel@tonic-gate  *
15407c478bd9Sstevel@tonic-gate  * Implementation: Standard grammar school algorithm
15417c478bd9Sstevel@tonic-gate  *
15427c478bd9Sstevel@tonic-gate  */
15437c478bd9Sstevel@tonic-gate BIG_ERR_CODE
15447c478bd9Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
15457c478bd9Sstevel@tonic-gate {
15467c478bd9Sstevel@tonic-gate 	BIGNUM		tmp1;
1547b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
1548b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*r, *t, *a, *b;
15497c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
15507c478bd9Sstevel@tonic-gate 	int		i, alen, blen, rsize, sign, diff;
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 	if (aa == bb) {
15537c478bd9Sstevel@tonic-gate 		diff = 0;
15547c478bd9Sstevel@tonic-gate 	} else {
15557c478bd9Sstevel@tonic-gate 		diff = big_cmp_abs(aa, bb);
15567c478bd9Sstevel@tonic-gate 		if (diff < 0) {
15577c478bd9Sstevel@tonic-gate 			BIGNUM *tt;
15587c478bd9Sstevel@tonic-gate 			tt = aa;
15597c478bd9Sstevel@tonic-gate 			aa = bb;
15607c478bd9Sstevel@tonic-gate 			bb = tt;
15617c478bd9Sstevel@tonic-gate 		}
15627c478bd9Sstevel@tonic-gate 	}
15637c478bd9Sstevel@tonic-gate 	a = aa->value;
15647c478bd9Sstevel@tonic-gate 	b = bb->value;
15657c478bd9Sstevel@tonic-gate 	alen = aa->len;
15667c478bd9Sstevel@tonic-gate 	blen = bb->len;
1567b60f2a0bSfr41279 	while ((alen > 1) && (a[alen - 1] == 0)) {
1568b60f2a0bSfr41279 		alen--;
1569b60f2a0bSfr41279 	}
15707c478bd9Sstevel@tonic-gate 	aa->len = alen;
1571b60f2a0bSfr41279 	while ((blen > 1) && (b[blen - 1] == 0)) {
1572b60f2a0bSfr41279 		blen--;
1573b60f2a0bSfr41279 	}
15747c478bd9Sstevel@tonic-gate 	bb->len = blen;
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	rsize = alen + blen;
15778475e043SDan OpenSolaris Anderson 	ASSERT(rsize > 0);
15787c478bd9Sstevel@tonic-gate 	if (result->size < rsize) {
15797c478bd9Sstevel@tonic-gate 		err = big_extend(result, rsize);
1580b60f2a0bSfr41279 		if (err != BIG_OK) {
15817c478bd9Sstevel@tonic-gate 			return (err);
1582b60f2a0bSfr41279 		}
15837c478bd9Sstevel@tonic-gate 		/* aa or bb might be an alias to result */
15847c478bd9Sstevel@tonic-gate 		a = aa->value;
15857c478bd9Sstevel@tonic-gate 		b = bb->value;
15867c478bd9Sstevel@tonic-gate 	}
15877c478bd9Sstevel@tonic-gate 	r = result->value;
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 	if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) {
15907c478bd9Sstevel@tonic-gate 		result->len = 1;
15917c478bd9Sstevel@tonic-gate 		result->sign = 1;
15927c478bd9Sstevel@tonic-gate 		r[0] = 0;
15937c478bd9Sstevel@tonic-gate 		return (BIG_OK);
15947c478bd9Sstevel@tonic-gate 	}
15957c478bd9Sstevel@tonic-gate 	sign = aa->sign * bb->sign;
15967c478bd9Sstevel@tonic-gate 	if ((alen == 1) && (a[0] == 1)) {
1597b60f2a0bSfr41279 		for (i = 0; i < blen; i++) {
1598b60f2a0bSfr41279 			r[i] = b[i];
1599b60f2a0bSfr41279 		}
16007c478bd9Sstevel@tonic-gate 		result->len = blen;
16017c478bd9Sstevel@tonic-gate 		result->sign = sign;
16027c478bd9Sstevel@tonic-gate 		return (BIG_OK);
16037c478bd9Sstevel@tonic-gate 	}
16047c478bd9Sstevel@tonic-gate 	if ((blen == 1) && (b[0] == 1)) {
1605b60f2a0bSfr41279 		for (i = 0; i < alen; i++) {
1606b60f2a0bSfr41279 			r[i] = a[i];
1607b60f2a0bSfr41279 		}
16087c478bd9Sstevel@tonic-gate 		result->len = alen;
16097c478bd9Sstevel@tonic-gate 		result->sign = sign;
16107c478bd9Sstevel@tonic-gate 		return (BIG_OK);
16117c478bd9Sstevel@tonic-gate 	}
16127c478bd9Sstevel@tonic-gate 
1613b60f2a0bSfr41279 	if ((err = big_init1(&tmp1, rsize,
1614b60f2a0bSfr41279 	    tmp1value, arraysize(tmp1value))) != BIG_OK) {
16157c478bd9Sstevel@tonic-gate 		return (err);
1616b60f2a0bSfr41279 	}
16177c478bd9Sstevel@tonic-gate 	t = tmp1.value;
16187c478bd9Sstevel@tonic-gate 
1619b60f2a0bSfr41279 	for (i = 0; i < rsize; i++) {
1620b60f2a0bSfr41279 		t[i] = 0;
1621b60f2a0bSfr41279 	}
1622b60f2a0bSfr41279 
1623b60f2a0bSfr41279 	if (diff == 0 && alen > 2) {
16247c478bd9Sstevel@tonic-gate 		BIG_SQR_VEC(t, a, alen);
1625b60f2a0bSfr41279 	} else if (blen > 0) {
16267c478bd9Sstevel@tonic-gate 		BIG_MUL_VEC(t, a, alen, b, blen);
1627b60f2a0bSfr41279 	}
16287c478bd9Sstevel@tonic-gate 
1629b60f2a0bSfr41279 	if (t[rsize - 1] == 0) {
1630b60f2a0bSfr41279 		tmp1.len = rsize - 1;
1631b60f2a0bSfr41279 	} else {
1632b60f2a0bSfr41279 		tmp1.len = rsize;
1633b60f2a0bSfr41279 	}
16348475e043SDan OpenSolaris Anderson 
16358475e043SDan OpenSolaris Anderson 	err = big_copy(result, &tmp1);
16368475e043SDan OpenSolaris Anderson 
16377c478bd9Sstevel@tonic-gate 	result->sign = sign;
16387c478bd9Sstevel@tonic-gate 
1639b60f2a0bSfr41279 	big_finish(&tmp1);
16407c478bd9Sstevel@tonic-gate 
16418475e043SDan OpenSolaris Anderson 	return (err);
16427c478bd9Sstevel@tonic-gate }
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate /*
1646*0a1ad920SDan OpenSolaris Anderson  * big_mont_mul()
1647*0a1ad920SDan OpenSolaris Anderson  * Montgomery multiplication.
1648*0a1ad920SDan OpenSolaris Anderson  *
1649*0a1ad920SDan OpenSolaris Anderson  * Caller must ensure that  a < n,  b < n,  ret->size >=  2 * n->len + 1,
1650*0a1ad920SDan OpenSolaris Anderson  * and that ret is not n.
16517c478bd9Sstevel@tonic-gate  */
16527c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1653b60f2a0bSfr41279 big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, BIG_CHUNK_TYPE n0)
16547c478bd9Sstevel@tonic-gate {
16557c478bd9Sstevel@tonic-gate 	int		i, j, nlen, needsubtract;
1656*0a1ad920SDan OpenSolaris Anderson 	BIG_CHUNK_TYPE	*nn, *rr, *rrplusi;
1657b60f2a0bSfr41279 	BIG_CHUNK_TYPE	digit, c;
16587c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
1659*0a1ad920SDan OpenSolaris Anderson #ifdef	__amd64
1660*0a1ad920SDan OpenSolaris Anderson #define	BIG_CPU_UNKNOWN	0
1661*0a1ad920SDan OpenSolaris Anderson #define	BIG_CPU_AMD	1
1662*0a1ad920SDan OpenSolaris Anderson #define	BIG_CPU_INTEL	2
1663*0a1ad920SDan OpenSolaris Anderson 	static int	big_cpu = BIG_CPU_UNKNOWN;
1664*0a1ad920SDan OpenSolaris Anderson 	BIG_CHUNK_TYPE	carry[BIGTMPSIZE];
1665*0a1ad920SDan OpenSolaris Anderson 
1666*0a1ad920SDan OpenSolaris Anderson 	if (big_cpu == BIG_CPU_UNKNOWN) {
1667*0a1ad920SDan OpenSolaris Anderson 		big_cpu = 1 + bignum_on_intel();
1668*0a1ad920SDan OpenSolaris Anderson 	}
1669*0a1ad920SDan OpenSolaris Anderson #endif	/* __amd64 */
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 	nlen = n->len;
16727c478bd9Sstevel@tonic-gate 	nn = n->value;
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	rr = ret->value;
16757c478bd9Sstevel@tonic-gate 
1676b60f2a0bSfr41279 	if ((err = big_mul(ret, a, b)) != BIG_OK) {
16777c478bd9Sstevel@tonic-gate 		return (err);
1678b60f2a0bSfr41279 	}
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 	rr = ret->value;
1681b60f2a0bSfr41279 	for (i = ret->len; i < 2 * nlen + 1; i++) {
1682b60f2a0bSfr41279 		rr[i] = 0;
1683b60f2a0bSfr41279 	}
16847c478bd9Sstevel@tonic-gate 
1685*0a1ad920SDan OpenSolaris Anderson #ifdef	__amd64	/* pipelining optimization for Intel 64, but not AMD64 */
1686*0a1ad920SDan OpenSolaris Anderson 	if ((big_cpu == BIG_CPU_INTEL) && (nlen <= BIGTMPSIZE)) {
1687*0a1ad920SDan OpenSolaris Anderson 		/*
1688*0a1ad920SDan OpenSolaris Anderson 		 * Perform the following in two for loops to reduce the
1689*0a1ad920SDan OpenSolaris Anderson 		 * dependency between computing the carryover bits with
1690*0a1ad920SDan OpenSolaris Anderson 		 * BIG_MUL_ADD_VEC() and adding them, thus improving pipelining.
1691*0a1ad920SDan OpenSolaris Anderson 		 */
1692*0a1ad920SDan OpenSolaris Anderson 		for (i = 0; i < nlen; i++) {
1693*0a1ad920SDan OpenSolaris Anderson 			rrplusi = rr + i;
1694*0a1ad920SDan OpenSolaris Anderson 			digit = *rrplusi * n0;
1695*0a1ad920SDan OpenSolaris Anderson 			carry[i] = BIG_MUL_ADD_VEC(rrplusi, nn, nlen, digit);
1696*0a1ad920SDan OpenSolaris Anderson 		}
1697*0a1ad920SDan OpenSolaris Anderson 		for (i = 0; i < nlen; i++) {
1698*0a1ad920SDan OpenSolaris Anderson 			j = i + nlen;
1699*0a1ad920SDan OpenSolaris Anderson 			rr[j] += carry[i];
1700*0a1ad920SDan OpenSolaris Anderson 			while (rr[j] < carry[i]) {
1701*0a1ad920SDan OpenSolaris Anderson 				rr[++j] += 1;
1702*0a1ad920SDan OpenSolaris Anderson 				carry[i] = 1;
1703*0a1ad920SDan OpenSolaris Anderson 			}
1704*0a1ad920SDan OpenSolaris Anderson 		}
1705*0a1ad920SDan OpenSolaris Anderson 	} else
1706*0a1ad920SDan OpenSolaris Anderson #endif	/* __amd64 */
1707*0a1ad920SDan OpenSolaris Anderson 	{ /* no pipelining optimization */
1708*0a1ad920SDan OpenSolaris Anderson 		for (i = 0; i < nlen; i++) {
1709*0a1ad920SDan OpenSolaris Anderson 			rrplusi = rr + i;
1710*0a1ad920SDan OpenSolaris Anderson 			digit = *rrplusi * n0;
1711*0a1ad920SDan OpenSolaris Anderson 			c = BIG_MUL_ADD_VEC(rrplusi, nn, nlen, digit);
17127c478bd9Sstevel@tonic-gate 			j = i + nlen;
17137c478bd9Sstevel@tonic-gate 			rr[j] += c;
17147c478bd9Sstevel@tonic-gate 			while (rr[j] < c) {
1715*0a1ad920SDan OpenSolaris Anderson 				rr[++j] += 1;
17167c478bd9Sstevel@tonic-gate 				c = 1;
17177c478bd9Sstevel@tonic-gate 			}
17187c478bd9Sstevel@tonic-gate 		}
1719*0a1ad920SDan OpenSolaris Anderson 	}
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	needsubtract = 0;
17227c478bd9Sstevel@tonic-gate 	if ((rr[2 * nlen]  != 0))
17237c478bd9Sstevel@tonic-gate 		needsubtract = 1;
17247c478bd9Sstevel@tonic-gate 	else {
17257c478bd9Sstevel@tonic-gate 		for (i = 2 * nlen - 1; i >= nlen; i--) {
17267c478bd9Sstevel@tonic-gate 			if (rr[i] > nn[i - nlen]) {
17277c478bd9Sstevel@tonic-gate 				needsubtract = 1;
17287c478bd9Sstevel@tonic-gate 				break;
1729b60f2a0bSfr41279 			} else if (rr[i] < nn[i - nlen]) {
1730b60f2a0bSfr41279 				break;
1731b60f2a0bSfr41279 			}
17327c478bd9Sstevel@tonic-gate 		}
17337c478bd9Sstevel@tonic-gate 	}
17347c478bd9Sstevel@tonic-gate 	if (needsubtract)
17357c478bd9Sstevel@tonic-gate 		big_sub_vec(rr, rr + nlen, nn, nlen);
17367c478bd9Sstevel@tonic-gate 	else {
1737b60f2a0bSfr41279 		for (i = 0; i < nlen; i++) {
17387c478bd9Sstevel@tonic-gate 			rr[i] = rr[i + nlen];
17397c478bd9Sstevel@tonic-gate 		}
1740b60f2a0bSfr41279 	}
17418475e043SDan OpenSolaris Anderson 
17428475e043SDan OpenSolaris Anderson 	/* Remove leading zeros, but keep at least 1 digit: */
17438475e043SDan OpenSolaris Anderson 	for (i = nlen - 1; (i > 0) && (rr[i] == 0); i--)
1744b60f2a0bSfr41279 		;
17457c478bd9Sstevel@tonic-gate 	ret->len = i + 1;
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 	return (BIG_OK);
17487c478bd9Sstevel@tonic-gate }
17497c478bd9Sstevel@tonic-gate 
1750b60f2a0bSfr41279 
1751b60f2a0bSfr41279 BIG_CHUNK_TYPE
1752b60f2a0bSfr41279 big_n0(BIG_CHUNK_TYPE n)
17537c478bd9Sstevel@tonic-gate {
17547c478bd9Sstevel@tonic-gate 	int		i;
1755b60f2a0bSfr41279 	BIG_CHUNK_TYPE	result, tmp;
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 	result = 0;
1758b60f2a0bSfr41279 	tmp = BIG_CHUNK_ALLBITS;
1759b60f2a0bSfr41279 	for (i = 0; i < BIG_CHUNK_SIZE; i++) {
17607c478bd9Sstevel@tonic-gate 		if ((tmp & 1) == 1) {
1761b60f2a0bSfr41279 			result = (result >> 1) | BIG_CHUNK_HIGHBIT;
17627c478bd9Sstevel@tonic-gate 			tmp = tmp - n;
1763b60f2a0bSfr41279 		} else {
1764b60f2a0bSfr41279 			result = (result >> 1);
1765b60f2a0bSfr41279 		}
17667c478bd9Sstevel@tonic-gate 		tmp = tmp >> 1;
17677c478bd9Sstevel@tonic-gate 	}
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 	return (result);
17707c478bd9Sstevel@tonic-gate }
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate int
17747c478bd9Sstevel@tonic-gate big_numbits(BIGNUM *n)
17757c478bd9Sstevel@tonic-gate {
17767c478bd9Sstevel@tonic-gate 	int		i, j;
1777b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t;
17787c478bd9Sstevel@tonic-gate 
1779b60f2a0bSfr41279 	for (i = n->len - 1; i > 0; i--) {
1780b60f2a0bSfr41279 		if (n->value[i] != 0) {
1781b60f2a0bSfr41279 			break;
1782b60f2a0bSfr41279 		}
1783b60f2a0bSfr41279 	}
17847c478bd9Sstevel@tonic-gate 	t = n->value[i];
1785b60f2a0bSfr41279 	for (j = BIG_CHUNK_SIZE; j > 0; j--) {
1786b60f2a0bSfr41279 		if ((t & BIG_CHUNK_HIGHBIT) == 0) {
17877c478bd9Sstevel@tonic-gate 			t = t << 1;
1788b60f2a0bSfr41279 		} else {
1789b60f2a0bSfr41279 			return (BIG_CHUNK_SIZE * i + j);
1790b60f2a0bSfr41279 		}
17917c478bd9Sstevel@tonic-gate 	}
17927c478bd9Sstevel@tonic-gate 	return (0);
17937c478bd9Sstevel@tonic-gate }
17947c478bd9Sstevel@tonic-gate 
1795b60f2a0bSfr41279 
17967c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */
17977c478bd9Sstevel@tonic-gate BIG_ERR_CODE
17987c478bd9Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n)
17997c478bd9Sstevel@tonic-gate {
18007c478bd9Sstevel@tonic-gate 	BIGNUM		rr;
1801b60f2a0bSfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
18027c478bd9Sstevel@tonic-gate 	int		len, i;
18037c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
18067c478bd9Sstevel@tonic-gate 	len = n->len;
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1,
1809b60f2a0bSfr41279 	    rrvalue, arraysize(rrvalue))) != BIG_OK) {
18107c478bd9Sstevel@tonic-gate 		return (err);
18117c478bd9Sstevel@tonic-gate 	}
18127c478bd9Sstevel@tonic-gate 
1813b60f2a0bSfr41279 	for (i = 0; i < 2 * len; i++) {
1814b60f2a0bSfr41279 		rr.value[i] = 0;
1815b60f2a0bSfr41279 	}
1816b60f2a0bSfr41279 	rr.value[2 * len] = 1;
1817b60f2a0bSfr41279 	rr.len = 2 * len + 1;
1818b60f2a0bSfr41279 	if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) {
1819b60f2a0bSfr41279 		goto ret;
1820b60f2a0bSfr41279 	}
1821b60f2a0bSfr41279 	err = big_copy(result, &rr);
1822b60f2a0bSfr41279 ret:
1823b60f2a0bSfr41279 	big_finish(&rr);
1824b60f2a0bSfr41279 	return (err);
1825b60f2a0bSfr41279 }
1826b60f2a0bSfr41279 
1827b60f2a0bSfr41279 
18287c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */
18297c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1830b60f2a0bSfr41279 big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, BIG_CHUNK_TYPE n0,
1831b60f2a0bSfr41279     BIGNUM *n_rr)
18327c478bd9Sstevel@tonic-gate {
18337c478bd9Sstevel@tonic-gate 	BIGNUM		rr;
1834b60f2a0bSfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
18357c478bd9Sstevel@tonic-gate 	int		len, i;
18367c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
18397c478bd9Sstevel@tonic-gate 	len = n->len;
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue)))
1842b60f2a0bSfr41279 	    != BIG_OK) {
18437c478bd9Sstevel@tonic-gate 		return (err);
1844b60f2a0bSfr41279 	}
18457c478bd9Sstevel@tonic-gate 
18467c478bd9Sstevel@tonic-gate 	if (n_rr == NULL) {
1847b60f2a0bSfr41279 		for (i = 0; i < 2 * len; i++) {
1848b60f2a0bSfr41279 			rr.value[i] = 0;
1849b60f2a0bSfr41279 		}
18507c478bd9Sstevel@tonic-gate 		rr.value[2 * len] = 1;
18517c478bd9Sstevel@tonic-gate 		rr.len = 2 * len + 1;
1852b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) {
18537c478bd9Sstevel@tonic-gate 			goto ret;
1854b60f2a0bSfr41279 		}
18557c478bd9Sstevel@tonic-gate 		n_rr = &rr;
18567c478bd9Sstevel@tonic-gate 	}
18577c478bd9Sstevel@tonic-gate 
1858b60f2a0bSfr41279 	if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK) {
18597c478bd9Sstevel@tonic-gate 		goto ret;
1860b60f2a0bSfr41279 	}
18617c478bd9Sstevel@tonic-gate 	err = big_copy(result, &rr);
1862b60f2a0bSfr41279 
18637c478bd9Sstevel@tonic-gate ret:
1864b60f2a0bSfr41279 	big_finish(&rr);
18657c478bd9Sstevel@tonic-gate 	return (err);
18667c478bd9Sstevel@tonic-gate }
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 
1869b60f2a0bSfr41279 #ifdef	USE_FLOATING_POINT
1870b60f2a0bSfr41279 #define	big_modexp_ncp_float	big_modexp_ncp_sw
1871b60f2a0bSfr41279 #else
1872b60f2a0bSfr41279 #define	big_modexp_ncp_int	big_modexp_ncp_sw
1873b60f2a0bSfr41279 #endif
1874b60f2a0bSfr41279 
18757c478bd9Sstevel@tonic-gate #define	MAX_EXP_BIT_GROUP_SIZE 6
18767c478bd9Sstevel@tonic-gate #define	APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1))
18777c478bd9Sstevel@tonic-gate 
1878b60f2a0bSfr41279 /* ARGSUSED */
18797c478bd9Sstevel@tonic-gate static BIG_ERR_CODE
1880b60f2a0bSfr41279 big_modexp_ncp_int(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n,
1881b60f2a0bSfr41279     BIGNUM *tmp, BIG_CHUNK_TYPE n0)
1882b60f2a0bSfr41279 
18837c478bd9Sstevel@tonic-gate {
1884b60f2a0bSfr41279 	BIGNUM		apowers[APOWERS_MAX_SIZE];
1885b60f2a0bSfr41279 	BIGNUM		tmp1;
1886b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
1887b60f2a0bSfr41279 	int		i, j, k, l, m, p;
18888475e043SDan OpenSolaris Anderson 	uint32_t	bit, bitind, bitcount, groupbits, apowerssize;
18898475e043SDan OpenSolaris Anderson 	uint32_t	nbits;
18907c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate 	nbits = big_numbits(e);
18937c478bd9Sstevel@tonic-gate 	if (nbits < 50) {
18947c478bd9Sstevel@tonic-gate 		groupbits = 1;
18957c478bd9Sstevel@tonic-gate 		apowerssize = 1;
18967c478bd9Sstevel@tonic-gate 	} else {
18977c478bd9Sstevel@tonic-gate 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
18987c478bd9Sstevel@tonic-gate 		apowerssize = 1 << (groupbits - 1);
18997c478bd9Sstevel@tonic-gate 	}
19007c478bd9Sstevel@tonic-gate 
1901b60f2a0bSfr41279 
1902b60f2a0bSfr41279 	if ((err = big_init1(&tmp1, 2 * n->len + 1,
1903b60f2a0bSfr41279 	    tmp1value, arraysize(tmp1value))) != BIG_OK) {
19047c478bd9Sstevel@tonic-gate 		return (err);
19057c478bd9Sstevel@tonic-gate 	}
19067c478bd9Sstevel@tonic-gate 
19078475e043SDan OpenSolaris Anderson 	/* clear the malloced bit to help cleanup */
1908b60f2a0bSfr41279 	for (i = 0; i < apowerssize; i++) {
1909b60f2a0bSfr41279 		apowers[i].malloced = 0;
1910b60f2a0bSfr41279 	}
19118475e043SDan OpenSolaris Anderson 
1912b60f2a0bSfr41279 	for (i = 0; i < apowerssize; i++) {
1913b60f2a0bSfr41279 		if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) !=
1914b60f2a0bSfr41279 		    BIG_OK) {
1915b60f2a0bSfr41279 			goto ret;
1916b60f2a0bSfr41279 		}
1917b60f2a0bSfr41279 	}
19187c478bd9Sstevel@tonic-gate 
1919b60f2a0bSfr41279 	(void) big_copy(&(apowers[0]), ma);
1920b60f2a0bSfr41279 
1921b60f2a0bSfr41279 	if ((err = big_mont_mul(&tmp1, ma, ma, n, n0)) != BIG_OK) {
1922b60f2a0bSfr41279 		goto ret;
1923b60f2a0bSfr41279 	}
1924b60f2a0bSfr41279 	(void) big_copy(ma, &tmp1);
1925b60f2a0bSfr41279 
1926b60f2a0bSfr41279 	for (i = 1; i < apowerssize; i++) {
1927b60f2a0bSfr41279 		if ((err = big_mont_mul(&tmp1, ma,
1928b60f2a0bSfr41279 		    &(apowers[i - 1]), n, n0)) != BIG_OK) {
1929b60f2a0bSfr41279 			goto ret;
1930b60f2a0bSfr41279 		}
1931b60f2a0bSfr41279 		(void) big_copy(&apowers[i], &tmp1);
1932b60f2a0bSfr41279 	}
1933b60f2a0bSfr41279 
1934b60f2a0bSfr41279 	bitind = nbits % BIG_CHUNK_SIZE;
1935b60f2a0bSfr41279 	k = 0;
1936b60f2a0bSfr41279 	l = 0;
1937b60f2a0bSfr41279 	p = 0;
1938b60f2a0bSfr41279 	bitcount = 0;
1939b60f2a0bSfr41279 	for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) {
1940b60f2a0bSfr41279 		for (j = bitind - 1; j >= 0; j--) {
1941b60f2a0bSfr41279 			bit = (e->value[i] >> j) & 1;
1942b60f2a0bSfr41279 			if ((bitcount == 0) && (bit == 0)) {
1943b60f2a0bSfr41279 				if ((err = big_mont_mul(tmp,
1944b60f2a0bSfr41279 				    tmp, tmp, n, n0)) != BIG_OK) {
1945b60f2a0bSfr41279 					goto ret;
1946b60f2a0bSfr41279 				}
19477c478bd9Sstevel@tonic-gate 			} else {
1948b60f2a0bSfr41279 				bitcount++;
1949b60f2a0bSfr41279 				p = p * 2 + bit;
1950b60f2a0bSfr41279 				if (bit == 1) {
1951b60f2a0bSfr41279 					k = k + l + 1;
1952b60f2a0bSfr41279 					l = 0;
1953b60f2a0bSfr41279 				} else {
1954b60f2a0bSfr41279 					l++;
19557c478bd9Sstevel@tonic-gate 				}
1956b60f2a0bSfr41279 				if (bitcount == groupbits) {
1957b60f2a0bSfr41279 					for (m = 0; m < k; m++) {
1958b60f2a0bSfr41279 						if ((err = big_mont_mul(tmp,
1959b60f2a0bSfr41279 						    tmp, tmp, n, n0)) !=
1960b60f2a0bSfr41279 						    BIG_OK) {
1961b60f2a0bSfr41279 							goto ret;
1962b60f2a0bSfr41279 						}
1963b60f2a0bSfr41279 					}
1964b60f2a0bSfr41279 					if ((err = big_mont_mul(tmp, tmp,
1965b60f2a0bSfr41279 					    &(apowers[p >> (l + 1)]),
1966b60f2a0bSfr41279 					    n, n0)) != BIG_OK) {
1967b60f2a0bSfr41279 						goto ret;
1968b60f2a0bSfr41279 					}
1969b60f2a0bSfr41279 					for (m = 0; m < l; m++) {
1970b60f2a0bSfr41279 						if ((err = big_mont_mul(tmp,
1971b60f2a0bSfr41279 						    tmp, tmp, n, n0)) !=
1972b60f2a0bSfr41279 						    BIG_OK) {
1973b60f2a0bSfr41279 							goto ret;
1974b60f2a0bSfr41279 						}
1975b60f2a0bSfr41279 					}
1976b60f2a0bSfr41279 					k = 0;
1977b60f2a0bSfr41279 					l = 0;
1978b60f2a0bSfr41279 					p = 0;
1979b60f2a0bSfr41279 					bitcount = 0;
1980b60f2a0bSfr41279 				}
1981b60f2a0bSfr41279 			}
1982b60f2a0bSfr41279 		}
1983b60f2a0bSfr41279 		bitind = BIG_CHUNK_SIZE;
1984b60f2a0bSfr41279 	}
19857c478bd9Sstevel@tonic-gate 
1986b60f2a0bSfr41279 	for (m = 0; m < k; m++) {
1987b60f2a0bSfr41279 		if ((err = big_mont_mul(tmp, tmp, tmp, n, n0)) != BIG_OK) {
1988b60f2a0bSfr41279 			goto ret;
1989b60f2a0bSfr41279 		}
1990b60f2a0bSfr41279 	}
1991b60f2a0bSfr41279 	if (p != 0) {
1992b60f2a0bSfr41279 		if ((err = big_mont_mul(tmp, tmp,
1993b60f2a0bSfr41279 		    &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK) {
1994b60f2a0bSfr41279 			goto ret;
1995b60f2a0bSfr41279 		}
1996b60f2a0bSfr41279 	}
1997b60f2a0bSfr41279 	for (m = 0; m < l; m++) {
1998b60f2a0bSfr41279 		if ((err = big_mont_mul(result, tmp, tmp, n, n0)) != BIG_OK) {
1999b60f2a0bSfr41279 			goto ret;
2000b60f2a0bSfr41279 		}
2001b60f2a0bSfr41279 	}
20027c478bd9Sstevel@tonic-gate 
2003b60f2a0bSfr41279 ret:
2004b60f2a0bSfr41279 	for (i = apowerssize - 1; i >= 0; i--) {
2005b60f2a0bSfr41279 		big_finish(&(apowers[i]));
2006b60f2a0bSfr41279 	}
2007b60f2a0bSfr41279 	big_finish(&tmp1);
2008b60f2a0bSfr41279 
2009b60f2a0bSfr41279 	return (err);
2010b60f2a0bSfr41279 }
2011b60f2a0bSfr41279 
2012b60f2a0bSfr41279 
2013b60f2a0bSfr41279 #ifdef USE_FLOATING_POINT
2014b60f2a0bSfr41279 
2015b60f2a0bSfr41279 #ifdef _KERNEL
2016b60f2a0bSfr41279 
2017b60f2a0bSfr41279 #include <sys/sysmacros.h>
2018b60f2a0bSfr41279 #include <sys/regset.h>
2019b60f2a0bSfr41279 #include <sys/fpu/fpusystm.h>
2020b60f2a0bSfr41279 
2021b60f2a0bSfr41279 /* the alignment for block stores to save fp registers */
2022b60f2a0bSfr41279 #define	FPR_ALIGN	(64)
2023b60f2a0bSfr41279 
2024b60f2a0bSfr41279 extern void big_savefp(kfpu_t *);
2025b60f2a0bSfr41279 extern void big_restorefp(kfpu_t *);
2026b60f2a0bSfr41279 
2027b60f2a0bSfr41279 #endif /* _KERNEL */
2028b60f2a0bSfr41279 
2029b60f2a0bSfr41279 /*
2030b60f2a0bSfr41279  * This version makes use of floating point for performance
2031b60f2a0bSfr41279  */
2032b60f2a0bSfr41279 static BIG_ERR_CODE
2033b60f2a0bSfr41279 big_modexp_ncp_float(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n,
2034b60f2a0bSfr41279     BIGNUM *tmp, BIG_CHUNK_TYPE n0)
2035b60f2a0bSfr41279 {
2036b60f2a0bSfr41279 
20378475e043SDan OpenSolaris Anderson 	int		i, j, k, l, m, p;
20388475e043SDan OpenSolaris Anderson 	uint32_t	bit, bitind, bitcount, nlen;
2039b60f2a0bSfr41279 	double		dn0;
2040b60f2a0bSfr41279 	double		*dn, *dt, *d16r, *d32r;
2041b60f2a0bSfr41279 	uint32_t	*nint, *prod;
2042b60f2a0bSfr41279 	double		*apowers[APOWERS_MAX_SIZE];
20438475e043SDan OpenSolaris Anderson 	uint32_t	nbits, groupbits, apowerssize;
2044b60f2a0bSfr41279 	BIG_ERR_CODE	err = BIG_OK;
2045b60f2a0bSfr41279 
2046b60f2a0bSfr41279 #ifdef _KERNEL
2047b60f2a0bSfr41279 	uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN];
2048b60f2a0bSfr41279 	kfpu_t *fpu;
2049b60f2a0bSfr41279 
2050b60f2a0bSfr41279 #ifdef DEBUG
2051b60f2a0bSfr41279 	if (!fpu_exists)
2052b60f2a0bSfr41279 		return (BIG_GENERAL_ERR);
2053b60f2a0bSfr41279 #endif
2054b60f2a0bSfr41279 
2055b60f2a0bSfr41279 	fpu =  (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN);
2056b60f2a0bSfr41279 	big_savefp(fpu);
2057b60f2a0bSfr41279 
2058b60f2a0bSfr41279 #endif /* _KERNEL */
2059b60f2a0bSfr41279 
2060b60f2a0bSfr41279 	nbits = big_numbits(e);
2061b60f2a0bSfr41279 	if (nbits < 50) {
2062b60f2a0bSfr41279 		groupbits = 1;
2063b60f2a0bSfr41279 		apowerssize = 1;
2064b60f2a0bSfr41279 	} else {
2065b60f2a0bSfr41279 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
2066b60f2a0bSfr41279 		apowerssize = 1 << (groupbits - 1);
2067b60f2a0bSfr41279 	}
2068b60f2a0bSfr41279 
2069b60f2a0bSfr41279 	nlen = (BIG_CHUNK_SIZE / 32) * n->len;
20707c478bd9Sstevel@tonic-gate 	dn0 = (double)(n0 & 0xffff);
20717c478bd9Sstevel@tonic-gate 
20727c478bd9Sstevel@tonic-gate 	dn = dt = d16r = d32r = NULL;
20737c478bd9Sstevel@tonic-gate 	nint = prod = NULL;
20747c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
20757c478bd9Sstevel@tonic-gate 		apowers[i] = NULL;
20767c478bd9Sstevel@tonic-gate 	}
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 	if ((dn = big_malloc(nlen * sizeof (double))) == NULL) {
20797c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
20807c478bd9Sstevel@tonic-gate 		goto ret;
20817c478bd9Sstevel@tonic-gate 	}
20827c478bd9Sstevel@tonic-gate 	if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) {
20837c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
20847c478bd9Sstevel@tonic-gate 		goto ret;
20857c478bd9Sstevel@tonic-gate 	}
20867c478bd9Sstevel@tonic-gate 	if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) {
20877c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
20887c478bd9Sstevel@tonic-gate 		goto ret;
20897c478bd9Sstevel@tonic-gate 	}
20907c478bd9Sstevel@tonic-gate 	if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) {
20917c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
20927c478bd9Sstevel@tonic-gate 		goto ret;
20937c478bd9Sstevel@tonic-gate 	}
20947c478bd9Sstevel@tonic-gate 	if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) {
20957c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
20967c478bd9Sstevel@tonic-gate 		goto ret;
20977c478bd9Sstevel@tonic-gate 	}
20987c478bd9Sstevel@tonic-gate 	if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) {
20997c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
21007c478bd9Sstevel@tonic-gate 		goto ret;
21017c478bd9Sstevel@tonic-gate 	}
21027c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
21037c478bd9Sstevel@tonic-gate 		if ((apowers[i] = big_malloc((2 * nlen + 1) *
21047c478bd9Sstevel@tonic-gate 		    sizeof (double))) == NULL) {
21057c478bd9Sstevel@tonic-gate 			err = BIG_NO_MEM;
21067c478bd9Sstevel@tonic-gate 			goto ret;
21077c478bd9Sstevel@tonic-gate 		}
21087c478bd9Sstevel@tonic-gate 	}
21097c478bd9Sstevel@tonic-gate 
2110b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
2111b60f2a0bSfr41279 	for (i = 0; i < ma->len; i++) {
2112b60f2a0bSfr41279 		nint[i] = ma->value[i];
2113b60f2a0bSfr41279 	}
2114b60f2a0bSfr41279 	for (; i < nlen; i++) {
2115b60f2a0bSfr41279 		nint[i] = 0;
2116b60f2a0bSfr41279 	}
2117b60f2a0bSfr41279 #else
2118b60f2a0bSfr41279 	for (i = 0; i < ma->len; i++) {
2119b60f2a0bSfr41279 		nint[2 * i] = (uint32_t)(ma->value[i] & 0xffffffffULL);
2120b60f2a0bSfr41279 		nint[2 * i + 1] = (uint32_t)(ma->value[i] >> 32);
2121b60f2a0bSfr41279 	}
2122b60f2a0bSfr41279 	for (i = ma->len * 2; i < nlen; i++) {
2123b60f2a0bSfr41279 		nint[i] = 0;
2124b60f2a0bSfr41279 	}
2125b60f2a0bSfr41279 #endif
21267c478bd9Sstevel@tonic-gate 	conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen);
21277c478bd9Sstevel@tonic-gate 
2128b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
2129b60f2a0bSfr41279 	for (i = 0; i < n->len; i++) {
2130b60f2a0bSfr41279 		nint[i] = n->value[i];
2131b60f2a0bSfr41279 	}
2132b60f2a0bSfr41279 	for (; i < nlen; i++) {
2133b60f2a0bSfr41279 		nint[i] = 0;
2134b60f2a0bSfr41279 	}
2135b60f2a0bSfr41279 #else
2136b60f2a0bSfr41279 	for (i = 0; i < n->len; i++) {
2137b60f2a0bSfr41279 		nint[2 * i] = (uint32_t)(n->value[i] & 0xffffffffULL);
2138b60f2a0bSfr41279 		nint[2 * i + 1] = (uint32_t)(n->value[i] >> 32);
2139b60f2a0bSfr41279 	}
2140b60f2a0bSfr41279 	for (i = n->len * 2; i < nlen; i++) {
2141b60f2a0bSfr41279 		nint[i] = 0;
2142b60f2a0bSfr41279 	}
2143b60f2a0bSfr41279 #endif
21447c478bd9Sstevel@tonic-gate 	conv_i32_to_d32(dn, nint, nlen);
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 	mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0);
21477c478bd9Sstevel@tonic-gate 	conv_i32_to_d32(d32r, prod, nlen);
21487c478bd9Sstevel@tonic-gate 	for (i = 1; i < apowerssize; i++) {
21497c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[i - 1],
21507c478bd9Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
21517c478bd9Sstevel@tonic-gate 		conv_i32_to_d16(apowers[i], prod, nlen);
21527c478bd9Sstevel@tonic-gate 	}
21537c478bd9Sstevel@tonic-gate 
2154b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
2155b60f2a0bSfr41279 	for (i = 0; i < tmp->len; i++) {
2156b60f2a0bSfr41279 		prod[i] = tmp->value[i];
2157b60f2a0bSfr41279 	}
2158b60f2a0bSfr41279 	for (; i < nlen + 1; i++) {
2159b60f2a0bSfr41279 		prod[i] = 0;
2160b60f2a0bSfr41279 	}
2161b60f2a0bSfr41279 #else
2162b60f2a0bSfr41279 	for (i = 0; i < tmp->len; i++) {
2163b60f2a0bSfr41279 		prod[2 * i] = (uint32_t)(tmp->value[i] & 0xffffffffULL);
2164b60f2a0bSfr41279 		prod[2 * i + 1] = (uint32_t)(tmp->value[i] >> 32);
2165b60f2a0bSfr41279 	}
2166b60f2a0bSfr41279 	for (i = tmp->len * 2; i < nlen + 1; i++) {
2167b60f2a0bSfr41279 		prod[i] = 0;
2168b60f2a0bSfr41279 	}
2169b60f2a0bSfr41279 #endif
21707c478bd9Sstevel@tonic-gate 
2171b60f2a0bSfr41279 	bitind = nbits % BIG_CHUNK_SIZE;
21727c478bd9Sstevel@tonic-gate 	k = 0;
21737c478bd9Sstevel@tonic-gate 	l = 0;
21747c478bd9Sstevel@tonic-gate 	p = 0;
21757c478bd9Sstevel@tonic-gate 	bitcount = 0;
2176b60f2a0bSfr41279 	for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) {
21777c478bd9Sstevel@tonic-gate 		for (j = bitind - 1; j >= 0; j--) {
21787c478bd9Sstevel@tonic-gate 			bit = (e->value[i] >> j) & 1;
21797c478bd9Sstevel@tonic-gate 			if ((bitcount == 0) && (bit == 0)) {
21807c478bd9Sstevel@tonic-gate 				conv_i32_to_d32_and_d16(d32r, d16r,
21817c478bd9Sstevel@tonic-gate 				    prod, nlen);
21827c478bd9Sstevel@tonic-gate 				mont_mulf_noconv(prod, d32r, d16r,
21837c478bd9Sstevel@tonic-gate 				    dt, dn, nint, nlen, dn0);
21847c478bd9Sstevel@tonic-gate 			} else {
21857c478bd9Sstevel@tonic-gate 				bitcount++;
21867c478bd9Sstevel@tonic-gate 				p = p * 2 + bit;
21877c478bd9Sstevel@tonic-gate 				if (bit == 1) {
21887c478bd9Sstevel@tonic-gate 					k = k + l + 1;
21897c478bd9Sstevel@tonic-gate 					l = 0;
21907c478bd9Sstevel@tonic-gate 				} else {
21917c478bd9Sstevel@tonic-gate 					l++;
21927c478bd9Sstevel@tonic-gate 				}
21937c478bd9Sstevel@tonic-gate 				if (bitcount == groupbits) {
21947c478bd9Sstevel@tonic-gate 					for (m = 0; m < k; m++) {
2195b60f2a0bSfr41279 						conv_i32_to_d32_and_d16(d32r,
2196b60f2a0bSfr41279 						    d16r, prod, nlen);
21977c478bd9Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
21987c478bd9Sstevel@tonic-gate 						    d16r, dt, dn, nint,
21997c478bd9Sstevel@tonic-gate 						    nlen, dn0);
22007c478bd9Sstevel@tonic-gate 					}
22017c478bd9Sstevel@tonic-gate 					conv_i32_to_d32(d32r, prod, nlen);
22027c478bd9Sstevel@tonic-gate 					mont_mulf_noconv(prod, d32r,
22037c478bd9Sstevel@tonic-gate 					    apowers[p >> (l + 1)],
22047c478bd9Sstevel@tonic-gate 					    dt, dn, nint, nlen, dn0);
22057c478bd9Sstevel@tonic-gate 					for (m = 0; m < l; m++) {
2206b60f2a0bSfr41279 						conv_i32_to_d32_and_d16(d32r,
2207b60f2a0bSfr41279 						    d16r, prod, nlen);
22087c478bd9Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
22097c478bd9Sstevel@tonic-gate 						    d16r, dt, dn, nint,
22107c478bd9Sstevel@tonic-gate 						    nlen, dn0);
22117c478bd9Sstevel@tonic-gate 					}
22127c478bd9Sstevel@tonic-gate 					k = 0;
22137c478bd9Sstevel@tonic-gate 					l = 0;
22147c478bd9Sstevel@tonic-gate 					p = 0;
22157c478bd9Sstevel@tonic-gate 					bitcount = 0;
22167c478bd9Sstevel@tonic-gate 				}
22177c478bd9Sstevel@tonic-gate 			}
22187c478bd9Sstevel@tonic-gate 		}
2219b60f2a0bSfr41279 		bitind = BIG_CHUNK_SIZE;
22207c478bd9Sstevel@tonic-gate 	}
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate 	for (m = 0; m < k; m++) {
22237c478bd9Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
22247c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
22257c478bd9Sstevel@tonic-gate 	}
22267c478bd9Sstevel@tonic-gate 	if (p != 0) {
22277c478bd9Sstevel@tonic-gate 		conv_i32_to_d32(d32r, prod, nlen);
22287c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)],
22297c478bd9Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
22307c478bd9Sstevel@tonic-gate 	}
22317c478bd9Sstevel@tonic-gate 	for (m = 0; m < l; m++) {
22327c478bd9Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
22337c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
22347c478bd9Sstevel@tonic-gate 	}
22357c478bd9Sstevel@tonic-gate 
2236b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
2237b60f2a0bSfr41279 	for (i = 0; i < nlen; i++) {
2238b60f2a0bSfr41279 		result->value[i] = prod[i];
2239b60f2a0bSfr41279 	}
2240b60f2a0bSfr41279 	for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--)
2241b60f2a0bSfr41279 		;
2242b60f2a0bSfr41279 #else
2243b60f2a0bSfr41279 	for (i = 0; i < nlen / 2; i++) {
2244b60f2a0bSfr41279 		result->value[i] = (uint64_t)(prod[2 * i]) +
2245b60f2a0bSfr41279 		    (((uint64_t)(prod[2 * i + 1])) << 32);
2246b60f2a0bSfr41279 	}
2247b60f2a0bSfr41279 	for (i = nlen / 2 - 1; (i > 0) && (result->value[i] == 0); i--)
2248b60f2a0bSfr41279 		;
2249b60f2a0bSfr41279 #endif
2250b60f2a0bSfr41279 	result->len = i + 1;
2251b60f2a0bSfr41279 
22527c478bd9Sstevel@tonic-gate ret:
22537c478bd9Sstevel@tonic-gate 	for (i = apowerssize - 1; i >= 0; i--) {
22547c478bd9Sstevel@tonic-gate 		if (apowers[i] != NULL)
22557c478bd9Sstevel@tonic-gate 			big_free(apowers[i], (2 * nlen + 1) * sizeof (double));
22567c478bd9Sstevel@tonic-gate 	}
2257b60f2a0bSfr41279 	if (d32r != NULL) {
22587c478bd9Sstevel@tonic-gate 		big_free(d32r, nlen * sizeof (double));
2259b60f2a0bSfr41279 	}
2260b60f2a0bSfr41279 	if (d16r != NULL) {
22617c478bd9Sstevel@tonic-gate 		big_free(d16r, (2 * nlen + 1) * sizeof (double));
2262b60f2a0bSfr41279 	}
2263b60f2a0bSfr41279 	if (prod != NULL) {
22647c478bd9Sstevel@tonic-gate 		big_free(prod, (nlen + 1) * sizeof (uint32_t));
2265b60f2a0bSfr41279 	}
2266b60f2a0bSfr41279 	if (nint != NULL) {
22677c478bd9Sstevel@tonic-gate 		big_free(nint, nlen * sizeof (uint32_t));
2268b60f2a0bSfr41279 	}
2269b60f2a0bSfr41279 	if (dt != NULL) {
22707c478bd9Sstevel@tonic-gate 		big_free(dt, (4 * nlen + 2) * sizeof (double));
2271b60f2a0bSfr41279 	}
2272b60f2a0bSfr41279 	if (dn != NULL) {
22737c478bd9Sstevel@tonic-gate 		big_free(dn, nlen * sizeof (double));
22747c478bd9Sstevel@tonic-gate 	}
22757c478bd9Sstevel@tonic-gate 
22767c478bd9Sstevel@tonic-gate #ifdef _KERNEL
2277b60f2a0bSfr41279 	big_restorefp(fpu);
22787c478bd9Sstevel@tonic-gate #endif
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate 	return (err);
22817c478bd9Sstevel@tonic-gate }
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */
22847c478bd9Sstevel@tonic-gate 
22857c478bd9Sstevel@tonic-gate 
22867c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2287b60f2a0bSfr41279 big_modexp_ext(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr,
2288b60f2a0bSfr41279     big_modexp_ncp_info_t *info)
2289b60f2a0bSfr41279 {
2290b60f2a0bSfr41279 	BIGNUM		ma, tmp, rr;
2291b60f2a0bSfr41279 	BIG_CHUNK_TYPE	mavalue[BIGTMPSIZE];
2292b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
2293b60f2a0bSfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
2294b60f2a0bSfr41279 	BIG_ERR_CODE	err;
2295b60f2a0bSfr41279 	BIG_CHUNK_TYPE	n0;
2296b60f2a0bSfr41279 
2297b60f2a0bSfr41279 	if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue)))	!=
2298b60f2a0bSfr41279 	    BIG_OK) {
2299b60f2a0bSfr41279 		return (err);
2300b60f2a0bSfr41279 	}
2301b60f2a0bSfr41279 	ma.len = 1;
2302b60f2a0bSfr41279 	ma.value[0] = 0;
2303b60f2a0bSfr41279 
2304b60f2a0bSfr41279 	if ((err = big_init1(&tmp, 2 * n->len + 1,
2305b60f2a0bSfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
2306b60f2a0bSfr41279 		goto ret1;
2307b60f2a0bSfr41279 	}
2308b60f2a0bSfr41279 
23098475e043SDan OpenSolaris Anderson 	/* clear the malloced bit to help cleanup */
2310b60f2a0bSfr41279 	rr.malloced = 0;
23118475e043SDan OpenSolaris Anderson 
2312b60f2a0bSfr41279 	if (n_rr == NULL) {
2313b60f2a0bSfr41279 		if ((err = big_init1(&rr, 2 * n->len + 1,
2314b60f2a0bSfr41279 		    rrvalue, arraysize(rrvalue))) != BIG_OK) {
2315b60f2a0bSfr41279 			goto ret2;
2316b60f2a0bSfr41279 		}
2317b60f2a0bSfr41279 		if (big_mont_rr(&rr, n) != BIG_OK) {
2318b60f2a0bSfr41279 			goto ret;
2319b60f2a0bSfr41279 		}
2320b60f2a0bSfr41279 		n_rr = &rr;
2321b60f2a0bSfr41279 	}
2322b60f2a0bSfr41279 
2323b60f2a0bSfr41279 	n0 = big_n0(n->value[0]);
2324b60f2a0bSfr41279 
2325b60f2a0bSfr41279 	if (big_cmp_abs(a, n) > 0) {
2326b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK) {
2327b60f2a0bSfr41279 			goto ret;
2328b60f2a0bSfr41279 		}
2329b60f2a0bSfr41279 		err = big_mont_conv(&ma, &ma, n, n0, n_rr);
2330b60f2a0bSfr41279 	} else {
2331b60f2a0bSfr41279 		err = big_mont_conv(&ma, a, n, n0, n_rr);
2332b60f2a0bSfr41279 	}
2333b60f2a0bSfr41279 	if (err != BIG_OK) {
2334b60f2a0bSfr41279 		goto ret;
2335b60f2a0bSfr41279 	}
2336b60f2a0bSfr41279 
2337b60f2a0bSfr41279 	tmp.len = 1;
2338b60f2a0bSfr41279 	tmp.value[0] = 1;
2339b60f2a0bSfr41279 	if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK) {
2340b60f2a0bSfr41279 		goto ret;
2341b60f2a0bSfr41279 	}
2342b60f2a0bSfr41279 
2343b60f2a0bSfr41279 	if ((info != NULL) && (info->func != NULL)) {
2344b60f2a0bSfr41279 		err = (*(info->func))(&tmp, &ma, e, n, &tmp, n0,
2345b60f2a0bSfr41279 		    info->ncp, info->reqp);
2346b60f2a0bSfr41279 	} else {
2347b60f2a0bSfr41279 		err = big_modexp_ncp_sw(&tmp, &ma, e, n, &tmp, n0);
2348b60f2a0bSfr41279 	}
2349b60f2a0bSfr41279 	if (err != BIG_OK) {
2350b60f2a0bSfr41279 		goto ret;
2351b60f2a0bSfr41279 	}
2352b60f2a0bSfr41279 
2353b60f2a0bSfr41279 	ma.value[0] = 1;
2354b60f2a0bSfr41279 	ma.len = 1;
2355b60f2a0bSfr41279 	if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK) {
2356b60f2a0bSfr41279 		goto ret;
2357b60f2a0bSfr41279 	}
2358b60f2a0bSfr41279 	err = big_copy(result, &tmp);
2359b60f2a0bSfr41279 
2360b60f2a0bSfr41279 ret:
2361b60f2a0bSfr41279 	if (rr.malloced) {
2362b60f2a0bSfr41279 		big_finish(&rr);
2363b60f2a0bSfr41279 	}
2364b60f2a0bSfr41279 ret2:
2365b60f2a0bSfr41279 	big_finish(&tmp);
2366b60f2a0bSfr41279 ret1:
2367b60f2a0bSfr41279 	big_finish(&ma);
2368b60f2a0bSfr41279 
2369b60f2a0bSfr41279 	return (err);
2370b60f2a0bSfr41279 }
2371b60f2a0bSfr41279 
2372b60f2a0bSfr41279 BIG_ERR_CODE
2373b60f2a0bSfr41279 big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
2374b60f2a0bSfr41279 {
2375b60f2a0bSfr41279 	return (big_modexp_ext(result, a, e, n, n_rr, NULL));
2376b60f2a0bSfr41279 }
2377b60f2a0bSfr41279 
2378b60f2a0bSfr41279 
2379b60f2a0bSfr41279 BIG_ERR_CODE
2380b60f2a0bSfr41279 big_modexp_crt_ext(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
23817c478bd9Sstevel@tonic-gate     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
2382b60f2a0bSfr41279     BIGNUM *p_rr, BIGNUM *q_rr, big_modexp_ncp_info_t *info)
23837c478bd9Sstevel@tonic-gate {
23847c478bd9Sstevel@tonic-gate 	BIGNUM		ap, aq, tmp;
23857c478bd9Sstevel@tonic-gate 	int		alen, biglen, sign;
23867c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
23877c478bd9Sstevel@tonic-gate 
2388b60f2a0bSfr41279 	if (p->len > q->len) {
2389b60f2a0bSfr41279 		biglen = p->len;
2390b60f2a0bSfr41279 	} else {
2391b60f2a0bSfr41279 		biglen = q->len;
2392b60f2a0bSfr41279 	}
23937c478bd9Sstevel@tonic-gate 
2394b60f2a0bSfr41279 	if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK) {
23957c478bd9Sstevel@tonic-gate 		return (err);
2396b60f2a0bSfr41279 	}
2397b60f2a0bSfr41279 	if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK) {
23987c478bd9Sstevel@tonic-gate 		goto ret1;
2399b60f2a0bSfr41279 	}
2400b60f2a0bSfr41279 	if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK) {
24017c478bd9Sstevel@tonic-gate 		goto ret2;
2402b60f2a0bSfr41279 	}
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 	/*
24057c478bd9Sstevel@tonic-gate 	 * check whether a is too short - to avoid timing attacks
24067c478bd9Sstevel@tonic-gate 	 */
24077c478bd9Sstevel@tonic-gate 	alen = a->len;
24087c478bd9Sstevel@tonic-gate 	while ((alen > p->len) && (a->value[alen - 1] == 0)) {
24097c478bd9Sstevel@tonic-gate 		alen--;
24107c478bd9Sstevel@tonic-gate 	}
24117c478bd9Sstevel@tonic-gate 	if (alen < p->len + q->len) {
24127c478bd9Sstevel@tonic-gate 		/*
24137c478bd9Sstevel@tonic-gate 		 * a is too short, add p*q to it before
24147c478bd9Sstevel@tonic-gate 		 * taking it modulo p and q
24157c478bd9Sstevel@tonic-gate 		 * this will also affect timing, but this difference
24167c478bd9Sstevel@tonic-gate 		 * does not depend on p or q, only on a
24177c478bd9Sstevel@tonic-gate 		 * (in "normal" operation, this path will never be
24187c478bd9Sstevel@tonic-gate 		 * taken, so it is not a performance penalty
24197c478bd9Sstevel@tonic-gate 		 */
2420b60f2a0bSfr41279 		if ((err = big_mul(&tmp, p, q)) != BIG_OK) {
24217c478bd9Sstevel@tonic-gate 			goto ret;
24227c478bd9Sstevel@tonic-gate 		}
2423b60f2a0bSfr41279 		if ((err = big_add(&tmp, &tmp, a)) != BIG_OK) {
2424b60f2a0bSfr41279 			goto ret;
2425b60f2a0bSfr41279 		}
2426b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK) {
2427b60f2a0bSfr41279 			goto ret;
2428b60f2a0bSfr41279 		}
2429b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) {
2430b60f2a0bSfr41279 			goto ret;
2431b60f2a0bSfr41279 		}
2432b60f2a0bSfr41279 	} else {
2433b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK) {
2434b60f2a0bSfr41279 			goto ret;
2435b60f2a0bSfr41279 		}
2436b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK) {
2437b60f2a0bSfr41279 			goto ret;
2438b60f2a0bSfr41279 		}
2439b60f2a0bSfr41279 	}
24407c478bd9Sstevel@tonic-gate 
2441b60f2a0bSfr41279 	if ((err = big_modexp_ext(&ap, &ap, dmodpminus1, p, p_rr, info)) !=
2442b60f2a0bSfr41279 	    BIG_OK) {
24437c478bd9Sstevel@tonic-gate 		goto ret;
2444b60f2a0bSfr41279 	}
2445b60f2a0bSfr41279 	if ((err = big_modexp_ext(&aq, &aq, dmodqminus1, q, q_rr, info)) !=
2446b60f2a0bSfr41279 	    BIG_OK) {
24477c478bd9Sstevel@tonic-gate 		goto ret;
2448b60f2a0bSfr41279 	}
2449b60f2a0bSfr41279 	if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK) {
24507c478bd9Sstevel@tonic-gate 		goto ret;
2451b60f2a0bSfr41279 	}
2452b60f2a0bSfr41279 	if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK) {
24537c478bd9Sstevel@tonic-gate 		goto ret;
2454b60f2a0bSfr41279 	}
24557c478bd9Sstevel@tonic-gate 	sign = tmp.sign;
24567c478bd9Sstevel@tonic-gate 	tmp.sign = 1;
2457b60f2a0bSfr41279 	if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) {
24587c478bd9Sstevel@tonic-gate 		goto ret;
2459b60f2a0bSfr41279 	}
24607c478bd9Sstevel@tonic-gate 	if ((sign == -1) && (!big_is_zero(&aq))) {
24617c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(&aq, q, &aq);
24627c478bd9Sstevel@tonic-gate 	}
2463b60f2a0bSfr41279 	if ((err = big_mul(&tmp, &aq, p)) != BIG_OK) {
24647c478bd9Sstevel@tonic-gate 		goto ret;
2465b60f2a0bSfr41279 	}
24667c478bd9Sstevel@tonic-gate 	err = big_add_abs(result, &ap, &tmp);
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate ret:
24697c478bd9Sstevel@tonic-gate 	big_finish(&tmp);
24707c478bd9Sstevel@tonic-gate ret2:
24717c478bd9Sstevel@tonic-gate 	big_finish(&aq);
24727c478bd9Sstevel@tonic-gate ret1:
24737c478bd9Sstevel@tonic-gate 	big_finish(&ap);
24747c478bd9Sstevel@tonic-gate 
24757c478bd9Sstevel@tonic-gate 	return (err);
24767c478bd9Sstevel@tonic-gate }
24777c478bd9Sstevel@tonic-gate 
24787c478bd9Sstevel@tonic-gate 
2479b60f2a0bSfr41279 BIG_ERR_CODE
2480b60f2a0bSfr41279 big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
2481b60f2a0bSfr41279     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
2482b60f2a0bSfr41279     BIGNUM *p_rr, BIGNUM *q_rr)
2483b60f2a0bSfr41279 {
2484b60f2a0bSfr41279 	return (big_modexp_crt_ext(result, a, dmodpminus1, dmodqminus1,
2485b60f2a0bSfr41279 	    p, q, pinvmodq, p_rr, q_rr, NULL));
2486b60f2a0bSfr41279 }
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate 
2489b60f2a0bSfr41279 static BIG_CHUNK_TYPE onearr[1] = {(BIG_CHUNK_TYPE)1};
2490b60f2a0bSfr41279 BIGNUM big_One = {1, 1, 1, 0, onearr};
2491b60f2a0bSfr41279 
2492b60f2a0bSfr41279 static BIG_CHUNK_TYPE twoarr[1] = {(BIG_CHUNK_TYPE)2};
2493b60f2a0bSfr41279 BIGNUM big_Two = {1, 1, 1, 0, twoarr};
2494b60f2a0bSfr41279 
2495b60f2a0bSfr41279 static BIG_CHUNK_TYPE fourarr[1] = {(BIG_CHUNK_TYPE)4};
2496b60f2a0bSfr41279 static BIGNUM big_Four = {1, 1, 1, 0, fourarr};
2497b60f2a0bSfr41279 
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate BIG_ERR_CODE
25007c478bd9Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n)
25017c478bd9Sstevel@tonic-gate {
25027c478bd9Sstevel@tonic-gate 	BIGNUM		*high, *low, *mid, *t;
25037c478bd9Sstevel@tonic-gate 	BIGNUM		t1, t2, t3, prod;
2504b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
2505b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
2506b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
2507b60f2a0bSfr41279 	BIG_CHUNK_TYPE	prodvalue[BIGTMPSIZE];
25088475e043SDan OpenSolaris Anderson 	int		i, diff;
25098475e043SDan OpenSolaris Anderson 	uint32_t	nbits, nrootbits, highbits;
25107c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
25117c478bd9Sstevel@tonic-gate 
25127c478bd9Sstevel@tonic-gate 	nbits = big_numbits(n);
25137c478bd9Sstevel@tonic-gate 
25147c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, n->len + 1,
25157c478bd9Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
25167c478bd9Sstevel@tonic-gate 		return (err);
25177c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, n->len + 1,
25187c478bd9Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
25197c478bd9Sstevel@tonic-gate 		goto ret1;
25207c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, n->len + 1,
25217c478bd9Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
25227c478bd9Sstevel@tonic-gate 		goto ret2;
25237c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&prod, n->len + 1,
25247c478bd9Sstevel@tonic-gate 	    prodvalue, arraysize(prodvalue))) != BIG_OK)
25257c478bd9Sstevel@tonic-gate 		goto ret3;
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate 	nrootbits = (nbits + 1) / 2;
2528b60f2a0bSfr41279 	t1.len = t2.len = t3.len = (nrootbits - 1) / BIG_CHUNK_SIZE + 1;
25297c478bd9Sstevel@tonic-gate 	for (i = 0; i < t1.len; i++) {
25307c478bd9Sstevel@tonic-gate 		t1.value[i] = 0;
2531b60f2a0bSfr41279 		t2.value[i] = BIG_CHUNK_ALLBITS;
25327c478bd9Sstevel@tonic-gate 	}
2533b60f2a0bSfr41279 	highbits = nrootbits - BIG_CHUNK_SIZE * (t1.len - 1);
2534b60f2a0bSfr41279 	if (highbits == BIG_CHUNK_SIZE) {
2535b60f2a0bSfr41279 		t1.value[t1.len - 1] = BIG_CHUNK_HIGHBIT;
2536b60f2a0bSfr41279 		t2.value[t2.len - 1] = BIG_CHUNK_ALLBITS;
25377c478bd9Sstevel@tonic-gate 	} else {
2538b60f2a0bSfr41279 		t1.value[t1.len - 1] = (BIG_CHUNK_TYPE)1 << (highbits - 1);
25397c478bd9Sstevel@tonic-gate 		t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1;
25407c478bd9Sstevel@tonic-gate 	}
2541b60f2a0bSfr41279 
25427c478bd9Sstevel@tonic-gate 	high = &t2;
25437c478bd9Sstevel@tonic-gate 	low = &t1;
25447c478bd9Sstevel@tonic-gate 	mid = &t3;
25457c478bd9Sstevel@tonic-gate 
2546b60f2a0bSfr41279 	if ((err = big_mul(&prod, high, high)) != BIG_OK) {
25477c478bd9Sstevel@tonic-gate 		goto ret;
2548b60f2a0bSfr41279 	}
25497c478bd9Sstevel@tonic-gate 	diff = big_cmp_abs(&prod, n);
25507c478bd9Sstevel@tonic-gate 	if (diff <= 0) {
25517c478bd9Sstevel@tonic-gate 		err = big_copy(result, high);
25527c478bd9Sstevel@tonic-gate 		goto ret;
25537c478bd9Sstevel@tonic-gate 	}
25547c478bd9Sstevel@tonic-gate 
25557c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(mid, high, low);
2556b60f2a0bSfr41279 	while (big_cmp_abs(&big_One, mid) != 0) {
25577c478bd9Sstevel@tonic-gate 		(void) big_add_abs(mid, high, low);
25587c478bd9Sstevel@tonic-gate 		(void) big_half_pos(mid, mid);
25597c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&prod, mid, mid)) != BIG_OK)
25607c478bd9Sstevel@tonic-gate 			goto ret;
25617c478bd9Sstevel@tonic-gate 		diff = big_cmp_abs(&prod, n);
25627c478bd9Sstevel@tonic-gate 		if (diff > 0) {
25637c478bd9Sstevel@tonic-gate 			t = high;
25647c478bd9Sstevel@tonic-gate 			high = mid;
25657c478bd9Sstevel@tonic-gate 			mid = t;
25667c478bd9Sstevel@tonic-gate 		} else if (diff < 0) {
25677c478bd9Sstevel@tonic-gate 			t = low;
25687c478bd9Sstevel@tonic-gate 			low = mid;
25697c478bd9Sstevel@tonic-gate 			mid = t;
25707c478bd9Sstevel@tonic-gate 		} else {
25717c478bd9Sstevel@tonic-gate 			err = big_copy(result, low);
25727c478bd9Sstevel@tonic-gate 			goto ret;
25737c478bd9Sstevel@tonic-gate 		}
25747c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(mid, high, low);
25757c478bd9Sstevel@tonic-gate 	}
25767c478bd9Sstevel@tonic-gate 
25777c478bd9Sstevel@tonic-gate 	err = big_copy(result, low);
25787c478bd9Sstevel@tonic-gate ret:
25797c478bd9Sstevel@tonic-gate 	if (prod.malloced) big_finish(&prod);
25807c478bd9Sstevel@tonic-gate ret3:
25817c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
25827c478bd9Sstevel@tonic-gate ret2:
25837c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
25847c478bd9Sstevel@tonic-gate ret1:
25857c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
25867c478bd9Sstevel@tonic-gate 
25877c478bd9Sstevel@tonic-gate 	return (err);
25887c478bd9Sstevel@tonic-gate }
25897c478bd9Sstevel@tonic-gate 
25907c478bd9Sstevel@tonic-gate 
25917c478bd9Sstevel@tonic-gate BIG_ERR_CODE
25927c478bd9Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm)
25937c478bd9Sstevel@tonic-gate {
25947c478bd9Sstevel@tonic-gate 	BIGNUM		*t, *tmp2, *m, *n;
25957c478bd9Sstevel@tonic-gate 	BIGNUM		t1, t2, t3;
2596b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
2597b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
2598b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
25997c478bd9Sstevel@tonic-gate 	int		len, err;
26007c478bd9Sstevel@tonic-gate 
26017c478bd9Sstevel@tonic-gate 	if (big_is_zero(nn) ||
26027c478bd9Sstevel@tonic-gate 	    (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) {
26037c478bd9Sstevel@tonic-gate 		*jac = 0;
26047c478bd9Sstevel@tonic-gate 		return (BIG_OK);
26057c478bd9Sstevel@tonic-gate 	}
26067c478bd9Sstevel@tonic-gate 
2607b60f2a0bSfr41279 	if (nn->len > mm->len) {
2608b60f2a0bSfr41279 		len = nn->len;
2609b60f2a0bSfr41279 	} else {
2610b60f2a0bSfr41279 		len = mm->len;
2611b60f2a0bSfr41279 	}
26127c478bd9Sstevel@tonic-gate 
26137c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
2614b60f2a0bSfr41279 	    t1value, arraysize(t1value))) != BIG_OK) {
26157c478bd9Sstevel@tonic-gate 		return (err);
2616b60f2a0bSfr41279 	}
26177c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
2618b60f2a0bSfr41279 	    t2value, arraysize(t2value))) != BIG_OK) {
26197c478bd9Sstevel@tonic-gate 		goto ret1;
2620b60f2a0bSfr41279 	}
26217c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
2622b60f2a0bSfr41279 	    t3value, arraysize(t3value))) != BIG_OK) {
26237c478bd9Sstevel@tonic-gate 		goto ret2;
2624b60f2a0bSfr41279 	}
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	n = &t1;
26277c478bd9Sstevel@tonic-gate 	m = &t2;
26287c478bd9Sstevel@tonic-gate 	tmp2 = &t3;
26297c478bd9Sstevel@tonic-gate 
26307c478bd9Sstevel@tonic-gate 	(void) big_copy(n, nn);
26317c478bd9Sstevel@tonic-gate 	(void) big_copy(m, mm);
26327c478bd9Sstevel@tonic-gate 
26337c478bd9Sstevel@tonic-gate 	*jac = 1;
2634b60f2a0bSfr41279 	while (big_cmp_abs(&big_One, m) != 0) {
26357c478bd9Sstevel@tonic-gate 		if (big_is_zero(n)) {
26367c478bd9Sstevel@tonic-gate 			*jac = 0;
26377c478bd9Sstevel@tonic-gate 			goto ret;
26387c478bd9Sstevel@tonic-gate 		}
26397c478bd9Sstevel@tonic-gate 		if ((m->value[0] & 1) == 0) {
26407c478bd9Sstevel@tonic-gate 			if (((n->value[0] & 7) == 3) ||
2641b60f2a0bSfr41279 			    ((n->value[0] & 7) == 5))
2642b60f2a0bSfr41279 				*jac = -*jac;
26437c478bd9Sstevel@tonic-gate 			(void) big_half_pos(m, m);
26447c478bd9Sstevel@tonic-gate 		} else if ((n->value[0] & 1) == 0) {
26457c478bd9Sstevel@tonic-gate 			if (((m->value[0] & 7) == 3) ||
2646b60f2a0bSfr41279 			    ((m->value[0] & 7) == 5))
2647b60f2a0bSfr41279 				*jac = -*jac;
26487c478bd9Sstevel@tonic-gate 			(void) big_half_pos(n, n);
26497c478bd9Sstevel@tonic-gate 		} else {
26507c478bd9Sstevel@tonic-gate 			if (((m->value[0] & 3) == 3) &&
26517c478bd9Sstevel@tonic-gate 			    ((n->value[0] & 3) == 3)) {
26527c478bd9Sstevel@tonic-gate 				*jac = -*jac;
26537c478bd9Sstevel@tonic-gate 			}
2654b60f2a0bSfr41279 			if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK) {
26557c478bd9Sstevel@tonic-gate 				goto ret;
2656b60f2a0bSfr41279 			}
26577c478bd9Sstevel@tonic-gate 			t = tmp2;
26587c478bd9Sstevel@tonic-gate 			tmp2 = m;
26597c478bd9Sstevel@tonic-gate 			m = n;
26607c478bd9Sstevel@tonic-gate 			n = t;
26617c478bd9Sstevel@tonic-gate 		}
26627c478bd9Sstevel@tonic-gate 	}
26637c478bd9Sstevel@tonic-gate 	err = BIG_OK;
26647c478bd9Sstevel@tonic-gate 
26657c478bd9Sstevel@tonic-gate ret:
26667c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
26677c478bd9Sstevel@tonic-gate ret2:
26687c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
26697c478bd9Sstevel@tonic-gate ret1:
26707c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
26717c478bd9Sstevel@tonic-gate 
26727c478bd9Sstevel@tonic-gate 	return (err);
26737c478bd9Sstevel@tonic-gate }
26747c478bd9Sstevel@tonic-gate 
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate BIG_ERR_CODE
26777c478bd9Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n)
26787c478bd9Sstevel@tonic-gate {
26798475e043SDan OpenSolaris Anderson 	int		i;
26808475e043SDan OpenSolaris Anderson 	uint32_t	m, w;
2681b60f2a0bSfr41279 	BIG_CHUNK_TYPE	bit;
26827c478bd9Sstevel@tonic-gate 	BIGNUM		ki, tmp, tmp2;
2683b60f2a0bSfr41279 	BIG_CHUNK_TYPE	kivalue[BIGTMPSIZE];
2684b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
2685b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp2value[BIGTMPSIZE];
26867c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
26877c478bd9Sstevel@tonic-gate 
2688b60f2a0bSfr41279 	if (big_cmp_abs(k, &big_One) == 0) {
26897c478bd9Sstevel@tonic-gate 		(void) big_copy(Lk, p);
2690b60f2a0bSfr41279 		(void) big_copy(Lkminus1, &big_Two);
26917c478bd9Sstevel@tonic-gate 		return (BIG_OK);
26927c478bd9Sstevel@tonic-gate 	}
26937c478bd9Sstevel@tonic-gate 
26947c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&ki, k->len + 1,
26957c478bd9Sstevel@tonic-gate 	    kivalue, arraysize(kivalue))) != BIG_OK)
26967c478bd9Sstevel@tonic-gate 		return (err);
26977c478bd9Sstevel@tonic-gate 
26987c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len + 1,
26997c478bd9Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
27007c478bd9Sstevel@tonic-gate 		goto ret1;
27017c478bd9Sstevel@tonic-gate 
27027c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, n->len,
27037c478bd9Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
27047c478bd9Sstevel@tonic-gate 		goto ret2;
27057c478bd9Sstevel@tonic-gate 
27067c478bd9Sstevel@tonic-gate 	m = big_numbits(k);
2707b60f2a0bSfr41279 	ki.len = (m - 1) / BIG_CHUNK_SIZE + 1;
2708b60f2a0bSfr41279 	w = (m - 1) / BIG_CHUNK_SIZE;
2709b60f2a0bSfr41279 	bit = (BIG_CHUNK_TYPE)1 << ((m - 1) % BIG_CHUNK_SIZE);
2710b60f2a0bSfr41279 	for (i = 0; i < ki.len; i++) {
2711b60f2a0bSfr41279 		ki.value[i] = 0;
2712b60f2a0bSfr41279 	}
27137c478bd9Sstevel@tonic-gate 	ki.value[ki.len - 1] = bit;
2714b60f2a0bSfr41279 	if (big_cmp_abs(k, &ki) != 0) {
27157c478bd9Sstevel@tonic-gate 		(void) big_double(&ki, &ki);
2716b60f2a0bSfr41279 	}
27177c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(&ki, &ki, k);
27187c478bd9Sstevel@tonic-gate 
27197c478bd9Sstevel@tonic-gate 	(void) big_copy(Lk, p);
2720b60f2a0bSfr41279 	(void) big_copy(Lkminus1, &big_Two);
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate 	for (i = 0; i < m; i++) {
2723b60f2a0bSfr41279 		if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK) {
27247c478bd9Sstevel@tonic-gate 			goto ret;
2725b60f2a0bSfr41279 		}
27267c478bd9Sstevel@tonic-gate 		(void) big_add_abs(&tmp, &tmp, n);
27277c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(&tmp, &tmp, p);
2728b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK) {
27297c478bd9Sstevel@tonic-gate 			goto ret;
2730b60f2a0bSfr41279 		}
27317c478bd9Sstevel@tonic-gate 		if ((ki.value[w] & bit) != 0) {
27327c478bd9Sstevel@tonic-gate 			if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) !=
2733b60f2a0bSfr41279 			    BIG_OK) {
27347c478bd9Sstevel@tonic-gate 				goto ret;
2735b60f2a0bSfr41279 			}
27367c478bd9Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
2737b60f2a0bSfr41279 			(void) big_sub_pos(&tmp, &tmp, &big_Two);
27387c478bd9Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) !=
2739b60f2a0bSfr41279 			    BIG_OK) {
27407c478bd9Sstevel@tonic-gate 				goto ret;
2741b60f2a0bSfr41279 			}
27427c478bd9Sstevel@tonic-gate 			(void) big_copy(Lk, &tmp2);
27437c478bd9Sstevel@tonic-gate 		} else {
2744b60f2a0bSfr41279 			if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK) {
27457c478bd9Sstevel@tonic-gate 				goto ret;
2746b60f2a0bSfr41279 			}
27477c478bd9Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
2748b60f2a0bSfr41279 			(void) big_sub_pos(&tmp, &tmp, &big_Two);
2749b60f2a0bSfr41279 			if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK) {
27507c478bd9Sstevel@tonic-gate 				goto ret;
2751b60f2a0bSfr41279 			}
27527c478bd9Sstevel@tonic-gate 			(void) big_copy(Lkminus1, &tmp2);
27537c478bd9Sstevel@tonic-gate 		}
27547c478bd9Sstevel@tonic-gate 		bit = bit >> 1;
27557c478bd9Sstevel@tonic-gate 		if (bit == 0) {
2756b60f2a0bSfr41279 			bit = BIG_CHUNK_HIGHBIT;
27577c478bd9Sstevel@tonic-gate 			w--;
27587c478bd9Sstevel@tonic-gate 		}
27597c478bd9Sstevel@tonic-gate 	}
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate 	err = BIG_OK;
27627c478bd9Sstevel@tonic-gate 
27637c478bd9Sstevel@tonic-gate ret:
27647c478bd9Sstevel@tonic-gate 	if (tmp2.malloced) big_finish(&tmp2);
27657c478bd9Sstevel@tonic-gate ret2:
27667c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
27677c478bd9Sstevel@tonic-gate ret1:
27687c478bd9Sstevel@tonic-gate 	if (ki.malloced) big_finish(&ki);
27697c478bd9Sstevel@tonic-gate 
27707c478bd9Sstevel@tonic-gate 	return (err);
27717c478bd9Sstevel@tonic-gate }
27727c478bd9Sstevel@tonic-gate 
27737c478bd9Sstevel@tonic-gate 
27747c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2775b60f2a0bSfr41279 big_isprime_pos_ext(BIGNUM *n, big_modexp_ncp_info_t *info)
27767c478bd9Sstevel@tonic-gate {
27777c478bd9Sstevel@tonic-gate 	BIGNUM		o, nminus1, tmp, Lkminus1, Lk;
2778b60f2a0bSfr41279 	BIG_CHUNK_TYPE	ovalue[BIGTMPSIZE];
2779b60f2a0bSfr41279 	BIG_CHUNK_TYPE	nminus1value[BIGTMPSIZE];
2780b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
2781b60f2a0bSfr41279 	BIG_CHUNK_TYPE	Lkminus1value[BIGTMPSIZE];
2782b60f2a0bSfr41279 	BIG_CHUNK_TYPE	Lkvalue[BIGTMPSIZE];
27837c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
27847c478bd9Sstevel@tonic-gate 	int		e, i, jac;
27857c478bd9Sstevel@tonic-gate 
2786b60f2a0bSfr41279 	if (big_cmp_abs(n, &big_One) == 0) {
27877c478bd9Sstevel@tonic-gate 		return (BIG_FALSE);
2788b60f2a0bSfr41279 	}
2789b60f2a0bSfr41279 	if (big_cmp_abs(n, &big_Two) == 0) {
27907c478bd9Sstevel@tonic-gate 		return (BIG_TRUE);
2791b60f2a0bSfr41279 	}
2792b60f2a0bSfr41279 	if ((n->value[0] & 1) == 0) {
27937c478bd9Sstevel@tonic-gate 		return (BIG_FALSE);
2794b60f2a0bSfr41279 	}
27957c478bd9Sstevel@tonic-gate 
2796b60f2a0bSfr41279 	if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) !=
2797b60f2a0bSfr41279 	    BIG_OK) {
27987c478bd9Sstevel@tonic-gate 		return (err);
2799b60f2a0bSfr41279 	}
28007c478bd9Sstevel@tonic-gate 
28017c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&nminus1, n->len,
2802b60f2a0bSfr41279 	    nminus1value, arraysize(nminus1value))) != BIG_OK) {
28037c478bd9Sstevel@tonic-gate 		goto ret1;
2804b60f2a0bSfr41279 	}
28057c478bd9Sstevel@tonic-gate 
28067c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len,
2807b60f2a0bSfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
28087c478bd9Sstevel@tonic-gate 		goto ret2;
2809b60f2a0bSfr41279 	}
28107c478bd9Sstevel@tonic-gate 
28117c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&Lkminus1, n->len,
2812b60f2a0bSfr41279 	    Lkminus1value, arraysize(Lkminus1value))) != BIG_OK) {
28137c478bd9Sstevel@tonic-gate 		goto ret3;
2814b60f2a0bSfr41279 	}
28157c478bd9Sstevel@tonic-gate 
28167c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&Lk, n->len,
2817b60f2a0bSfr41279 	    Lkvalue, arraysize(Lkvalue))) != BIG_OK) {
28187c478bd9Sstevel@tonic-gate 		goto ret4;
2819b60f2a0bSfr41279 	}
28207c478bd9Sstevel@tonic-gate 
2821b60f2a0bSfr41279 	(void) big_sub_pos(&o, n, &big_One);	/* cannot fail */
28227c478bd9Sstevel@tonic-gate 	(void) big_copy(&nminus1, &o);		/* cannot fail */
28237c478bd9Sstevel@tonic-gate 	e = 0;
28247c478bd9Sstevel@tonic-gate 	while ((o.value[0] & 1) == 0) {
28257c478bd9Sstevel@tonic-gate 		e++;
28267c478bd9Sstevel@tonic-gate 		(void) big_half_pos(&o, &o);  /* cannot fail */
28277c478bd9Sstevel@tonic-gate 	}
2828b60f2a0bSfr41279 	if ((err = big_modexp_ext(&tmp, &big_Two, &o, n, NULL, info)) !=
2829b60f2a0bSfr41279 	    BIG_OK) {
28307c478bd9Sstevel@tonic-gate 		goto ret;
2831b60f2a0bSfr41279 	}
2832b60f2a0bSfr41279 
28337c478bd9Sstevel@tonic-gate 	i = 0;
28347c478bd9Sstevel@tonic-gate 	while ((i < e) &&
2835b60f2a0bSfr41279 	    (big_cmp_abs(&tmp, &big_One) != 0) &&
28367c478bd9Sstevel@tonic-gate 	    (big_cmp_abs(&tmp, &nminus1) != 0)) {
2837b60f2a0bSfr41279 		if ((err =
2838b60f2a0bSfr41279 		    big_modexp_ext(&tmp, &tmp, &big_Two, n, NULL, info)) !=
2839b60f2a0bSfr41279 		    BIG_OK)
28407c478bd9Sstevel@tonic-gate 			goto ret;
28417c478bd9Sstevel@tonic-gate 		i++;
28427c478bd9Sstevel@tonic-gate 	}
2843b60f2a0bSfr41279 
28447c478bd9Sstevel@tonic-gate 	if (!((big_cmp_abs(&tmp, &nminus1) == 0) ||
2845b60f2a0bSfr41279 	    ((i == 0) && (big_cmp_abs(&tmp, &big_One) == 0)))) {
28467c478bd9Sstevel@tonic-gate 		err = BIG_FALSE;
28477c478bd9Sstevel@tonic-gate 		goto ret;
28487c478bd9Sstevel@tonic-gate 	}
28497c478bd9Sstevel@tonic-gate 
2850b60f2a0bSfr41279 	if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK) {
28517c478bd9Sstevel@tonic-gate 		goto ret;
2852b60f2a0bSfr41279 	}
2853b60f2a0bSfr41279 
2854b60f2a0bSfr41279 	if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK) {
28557c478bd9Sstevel@tonic-gate 		goto ret;
2856b60f2a0bSfr41279 	}
28577c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(&tmp, n) == 0) {
28587c478bd9Sstevel@tonic-gate 		err = BIG_FALSE;
28597c478bd9Sstevel@tonic-gate 		goto ret;
28607c478bd9Sstevel@tonic-gate 	}
28617c478bd9Sstevel@tonic-gate 
2862b60f2a0bSfr41279 	(void) big_copy(&o, &big_Two);
28637c478bd9Sstevel@tonic-gate 	do {
2864b60f2a0bSfr41279 		(void) big_add_abs(&o, &o, &big_One);
2865b60f2a0bSfr41279 		if ((err = big_mul(&tmp, &o, &o)) != BIG_OK) {
28667c478bd9Sstevel@tonic-gate 			goto ret;
2867b60f2a0bSfr41279 		}
2868b60f2a0bSfr41279 		(void) big_sub_pos(&tmp, &tmp, &big_Four);
2869b60f2a0bSfr41279 		if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK) {
28707c478bd9Sstevel@tonic-gate 			goto ret;
2871b60f2a0bSfr41279 		}
28727c478bd9Sstevel@tonic-gate 	} while (jac != -1);
28737c478bd9Sstevel@tonic-gate 
2874b60f2a0bSfr41279 	(void) big_add_abs(&tmp, n, &big_One);
2875b60f2a0bSfr41279 	if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK) {
28767c478bd9Sstevel@tonic-gate 		goto ret;
2877b60f2a0bSfr41279 	}
2878b60f2a0bSfr41279 
2879b60f2a0bSfr41279 	if ((big_cmp_abs(&Lkminus1, &o) == 0) &&
2880b60f2a0bSfr41279 	    (big_cmp_abs(&Lk, &big_Two) == 0)) {
28817c478bd9Sstevel@tonic-gate 		err = BIG_TRUE;
2882b60f2a0bSfr41279 	} else {
2883b60f2a0bSfr41279 		err = BIG_FALSE;
2884b60f2a0bSfr41279 	}
28857c478bd9Sstevel@tonic-gate 
28867c478bd9Sstevel@tonic-gate ret:
28877c478bd9Sstevel@tonic-gate 	if (Lk.malloced) big_finish(&Lk);
28887c478bd9Sstevel@tonic-gate ret4:
28897c478bd9Sstevel@tonic-gate 	if (Lkminus1.malloced) big_finish(&Lkminus1);
28907c478bd9Sstevel@tonic-gate ret3:
28917c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
28927c478bd9Sstevel@tonic-gate ret2:
28937c478bd9Sstevel@tonic-gate 	if (nminus1.malloced) big_finish(&nminus1);
28947c478bd9Sstevel@tonic-gate ret1:
28957c478bd9Sstevel@tonic-gate 	if (o.malloced) big_finish(&o);
28967c478bd9Sstevel@tonic-gate 
28977c478bd9Sstevel@tonic-gate 	return (err);
28987c478bd9Sstevel@tonic-gate }
28997c478bd9Sstevel@tonic-gate 
29007c478bd9Sstevel@tonic-gate 
2901b60f2a0bSfr41279 BIG_ERR_CODE
2902b60f2a0bSfr41279 big_isprime_pos(BIGNUM *n)
2903b60f2a0bSfr41279 {
2904b60f2a0bSfr41279 	return (big_isprime_pos_ext(n, NULL));
2905b60f2a0bSfr41279 }
2906b60f2a0bSfr41279 
2907b60f2a0bSfr41279 
29087c478bd9Sstevel@tonic-gate #define	SIEVESIZE 1000
29097c478bd9Sstevel@tonic-gate 
29107c478bd9Sstevel@tonic-gate 
29117c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2912b60f2a0bSfr41279 big_nextprime_pos_ext(BIGNUM *result, BIGNUM *n, big_modexp_ncp_info_t *info)
29137c478bd9Sstevel@tonic-gate {
29148475e043SDan OpenSolaris Anderson 	static const uint32_t smallprimes[] = {
29158475e043SDan OpenSolaris Anderson 	    3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
29168475e043SDan OpenSolaris Anderson 	    51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97 };
29177c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
29187c478bd9Sstevel@tonic-gate 	int		sieve[SIEVESIZE];
29197c478bd9Sstevel@tonic-gate 	int		i;
29207c478bd9Sstevel@tonic-gate 	uint32_t	off, p;
29217c478bd9Sstevel@tonic-gate 
2922b60f2a0bSfr41279 	if ((err = big_copy(result, n)) != BIG_OK) {
29237c478bd9Sstevel@tonic-gate 		return (err);
2924b60f2a0bSfr41279 	}
29257c478bd9Sstevel@tonic-gate 	result->value[0] |= 1;
2926f56c1286Srobinson 	/* CONSTCOND */
29277c478bd9Sstevel@tonic-gate 	while (1) {
29287c478bd9Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0;
29297c478bd9Sstevel@tonic-gate 		for (i = 0;
2930b60f2a0bSfr41279 		    i < sizeof (smallprimes) / sizeof (smallprimes[0]); i++) {
29317c478bd9Sstevel@tonic-gate 			p = smallprimes[i];
2932b60f2a0bSfr41279 			off = big_modhalf_pos(result, p);
29337c478bd9Sstevel@tonic-gate 			off = p - off;
2934b60f2a0bSfr41279 			if ((off % 2) == 1) {
2935b60f2a0bSfr41279 				off = off + p;
2936b60f2a0bSfr41279 			}
29377c478bd9Sstevel@tonic-gate 			off = off / 2;
29387c478bd9Sstevel@tonic-gate 			while (off < SIEVESIZE) {
29397c478bd9Sstevel@tonic-gate 				sieve[off] = 1;
29407c478bd9Sstevel@tonic-gate 				off = off + p;
29417c478bd9Sstevel@tonic-gate 			}
29427c478bd9Sstevel@tonic-gate 		}
29437c478bd9Sstevel@tonic-gate 
29447c478bd9Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) {
29457c478bd9Sstevel@tonic-gate 			if (sieve[i] == 0) {
2946b60f2a0bSfr41279 				err = big_isprime_pos_ext(result, info);
29477c478bd9Sstevel@tonic-gate 				if (err != BIG_FALSE) {
2948b60f2a0bSfr41279 					if (err != BIG_TRUE) {
29497c478bd9Sstevel@tonic-gate 						return (err);
2950b60f2a0bSfr41279 					} else {
2951b60f2a0bSfr41279 						goto out;
2952b60f2a0bSfr41279 					}
29537c478bd9Sstevel@tonic-gate 				}
29547c478bd9Sstevel@tonic-gate 
29557c478bd9Sstevel@tonic-gate 			}
2956b60f2a0bSfr41279 			if ((err = big_add_abs(result, result, &big_Two)) !=
2957b60f2a0bSfr41279 			    BIG_OK) {
29587c478bd9Sstevel@tonic-gate 				return (err);
29597c478bd9Sstevel@tonic-gate 			}
29607c478bd9Sstevel@tonic-gate 		}
2961b60f2a0bSfr41279 	}
2962b60f2a0bSfr41279 
2963b60f2a0bSfr41279 out:
2964b60f2a0bSfr41279 	return (BIG_OK);
2965b60f2a0bSfr41279 }
2966b60f2a0bSfr41279 
2967b60f2a0bSfr41279 
2968b60f2a0bSfr41279 BIG_ERR_CODE
2969b60f2a0bSfr41279 big_nextprime_pos(BIGNUM *result, BIGNUM *n)
2970b60f2a0bSfr41279 {
2971b60f2a0bSfr41279 	return (big_nextprime_pos_ext(result, n, NULL));
29727c478bd9Sstevel@tonic-gate }
29737c478bd9Sstevel@tonic-gate 
29747c478bd9Sstevel@tonic-gate 
29757c478bd9Sstevel@tonic-gate BIG_ERR_CODE
29767c478bd9Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n)
29777c478bd9Sstevel@tonic-gate {
29787c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
29797c478bd9Sstevel@tonic-gate 
29807c478bd9Sstevel@tonic-gate 
29817c478bd9Sstevel@tonic-gate 	if ((err = big_copy(result, n)) != BIG_OK)
29827c478bd9Sstevel@tonic-gate 		return (err);
29837c478bd9Sstevel@tonic-gate 	result->value[0] |= 1;
2984b60f2a0bSfr41279 	while ((err = big_isprime_pos_ext(result, NULL)) != BIG_TRUE) {
29857c478bd9Sstevel@tonic-gate 		if (err != BIG_FALSE)
29867c478bd9Sstevel@tonic-gate 			return (err);
2987b60f2a0bSfr41279 		if ((err = big_add_abs(result, result, &big_Two)) != BIG_OK)
29887c478bd9Sstevel@tonic-gate 			return (err);
29897c478bd9Sstevel@tonic-gate 	}
29907c478bd9Sstevel@tonic-gate 	return (BIG_OK);
29917c478bd9Sstevel@tonic-gate }
29927c478bd9Sstevel@tonic-gate 
29937c478bd9Sstevel@tonic-gate 
29947c478bd9Sstevel@tonic-gate /*
29957c478bd9Sstevel@tonic-gate  * given m and e, computes the rest in the equation
29967c478bd9Sstevel@tonic-gate  * gcd(m, e) = cm * m + ce * e
29977c478bd9Sstevel@tonic-gate  */
29987c478bd9Sstevel@tonic-gate BIG_ERR_CODE
29997c478bd9Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e)
30007c478bd9Sstevel@tonic-gate {
3001b60f2a0bSfr41279 	BIGNUM		*xi, *ri, *riminus1, *riminus2, *t;
3002b60f2a0bSfr41279 	BIGNUM		*vmi, *vei, *vmiminus1, *veiminus1;
30037c478bd9Sstevel@tonic-gate 	BIGNUM		t1, t2, t3, t4, t5, t6, t7, t8, tmp;
3004b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
3005b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
3006b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
3007b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t4value[BIGTMPSIZE];
3008b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t5value[BIGTMPSIZE];
3009b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t6value[BIGTMPSIZE];
3010b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t7value[BIGTMPSIZE];
3011b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t8value[BIGTMPSIZE];
3012b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
30137c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
30147c478bd9Sstevel@tonic-gate 	int		len;
30157c478bd9Sstevel@tonic-gate 
3016b60f2a0bSfr41279 	if (big_cmp_abs(m, e) >= 0) {
3017b60f2a0bSfr41279 		len = m->len;
3018b60f2a0bSfr41279 	} else {
3019b60f2a0bSfr41279 		len = e->len;
3020b60f2a0bSfr41279 	}
30217c478bd9Sstevel@tonic-gate 
30227c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
3023b60f2a0bSfr41279 	    t1value, arraysize(t1value))) != BIG_OK) {
30247c478bd9Sstevel@tonic-gate 		return (err);
3025b60f2a0bSfr41279 	}
30267c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
3027b60f2a0bSfr41279 	    t2value, arraysize(t2value))) != BIG_OK) {
30287c478bd9Sstevel@tonic-gate 		goto ret1;
3029b60f2a0bSfr41279 	}
30307c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
3031b60f2a0bSfr41279 	    t3value, arraysize(t3value))) != BIG_OK) {
30327c478bd9Sstevel@tonic-gate 		goto ret2;
3033b60f2a0bSfr41279 	}
30347c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t4, len,
3035b60f2a0bSfr41279 	    t4value, arraysize(t3value))) != BIG_OK) {
30367c478bd9Sstevel@tonic-gate 		goto ret3;
3037b60f2a0bSfr41279 	}
30387c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t5, len,
3039b60f2a0bSfr41279 	    t5value, arraysize(t5value))) != BIG_OK) {
30407c478bd9Sstevel@tonic-gate 		goto ret4;
3041b60f2a0bSfr41279 	}
30427c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t6, len,
3043b60f2a0bSfr41279 	    t6value, arraysize(t6value))) != BIG_OK) {
30447c478bd9Sstevel@tonic-gate 		goto ret5;
3045b60f2a0bSfr41279 	}
30467c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t7, len,
3047b60f2a0bSfr41279 	    t7value, arraysize(t7value))) != BIG_OK) {
30487c478bd9Sstevel@tonic-gate 		goto ret6;
3049b60f2a0bSfr41279 	}
30507c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t8, len,
3051b60f2a0bSfr41279 	    t8value, arraysize(t8value))) != BIG_OK) {
30527c478bd9Sstevel@tonic-gate 		goto ret7;
3053b60f2a0bSfr41279 	}
30547c478bd9Sstevel@tonic-gate 
30557c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * len,
3056b60f2a0bSfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
30577c478bd9Sstevel@tonic-gate 		goto ret8;
3058b60f2a0bSfr41279 	}
30597c478bd9Sstevel@tonic-gate 
30607c478bd9Sstevel@tonic-gate 	ri = &t1;
30617c478bd9Sstevel@tonic-gate 	ri->value[0] = 1;
30627c478bd9Sstevel@tonic-gate 	ri->len = 1;
30637c478bd9Sstevel@tonic-gate 	xi = &t2;
30647c478bd9Sstevel@tonic-gate 	riminus1 = &t3;
30657c478bd9Sstevel@tonic-gate 	riminus2 = &t4;
30667c478bd9Sstevel@tonic-gate 	vmi = &t5;
30677c478bd9Sstevel@tonic-gate 	vei = &t6;
30687c478bd9Sstevel@tonic-gate 	vmiminus1 = &t7;
30697c478bd9Sstevel@tonic-gate 	veiminus1 = &t8;
30707c478bd9Sstevel@tonic-gate 
3071b60f2a0bSfr41279 	(void) big_copy(vmiminus1, &big_One);
3072b60f2a0bSfr41279 	(void) big_copy(vmi, &big_One);
3073b60f2a0bSfr41279 	(void) big_copy(veiminus1, &big_One);
3074b60f2a0bSfr41279 	(void) big_copy(xi, &big_One);
30757c478bd9Sstevel@tonic-gate 	vei->len = 1;
30767c478bd9Sstevel@tonic-gate 	vei->value[0] = 0;
30777c478bd9Sstevel@tonic-gate 
30787c478bd9Sstevel@tonic-gate 	(void) big_copy(riminus1, m);
30797c478bd9Sstevel@tonic-gate 	(void) big_copy(ri, e);
30807c478bd9Sstevel@tonic-gate 
30817c478bd9Sstevel@tonic-gate 	while (!big_is_zero(ri)) {
30827c478bd9Sstevel@tonic-gate 		t = riminus2;
30837c478bd9Sstevel@tonic-gate 		riminus2 = riminus1;
30847c478bd9Sstevel@tonic-gate 		riminus1 = ri;
30857c478bd9Sstevel@tonic-gate 		ri = t;
3086b60f2a0bSfr41279 		if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK) {
30877c478bd9Sstevel@tonic-gate 			goto ret;
3088b60f2a0bSfr41279 		}
3089b60f2a0bSfr41279 		if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK) {
30907c478bd9Sstevel@tonic-gate 			goto ret;
3091b60f2a0bSfr41279 		}
30927c478bd9Sstevel@tonic-gate 		t = vmiminus1;
30937c478bd9Sstevel@tonic-gate 		vmiminus1 = vmi;
30947c478bd9Sstevel@tonic-gate 		vmi = t;
3095b60f2a0bSfr41279 		if ((err = big_mul(&tmp, vei, xi)) != BIG_OK) {
30967c478bd9Sstevel@tonic-gate 			goto ret;
3097b60f2a0bSfr41279 		}
3098b60f2a0bSfr41279 		if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK) {
30997c478bd9Sstevel@tonic-gate 			goto ret;
3100b60f2a0bSfr41279 		}
31017c478bd9Sstevel@tonic-gate 		t = veiminus1;
31027c478bd9Sstevel@tonic-gate 		veiminus1 = vei;
31037c478bd9Sstevel@tonic-gate 		vei = t;
3104b60f2a0bSfr41279 		if ((err = big_div_pos(xi, ri, riminus2, riminus1)) !=
3105b60f2a0bSfr41279 		    BIG_OK) {
31067c478bd9Sstevel@tonic-gate 			goto ret;
31077c478bd9Sstevel@tonic-gate 		}
3108b60f2a0bSfr41279 	}
3109b60f2a0bSfr41279 	if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK)) {
31107c478bd9Sstevel@tonic-gate 		goto ret;
3111b60f2a0bSfr41279 	}
3112b60f2a0bSfr41279 	if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK)) {
31137c478bd9Sstevel@tonic-gate 		goto ret;
3114b60f2a0bSfr41279 	}
3115b60f2a0bSfr41279 	if (ce != NULL) {
31167c478bd9Sstevel@tonic-gate 		err = big_copy(ce, vei);
3117b60f2a0bSfr41279 	}
31187c478bd9Sstevel@tonic-gate ret:
31197c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
31207c478bd9Sstevel@tonic-gate ret8:
31217c478bd9Sstevel@tonic-gate 	if (t8.malloced) big_finish(&t8);
31227c478bd9Sstevel@tonic-gate ret7:
31237c478bd9Sstevel@tonic-gate 	if (t7.malloced) big_finish(&t7);
31247c478bd9Sstevel@tonic-gate ret6:
31257c478bd9Sstevel@tonic-gate 	if (t6.malloced) big_finish(&t6);
31267c478bd9Sstevel@tonic-gate ret5:
31277c478bd9Sstevel@tonic-gate 	if (t5.malloced) big_finish(&t5);
31287c478bd9Sstevel@tonic-gate ret4:
31297c478bd9Sstevel@tonic-gate 	if (t4.malloced) big_finish(&t4);
31307c478bd9Sstevel@tonic-gate ret3:
31317c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
31327c478bd9Sstevel@tonic-gate ret2:
31337c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
31347c478bd9Sstevel@tonic-gate ret1:
31357c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
31367c478bd9Sstevel@tonic-gate 
31377c478bd9Sstevel@tonic-gate 	return (err);
31387c478bd9Sstevel@tonic-gate }
3139