xref: /titanic_50/usr/src/common/bignum/bignumimpl.c (revision b60f2a0b921611326383e4789e0874e9e8a2e708)
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
5*b60f2a0bSfr41279  * Common Development and Distribution License (the "License").
6*b60f2a0bSfr41279  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*b60f2a0bSfr41279  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #define	big_div_pos_fast big_div_pos
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include "bignum.h"
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * Configuration guide
347c478bd9Sstevel@tonic-gate  * -------------------
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * There are 4 preprocessor symbols used to configure the bignum
377c478bd9Sstevel@tonic-gate  * implementation.  This file contains no logic to configure based on
387c478bd9Sstevel@tonic-gate  * processor; we leave that to the Makefiles to specify.
397c478bd9Sstevel@tonic-gate  *
407c478bd9Sstevel@tonic-gate  * USE_FLOATING_POINT
417c478bd9Sstevel@tonic-gate  *   Meaning: There is support for a fast floating-point implementation of
427c478bd9Sstevel@tonic-gate  *   Montgomery multiply.
437c478bd9Sstevel@tonic-gate  *
447c478bd9Sstevel@tonic-gate  * PSR_MUL
457c478bd9Sstevel@tonic-gate  *   Meaning: There are processor-specific versions of the low level
467c478bd9Sstevel@tonic-gate  *   functions to implement big_mul.  Those functions are: big_mul_set_vec,
477c478bd9Sstevel@tonic-gate  *   big_mul_add_vec, big_mul_vec, and big_sqr_vec.  PSR_MUL implies support
487c478bd9Sstevel@tonic-gate  *   for all 4 functions.  You cannot pick and choose which subset of these
497c478bd9Sstevel@tonic-gate  *   functions to support; that would lead to a rat's nest of #ifdefs.
507c478bd9Sstevel@tonic-gate  *
517c478bd9Sstevel@tonic-gate  * HWCAP
527c478bd9Sstevel@tonic-gate  *   Meaning: Call multiply support functions through a function pointer.
537c478bd9Sstevel@tonic-gate  *   On x86, there are multiple implementations for differnt hardware
547c478bd9Sstevel@tonic-gate  *   capabilities, such as MMX, SSE2, etc.  Tests are made at run-time, when
557c478bd9Sstevel@tonic-gate  *   a function is first used.  So, the support functions are called through
567c478bd9Sstevel@tonic-gate  *   a function pointer.  There is no need for that on Sparc, because there
577c478bd9Sstevel@tonic-gate  *   is only one implementation; support functions are called directly.
587c478bd9Sstevel@tonic-gate  *   Later, if there were some new VIS instruction, or something, and a
597c478bd9Sstevel@tonic-gate  *   run-time test were needed, rather than variant kernel modules and
607c478bd9Sstevel@tonic-gate  *   libraries, then HWCAP would be defined for Sparc, as well.
617c478bd9Sstevel@tonic-gate  *
627c478bd9Sstevel@tonic-gate  * UMUL64
637c478bd9Sstevel@tonic-gate  *   Meaning: It is safe to use generic C code that assumes the existence
647c478bd9Sstevel@tonic-gate  *   of a 32 x 32 --> 64 bit unsigned multiply.  If this is not defined,
657c478bd9Sstevel@tonic-gate  *   then the generic code for big_mul_add_vec() must necessarily be very slow,
667c478bd9Sstevel@tonic-gate  *   because it must fall back to using 16 x 16 --> 32 bit multiplication.
677c478bd9Sstevel@tonic-gate  *
687c478bd9Sstevel@tonic-gate  */
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate #ifdef	_KERNEL
72*b60f2a0bSfr41279 #include <sys/ddi.h>
73*b60f2a0bSfr41279 #include <sys/mdesc.h>
74*b60f2a0bSfr41279 #include <sys/crypto/common.h>
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate #include <sys/types.h>
777c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
787c478bd9Sstevel@tonic-gate #include <sys/param.h>
797c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate #define	big_malloc(size)	kmem_alloc(size, KM_NOSLEEP)
827c478bd9Sstevel@tonic-gate #define	big_free(ptr, size)	kmem_free(ptr, size)
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate void *
857c478bd9Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate 	void *rv;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	rv = kmem_alloc(newsize, KM_NOSLEEP);
907c478bd9Sstevel@tonic-gate 	if (rv != NULL)
917c478bd9Sstevel@tonic-gate 		bcopy(from, rv, oldsize);
927c478bd9Sstevel@tonic-gate 	kmem_free(from, oldsize);
937c478bd9Sstevel@tonic-gate 	return (rv);
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate #else	/* _KERNEL */
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate #include <stdlib.h>
997c478bd9Sstevel@tonic-gate #include <stdio.h>
100*b60f2a0bSfr41279 #include <assert.h>
101*b60f2a0bSfr41279 #define	ASSERT	assert
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate #ifndef MALLOC_DEBUG
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate #define	big_malloc(size)	malloc(size)
1067c478bd9Sstevel@tonic-gate #define	big_free(ptr, size)	free(ptr)
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate #else
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate void
1117c478bd9Sstevel@tonic-gate big_free(void *ptr, size_t size)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate 	printf("freed %d bytes at %p\n", size, ptr);
1147c478bd9Sstevel@tonic-gate 	free(ptr);
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate void *
1187c478bd9Sstevel@tonic-gate big_malloc(size_t size)
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate 	void *rv;
1217c478bd9Sstevel@tonic-gate 	rv = malloc(size);
1227c478bd9Sstevel@tonic-gate 	printf("malloced %d bytes, addr:%p\n", size, rv);
1237c478bd9Sstevel@tonic-gate 	return (rv);
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate #endif /* MALLOC_DEBUG */
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate #define	big_realloc(x, y, z) realloc((x), (z))
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate void
1307c478bd9Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	int i;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	(void) printf("\n%s\n%d\n", aname, a->sign*a->len);
1357c478bd9Sstevel@tonic-gate 	for (i = a->len - 1; i >= 0; i--) {
136*b60f2a0bSfr41279 #ifdef BIGNUM_CHUNK_32
1377c478bd9Sstevel@tonic-gate 		(void) printf("%08x ", a->value[i]);
138*b60f2a0bSfr41279 		if ((i % 8 == 0) && (i != 0)) {
1397c478bd9Sstevel@tonic-gate 			(void) printf("\n");
1407c478bd9Sstevel@tonic-gate 		}
141*b60f2a0bSfr41279 #else
142*b60f2a0bSfr41279 		(void) printf("%08x %08x ", (uint32_t)((a->value[i]) >> 32),
143*b60f2a0bSfr41279 		    (uint32_t)((a->value[i]) & 0xffffffff));
144*b60f2a0bSfr41279 		if ((i % 4 == 0) && (i != 0)) {
145*b60f2a0bSfr41279 			(void) printf("\n");
146*b60f2a0bSfr41279 		}
147*b60f2a0bSfr41279 #endif
148*b60f2a0bSfr41279 	}
1497c478bd9Sstevel@tonic-gate 	(void) printf("\n");
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate #endif	/* _KERNEL */
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 
155*b60f2a0bSfr41279 /* size in BIG_CHUNK_SIZE-bit words */
1567c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1577c478bd9Sstevel@tonic-gate big_init(BIGNUM *number, int size)
1587c478bd9Sstevel@tonic-gate {
159*b60f2a0bSfr41279 	number->value = big_malloc(sizeof (BIG_CHUNK_TYPE) * size);
1607c478bd9Sstevel@tonic-gate 	if (number->value == NULL) {
1617c478bd9Sstevel@tonic-gate 		return (BIG_NO_MEM);
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 	number->size = size;
1647c478bd9Sstevel@tonic-gate 	number->len = 0;
1657c478bd9Sstevel@tonic-gate 	number->sign = 1;
1667c478bd9Sstevel@tonic-gate 	number->malloced = 1;
1677c478bd9Sstevel@tonic-gate 	return (BIG_OK);
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate 
170*b60f2a0bSfr41279 /* size in BIG_CHUNK_SIZE-bit words */
1717c478bd9Sstevel@tonic-gate BIG_ERR_CODE
172*b60f2a0bSfr41279 big_init1(BIGNUM *number, int size, BIG_CHUNK_TYPE *buf, int bufsize)
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (size > bufsize)) {
175*b60f2a0bSfr41279 		number->value = big_malloc(sizeof (BIG_CHUNK_TYPE) * size);
1767c478bd9Sstevel@tonic-gate 		if (number->value == NULL) {
1777c478bd9Sstevel@tonic-gate 			return (BIG_NO_MEM);
1787c478bd9Sstevel@tonic-gate 		}
1797c478bd9Sstevel@tonic-gate 		number->size = size;
1807c478bd9Sstevel@tonic-gate 		number->malloced = 1;
1817c478bd9Sstevel@tonic-gate 	} else {
1827c478bd9Sstevel@tonic-gate 		number->value = buf;
1837c478bd9Sstevel@tonic-gate 		number->size = bufsize;
1847c478bd9Sstevel@tonic-gate 		number->malloced = 0;
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate 		number->len = 0;
1877c478bd9Sstevel@tonic-gate 		number->sign = 1;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	return (BIG_OK);
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate void
1937c478bd9Sstevel@tonic-gate big_finish(BIGNUM *number)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	if (number->malloced == 1) {
196*b60f2a0bSfr41279 		big_free(number->value,
197*b60f2a0bSfr41279 		    sizeof (BIG_CHUNK_TYPE) * number->size);
1987c478bd9Sstevel@tonic-gate 		number->malloced = 0;
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
202*b60f2a0bSfr41279 
2037c478bd9Sstevel@tonic-gate /*
204*b60f2a0bSfr41279  *  bn->size should be at least
205*b60f2a0bSfr41279  * (len + sizeof (BIG_CHUNK_TYPE) - 1) / sizeof (BIG_CHUNK_TYPE) bytes
2067c478bd9Sstevel@tonic-gate  * converts from byte-big-endian format to bignum format (words in
2077c478bd9Sstevel@tonic-gate  * little endian order, but bytes within the words big endian)
2087c478bd9Sstevel@tonic-gate  */
2097c478bd9Sstevel@tonic-gate void
2107c478bd9Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len)
2117c478bd9Sstevel@tonic-gate {
2127c478bd9Sstevel@tonic-gate 	int		i, j, offs;
213*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	word;
2147c478bd9Sstevel@tonic-gate 	uchar_t		*knwordp;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate #ifdef	_LP64
217*b60f2a0bSfr41279 	offs = (uint32_t)len % sizeof (BIG_CHUNK_TYPE);
218*b60f2a0bSfr41279 	bn->len = (uint32_t)len / sizeof (BIG_CHUNK_TYPE);
219*b60f2a0bSfr41279 
220*b60f2a0bSfr41279 	for (i = 0; i < (uint32_t)len / sizeof (BIG_CHUNK_TYPE); i++) {
2217c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
222*b60f2a0bSfr41279 	offs = len % sizeof (BIG_CHUNK_TYPE);
223*b60f2a0bSfr41279 	bn->len = len / sizeof (BIG_CHUNK_TYPE);
224*b60f2a0bSfr41279 	for (i = 0; i < len / sizeof (BIG_CHUNK_TYPE); i++) {
2257c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
226*b60f2a0bSfr41279 		knwordp = &(kn[len - sizeof (BIG_CHUNK_TYPE) * (i + 1)]);
2277c478bd9Sstevel@tonic-gate 		word = knwordp[0];
228*b60f2a0bSfr41279 		for (j = 1; j < sizeof (BIG_CHUNK_TYPE); j++) {
2297c478bd9Sstevel@tonic-gate 			word = (word << 8)+ knwordp[j];
2307c478bd9Sstevel@tonic-gate 		}
2317c478bd9Sstevel@tonic-gate 		bn->value[i] = word;
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 	if (offs > 0) {
2347c478bd9Sstevel@tonic-gate 		word = kn[0];
2357c478bd9Sstevel@tonic-gate 		for (i = 1; i < offs; i++) word = (word << 8) + kn[i];
2367c478bd9Sstevel@tonic-gate 		bn->value[bn->len++] = word;
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate 	while ((bn->len > 1) && (bn->value[bn->len-1] == 0)) {
2397c478bd9Sstevel@tonic-gate 		bn->len --;
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate /*
2447c478bd9Sstevel@tonic-gate  * copies the least significant len bytes if
245*b60f2a0bSfr41279  * len < bn->len * sizeof (BIG_CHUNK_TYPE)
2467c478bd9Sstevel@tonic-gate  * converts from bignum format to byte-big-endian format.
247*b60f2a0bSfr41279  * bignum format is words of type  BIG_CHUNK_TYPE in little endian order.
2487c478bd9Sstevel@tonic-gate  */
2497c478bd9Sstevel@tonic-gate void
2507c478bd9Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len)
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate 	int		i, j, offs;
253*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	word;
2547c478bd9Sstevel@tonic-gate 
255*b60f2a0bSfr41279 	if (len < sizeof (BIG_CHUNK_TYPE) * bn->len) {
2567c478bd9Sstevel@tonic-gate #ifdef	_LP64
257*b60f2a0bSfr41279 		for (i = 0; i < (uint32_t)len / sizeof (BIG_CHUNK_TYPE); i++) {
2587c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
259*b60f2a0bSfr41279 		for (i = 0; i < len / sizeof (BIG_CHUNK_TYPE); i++) {
2607c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
2617c478bd9Sstevel@tonic-gate 			word = bn->value[i];
262*b60f2a0bSfr41279 			for (j = 0; j < sizeof (BIG_CHUNK_TYPE); j++) {
263*b60f2a0bSfr41279 				kn[len - sizeof (BIG_CHUNK_TYPE) * i - j - 1] =
2647c478bd9Sstevel@tonic-gate 				    word & 0xff;
2657c478bd9Sstevel@tonic-gate 				word = word >> 8;
2667c478bd9Sstevel@tonic-gate 			}
2677c478bd9Sstevel@tonic-gate 		}
2687c478bd9Sstevel@tonic-gate #ifdef	_LP64
269*b60f2a0bSfr41279 		offs = (uint32_t)len % sizeof (BIG_CHUNK_TYPE);
2707c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
271*b60f2a0bSfr41279 		offs = len % sizeof (BIG_CHUNK_TYPE);
2727c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
2737c478bd9Sstevel@tonic-gate 		if (offs > 0) {
274*b60f2a0bSfr41279 			word = bn->value[len / sizeof (BIG_CHUNK_TYPE)];
2757c478bd9Sstevel@tonic-gate #ifdef	_LP64
276*b60f2a0bSfr41279 			for (i =  (uint32_t)len % sizeof (BIG_CHUNK_TYPE);
2777c478bd9Sstevel@tonic-gate 			    i > 0; i --) {
2787c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
279*b60f2a0bSfr41279 			for (i = len % sizeof (BIG_CHUNK_TYPE);
280*b60f2a0bSfr41279 			    i > 0; i --) {
2817c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
2827c478bd9Sstevel@tonic-gate 				kn[i - 1] = word & 0xff;
2837c478bd9Sstevel@tonic-gate 				word = word >> 8;
2847c478bd9Sstevel@tonic-gate 			}
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 	} else {
2877c478bd9Sstevel@tonic-gate 		for (i = 0; i < bn->len; i++) {
2887c478bd9Sstevel@tonic-gate 			word = bn->value[i];
289*b60f2a0bSfr41279 			for (j = 0; j < sizeof (BIG_CHUNK_TYPE); j++) {
290*b60f2a0bSfr41279 				kn[len - sizeof (BIG_CHUNK_TYPE) * i - j - 1] =
2917c478bd9Sstevel@tonic-gate 				    word & 0xff;
2927c478bd9Sstevel@tonic-gate 				word = word >> 8;
2937c478bd9Sstevel@tonic-gate 			}
2947c478bd9Sstevel@tonic-gate 		}
2957c478bd9Sstevel@tonic-gate #ifdef	_LP64
296*b60f2a0bSfr41279 		for (i = 0;
297*b60f2a0bSfr41279 		    i < (uint32_t)len - sizeof (BIG_CHUNK_TYPE) * bn->len;
2987c478bd9Sstevel@tonic-gate 		    i++) {
2997c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
300*b60f2a0bSfr41279 		for (i = 0; i < len - sizeof (BIG_CHUNK_TYPE) * bn->len; i++) {
3017c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
3027c478bd9Sstevel@tonic-gate 			kn[i] = 0;
3037c478bd9Sstevel@tonic-gate 		}
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate int
3097c478bd9Sstevel@tonic-gate big_bitlength(BIGNUM *a)
3107c478bd9Sstevel@tonic-gate {
311*b60f2a0bSfr41279 	int		l = 0, b = 0;
312*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	c;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	l = a->len - 1;
3157c478bd9Sstevel@tonic-gate 	while ((l > 0) && (a->value[l] == 0)) {
3167c478bd9Sstevel@tonic-gate 		l--;
3177c478bd9Sstevel@tonic-gate 	}
318*b60f2a0bSfr41279 	b = sizeof (BIG_CHUNK_TYPE) * BITSINBYTE;
3197c478bd9Sstevel@tonic-gate 	c = a->value[l];
320*b60f2a0bSfr41279 	while ((b > 1) && ((c & BIG_CHUNK_HIGHBIT) == 0)) {
3217c478bd9Sstevel@tonic-gate 		c = c << 1;
3227c478bd9Sstevel@tonic-gate 		b--;
3237c478bd9Sstevel@tonic-gate 	}
324*b60f2a0bSfr41279 
325*b60f2a0bSfr41279 	return (l * sizeof (BIG_CHUNK_TYPE) * BITSINBYTE + b);
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate BIG_ERR_CODE
3307c478bd9Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src)
3317c478bd9Sstevel@tonic-gate {
332*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*newptr;
3337c478bd9Sstevel@tonic-gate 	int		i, len;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	len = src->len;
336*b60f2a0bSfr41279 	while ((len > 1) && (src->value[len - 1] == 0)) {
3377c478bd9Sstevel@tonic-gate 		len--;
338*b60f2a0bSfr41279 	}
3397c478bd9Sstevel@tonic-gate 	src->len = len;
3407c478bd9Sstevel@tonic-gate 	if (dest->size < len) {
3417c478bd9Sstevel@tonic-gate 		if (dest->malloced == 1) {
342*b60f2a0bSfr41279 			newptr = (BIG_CHUNK_TYPE *)big_realloc(dest->value,
343*b60f2a0bSfr41279 			    sizeof (BIG_CHUNK_TYPE) * dest->size,
344*b60f2a0bSfr41279 			    sizeof (BIG_CHUNK_TYPE) * len);
3457c478bd9Sstevel@tonic-gate 		} else {
346*b60f2a0bSfr41279 			newptr = (BIG_CHUNK_TYPE *)
347*b60f2a0bSfr41279 			    big_malloc(sizeof (BIG_CHUNK_TYPE) * len);
348*b60f2a0bSfr41279 			if (newptr != NULL) {
349*b60f2a0bSfr41279 				dest->malloced = 1;
3507c478bd9Sstevel@tonic-gate 			}
351*b60f2a0bSfr41279 		}
352*b60f2a0bSfr41279 		if (newptr == NULL) {
3537c478bd9Sstevel@tonic-gate 			return (BIG_NO_MEM);
354*b60f2a0bSfr41279 		}
3557c478bd9Sstevel@tonic-gate 		dest->value = newptr;
3567c478bd9Sstevel@tonic-gate 		dest->size = len;
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 	dest->len = len;
3597c478bd9Sstevel@tonic-gate 	dest->sign = src->sign;
360*b60f2a0bSfr41279 	for (i = 0; i < len; i++) {
361*b60f2a0bSfr41279 		dest->value[i] = src->value[i];
362*b60f2a0bSfr41279 	}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	return (BIG_OK);
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate BIG_ERR_CODE
3697c478bd9Sstevel@tonic-gate big_extend(BIGNUM *number, int size)
3707c478bd9Sstevel@tonic-gate {
371*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*newptr;
3727c478bd9Sstevel@tonic-gate 	int		i;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	if (number->size >= size)
3757c478bd9Sstevel@tonic-gate 		return (BIG_OK);
3767c478bd9Sstevel@tonic-gate 	if (number->malloced) {
377*b60f2a0bSfr41279 		number->value = big_realloc(number->value,
378*b60f2a0bSfr41279 		    sizeof (BIG_CHUNK_TYPE) * number->size,
379*b60f2a0bSfr41279 		    sizeof (BIG_CHUNK_TYPE) * size);
3807c478bd9Sstevel@tonic-gate 	} else {
381*b60f2a0bSfr41279 		newptr = big_malloc(sizeof (BIG_CHUNK_TYPE) * size);
3827c478bd9Sstevel@tonic-gate 		if (newptr != NULL) {
3837c478bd9Sstevel@tonic-gate 			for (i = 0; i < number->size; i++) {
3847c478bd9Sstevel@tonic-gate 				newptr[i] = number->value[i];
3857c478bd9Sstevel@tonic-gate 			}
3867c478bd9Sstevel@tonic-gate 		}
3877c478bd9Sstevel@tonic-gate 		number->value = newptr;
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 
390*b60f2a0bSfr41279 	if (number->value == NULL) {
3917c478bd9Sstevel@tonic-gate 		return (BIG_NO_MEM);
392*b60f2a0bSfr41279 	}
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	number->size = size;
3957c478bd9Sstevel@tonic-gate 	number->malloced = 1;
3967c478bd9Sstevel@tonic-gate 	return (BIG_OK);
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 
400*b60f2a0bSfr41279 /* returns 1 if n == 0 */
4017c478bd9Sstevel@tonic-gate int
4027c478bd9Sstevel@tonic-gate big_is_zero(BIGNUM *n)
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 	int	i, result;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	result = 1;
407*b60f2a0bSfr41279 	for (i = 0; i < n->len; i++) {
408*b60f2a0bSfr41279 		if (n->value[i] != 0) {
409*b60f2a0bSfr41279 			result = 0;
410*b60f2a0bSfr41279 		}
411*b60f2a0bSfr41279 	}
4127c478bd9Sstevel@tonic-gate 	return (result);
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate BIG_ERR_CODE
4177c478bd9Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate 	int		i, shorter, longer;
420*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, ai;
421*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*r, *a, *b, *c;
4227c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
423*b60f2a0bSfr41279 	BIGNUM		*longerarg;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	if (aa->len > bb->len) {
4267c478bd9Sstevel@tonic-gate 		shorter = bb->len;
4277c478bd9Sstevel@tonic-gate 		longer = aa->len;
428*b60f2a0bSfr41279 		longerarg = aa;
4297c478bd9Sstevel@tonic-gate 	} else {
4307c478bd9Sstevel@tonic-gate 		shorter = aa->len;
4317c478bd9Sstevel@tonic-gate 		longer = bb->len;
432*b60f2a0bSfr41279 		longerarg = bb;
4337c478bd9Sstevel@tonic-gate 	}
4347c478bd9Sstevel@tonic-gate 	if (result->size < longer + 1) {
4357c478bd9Sstevel@tonic-gate 		err = big_extend(result, longer + 1);
436*b60f2a0bSfr41279 		if (err != BIG_OK) {
4377c478bd9Sstevel@tonic-gate 			return (err);
4387c478bd9Sstevel@tonic-gate 		}
439*b60f2a0bSfr41279 	}
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	r = result->value;
4427c478bd9Sstevel@tonic-gate 	a = aa->value;
4437c478bd9Sstevel@tonic-gate 	b = bb->value;
444*b60f2a0bSfr41279 	c = longerarg->value;
4457c478bd9Sstevel@tonic-gate 	cy = 0;
4467c478bd9Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
4477c478bd9Sstevel@tonic-gate 		ai = a[i];
4487c478bd9Sstevel@tonic-gate 		r[i] = ai + b[i] + cy;
449*b60f2a0bSfr41279 		if (r[i] > ai) {
450*b60f2a0bSfr41279 			cy = 0;
451*b60f2a0bSfr41279 		} else if (r[i] < ai) {
452*b60f2a0bSfr41279 			cy = 1;
453*b60f2a0bSfr41279 		}
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 	for (; i < longer; i++) {
4567c478bd9Sstevel@tonic-gate 		ai = c[i];
4577c478bd9Sstevel@tonic-gate 		r[i] = ai + cy;
458*b60f2a0bSfr41279 		if (r[i] >= ai) {
459*b60f2a0bSfr41279 			cy = 0;
460*b60f2a0bSfr41279 		}
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 	if (cy == 1) {
4637c478bd9Sstevel@tonic-gate 		r[i] = cy;
4647c478bd9Sstevel@tonic-gate 		result->len = longer + 1;
4657c478bd9Sstevel@tonic-gate 	} else {
4667c478bd9Sstevel@tonic-gate 		result->len = longer;
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 	result->sign = 1;
4697c478bd9Sstevel@tonic-gate 	return (BIG_OK);
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */
4747c478bd9Sstevel@tonic-gate void
475*b60f2a0bSfr41279 big_sub_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, BIG_CHUNK_TYPE *b, int len)
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate 	int		i;
478*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, ai;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	cy = 1;
4817c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
4827c478bd9Sstevel@tonic-gate 		ai = a[i];
4837c478bd9Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
484*b60f2a0bSfr41279 		if (r[i] > ai) {
485*b60f2a0bSfr41279 			cy = 0;
486*b60f2a0bSfr41279 		} else if (r[i] < ai) {
487*b60f2a0bSfr41279 			cy = 1;
488*b60f2a0bSfr41279 		}
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate /* result=aa-bb  it is assumed that aa>=bb */
4947c478bd9Sstevel@tonic-gate BIG_ERR_CODE
4957c478bd9Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
4967c478bd9Sstevel@tonic-gate {
4977c478bd9Sstevel@tonic-gate 	int		i, shorter;
498*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy = 1, ai;
499*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*r, *a, *b;
500*b60f2a0bSfr41279 	BIG_ERR_CODE	err = BIG_OK;
5017c478bd9Sstevel@tonic-gate 
502*b60f2a0bSfr41279 	if (aa->len > bb->len) {
503*b60f2a0bSfr41279 		shorter = bb->len;
504*b60f2a0bSfr41279 	} else {
505*b60f2a0bSfr41279 		shorter = aa->len;
506*b60f2a0bSfr41279 	}
5077c478bd9Sstevel@tonic-gate 	if (result->size < aa->len) {
5087c478bd9Sstevel@tonic-gate 		err = big_extend(result, aa->len);
509*b60f2a0bSfr41279 		if (err != BIG_OK) {
5107c478bd9Sstevel@tonic-gate 			return (err);
5117c478bd9Sstevel@tonic-gate 		}
512*b60f2a0bSfr41279 	}
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	r = result->value;
5157c478bd9Sstevel@tonic-gate 	a = aa->value;
5167c478bd9Sstevel@tonic-gate 	b = bb->value;
5177c478bd9Sstevel@tonic-gate 	result->len = aa->len;
5187c478bd9Sstevel@tonic-gate 	cy = 1;
5197c478bd9Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
5207c478bd9Sstevel@tonic-gate 		ai = a[i];
5217c478bd9Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
522*b60f2a0bSfr41279 		if (r[i] > ai) {
523*b60f2a0bSfr41279 			cy = 0;
524*b60f2a0bSfr41279 		} else if (r[i] < ai) {
525*b60f2a0bSfr41279 			cy = 1;
526*b60f2a0bSfr41279 		}
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 	for (; i < aa->len; i++) {
5297c478bd9Sstevel@tonic-gate 		ai = a[i];
5307c478bd9Sstevel@tonic-gate 		r[i] = ai + (~0) + cy;
531*b60f2a0bSfr41279 		if (r[i] < ai) {
532*b60f2a0bSfr41279 			cy = 1;
533*b60f2a0bSfr41279 		}
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 	result->sign = 1;
536*b60f2a0bSfr41279 
537*b60f2a0bSfr41279 	if (cy == 0) {
5387c478bd9Sstevel@tonic-gate 		return (BIG_INVALID_ARGS);
539*b60f2a0bSfr41279 	} else {
5407c478bd9Sstevel@tonic-gate 		return (BIG_OK);
5417c478bd9Sstevel@tonic-gate 	}
542*b60f2a0bSfr41279 }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */
5467c478bd9Sstevel@tonic-gate int
5477c478bd9Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb)
5487c478bd9Sstevel@tonic-gate {
5497c478bd9Sstevel@tonic-gate 	int	i;
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	if (aa->len > bb->len) {
5527c478bd9Sstevel@tonic-gate 		for (i = aa->len - 1; i > bb->len - 1; i--) {
553*b60f2a0bSfr41279 			if (aa->value[i] > 0) {
5547c478bd9Sstevel@tonic-gate 				return (1);
5557c478bd9Sstevel@tonic-gate 			}
556*b60f2a0bSfr41279 		}
5577c478bd9Sstevel@tonic-gate 	} else if (aa->len < bb->len) {
5587c478bd9Sstevel@tonic-gate 		for (i = bb->len - 1; i > aa->len - 1; i--) {
559*b60f2a0bSfr41279 			if (bb->value[i] > 0) {
5607c478bd9Sstevel@tonic-gate 				return (-1);
5617c478bd9Sstevel@tonic-gate 			}
562*b60f2a0bSfr41279 		}
563*b60f2a0bSfr41279 	} else {
564*b60f2a0bSfr41279 		i = aa->len-1;
565*b60f2a0bSfr41279 	}
5667c478bd9Sstevel@tonic-gate 	for (; i >= 0; i--) {
567*b60f2a0bSfr41279 		if (aa->value[i] > bb->value[i]) {
5687c478bd9Sstevel@tonic-gate 			return (1);
569*b60f2a0bSfr41279 		} else if (aa->value[i] < bb->value[i]) {
5707c478bd9Sstevel@tonic-gate 			return (-1);
5717c478bd9Sstevel@tonic-gate 		}
572*b60f2a0bSfr41279 	}
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	return (0);
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate BIG_ERR_CODE
5797c478bd9Sstevel@tonic-gate big_sub(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
5807c478bd9Sstevel@tonic-gate {
5817c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == 1)) {
584*b60f2a0bSfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
5857c478bd9Sstevel@tonic-gate 			return (err);
586*b60f2a0bSfr41279 		}
5877c478bd9Sstevel@tonic-gate 		result->sign = 1;
5887c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == -1) && (bb->sign == 1)) {
589*b60f2a0bSfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
5907c478bd9Sstevel@tonic-gate 			return (err);
591*b60f2a0bSfr41279 		}
5927c478bd9Sstevel@tonic-gate 		result->sign = -1;
5937c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
5947c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
595*b60f2a0bSfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
5967c478bd9Sstevel@tonic-gate 				return (err);
597*b60f2a0bSfr41279 			}
5987c478bd9Sstevel@tonic-gate 			result->sign = 1;
5997c478bd9Sstevel@tonic-gate 		} else {
600*b60f2a0bSfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6017c478bd9Sstevel@tonic-gate 				return (err);
602*b60f2a0bSfr41279 			}
6037c478bd9Sstevel@tonic-gate 			result->sign = -1;
6047c478bd9Sstevel@tonic-gate 		}
6057c478bd9Sstevel@tonic-gate 	} else {
6067c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
607*b60f2a0bSfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6087c478bd9Sstevel@tonic-gate 				return (err);
609*b60f2a0bSfr41279 			}
6107c478bd9Sstevel@tonic-gate 			result->sign = -1;
6117c478bd9Sstevel@tonic-gate 		} else {
612*b60f2a0bSfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6137c478bd9Sstevel@tonic-gate 				return (err);
614*b60f2a0bSfr41279 			}
6157c478bd9Sstevel@tonic-gate 			result->sign = 1;
6167c478bd9Sstevel@tonic-gate 		}
6177c478bd9Sstevel@tonic-gate 	}
6187c478bd9Sstevel@tonic-gate 	return (BIG_OK);
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate BIG_ERR_CODE
6237c478bd9Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
6247c478bd9Sstevel@tonic-gate {
6257c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == -1)) {
628*b60f2a0bSfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
6297c478bd9Sstevel@tonic-gate 			return (err);
630*b60f2a0bSfr41279 		}
6317c478bd9Sstevel@tonic-gate 		result->sign = -1;
6327c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
633*b60f2a0bSfr41279 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK) {
6347c478bd9Sstevel@tonic-gate 			return (err);
635*b60f2a0bSfr41279 		}
6367c478bd9Sstevel@tonic-gate 		result->sign = 1;
6377c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == -1)) {
6387c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
639*b60f2a0bSfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6407c478bd9Sstevel@tonic-gate 				return (err);
641*b60f2a0bSfr41279 			}
6427c478bd9Sstevel@tonic-gate 			result->sign = 1;
6437c478bd9Sstevel@tonic-gate 		} else {
644*b60f2a0bSfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6457c478bd9Sstevel@tonic-gate 				return (err);
646*b60f2a0bSfr41279 			}
6477c478bd9Sstevel@tonic-gate 			result->sign = -1;
6487c478bd9Sstevel@tonic-gate 		}
6497c478bd9Sstevel@tonic-gate 	} else {
6507c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
651*b60f2a0bSfr41279 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) {
6527c478bd9Sstevel@tonic-gate 				return (err);
653*b60f2a0bSfr41279 			}
6547c478bd9Sstevel@tonic-gate 			result->sign = -1;
6557c478bd9Sstevel@tonic-gate 		} else {
656*b60f2a0bSfr41279 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) {
6577c478bd9Sstevel@tonic-gate 				return (err);
658*b60f2a0bSfr41279 			}
6597c478bd9Sstevel@tonic-gate 			result->sign = 1;
6607c478bd9Sstevel@tonic-gate 		}
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 	return (BIG_OK);
6637c478bd9Sstevel@tonic-gate }
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 
666*b60f2a0bSfr41279 /* result = aa/2 */
6677c478bd9Sstevel@tonic-gate BIG_ERR_CODE
6687c478bd9Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa)
6697c478bd9Sstevel@tonic-gate {
6707c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
6717c478bd9Sstevel@tonic-gate 	int		i;
672*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, cy1;
673*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *r;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	if (result->size < aa->len) {
6767c478bd9Sstevel@tonic-gate 		err = big_extend(result, aa->len);
677*b60f2a0bSfr41279 		if (err != BIG_OK) {
6787c478bd9Sstevel@tonic-gate 			return (err);
6797c478bd9Sstevel@tonic-gate 		}
680*b60f2a0bSfr41279 	}
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	result->len = aa->len;
6837c478bd9Sstevel@tonic-gate 	a = aa->value;
6847c478bd9Sstevel@tonic-gate 	r = result->value;
6857c478bd9Sstevel@tonic-gate 	cy = 0;
6867c478bd9Sstevel@tonic-gate 	for (i = aa->len - 1; i >= 0; i--) {
687*b60f2a0bSfr41279 		cy1 = a[i] << (BIG_CHUNK_SIZE - 1);
6887c478bd9Sstevel@tonic-gate 		r[i] = (cy | (a[i] >> 1));
6897c478bd9Sstevel@tonic-gate 		cy = cy1;
6907c478bd9Sstevel@tonic-gate 	}
691*b60f2a0bSfr41279 	if (r[result->len - 1] == 0) {
692*b60f2a0bSfr41279 		result->len--;
693*b60f2a0bSfr41279 	}
694*b60f2a0bSfr41279 
6957c478bd9Sstevel@tonic-gate 	return (BIG_OK);
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate 
698*b60f2a0bSfr41279 /* result  =  aa*2 */
6997c478bd9Sstevel@tonic-gate BIG_ERR_CODE
7007c478bd9Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa)
7017c478bd9Sstevel@tonic-gate {
7027c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
7037c478bd9Sstevel@tonic-gate 	int		i, rsize;
704*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, cy1;
705*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *r;
7067c478bd9Sstevel@tonic-gate 
707*b60f2a0bSfr41279 	if ((aa->len > 0) &&
708*b60f2a0bSfr41279 	    ((aa->value[aa->len - 1] & BIG_CHUNK_HIGHBIT) != 0)) {
7097c478bd9Sstevel@tonic-gate 		rsize = aa->len + 1;
710*b60f2a0bSfr41279 	} else {
711*b60f2a0bSfr41279 		rsize = aa->len;
712*b60f2a0bSfr41279 	}
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	if (result->size < rsize) {
7157c478bd9Sstevel@tonic-gate 		err = big_extend(result, rsize);
7167c478bd9Sstevel@tonic-gate 		if (err != BIG_OK)
7177c478bd9Sstevel@tonic-gate 			return (err);
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	a = aa->value;
7217c478bd9Sstevel@tonic-gate 	r = result->value;
722*b60f2a0bSfr41279 	if (rsize == aa->len + 1) {
723*b60f2a0bSfr41279 		r[rsize - 1] = 1;
724*b60f2a0bSfr41279 	}
7257c478bd9Sstevel@tonic-gate 	cy = 0;
7267c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
727*b60f2a0bSfr41279 		cy1 = a[i] >> (BIG_CHUNK_SIZE - 1);
7287c478bd9Sstevel@tonic-gate 		r[i] = (cy | (a[i] << 1));
7297c478bd9Sstevel@tonic-gate 		cy = cy1;
7307c478bd9Sstevel@tonic-gate 	}
7317c478bd9Sstevel@tonic-gate 	result->len = rsize;
7327c478bd9Sstevel@tonic-gate 	return (BIG_OK);
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate 
735*b60f2a0bSfr41279 
736*b60f2a0bSfr41279 /*
737*b60f2a0bSfr41279  * returns aa mod b, aa must be nonneg, b must be a max
738*b60f2a0bSfr41279  * (BIG_CHUNK_SIZE / 2)-bit integer
739*b60f2a0bSfr41279  */
740*b60f2a0bSfr41279 static uint32_t
741*b60f2a0bSfr41279 big_modhalf_pos(BIGNUM *aa, uint32_t b)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate 	int		i;
744*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	rem;
7457c478bd9Sstevel@tonic-gate 
746*b60f2a0bSfr41279 	if (aa->len == 0) {
7477c478bd9Sstevel@tonic-gate 		return (0);
748*b60f2a0bSfr41279 	}
7497c478bd9Sstevel@tonic-gate 	rem = aa->value[aa->len - 1] % b;
7507c478bd9Sstevel@tonic-gate 	for (i = aa->len - 2; i >= 0; i--) {
751*b60f2a0bSfr41279 		rem = ((rem << (BIG_CHUNK_SIZE / 2)) |
752*b60f2a0bSfr41279 		    (aa->value[i] >> (BIG_CHUNK_SIZE / 2))) % b;
753*b60f2a0bSfr41279 		rem = ((rem << (BIG_CHUNK_SIZE / 2)) |
754*b60f2a0bSfr41279 		    (aa->value[i] & BIG_CHUNK_LOWHALFBITS)) % b;
7557c478bd9Sstevel@tonic-gate 	}
756*b60f2a0bSfr41279 
757*b60f2a0bSfr41279 	return ((uint32_t)rem);
7587c478bd9Sstevel@tonic-gate }
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate /*
762*b60f2a0bSfr41279  * result = aa - (2^BIG_CHUNK_SIZE)^lendiff * bb
7637c478bd9Sstevel@tonic-gate  * result->size should be at least aa->len at entry
7647c478bd9Sstevel@tonic-gate  * aa, bb, and result should be positive
7657c478bd9Sstevel@tonic-gate  */
7667c478bd9Sstevel@tonic-gate void
7677c478bd9Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
7687c478bd9Sstevel@tonic-gate {
7697c478bd9Sstevel@tonic-gate 	int i, lendiff;
7707c478bd9Sstevel@tonic-gate 	BIGNUM res1, aa1;
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
7737c478bd9Sstevel@tonic-gate 	res1.size = result->size - lendiff;
7747c478bd9Sstevel@tonic-gate 	res1.malloced = 0;
7757c478bd9Sstevel@tonic-gate 	res1.value = result->value + lendiff;
7767c478bd9Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
7777c478bd9Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
7787c478bd9Sstevel@tonic-gate 	aa1.len = bb->len;
7797c478bd9Sstevel@tonic-gate 	aa1.sign = 1;
7807c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(&res1, &aa1, bb);
7817c478bd9Sstevel@tonic-gate 	if (result->value != aa->value) {
7827c478bd9Sstevel@tonic-gate 		for (i = 0; i < lendiff; i++) {
7837c478bd9Sstevel@tonic-gate 			result->value[i] = aa->value[i];
7847c478bd9Sstevel@tonic-gate 		}
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate 	result->len = aa->len;
7877c478bd9Sstevel@tonic-gate }
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate /*
7917c478bd9Sstevel@tonic-gate  * returns 1, 0, or -1 depending on whether |aa| > , ==, or <
792*b60f2a0bSfr41279  *					(2^BIG_CHUNK_SIZE)^lendiff * |bb|
7937c478bd9Sstevel@tonic-gate  * aa->len should be >= bb->len
7947c478bd9Sstevel@tonic-gate  */
7957c478bd9Sstevel@tonic-gate int
7967c478bd9Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb)
7977c478bd9Sstevel@tonic-gate {
7987c478bd9Sstevel@tonic-gate 	int lendiff;
7997c478bd9Sstevel@tonic-gate 	BIGNUM aa1;
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
8027c478bd9Sstevel@tonic-gate 	aa1.len = bb->len;
8037c478bd9Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
8047c478bd9Sstevel@tonic-gate 	aa1.malloced = 0;
8057c478bd9Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
8067c478bd9Sstevel@tonic-gate 	return (big_cmp_abs(&aa1, bb));
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate /*
811*b60f2a0bSfr41279  * result = aa * b where b is a max. (BIG_CHUNK_SIZE / 2)-bit positive integer.
8127c478bd9Sstevel@tonic-gate  * result should have enough space allocated.
8137c478bd9Sstevel@tonic-gate  */
814*b60f2a0bSfr41279 static void
815*b60f2a0bSfr41279 big_mulhalf_low(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b)
8167c478bd9Sstevel@tonic-gate {
8177c478bd9Sstevel@tonic-gate 	int		i;
818*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1, t2, ai, cy;
819*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *r;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	a = aa->value;
8227c478bd9Sstevel@tonic-gate 	r = result->value;
8237c478bd9Sstevel@tonic-gate 	cy = 0;
8247c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
8257c478bd9Sstevel@tonic-gate 		ai = a[i];
826*b60f2a0bSfr41279 		t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy;
827*b60f2a0bSfr41279 		t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b +
828*b60f2a0bSfr41279 		    (t1 >> (BIG_CHUNK_SIZE / 2));
829*b60f2a0bSfr41279 		r[i] = (t1 & BIG_CHUNK_LOWHALFBITS) |
830*b60f2a0bSfr41279 		    (t2 << (BIG_CHUNK_SIZE / 2));
831*b60f2a0bSfr41279 		cy = t2 >> (BIG_CHUNK_SIZE / 2);
8327c478bd9Sstevel@tonic-gate 	}
8337c478bd9Sstevel@tonic-gate 	r[i] = cy;
8347c478bd9Sstevel@tonic-gate 	result->len = aa->len + 1;
8357c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate /*
840*b60f2a0bSfr41279  * result = aa * b * 2^(BIG_CHUNK_SIZE / 2) where b is a max.
841*b60f2a0bSfr41279  * (BIG_CHUNK_SIZE / 2)-bit positive integer.
8427c478bd9Sstevel@tonic-gate  * result should have enough space allocated.
8437c478bd9Sstevel@tonic-gate  */
844*b60f2a0bSfr41279 static void
845*b60f2a0bSfr41279 big_mulhalf_high(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b)
8467c478bd9Sstevel@tonic-gate {
8477c478bd9Sstevel@tonic-gate 	int		i;
848*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1, t2, ai, cy, ri;
849*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *r;
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	a = aa->value;
8527c478bd9Sstevel@tonic-gate 	r = result->value;
8537c478bd9Sstevel@tonic-gate 	cy = 0;
8547c478bd9Sstevel@tonic-gate 	ri = 0;
8557c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
8567c478bd9Sstevel@tonic-gate 		ai = a[i];
857*b60f2a0bSfr41279 		t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy;
858*b60f2a0bSfr41279 		t2 = (ai >>  (BIG_CHUNK_SIZE / 2)) * b +
859*b60f2a0bSfr41279 		    (t1 >>  (BIG_CHUNK_SIZE / 2));
860*b60f2a0bSfr41279 		r[i] = (t1 <<  (BIG_CHUNK_SIZE / 2)) + ri;
861*b60f2a0bSfr41279 		ri = t2 & BIG_CHUNK_LOWHALFBITS;
862*b60f2a0bSfr41279 		cy = t2 >> (BIG_CHUNK_SIZE / 2);
8637c478bd9Sstevel@tonic-gate 	}
864*b60f2a0bSfr41279 	r[i] = (cy <<  (BIG_CHUNK_SIZE / 2)) + ri;
8657c478bd9Sstevel@tonic-gate 	result->len = aa->len + 1;
8667c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate 
869*b60f2a0bSfr41279 
8707c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */
8717c478bd9Sstevel@tonic-gate void
8727c478bd9Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs)
8737c478bd9Sstevel@tonic-gate {
8747c478bd9Sstevel@tonic-gate 	int		i;
875*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, ai;
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	if (offs == 0) {
8787c478bd9Sstevel@tonic-gate 		if (result != aa) {
8797c478bd9Sstevel@tonic-gate 			(void) big_copy(result, aa);
8807c478bd9Sstevel@tonic-gate 		}
8817c478bd9Sstevel@tonic-gate 		return;
8827c478bd9Sstevel@tonic-gate 	}
8837c478bd9Sstevel@tonic-gate 	cy = 0;
8847c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
8857c478bd9Sstevel@tonic-gate 		ai = aa->value[i];
8867c478bd9Sstevel@tonic-gate 		result->value[i] = (ai << offs) | cy;
887*b60f2a0bSfr41279 		cy = ai >> (BIG_CHUNK_SIZE - offs);
8887c478bd9Sstevel@tonic-gate 	}
8897c478bd9Sstevel@tonic-gate 	if (cy != 0) {
8907c478bd9Sstevel@tonic-gate 		result->len = aa->len + 1;
8917c478bd9Sstevel@tonic-gate 		result->value[result->len - 1] = cy;
8927c478bd9Sstevel@tonic-gate 	} else {
8937c478bd9Sstevel@tonic-gate 		result->len = aa->len;
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate 
898*b60f2a0bSfr41279 
8997c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */
9007c478bd9Sstevel@tonic-gate void
9017c478bd9Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs)
9027c478bd9Sstevel@tonic-gate {
9037c478bd9Sstevel@tonic-gate 	int		 i;
904*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, ai;
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	if (offs == 0) {
9077c478bd9Sstevel@tonic-gate 		if (result != aa) {
9087c478bd9Sstevel@tonic-gate 			(void) big_copy(result, aa);
9097c478bd9Sstevel@tonic-gate 		}
9107c478bd9Sstevel@tonic-gate 		return;
9117c478bd9Sstevel@tonic-gate 	}
9127c478bd9Sstevel@tonic-gate 	cy = aa->value[0] >> offs;
9137c478bd9Sstevel@tonic-gate 	for (i = 1; i < aa->len; i++) {
9147c478bd9Sstevel@tonic-gate 		ai = aa->value[i];
915*b60f2a0bSfr41279 		result->value[i-1] = (ai << (BIG_CHUNK_SIZE - offs)) | cy;
9167c478bd9Sstevel@tonic-gate 		cy = ai >> offs;
9177c478bd9Sstevel@tonic-gate 	}
9187c478bd9Sstevel@tonic-gate 	result->len = aa->len;
9197c478bd9Sstevel@tonic-gate 	result->value[result->len - 1] = cy;
9207c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate /*
9257c478bd9Sstevel@tonic-gate  * result = aa/bb   remainder = aa mod bb
9267c478bd9Sstevel@tonic-gate  * it is assumed that aa and bb are positive
9277c478bd9Sstevel@tonic-gate  */
9287c478bd9Sstevel@tonic-gate BIG_ERR_CODE
9297c478bd9Sstevel@tonic-gate big_div_pos_fast(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb)
9307c478bd9Sstevel@tonic-gate {
931*b60f2a0bSfr41279 	BIG_ERR_CODE	err = BIG_OK;
9327c478bd9Sstevel@tonic-gate 	int		i, alen, blen, tlen, rlen, offs;
933*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	higha, highb, coeff;
934*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*a, *b;
9357c478bd9Sstevel@tonic-gate 	BIGNUM		bbhigh, bblow, tresult, tmp1, tmp2;
936*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
937*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp2value[BIGTMPSIZE];
938*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tresultvalue[BIGTMPSIZE];
939*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	bblowvalue[BIGTMPSIZE];
940*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	bbhighvalue[BIGTMPSIZE];
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	a = aa->value;
9437c478bd9Sstevel@tonic-gate 	b = bb->value;
9447c478bd9Sstevel@tonic-gate 	alen = aa->len;
9457c478bd9Sstevel@tonic-gate 	blen = bb->len;
946*b60f2a0bSfr41279 	while ((alen > 1) && (a[alen - 1] == 0)) {
947*b60f2a0bSfr41279 		alen = alen - 1;
948*b60f2a0bSfr41279 	}
9497c478bd9Sstevel@tonic-gate 	aa->len = alen;
950*b60f2a0bSfr41279 	while ((blen > 1) && (b[blen - 1] == 0)) {
951*b60f2a0bSfr41279 		blen = blen - 1;
952*b60f2a0bSfr41279 	}
9537c478bd9Sstevel@tonic-gate 	bb->len = blen;
954*b60f2a0bSfr41279 	if ((blen == 1) && (b[0] == 0)) {
9557c478bd9Sstevel@tonic-gate 		return (BIG_DIV_BY_0);
956*b60f2a0bSfr41279 	}
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(aa, bb) < 0) {
9597c478bd9Sstevel@tonic-gate 		if ((remainder != NULL) &&
960*b60f2a0bSfr41279 		    ((err = big_copy(remainder, aa)) != BIG_OK)) {
9617c478bd9Sstevel@tonic-gate 			return (err);
962*b60f2a0bSfr41279 		}
9637c478bd9Sstevel@tonic-gate 		if (result != NULL) {
9647c478bd9Sstevel@tonic-gate 			result->len = 1;
9657c478bd9Sstevel@tonic-gate 			result->sign = 1;
9667c478bd9Sstevel@tonic-gate 			result->value[0] = 0;
9677c478bd9Sstevel@tonic-gate 		}
9687c478bd9Sstevel@tonic-gate 		return (BIG_OK);
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&bblow, blen + 1,
9727c478bd9Sstevel@tonic-gate 	    bblowvalue, arraysize(bblowvalue))) != BIG_OK)
9737c478bd9Sstevel@tonic-gate 		return (err);
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&bbhigh, blen + 1,
9767c478bd9Sstevel@tonic-gate 	    bbhighvalue, arraysize(bbhighvalue))) != BIG_OK)
9777c478bd9Sstevel@tonic-gate 		goto ret1;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp1, alen + 2,
9807c478bd9Sstevel@tonic-gate 	    tmp1value, arraysize(tmp1value))) != BIG_OK)
9817c478bd9Sstevel@tonic-gate 		goto ret2;
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, blen + 2,
9847c478bd9Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
9857c478bd9Sstevel@tonic-gate 		goto ret3;
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tresult, alen - blen + 2,
9887c478bd9Sstevel@tonic-gate 	    tresultvalue, arraysize(tresultvalue))) != BIG_OK)
9897c478bd9Sstevel@tonic-gate 		goto ret4;
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	offs = 0;
992*b60f2a0bSfr41279 	highb = b[blen - 1];
993*b60f2a0bSfr41279 	if (highb >= (BIG_CHUNK_HALF_HIGHBIT << 1)) {
994*b60f2a0bSfr41279 		highb = highb >> (BIG_CHUNK_SIZE / 2);
995*b60f2a0bSfr41279 		offs = (BIG_CHUNK_SIZE / 2);
9967c478bd9Sstevel@tonic-gate 	}
997*b60f2a0bSfr41279 	while ((highb & BIG_CHUNK_HALF_HIGHBIT) == 0) {
998*b60f2a0bSfr41279 		highb = highb << 1;
9997c478bd9Sstevel@tonic-gate 		offs++;
10007c478bd9Sstevel@tonic-gate 	}
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	big_shiftleft(&bblow, bb, offs);
1003*b60f2a0bSfr41279 
1004*b60f2a0bSfr41279 	if (offs <= (BIG_CHUNK_SIZE / 2 - 1)) {
1005*b60f2a0bSfr41279 		big_shiftleft(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2);
10067c478bd9Sstevel@tonic-gate 	} else {
1007*b60f2a0bSfr41279 		big_shiftright(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2);
10087c478bd9Sstevel@tonic-gate 	}
10097c478bd9Sstevel@tonic-gate 	if (bbhigh.value[bbhigh.len - 1] == 0) {
10107c478bd9Sstevel@tonic-gate 		bbhigh.len--;
10117c478bd9Sstevel@tonic-gate 	} else {
10127c478bd9Sstevel@tonic-gate 		bbhigh.value[bbhigh.len] = 0;
10137c478bd9Sstevel@tonic-gate 	}
10147c478bd9Sstevel@tonic-gate 
1015*b60f2a0bSfr41279 	highb = bblow.value[bblow.len - 1];
1016*b60f2a0bSfr41279 
10177c478bd9Sstevel@tonic-gate 	big_shiftleft(&tmp1, aa, offs);
10187c478bd9Sstevel@tonic-gate 	rlen = tmp1.len - bblow.len + 1;
10197c478bd9Sstevel@tonic-gate 	tresult.len = rlen;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	tmp1.len++;
10227c478bd9Sstevel@tonic-gate 	tlen = tmp1.len;
10237c478bd9Sstevel@tonic-gate 	tmp1.value[tmp1.len - 1] = 0;
10247c478bd9Sstevel@tonic-gate 	for (i = 0; i < rlen; i++) {
1025*b60f2a0bSfr41279 		higha = (tmp1.value[tlen - 1] << (BIG_CHUNK_SIZE / 2)) +
1026*b60f2a0bSfr41279 		    (tmp1.value[tlen - 2] >> (BIG_CHUNK_SIZE / 2));
10277c478bd9Sstevel@tonic-gate 		coeff = higha / (highb + 1);
1028*b60f2a0bSfr41279 		big_mulhalf_high(&tmp2, &bblow, coeff);
10297c478bd9Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
10307c478bd9Sstevel@tonic-gate 		bbhigh.len++;
10317c478bd9Sstevel@tonic-gate 		while (tmp1.value[tlen - 1] > 0) {
10327c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
10337c478bd9Sstevel@tonic-gate 			coeff++;
10347c478bd9Sstevel@tonic-gate 		}
10357c478bd9Sstevel@tonic-gate 		bbhigh.len--;
10367c478bd9Sstevel@tonic-gate 		tlen--;
10377c478bd9Sstevel@tonic-gate 		tmp1.len--;
10387c478bd9Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) {
10397c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
10407c478bd9Sstevel@tonic-gate 			coeff++;
10417c478bd9Sstevel@tonic-gate 		}
1042*b60f2a0bSfr41279 		tresult.value[rlen - i - 1] = coeff << (BIG_CHUNK_SIZE / 2);
10437c478bd9Sstevel@tonic-gate 		higha = tmp1.value[tlen - 1];
10447c478bd9Sstevel@tonic-gate 		coeff = higha / (highb + 1);
1045*b60f2a0bSfr41279 		big_mulhalf_low(&tmp2, &bblow, coeff);
10467c478bd9Sstevel@tonic-gate 		tmp2.len--;
10477c478bd9Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
10487c478bd9Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bblow) >= 0) {
10497c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bblow);
10507c478bd9Sstevel@tonic-gate 			coeff++;
10517c478bd9Sstevel@tonic-gate 		}
10527c478bd9Sstevel@tonic-gate 		tresult.value[rlen - i - 1] =
10537c478bd9Sstevel@tonic-gate 		    tresult.value[rlen - i - 1] + coeff;
10547c478bd9Sstevel@tonic-gate 	}
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	big_shiftright(&tmp1, &tmp1, offs);
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	err = BIG_OK;
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	if ((remainder != NULL) &&
10617c478bd9Sstevel@tonic-gate 	    ((err = big_copy(remainder, &tmp1)) != BIG_OK))
10627c478bd9Sstevel@tonic-gate 		goto ret;
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 	if (result != NULL)
10657c478bd9Sstevel@tonic-gate 		err = big_copy(result, &tresult);
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate ret:
10687c478bd9Sstevel@tonic-gate 	big_finish(&tresult);
10697c478bd9Sstevel@tonic-gate ret4:
10707c478bd9Sstevel@tonic-gate 	big_finish(&tmp1);
10717c478bd9Sstevel@tonic-gate ret3:
10727c478bd9Sstevel@tonic-gate 	big_finish(&tmp2);
10737c478bd9Sstevel@tonic-gate ret2:
10747c478bd9Sstevel@tonic-gate 	big_finish(&bbhigh);
10757c478bd9Sstevel@tonic-gate ret1:
10767c478bd9Sstevel@tonic-gate 	big_finish(&bblow);
10777c478bd9Sstevel@tonic-gate 	return (err);
10787c478bd9Sstevel@tonic-gate }
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate /*
10817c478bd9Sstevel@tonic-gate  * If there is no processor-specific integer implementation of
10827c478bd9Sstevel@tonic-gate  * the lower level multiply functions, then this code is provided
10837c478bd9Sstevel@tonic-gate  * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and
10847c478bd9Sstevel@tonic-gate  * big_sqr_vec().
10857c478bd9Sstevel@tonic-gate  *
10867c478bd9Sstevel@tonic-gate  * There are two generic implementations.  One that assumes that
10877c478bd9Sstevel@tonic-gate  * there is hardware and C compiler support for a 32 x 32 --> 64
10887c478bd9Sstevel@tonic-gate  * bit unsigned multiply, but otherwise is not specific to any
10897c478bd9Sstevel@tonic-gate  * processor, platform, or ISA.
10907c478bd9Sstevel@tonic-gate  *
10917c478bd9Sstevel@tonic-gate  * The other makes very few assumptions about hardware capabilities.
10927c478bd9Sstevel@tonic-gate  * It does not even assume that there is any implementation of a
10937c478bd9Sstevel@tonic-gate  * 32 x 32 --> 64 bit multiply that is accessible to C code and
10947c478bd9Sstevel@tonic-gate  * appropriate to use.  It falls constructs 32 x 32 --> 64 bit
10957c478bd9Sstevel@tonic-gate  * multiplies from 16 x 16 --> 32 bit multiplies.
10967c478bd9Sstevel@tonic-gate  *
10977c478bd9Sstevel@tonic-gate  */
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate #if !defined(PSR_MUL)
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate #ifdef UMUL64
11027c478bd9Sstevel@tonic-gate 
1103*b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
1104*b60f2a0bSfr41279 
11057c478bd9Sstevel@tonic-gate #define	UNROLL8
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_PREFETCH(R) \
11087c478bd9Sstevel@tonic-gate 	p = pf * d; \
11097c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[R+1]; \
11107c478bd9Sstevel@tonic-gate 	t = p + cy; \
11117c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11127c478bd9Sstevel@tonic-gate 	cy = t >> 32
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_NOPREFETCH(R) \
11157c478bd9Sstevel@tonic-gate 	p = pf * d; \
11167c478bd9Sstevel@tonic-gate 	t = p + cy; \
11177c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11187c478bd9Sstevel@tonic-gate 	cy = t >> 32
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_PREFETCH(R) \
11217c478bd9Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
11227c478bd9Sstevel@tonic-gate 	p = pf * d; \
11237c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[R+1]; \
11247c478bd9Sstevel@tonic-gate 	t = p + t + cy; \
11257c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11267c478bd9Sstevel@tonic-gate 	cy = t >> 32
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_NOPREFETCH(R) \
11297c478bd9Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
11307c478bd9Sstevel@tonic-gate 	p = pf * d; \
11317c478bd9Sstevel@tonic-gate 	t = p + t + cy; \
11327c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
11337c478bd9Sstevel@tonic-gate 	cy = t >> 32
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate #ifdef UNROLL8
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate #define	UNROLL 8
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate /*
11407c478bd9Sstevel@tonic-gate  * r = a * b
11417c478bd9Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
11427c478bd9Sstevel@tonic-gate  */
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate uint32_t
11457c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
11467c478bd9Sstevel@tonic-gate {
11477c478bd9Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	if (len == 0)
11507c478bd9Sstevel@tonic-gate 		return (0);
11517c478bd9Sstevel@tonic-gate 	cy = 0;
11527c478bd9Sstevel@tonic-gate 	d = (uint64_t)b;
11537c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[0];
11547c478bd9Sstevel@tonic-gate 	while (len > UNROLL) {
11557c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
11567c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
11577c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
11587c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
11597c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
11607c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
11617c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
11627c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(7);
11637c478bd9Sstevel@tonic-gate 		r += UNROLL;
11647c478bd9Sstevel@tonic-gate 		a += UNROLL;
11657c478bd9Sstevel@tonic-gate 		len -= UNROLL;
11667c478bd9Sstevel@tonic-gate 	}
11677c478bd9Sstevel@tonic-gate 	if (len == UNROLL) {
11687c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
11697c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
11707c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
11717c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
11727c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
11737c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
11747c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
11757c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(7);
11767c478bd9Sstevel@tonic-gate 		return ((uint32_t)cy);
11777c478bd9Sstevel@tonic-gate 	}
11787c478bd9Sstevel@tonic-gate 	while (len > 1) {
11797c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
11807c478bd9Sstevel@tonic-gate 		++r;
11817c478bd9Sstevel@tonic-gate 		++a;
11827c478bd9Sstevel@tonic-gate 		--len;
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate 	if (len > 0) {
11857c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(0);
11867c478bd9Sstevel@tonic-gate 	}
11877c478bd9Sstevel@tonic-gate 	return ((uint32_t)cy);
11887c478bd9Sstevel@tonic-gate }
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate /*
11917c478bd9Sstevel@tonic-gate  * r += a * b
11927c478bd9Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
11937c478bd9Sstevel@tonic-gate  */
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate uint32_t
11967c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
11977c478bd9Sstevel@tonic-gate {
11987c478bd9Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate 	if (len == 0)
12017c478bd9Sstevel@tonic-gate 		return (0);
12027c478bd9Sstevel@tonic-gate 	cy = 0;
12037c478bd9Sstevel@tonic-gate 	d = (uint64_t)b;
12047c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[0];
12057c478bd9Sstevel@tonic-gate 	while (len > 8) {
12067c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12077c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
12087c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
12097c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
12107c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
12117c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
12127c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
12137c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(7);
12147c478bd9Sstevel@tonic-gate 		r += 8;
12157c478bd9Sstevel@tonic-gate 		a += 8;
12167c478bd9Sstevel@tonic-gate 		len -= 8;
12177c478bd9Sstevel@tonic-gate 	}
12187c478bd9Sstevel@tonic-gate 	if (len == 8) {
12197c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12207c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
12217c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
12227c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
12237c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
12247c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
12257c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
12267c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(7);
12277c478bd9Sstevel@tonic-gate 		return ((uint32_t)cy);
12287c478bd9Sstevel@tonic-gate 	}
12297c478bd9Sstevel@tonic-gate 	while (len > 1) {
12307c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
12317c478bd9Sstevel@tonic-gate 		++r;
12327c478bd9Sstevel@tonic-gate 		++a;
12337c478bd9Sstevel@tonic-gate 		--len;
12347c478bd9Sstevel@tonic-gate 	}
12357c478bd9Sstevel@tonic-gate 	if (len > 0) {
12367c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(0);
12377c478bd9Sstevel@tonic-gate 	}
12387c478bd9Sstevel@tonic-gate 	return ((uint32_t)cy);
12397c478bd9Sstevel@tonic-gate }
12407c478bd9Sstevel@tonic-gate #endif /* UNROLL8 */
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate void
12437c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
12447c478bd9Sstevel@tonic-gate {
12457c478bd9Sstevel@tonic-gate 	uint32_t *tr, *ta;
12467c478bd9Sstevel@tonic-gate 	int tlen, row, col;
12477c478bd9Sstevel@tonic-gate 	uint64_t p, s, t, t2, cy;
12487c478bd9Sstevel@tonic-gate 	uint32_t d;
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 	tr = r + 1;
12517c478bd9Sstevel@tonic-gate 	ta = a;
12527c478bd9Sstevel@tonic-gate 	tlen = len - 1;
12537c478bd9Sstevel@tonic-gate 	tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]);
12547c478bd9Sstevel@tonic-gate 	while (--tlen > 0) {
12557c478bd9Sstevel@tonic-gate 		tr += 2;
12567c478bd9Sstevel@tonic-gate 		++ta;
12577c478bd9Sstevel@tonic-gate 		tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]);
12587c478bd9Sstevel@tonic-gate 	}
12597c478bd9Sstevel@tonic-gate 	s = (uint64_t)a[0];
12607c478bd9Sstevel@tonic-gate 	s = s * s;
12617c478bd9Sstevel@tonic-gate 	r[0] = (uint32_t)s;
12627c478bd9Sstevel@tonic-gate 	cy = s >> 32;
12637c478bd9Sstevel@tonic-gate 	p = ((uint64_t)r[1] << 1) + cy;
12647c478bd9Sstevel@tonic-gate 	r[1] = (uint32_t)p;
12657c478bd9Sstevel@tonic-gate 	cy = p >> 32;
12667c478bd9Sstevel@tonic-gate 	row = 1;
12677c478bd9Sstevel@tonic-gate 	col = 2;
12687c478bd9Sstevel@tonic-gate 	while (row < len) {
12697c478bd9Sstevel@tonic-gate 		s = (uint64_t)a[row];
12707c478bd9Sstevel@tonic-gate 		s = s * s;
12717c478bd9Sstevel@tonic-gate 		p = (uint64_t)r[col] << 1;
12727c478bd9Sstevel@tonic-gate 		t = p + s;
12737c478bd9Sstevel@tonic-gate 		d = (uint32_t)t;
12747c478bd9Sstevel@tonic-gate 		t2 = (uint64_t)d + cy;
12757c478bd9Sstevel@tonic-gate 		r[col] = (uint32_t)t2;
12767c478bd9Sstevel@tonic-gate 		cy = (t >> 32) + (t2 >> 32);
12777c478bd9Sstevel@tonic-gate 		if (row == len - 1)
12787c478bd9Sstevel@tonic-gate 			break;
12797c478bd9Sstevel@tonic-gate 		p = ((uint64_t)r[col+1] << 1) + cy;
12807c478bd9Sstevel@tonic-gate 		r[col+1] = (uint32_t)p;
12817c478bd9Sstevel@tonic-gate 		cy = p >> 32;
12827c478bd9Sstevel@tonic-gate 		++row;
12837c478bd9Sstevel@tonic-gate 		col += 2;
12847c478bd9Sstevel@tonic-gate 	}
12857c478bd9Sstevel@tonic-gate 	r[col+1] = (uint32_t)cy;
12867c478bd9Sstevel@tonic-gate }
12877c478bd9Sstevel@tonic-gate 
1288*b60f2a0bSfr41279 #else /* BIG_CHUNK_SIZE == 64 */
1289*b60f2a0bSfr41279 
1290*b60f2a0bSfr41279 /*
1291*b60f2a0bSfr41279  * r = r + a * digit, r and a are vectors of length len
1292*b60f2a0bSfr41279  * returns the carry digit
1293*b60f2a0bSfr41279  */
1294*b60f2a0bSfr41279 BIG_CHUNK_TYPE
1295*b60f2a0bSfr41279 big_mul_add_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len,
1296*b60f2a0bSfr41279     BIG_CHUNK_TYPE digit)
1297*b60f2a0bSfr41279 {
1298*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	cy, cy1, retcy, dlow, dhigh;
1299*b60f2a0bSfr41279 	int		i;
1300*b60f2a0bSfr41279 
1301*b60f2a0bSfr41279 	cy1 = 0;
1302*b60f2a0bSfr41279 	dlow = digit & BIG_CHUNK_LOWHALFBITS;
1303*b60f2a0bSfr41279 	dhigh = digit >> (BIG_CHUNK_SIZE / 2);
1304*b60f2a0bSfr41279 	for (i = 0; i < len; i++) {
1305*b60f2a0bSfr41279 		cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
1306*b60f2a0bSfr41279 		    dlow * (a[i] & BIG_CHUNK_LOWHALFBITS) +
1307*b60f2a0bSfr41279 		    (r[i] & BIG_CHUNK_LOWHALFBITS);
1308*b60f2a0bSfr41279 		cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) +
1309*b60f2a0bSfr41279 		    dlow * (a[i] >> (BIG_CHUNK_SIZE / 2)) +
1310*b60f2a0bSfr41279 		    (r[i] >> (BIG_CHUNK_SIZE / 2));
1311*b60f2a0bSfr41279 		r[i] = (cy & BIG_CHUNK_LOWHALFBITS) |
1312*b60f2a0bSfr41279 		    (cy1 << (BIG_CHUNK_SIZE / 2));
1313*b60f2a0bSfr41279 	}
1314*b60f2a0bSfr41279 	retcy = cy1 >> (BIG_CHUNK_SIZE / 2);
1315*b60f2a0bSfr41279 
1316*b60f2a0bSfr41279 	cy1 = r[0] & BIG_CHUNK_LOWHALFBITS;
1317*b60f2a0bSfr41279 	for (i = 0; i < len - 1; i++) {
1318*b60f2a0bSfr41279 		cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
1319*b60f2a0bSfr41279 		    dhigh * (a[i] & BIG_CHUNK_LOWHALFBITS) +
1320*b60f2a0bSfr41279 		    (r[i] >> (BIG_CHUNK_SIZE / 2));
1321*b60f2a0bSfr41279 		r[i] = (cy1 & BIG_CHUNK_LOWHALFBITS) |
1322*b60f2a0bSfr41279 		    (cy << (BIG_CHUNK_SIZE / 2));
1323*b60f2a0bSfr41279 		cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) +
1324*b60f2a0bSfr41279 		    dhigh * (a[i] >> (BIG_CHUNK_SIZE / 2)) +
1325*b60f2a0bSfr41279 		    (r[i + 1] & BIG_CHUNK_LOWHALFBITS);
1326*b60f2a0bSfr41279 	}
1327*b60f2a0bSfr41279 	cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) +
1328*b60f2a0bSfr41279 	    dhigh * (a[len - 1] & BIG_CHUNK_LOWHALFBITS) +
1329*b60f2a0bSfr41279 	    (r[len - 1] >> (BIG_CHUNK_SIZE / 2));
1330*b60f2a0bSfr41279 	r[len - 1] = (cy1 & BIG_CHUNK_LOWHALFBITS) |
1331*b60f2a0bSfr41279 	    (cy << (BIG_CHUNK_SIZE / 2));
1332*b60f2a0bSfr41279 	retcy = (cy >> (BIG_CHUNK_SIZE / 2)) +
1333*b60f2a0bSfr41279 	    dhigh * (a[len - 1] >> (BIG_CHUNK_SIZE / 2)) + retcy;
1334*b60f2a0bSfr41279 
1335*b60f2a0bSfr41279 	return (retcy);
1336*b60f2a0bSfr41279 }
1337*b60f2a0bSfr41279 
1338*b60f2a0bSfr41279 
1339*b60f2a0bSfr41279 /*
1340*b60f2a0bSfr41279  * r = a * digit, r and a are vectors of length len
1341*b60f2a0bSfr41279  * returns the carry digit
1342*b60f2a0bSfr41279  */
1343*b60f2a0bSfr41279 BIG_CHUNK_TYPE
1344*b60f2a0bSfr41279 big_mul_set_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len,
1345*b60f2a0bSfr41279     BIG_CHUNK_TYPE digit)
1346*b60f2a0bSfr41279 {
1347*b60f2a0bSfr41279 	int	i;
1348*b60f2a0bSfr41279 
1349*b60f2a0bSfr41279 	ASSERT(r != a);
1350*b60f2a0bSfr41279 	for (i = 0; i < len; i++) {
1351*b60f2a0bSfr41279 		r[i] = 0;
1352*b60f2a0bSfr41279 	}
1353*b60f2a0bSfr41279 	return (big_mul_add_vec(r, a, len, digit));
1354*b60f2a0bSfr41279 }
1355*b60f2a0bSfr41279 
1356*b60f2a0bSfr41279 void
1357*b60f2a0bSfr41279 big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len)
1358*b60f2a0bSfr41279 {
1359*b60f2a0bSfr41279 	int i;
1360*b60f2a0bSfr41279 
1361*b60f2a0bSfr41279 	ASSERT(r != a);
1362*b60f2a0bSfr41279 	r[len] = big_mul_set_vec(r, a, len, a[0]);
1363*b60f2a0bSfr41279 	for (i = 1; i < len; ++i)
1364*b60f2a0bSfr41279 		r[len + i] = big_mul_add_vec(r+i, a, len, a[i]);
1365*b60f2a0bSfr41279 }
1366*b60f2a0bSfr41279 
1367*b60f2a0bSfr41279 #endif /* BIG_CHUNK_SIZE == 32/64 */
1368*b60f2a0bSfr41279 
13697c478bd9Sstevel@tonic-gate #else /* ! UMUL64 */
13707c478bd9Sstevel@tonic-gate 
1371*b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE != 32)
1372*b60f2a0bSfr41279 #error Don't use 64-bit chunks without defining UMUL64
1373*b60f2a0bSfr41279 #endif
1374*b60f2a0bSfr41279 
1375*b60f2a0bSfr41279 
13767c478bd9Sstevel@tonic-gate /*
13777c478bd9Sstevel@tonic-gate  * r = r + a * digit, r and a are vectors of length len
13787c478bd9Sstevel@tonic-gate  * returns the carry digit
13797c478bd9Sstevel@tonic-gate  */
13807c478bd9Sstevel@tonic-gate uint32_t
13817c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
13827c478bd9Sstevel@tonic-gate {
13837c478bd9Sstevel@tonic-gate 	uint32_t cy, cy1, retcy, dlow, dhigh;
13847c478bd9Sstevel@tonic-gate 	int i;
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	cy1 = 0;
13877c478bd9Sstevel@tonic-gate 	dlow = digit & 0xffff;
13887c478bd9Sstevel@tonic-gate 	dhigh = digit >> 16;
13897c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
13907c478bd9Sstevel@tonic-gate 		cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff);
13917c478bd9Sstevel@tonic-gate 		cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16);
13927c478bd9Sstevel@tonic-gate 		r[i] = (cy & 0xffff) | (cy1 << 16);
13937c478bd9Sstevel@tonic-gate 	}
13947c478bd9Sstevel@tonic-gate 	retcy = cy1 >> 16;
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 	cy1 = r[0] & 0xffff;
13977c478bd9Sstevel@tonic-gate 	for (i = 0; i < len - 1; i++) {
13987c478bd9Sstevel@tonic-gate 		cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16);
13997c478bd9Sstevel@tonic-gate 		r[i] = (cy1 & 0xffff) | (cy << 16);
14007c478bd9Sstevel@tonic-gate 		cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff);
14017c478bd9Sstevel@tonic-gate 	}
14027c478bd9Sstevel@tonic-gate 	cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16);
14037c478bd9Sstevel@tonic-gate 	r[len - 1] = (cy1 & 0xffff) | (cy << 16);
14047c478bd9Sstevel@tonic-gate 	retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy;
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 	return (retcy);
14077c478bd9Sstevel@tonic-gate }
14087c478bd9Sstevel@tonic-gate 
1409*b60f2a0bSfr41279 
14107c478bd9Sstevel@tonic-gate /*
14117c478bd9Sstevel@tonic-gate  * r = a * digit, r and a are vectors of length len
14127c478bd9Sstevel@tonic-gate  * returns the carry digit
14137c478bd9Sstevel@tonic-gate  */
14147c478bd9Sstevel@tonic-gate uint32_t
14157c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
14167c478bd9Sstevel@tonic-gate {
1417*b60f2a0bSfr41279 	int	i;
1418*b60f2a0bSfr41279 
1419*b60f2a0bSfr41279 	ASSERT(r != a);
1420*b60f2a0bSfr41279 	for (i = 0; i < len; i++) {
1421*b60f2a0bSfr41279 		r[i] = 0;
1422*b60f2a0bSfr41279 	}
1423*b60f2a0bSfr41279 
14247c478bd9Sstevel@tonic-gate 	return (big_mul_add_vec(r, a, len, digit));
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate void
14287c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
14297c478bd9Sstevel@tonic-gate {
14307c478bd9Sstevel@tonic-gate 	int i;
14317c478bd9Sstevel@tonic-gate 
1432*b60f2a0bSfr41279 	ASSERT(r != a);
14337c478bd9Sstevel@tonic-gate 	r[len] = big_mul_set_vec(r, a, len, a[0]);
14347c478bd9Sstevel@tonic-gate 	for (i = 1; i < len; ++i)
14357c478bd9Sstevel@tonic-gate 		r[len + i] = big_mul_add_vec(r+i, a, len, a[i]);
14367c478bd9Sstevel@tonic-gate }
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate #endif /* UMUL64 */
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate void
1441*b60f2a0bSfr41279 big_mul_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int alen,
1442*b60f2a0bSfr41279     BIG_CHUNK_TYPE *b, int blen)
14437c478bd9Sstevel@tonic-gate {
14447c478bd9Sstevel@tonic-gate 	int i;
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 	r[alen] = big_mul_set_vec(r, a, alen, b[0]);
14477c478bd9Sstevel@tonic-gate 	for (i = 1; i < blen; ++i)
14487c478bd9Sstevel@tonic-gate 		r[alen + i] = big_mul_add_vec(r+i, a, alen, b[i]);
14497c478bd9Sstevel@tonic-gate }
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate #endif /* ! PSR_MUL */
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate /*
14567c478bd9Sstevel@tonic-gate  * result = aa * bb  result->value should be big enough to hold the result
14577c478bd9Sstevel@tonic-gate  *
14587c478bd9Sstevel@tonic-gate  * Implementation: Standard grammar school algorithm
14597c478bd9Sstevel@tonic-gate  *
14607c478bd9Sstevel@tonic-gate  */
14617c478bd9Sstevel@tonic-gate BIG_ERR_CODE
14627c478bd9Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
14637c478bd9Sstevel@tonic-gate {
14647c478bd9Sstevel@tonic-gate 	BIGNUM		tmp1;
1465*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
1466*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*r, *t, *a, *b;
14677c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
14687c478bd9Sstevel@tonic-gate 	int		i, alen, blen, rsize, sign, diff;
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	if (aa == bb) {
14717c478bd9Sstevel@tonic-gate 		diff = 0;
14727c478bd9Sstevel@tonic-gate 	} else {
14737c478bd9Sstevel@tonic-gate 		diff = big_cmp_abs(aa, bb);
14747c478bd9Sstevel@tonic-gate 		if (diff < 0) {
14757c478bd9Sstevel@tonic-gate 			BIGNUM *tt;
14767c478bd9Sstevel@tonic-gate 			tt = aa;
14777c478bd9Sstevel@tonic-gate 			aa = bb;
14787c478bd9Sstevel@tonic-gate 			bb = tt;
14797c478bd9Sstevel@tonic-gate 		}
14807c478bd9Sstevel@tonic-gate 	}
14817c478bd9Sstevel@tonic-gate 	a = aa->value;
14827c478bd9Sstevel@tonic-gate 	b = bb->value;
14837c478bd9Sstevel@tonic-gate 	alen = aa->len;
14847c478bd9Sstevel@tonic-gate 	blen = bb->len;
1485*b60f2a0bSfr41279 	while ((alen > 1) && (a[alen - 1] == 0)) {
1486*b60f2a0bSfr41279 		alen--;
1487*b60f2a0bSfr41279 	}
14887c478bd9Sstevel@tonic-gate 	aa->len = alen;
1489*b60f2a0bSfr41279 	while ((blen > 1) && (b[blen - 1] == 0)) {
1490*b60f2a0bSfr41279 		blen--;
1491*b60f2a0bSfr41279 	}
14927c478bd9Sstevel@tonic-gate 	bb->len = blen;
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 	rsize = alen + blen;
14957c478bd9Sstevel@tonic-gate 	if (result->size < rsize) {
14967c478bd9Sstevel@tonic-gate 		err = big_extend(result, rsize);
1497*b60f2a0bSfr41279 		if (err != BIG_OK) {
14987c478bd9Sstevel@tonic-gate 			return (err);
1499*b60f2a0bSfr41279 		}
15007c478bd9Sstevel@tonic-gate 		/* aa or bb might be an alias to result */
15017c478bd9Sstevel@tonic-gate 		a = aa->value;
15027c478bd9Sstevel@tonic-gate 		b = bb->value;
15037c478bd9Sstevel@tonic-gate 	}
15047c478bd9Sstevel@tonic-gate 	r = result->value;
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 	if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) {
15077c478bd9Sstevel@tonic-gate 		result->len = 1;
15087c478bd9Sstevel@tonic-gate 		result->sign = 1;
15097c478bd9Sstevel@tonic-gate 		r[0] = 0;
15107c478bd9Sstevel@tonic-gate 		return (BIG_OK);
15117c478bd9Sstevel@tonic-gate 	}
15127c478bd9Sstevel@tonic-gate 	sign = aa->sign * bb->sign;
15137c478bd9Sstevel@tonic-gate 	if ((alen == 1) && (a[0] == 1)) {
1514*b60f2a0bSfr41279 		for (i = 0; i < blen; i++) {
1515*b60f2a0bSfr41279 			r[i] = b[i];
1516*b60f2a0bSfr41279 		}
15177c478bd9Sstevel@tonic-gate 		result->len = blen;
15187c478bd9Sstevel@tonic-gate 		result->sign = sign;
15197c478bd9Sstevel@tonic-gate 		return (BIG_OK);
15207c478bd9Sstevel@tonic-gate 	}
15217c478bd9Sstevel@tonic-gate 	if ((blen == 1) && (b[0] == 1)) {
1522*b60f2a0bSfr41279 		for (i = 0; i < alen; i++) {
1523*b60f2a0bSfr41279 			r[i] = a[i];
1524*b60f2a0bSfr41279 		}
15257c478bd9Sstevel@tonic-gate 		result->len = alen;
15267c478bd9Sstevel@tonic-gate 		result->sign = sign;
15277c478bd9Sstevel@tonic-gate 		return (BIG_OK);
15287c478bd9Sstevel@tonic-gate 	}
15297c478bd9Sstevel@tonic-gate 
1530*b60f2a0bSfr41279 	if ((err = big_init1(&tmp1, rsize,
1531*b60f2a0bSfr41279 	    tmp1value, arraysize(tmp1value))) != BIG_OK) {
15327c478bd9Sstevel@tonic-gate 		return (err);
1533*b60f2a0bSfr41279 	}
1534*b60f2a0bSfr41279 	(void) big_copy(&tmp1, aa);
15357c478bd9Sstevel@tonic-gate 	t = tmp1.value;
15367c478bd9Sstevel@tonic-gate 
1537*b60f2a0bSfr41279 	for (i = 0; i < rsize; i++) {
1538*b60f2a0bSfr41279 		t[i] = 0;
1539*b60f2a0bSfr41279 	}
1540*b60f2a0bSfr41279 
1541*b60f2a0bSfr41279 	if (diff == 0 && alen > 2) {
15427c478bd9Sstevel@tonic-gate 		BIG_SQR_VEC(t, a, alen);
1543*b60f2a0bSfr41279 	} else if (blen > 0) {
15447c478bd9Sstevel@tonic-gate 		BIG_MUL_VEC(t, a, alen, b, blen);
1545*b60f2a0bSfr41279 	}
15467c478bd9Sstevel@tonic-gate 
1547*b60f2a0bSfr41279 	if (t[rsize - 1] == 0) {
1548*b60f2a0bSfr41279 		tmp1.len = rsize - 1;
1549*b60f2a0bSfr41279 	} else {
1550*b60f2a0bSfr41279 		tmp1.len = rsize;
1551*b60f2a0bSfr41279 	}
1552*b60f2a0bSfr41279 	if ((err = big_copy(result, &tmp1)) != BIG_OK) {
1553*b60f2a0bSfr41279 		return (err);
1554*b60f2a0bSfr41279 	}
15557c478bd9Sstevel@tonic-gate 	result->sign = sign;
15567c478bd9Sstevel@tonic-gate 
1557*b60f2a0bSfr41279 	big_finish(&tmp1);
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate 	return (BIG_OK);
15607c478bd9Sstevel@tonic-gate }
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate /*
15647c478bd9Sstevel@tonic-gate  * caller must ensure that  a < n,  b < n  and  ret->size >=  2 * n->len + 1
15657c478bd9Sstevel@tonic-gate  * and that ret is not n
15667c478bd9Sstevel@tonic-gate  */
15677c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1568*b60f2a0bSfr41279 big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, BIG_CHUNK_TYPE n0)
15697c478bd9Sstevel@tonic-gate {
15707c478bd9Sstevel@tonic-gate 	int	i, j, nlen, needsubtract;
1571*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	*nn, *rr;
1572*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	digit, c;
15737c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 	nlen = n->len;
15767c478bd9Sstevel@tonic-gate 	nn = n->value;
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 	rr = ret->value;
15797c478bd9Sstevel@tonic-gate 
1580*b60f2a0bSfr41279 	if ((err = big_mul(ret, a, b)) != BIG_OK) {
15817c478bd9Sstevel@tonic-gate 		return (err);
1582*b60f2a0bSfr41279 	}
15837c478bd9Sstevel@tonic-gate 
15847c478bd9Sstevel@tonic-gate 	rr = ret->value;
1585*b60f2a0bSfr41279 	for (i = ret->len; i < 2 * nlen + 1; i++) {
1586*b60f2a0bSfr41279 		rr[i] = 0;
1587*b60f2a0bSfr41279 	}
15887c478bd9Sstevel@tonic-gate 	for (i = 0; i < nlen; i++) {
15897c478bd9Sstevel@tonic-gate 		digit = rr[i];
15907c478bd9Sstevel@tonic-gate 		digit = digit * n0;
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 		c = BIG_MUL_ADD_VEC(rr + i, nn, nlen, digit);
15937c478bd9Sstevel@tonic-gate 		j = i + nlen;
15947c478bd9Sstevel@tonic-gate 		rr[j] += c;
15957c478bd9Sstevel@tonic-gate 		while (rr[j] < c) {
15967c478bd9Sstevel@tonic-gate 			rr[j + 1] += 1;
15977c478bd9Sstevel@tonic-gate 			j++;
15987c478bd9Sstevel@tonic-gate 			c = 1;
15997c478bd9Sstevel@tonic-gate 		}
16007c478bd9Sstevel@tonic-gate 	}
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	needsubtract = 0;
16037c478bd9Sstevel@tonic-gate 	if ((rr[2 * nlen]  != 0))
16047c478bd9Sstevel@tonic-gate 		needsubtract = 1;
16057c478bd9Sstevel@tonic-gate 	else {
16067c478bd9Sstevel@tonic-gate 		for (i = 2 * nlen - 1; i >= nlen; i--) {
16077c478bd9Sstevel@tonic-gate 			if (rr[i] > nn[i - nlen]) {
16087c478bd9Sstevel@tonic-gate 				needsubtract = 1;
16097c478bd9Sstevel@tonic-gate 				break;
1610*b60f2a0bSfr41279 			} else if (rr[i] < nn[i - nlen]) {
1611*b60f2a0bSfr41279 				break;
1612*b60f2a0bSfr41279 			}
16137c478bd9Sstevel@tonic-gate 		}
16147c478bd9Sstevel@tonic-gate 	}
16157c478bd9Sstevel@tonic-gate 	if (needsubtract)
16167c478bd9Sstevel@tonic-gate 		big_sub_vec(rr, rr + nlen, nn, nlen);
16177c478bd9Sstevel@tonic-gate 	else {
1618*b60f2a0bSfr41279 		for (i = 0; i < nlen; i++) {
16197c478bd9Sstevel@tonic-gate 			rr[i] = rr[i + nlen];
16207c478bd9Sstevel@tonic-gate 		}
1621*b60f2a0bSfr41279 	}
1622*b60f2a0bSfr41279 	for (i = nlen - 1; (i >= 0) && (rr[i] == 0); i--)
1623*b60f2a0bSfr41279 		;
16247c478bd9Sstevel@tonic-gate 	ret->len = i+1;
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	return (BIG_OK);
16277c478bd9Sstevel@tonic-gate }
16287c478bd9Sstevel@tonic-gate 
1629*b60f2a0bSfr41279 
1630*b60f2a0bSfr41279 BIG_CHUNK_TYPE
1631*b60f2a0bSfr41279 big_n0(BIG_CHUNK_TYPE n)
16327c478bd9Sstevel@tonic-gate {
16337c478bd9Sstevel@tonic-gate 	int		i;
1634*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	result, tmp;
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 	result = 0;
1637*b60f2a0bSfr41279 	tmp = BIG_CHUNK_ALLBITS;
1638*b60f2a0bSfr41279 	for (i = 0; i < BIG_CHUNK_SIZE; i++) {
16397c478bd9Sstevel@tonic-gate 		if ((tmp & 1) == 1) {
1640*b60f2a0bSfr41279 			result = (result >> 1) | BIG_CHUNK_HIGHBIT;
16417c478bd9Sstevel@tonic-gate 			tmp = tmp - n;
1642*b60f2a0bSfr41279 		} else {
1643*b60f2a0bSfr41279 			result = (result >> 1);
1644*b60f2a0bSfr41279 		}
16457c478bd9Sstevel@tonic-gate 		tmp = tmp >> 1;
16467c478bd9Sstevel@tonic-gate 	}
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 	return (result);
16497c478bd9Sstevel@tonic-gate }
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate int
16537c478bd9Sstevel@tonic-gate big_numbits(BIGNUM *n)
16547c478bd9Sstevel@tonic-gate {
16557c478bd9Sstevel@tonic-gate 	int		i, j;
1656*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t;
16577c478bd9Sstevel@tonic-gate 
1658*b60f2a0bSfr41279 	for (i = n->len - 1; i > 0; i--) {
1659*b60f2a0bSfr41279 		if (n->value[i] != 0) {
1660*b60f2a0bSfr41279 			break;
1661*b60f2a0bSfr41279 		}
1662*b60f2a0bSfr41279 	}
16637c478bd9Sstevel@tonic-gate 	t = n->value[i];
1664*b60f2a0bSfr41279 	for (j = BIG_CHUNK_SIZE; j > 0; j--) {
1665*b60f2a0bSfr41279 		if ((t & BIG_CHUNK_HIGHBIT) == 0) {
16667c478bd9Sstevel@tonic-gate 			t = t << 1;
1667*b60f2a0bSfr41279 		} else {
1668*b60f2a0bSfr41279 			return (BIG_CHUNK_SIZE * i + j);
1669*b60f2a0bSfr41279 		}
16707c478bd9Sstevel@tonic-gate 	}
16717c478bd9Sstevel@tonic-gate 	return (0);
16727c478bd9Sstevel@tonic-gate }
16737c478bd9Sstevel@tonic-gate 
1674*b60f2a0bSfr41279 
16757c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */
16767c478bd9Sstevel@tonic-gate BIG_ERR_CODE
16777c478bd9Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n)
16787c478bd9Sstevel@tonic-gate {
16797c478bd9Sstevel@tonic-gate 	BIGNUM		rr;
1680*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
16817c478bd9Sstevel@tonic-gate 	int		len, i;
16827c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
16857c478bd9Sstevel@tonic-gate 	len = n->len;
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1,
1688*b60f2a0bSfr41279 	    rrvalue, arraysize(rrvalue))) != BIG_OK) {
16897c478bd9Sstevel@tonic-gate 		return (err);
16907c478bd9Sstevel@tonic-gate 	}
16917c478bd9Sstevel@tonic-gate 
1692*b60f2a0bSfr41279 	for (i = 0; i < 2 * len; i++) {
1693*b60f2a0bSfr41279 		rr.value[i] = 0;
1694*b60f2a0bSfr41279 	}
1695*b60f2a0bSfr41279 	rr.value[2 * len] = 1;
1696*b60f2a0bSfr41279 	rr.len = 2 * len + 1;
1697*b60f2a0bSfr41279 	if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) {
1698*b60f2a0bSfr41279 		goto ret;
1699*b60f2a0bSfr41279 	}
1700*b60f2a0bSfr41279 	err = big_copy(result, &rr);
1701*b60f2a0bSfr41279 ret:
1702*b60f2a0bSfr41279 	big_finish(&rr);
1703*b60f2a0bSfr41279 	return (err);
1704*b60f2a0bSfr41279 }
1705*b60f2a0bSfr41279 
1706*b60f2a0bSfr41279 
17077c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */
17087c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1709*b60f2a0bSfr41279 big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, BIG_CHUNK_TYPE n0,
1710*b60f2a0bSfr41279     BIGNUM *n_rr)
17117c478bd9Sstevel@tonic-gate {
17127c478bd9Sstevel@tonic-gate 	BIGNUM		rr;
1713*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
17147c478bd9Sstevel@tonic-gate 	int		len, i;
17157c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
17187c478bd9Sstevel@tonic-gate 	len = n->len;
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue)))
1721*b60f2a0bSfr41279 	    != BIG_OK) {
17227c478bd9Sstevel@tonic-gate 		return (err);
1723*b60f2a0bSfr41279 	}
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 	if (n_rr == NULL) {
1726*b60f2a0bSfr41279 		for (i = 0; i < 2 * len; i++) {
1727*b60f2a0bSfr41279 			rr.value[i] = 0;
1728*b60f2a0bSfr41279 		}
17297c478bd9Sstevel@tonic-gate 		rr.value[2 * len] = 1;
17307c478bd9Sstevel@tonic-gate 		rr.len = 2 * len + 1;
1731*b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) {
17327c478bd9Sstevel@tonic-gate 			goto ret;
1733*b60f2a0bSfr41279 		}
17347c478bd9Sstevel@tonic-gate 		n_rr = &rr;
17357c478bd9Sstevel@tonic-gate 	}
17367c478bd9Sstevel@tonic-gate 
1737*b60f2a0bSfr41279 	if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK) {
17387c478bd9Sstevel@tonic-gate 		goto ret;
1739*b60f2a0bSfr41279 	}
17407c478bd9Sstevel@tonic-gate 	err = big_copy(result, &rr);
1741*b60f2a0bSfr41279 
17427c478bd9Sstevel@tonic-gate ret:
1743*b60f2a0bSfr41279 	big_finish(&rr);
17447c478bd9Sstevel@tonic-gate 	return (err);
17457c478bd9Sstevel@tonic-gate }
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 
1748*b60f2a0bSfr41279 #ifdef	USE_FLOATING_POINT
1749*b60f2a0bSfr41279 #define	big_modexp_ncp_float	big_modexp_ncp_sw
1750*b60f2a0bSfr41279 #else
1751*b60f2a0bSfr41279 #define	big_modexp_ncp_int	big_modexp_ncp_sw
1752*b60f2a0bSfr41279 #endif
1753*b60f2a0bSfr41279 
17547c478bd9Sstevel@tonic-gate #define	MAX_EXP_BIT_GROUP_SIZE 6
17557c478bd9Sstevel@tonic-gate #define	APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1))
17567c478bd9Sstevel@tonic-gate 
1757*b60f2a0bSfr41279 /* ARGSUSED */
17587c478bd9Sstevel@tonic-gate static BIG_ERR_CODE
1759*b60f2a0bSfr41279 big_modexp_ncp_int(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n,
1760*b60f2a0bSfr41279     BIGNUM *tmp, BIG_CHUNK_TYPE n0)
1761*b60f2a0bSfr41279 
17627c478bd9Sstevel@tonic-gate {
1763*b60f2a0bSfr41279 	BIGNUM		apowers[APOWERS_MAX_SIZE];
1764*b60f2a0bSfr41279 	BIGNUM		tmp1;
1765*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp1value[BIGTMPSIZE];
1766*b60f2a0bSfr41279 	int		i, j, k, l, m, p;
1767*b60f2a0bSfr41279 	int		bit, bitind, bitcount, groupbits, apowerssize;
1768*b60f2a0bSfr41279 	int		nbits;
17697c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
17707c478bd9Sstevel@tonic-gate 
17717c478bd9Sstevel@tonic-gate 	nbits = big_numbits(e);
17727c478bd9Sstevel@tonic-gate 	if (nbits < 50) {
17737c478bd9Sstevel@tonic-gate 		groupbits = 1;
17747c478bd9Sstevel@tonic-gate 		apowerssize = 1;
17757c478bd9Sstevel@tonic-gate 	} else {
17767c478bd9Sstevel@tonic-gate 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
17777c478bd9Sstevel@tonic-gate 		apowerssize = 1 << (groupbits - 1);
17787c478bd9Sstevel@tonic-gate 	}
17797c478bd9Sstevel@tonic-gate 
1780*b60f2a0bSfr41279 
1781*b60f2a0bSfr41279 	if ((err = big_init1(&tmp1, 2 * n->len + 1,
1782*b60f2a0bSfr41279 	    tmp1value, arraysize(tmp1value))) != BIG_OK) {
17837c478bd9Sstevel@tonic-gate 		return (err);
17847c478bd9Sstevel@tonic-gate 	}
17857c478bd9Sstevel@tonic-gate 
1786*b60f2a0bSfr41279 	/* set the malloced bit to help cleanup */
1787*b60f2a0bSfr41279 	for (i = 0; i < apowerssize; i++) {
1788*b60f2a0bSfr41279 		apowers[i].malloced = 0;
1789*b60f2a0bSfr41279 	}
1790*b60f2a0bSfr41279 	for (i = 0; i < apowerssize; i++) {
1791*b60f2a0bSfr41279 		if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) !=
1792*b60f2a0bSfr41279 		    BIG_OK) {
1793*b60f2a0bSfr41279 			goto ret;
1794*b60f2a0bSfr41279 		}
1795*b60f2a0bSfr41279 	}
17967c478bd9Sstevel@tonic-gate 
1797*b60f2a0bSfr41279 	(void) big_copy(&(apowers[0]), ma);
1798*b60f2a0bSfr41279 
1799*b60f2a0bSfr41279 	if ((err = big_mont_mul(&tmp1, ma, ma, n, n0)) != BIG_OK) {
1800*b60f2a0bSfr41279 		goto ret;
1801*b60f2a0bSfr41279 	}
1802*b60f2a0bSfr41279 	(void) big_copy(ma, &tmp1);
1803*b60f2a0bSfr41279 
1804*b60f2a0bSfr41279 	for (i = 1; i < apowerssize; i++) {
1805*b60f2a0bSfr41279 		if ((err = big_mont_mul(&tmp1, ma,
1806*b60f2a0bSfr41279 		    &(apowers[i-1]), n, n0)) != BIG_OK) {
1807*b60f2a0bSfr41279 			goto ret;
1808*b60f2a0bSfr41279 		}
1809*b60f2a0bSfr41279 		(void) big_copy(&apowers[i], &tmp1);
1810*b60f2a0bSfr41279 	}
1811*b60f2a0bSfr41279 
1812*b60f2a0bSfr41279 	bitind = nbits % BIG_CHUNK_SIZE;
1813*b60f2a0bSfr41279 	k = 0;
1814*b60f2a0bSfr41279 	l = 0;
1815*b60f2a0bSfr41279 	p = 0;
1816*b60f2a0bSfr41279 	bitcount = 0;
1817*b60f2a0bSfr41279 	for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) {
1818*b60f2a0bSfr41279 		for (j = bitind - 1; j >= 0; j--) {
1819*b60f2a0bSfr41279 			bit = (e->value[i] >> j) & 1;
1820*b60f2a0bSfr41279 			if ((bitcount == 0) && (bit == 0)) {
1821*b60f2a0bSfr41279 				if ((err = big_mont_mul(tmp,
1822*b60f2a0bSfr41279 				    tmp, tmp, n, n0)) != BIG_OK) {
1823*b60f2a0bSfr41279 					goto ret;
1824*b60f2a0bSfr41279 				}
18257c478bd9Sstevel@tonic-gate 			} else {
1826*b60f2a0bSfr41279 				bitcount++;
1827*b60f2a0bSfr41279 				p = p * 2 + bit;
1828*b60f2a0bSfr41279 				if (bit == 1) {
1829*b60f2a0bSfr41279 					k = k + l + 1;
1830*b60f2a0bSfr41279 					l = 0;
1831*b60f2a0bSfr41279 				} else {
1832*b60f2a0bSfr41279 					l++;
18337c478bd9Sstevel@tonic-gate 				}
1834*b60f2a0bSfr41279 				if (bitcount == groupbits) {
1835*b60f2a0bSfr41279 					for (m = 0; m < k; m++) {
1836*b60f2a0bSfr41279 						if ((err = big_mont_mul(tmp,
1837*b60f2a0bSfr41279 						    tmp, tmp, n, n0)) !=
1838*b60f2a0bSfr41279 						    BIG_OK) {
1839*b60f2a0bSfr41279 							goto ret;
1840*b60f2a0bSfr41279 						}
1841*b60f2a0bSfr41279 					}
1842*b60f2a0bSfr41279 					if ((err = big_mont_mul(tmp, tmp,
1843*b60f2a0bSfr41279 					    &(apowers[p >> (l + 1)]),
1844*b60f2a0bSfr41279 					    n, n0)) != BIG_OK) {
1845*b60f2a0bSfr41279 						goto ret;
1846*b60f2a0bSfr41279 					}
1847*b60f2a0bSfr41279 					for (m = 0; m < l; m++) {
1848*b60f2a0bSfr41279 						if ((err = big_mont_mul(tmp,
1849*b60f2a0bSfr41279 						    tmp, tmp, n, n0)) !=
1850*b60f2a0bSfr41279 						    BIG_OK) {
1851*b60f2a0bSfr41279 							goto ret;
1852*b60f2a0bSfr41279 						}
1853*b60f2a0bSfr41279 					}
1854*b60f2a0bSfr41279 					k = 0;
1855*b60f2a0bSfr41279 					l = 0;
1856*b60f2a0bSfr41279 					p = 0;
1857*b60f2a0bSfr41279 					bitcount = 0;
1858*b60f2a0bSfr41279 				}
1859*b60f2a0bSfr41279 			}
1860*b60f2a0bSfr41279 		}
1861*b60f2a0bSfr41279 		bitind = BIG_CHUNK_SIZE;
1862*b60f2a0bSfr41279 	}
18637c478bd9Sstevel@tonic-gate 
1864*b60f2a0bSfr41279 	for (m = 0; m < k; m++) {
1865*b60f2a0bSfr41279 		if ((err = big_mont_mul(tmp, tmp, tmp, n, n0)) != BIG_OK) {
1866*b60f2a0bSfr41279 			goto ret;
1867*b60f2a0bSfr41279 		}
1868*b60f2a0bSfr41279 	}
1869*b60f2a0bSfr41279 	if (p != 0) {
1870*b60f2a0bSfr41279 		if ((err = big_mont_mul(tmp, tmp,
1871*b60f2a0bSfr41279 		    &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK) {
1872*b60f2a0bSfr41279 			goto ret;
1873*b60f2a0bSfr41279 		}
1874*b60f2a0bSfr41279 	}
1875*b60f2a0bSfr41279 	for (m = 0; m < l; m++) {
1876*b60f2a0bSfr41279 		if ((err = big_mont_mul(result, tmp, tmp, n, n0)) != BIG_OK) {
1877*b60f2a0bSfr41279 			goto ret;
1878*b60f2a0bSfr41279 		}
1879*b60f2a0bSfr41279 	}
18807c478bd9Sstevel@tonic-gate 
1881*b60f2a0bSfr41279 ret:
1882*b60f2a0bSfr41279 	for (i = apowerssize - 1; i >= 0; i--) {
1883*b60f2a0bSfr41279 		big_finish(&(apowers[i]));
1884*b60f2a0bSfr41279 	}
1885*b60f2a0bSfr41279 	big_finish(&tmp1);
1886*b60f2a0bSfr41279 
1887*b60f2a0bSfr41279 	return (err);
1888*b60f2a0bSfr41279 }
1889*b60f2a0bSfr41279 
1890*b60f2a0bSfr41279 
1891*b60f2a0bSfr41279 #ifdef USE_FLOATING_POINT
1892*b60f2a0bSfr41279 
1893*b60f2a0bSfr41279 #ifdef _KERNEL
1894*b60f2a0bSfr41279 
1895*b60f2a0bSfr41279 #include <sys/sysmacros.h>
1896*b60f2a0bSfr41279 #include <sys/regset.h>
1897*b60f2a0bSfr41279 #include <sys/fpu/fpusystm.h>
1898*b60f2a0bSfr41279 
1899*b60f2a0bSfr41279 /* the alignment for block stores to save fp registers */
1900*b60f2a0bSfr41279 #define	FPR_ALIGN	(64)
1901*b60f2a0bSfr41279 
1902*b60f2a0bSfr41279 extern void big_savefp(kfpu_t *);
1903*b60f2a0bSfr41279 extern void big_restorefp(kfpu_t *);
1904*b60f2a0bSfr41279 
1905*b60f2a0bSfr41279 #endif /* _KERNEL */
1906*b60f2a0bSfr41279 
1907*b60f2a0bSfr41279 /*
1908*b60f2a0bSfr41279  * This version makes use of floating point for performance
1909*b60f2a0bSfr41279  */
1910*b60f2a0bSfr41279 static BIG_ERR_CODE
1911*b60f2a0bSfr41279 big_modexp_ncp_float(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n,
1912*b60f2a0bSfr41279     BIGNUM *tmp, BIG_CHUNK_TYPE n0)
1913*b60f2a0bSfr41279 {
1914*b60f2a0bSfr41279 
1915*b60f2a0bSfr41279 	int		i, j, k, l, m, p, bit, bitind, bitcount, nlen;
1916*b60f2a0bSfr41279 	double		dn0;
1917*b60f2a0bSfr41279 	double		*dn, *dt, *d16r, *d32r;
1918*b60f2a0bSfr41279 	uint32_t	*nint, *prod;
1919*b60f2a0bSfr41279 	double		*apowers[APOWERS_MAX_SIZE];
1920*b60f2a0bSfr41279 	int		nbits, groupbits, apowerssize;
1921*b60f2a0bSfr41279 	BIG_ERR_CODE	err = BIG_OK;
1922*b60f2a0bSfr41279 
1923*b60f2a0bSfr41279 #ifdef _KERNEL
1924*b60f2a0bSfr41279 	uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN];
1925*b60f2a0bSfr41279 	kfpu_t *fpu;
1926*b60f2a0bSfr41279 
1927*b60f2a0bSfr41279 #ifdef DEBUG
1928*b60f2a0bSfr41279 	if (!fpu_exists)
1929*b60f2a0bSfr41279 		return (BIG_GENERAL_ERR);
1930*b60f2a0bSfr41279 #endif
1931*b60f2a0bSfr41279 
1932*b60f2a0bSfr41279 	fpu =  (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN);
1933*b60f2a0bSfr41279 	big_savefp(fpu);
1934*b60f2a0bSfr41279 
1935*b60f2a0bSfr41279 #endif /* _KERNEL */
1936*b60f2a0bSfr41279 
1937*b60f2a0bSfr41279 	nbits = big_numbits(e);
1938*b60f2a0bSfr41279 	if (nbits < 50) {
1939*b60f2a0bSfr41279 		groupbits = 1;
1940*b60f2a0bSfr41279 		apowerssize = 1;
1941*b60f2a0bSfr41279 	} else {
1942*b60f2a0bSfr41279 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
1943*b60f2a0bSfr41279 		apowerssize = 1 << (groupbits - 1);
1944*b60f2a0bSfr41279 	}
1945*b60f2a0bSfr41279 
1946*b60f2a0bSfr41279 	nlen = (BIG_CHUNK_SIZE / 32) * n->len;
19477c478bd9Sstevel@tonic-gate 	dn0 = (double)(n0 & 0xffff);
19487c478bd9Sstevel@tonic-gate 
19497c478bd9Sstevel@tonic-gate 	dn = dt = d16r = d32r = NULL;
19507c478bd9Sstevel@tonic-gate 	nint = prod = NULL;
19517c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
19527c478bd9Sstevel@tonic-gate 		apowers[i] = NULL;
19537c478bd9Sstevel@tonic-gate 	}
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 	if ((dn = big_malloc(nlen * sizeof (double))) == NULL) {
19567c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
19577c478bd9Sstevel@tonic-gate 		goto ret;
19587c478bd9Sstevel@tonic-gate 	}
19597c478bd9Sstevel@tonic-gate 	if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) {
19607c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
19617c478bd9Sstevel@tonic-gate 		goto ret;
19627c478bd9Sstevel@tonic-gate 	}
19637c478bd9Sstevel@tonic-gate 	if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) {
19647c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
19657c478bd9Sstevel@tonic-gate 		goto ret;
19667c478bd9Sstevel@tonic-gate 	}
19677c478bd9Sstevel@tonic-gate 	if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) {
19687c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
19697c478bd9Sstevel@tonic-gate 		goto ret;
19707c478bd9Sstevel@tonic-gate 	}
19717c478bd9Sstevel@tonic-gate 	if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) {
19727c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
19737c478bd9Sstevel@tonic-gate 		goto ret;
19747c478bd9Sstevel@tonic-gate 	}
19757c478bd9Sstevel@tonic-gate 	if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) {
19767c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
19777c478bd9Sstevel@tonic-gate 		goto ret;
19787c478bd9Sstevel@tonic-gate 	}
19797c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
19807c478bd9Sstevel@tonic-gate 		if ((apowers[i] = big_malloc((2 * nlen + 1) *
19817c478bd9Sstevel@tonic-gate 		    sizeof (double))) == NULL) {
19827c478bd9Sstevel@tonic-gate 			err = BIG_NO_MEM;
19837c478bd9Sstevel@tonic-gate 			goto ret;
19847c478bd9Sstevel@tonic-gate 		}
19857c478bd9Sstevel@tonic-gate 	}
19867c478bd9Sstevel@tonic-gate 
1987*b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
1988*b60f2a0bSfr41279 	for (i = 0; i < ma->len; i++) {
1989*b60f2a0bSfr41279 		nint[i] = ma->value[i];
1990*b60f2a0bSfr41279 	}
1991*b60f2a0bSfr41279 	for (; i < nlen; i++) {
1992*b60f2a0bSfr41279 		nint[i] = 0;
1993*b60f2a0bSfr41279 	}
1994*b60f2a0bSfr41279 #else
1995*b60f2a0bSfr41279 	for (i = 0; i < ma->len; i++) {
1996*b60f2a0bSfr41279 		nint[2 * i] = (uint32_t)(ma->value[i] & 0xffffffffULL);
1997*b60f2a0bSfr41279 		nint[2 * i + 1] = (uint32_t)(ma->value[i] >> 32);
1998*b60f2a0bSfr41279 	}
1999*b60f2a0bSfr41279 	for (i = ma->len * 2; i < nlen; i++) {
2000*b60f2a0bSfr41279 		nint[i] = 0;
2001*b60f2a0bSfr41279 	}
2002*b60f2a0bSfr41279 #endif
20037c478bd9Sstevel@tonic-gate 	conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen);
20047c478bd9Sstevel@tonic-gate 
2005*b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
2006*b60f2a0bSfr41279 	for (i = 0; i < n->len; i++) {
2007*b60f2a0bSfr41279 		nint[i] = n->value[i];
2008*b60f2a0bSfr41279 	}
2009*b60f2a0bSfr41279 	for (; i < nlen; i++) {
2010*b60f2a0bSfr41279 		nint[i] = 0;
2011*b60f2a0bSfr41279 	}
2012*b60f2a0bSfr41279 #else
2013*b60f2a0bSfr41279 	for (i = 0; i < n->len; i++) {
2014*b60f2a0bSfr41279 		nint[2 * i] = (uint32_t)(n->value[i] & 0xffffffffULL);
2015*b60f2a0bSfr41279 		nint[2 * i + 1] = (uint32_t)(n->value[i] >> 32);
2016*b60f2a0bSfr41279 	}
2017*b60f2a0bSfr41279 	for (i = n->len * 2; i < nlen; i++) {
2018*b60f2a0bSfr41279 		nint[i] = 0;
2019*b60f2a0bSfr41279 	}
2020*b60f2a0bSfr41279 #endif
20217c478bd9Sstevel@tonic-gate 	conv_i32_to_d32(dn, nint, nlen);
20227c478bd9Sstevel@tonic-gate 
20237c478bd9Sstevel@tonic-gate 	mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0);
20247c478bd9Sstevel@tonic-gate 	conv_i32_to_d32(d32r, prod, nlen);
20257c478bd9Sstevel@tonic-gate 	for (i = 1; i < apowerssize; i++) {
20267c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[i - 1],
20277c478bd9Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
20287c478bd9Sstevel@tonic-gate 		conv_i32_to_d16(apowers[i], prod, nlen);
20297c478bd9Sstevel@tonic-gate 	}
20307c478bd9Sstevel@tonic-gate 
2031*b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
2032*b60f2a0bSfr41279 	for (i = 0; i < tmp->len; i++) {
2033*b60f2a0bSfr41279 		prod[i] = tmp->value[i];
2034*b60f2a0bSfr41279 	}
2035*b60f2a0bSfr41279 	for (; i < nlen + 1; i++) {
2036*b60f2a0bSfr41279 		prod[i] = 0;
2037*b60f2a0bSfr41279 	}
2038*b60f2a0bSfr41279 #else
2039*b60f2a0bSfr41279 	for (i = 0; i < tmp->len; i++) {
2040*b60f2a0bSfr41279 		prod[2 * i] = (uint32_t)(tmp->value[i] & 0xffffffffULL);
2041*b60f2a0bSfr41279 		prod[2 * i + 1] = (uint32_t)(tmp->value[i] >> 32);
2042*b60f2a0bSfr41279 	}
2043*b60f2a0bSfr41279 	for (i = tmp->len * 2; i < nlen + 1; i++) {
2044*b60f2a0bSfr41279 		prod[i] = 0;
2045*b60f2a0bSfr41279 	}
2046*b60f2a0bSfr41279 #endif
20477c478bd9Sstevel@tonic-gate 
2048*b60f2a0bSfr41279 	bitind = nbits % BIG_CHUNK_SIZE;
20497c478bd9Sstevel@tonic-gate 	k = 0;
20507c478bd9Sstevel@tonic-gate 	l = 0;
20517c478bd9Sstevel@tonic-gate 	p = 0;
20527c478bd9Sstevel@tonic-gate 	bitcount = 0;
2053*b60f2a0bSfr41279 	for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) {
20547c478bd9Sstevel@tonic-gate 		for (j = bitind - 1; j >= 0; j--) {
20557c478bd9Sstevel@tonic-gate 			bit = (e->value[i] >> j) & 1;
20567c478bd9Sstevel@tonic-gate 			if ((bitcount == 0) && (bit == 0)) {
20577c478bd9Sstevel@tonic-gate 				conv_i32_to_d32_and_d16(d32r, d16r,
20587c478bd9Sstevel@tonic-gate 				    prod, nlen);
20597c478bd9Sstevel@tonic-gate 				mont_mulf_noconv(prod, d32r, d16r,
20607c478bd9Sstevel@tonic-gate 				    dt, dn, nint, nlen, dn0);
20617c478bd9Sstevel@tonic-gate 			} else {
20627c478bd9Sstevel@tonic-gate 				bitcount++;
20637c478bd9Sstevel@tonic-gate 				p = p * 2 + bit;
20647c478bd9Sstevel@tonic-gate 				if (bit == 1) {
20657c478bd9Sstevel@tonic-gate 					k = k + l + 1;
20667c478bd9Sstevel@tonic-gate 					l = 0;
20677c478bd9Sstevel@tonic-gate 				} else {
20687c478bd9Sstevel@tonic-gate 					l++;
20697c478bd9Sstevel@tonic-gate 				}
20707c478bd9Sstevel@tonic-gate 				if (bitcount == groupbits) {
20717c478bd9Sstevel@tonic-gate 					for (m = 0; m < k; m++) {
2072*b60f2a0bSfr41279 						conv_i32_to_d32_and_d16(d32r,
2073*b60f2a0bSfr41279 						    d16r, prod, nlen);
20747c478bd9Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
20757c478bd9Sstevel@tonic-gate 						    d16r, dt, dn, nint,
20767c478bd9Sstevel@tonic-gate 						    nlen, dn0);
20777c478bd9Sstevel@tonic-gate 					}
20787c478bd9Sstevel@tonic-gate 					conv_i32_to_d32(d32r, prod, nlen);
20797c478bd9Sstevel@tonic-gate 					mont_mulf_noconv(prod, d32r,
20807c478bd9Sstevel@tonic-gate 					    apowers[p >> (l+1)],
20817c478bd9Sstevel@tonic-gate 					    dt, dn, nint, nlen, dn0);
20827c478bd9Sstevel@tonic-gate 					for (m = 0; m < l; m++) {
2083*b60f2a0bSfr41279 						conv_i32_to_d32_and_d16(d32r,
2084*b60f2a0bSfr41279 						    d16r, prod, nlen);
20857c478bd9Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
20867c478bd9Sstevel@tonic-gate 						    d16r, dt, dn, nint,
20877c478bd9Sstevel@tonic-gate 						    nlen, dn0);
20887c478bd9Sstevel@tonic-gate 					}
20897c478bd9Sstevel@tonic-gate 					k = 0;
20907c478bd9Sstevel@tonic-gate 					l = 0;
20917c478bd9Sstevel@tonic-gate 					p = 0;
20927c478bd9Sstevel@tonic-gate 					bitcount = 0;
20937c478bd9Sstevel@tonic-gate 				}
20947c478bd9Sstevel@tonic-gate 			}
20957c478bd9Sstevel@tonic-gate 		}
2096*b60f2a0bSfr41279 		bitind = BIG_CHUNK_SIZE;
20977c478bd9Sstevel@tonic-gate 	}
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 	for (m = 0; m < k; m++) {
21007c478bd9Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
21017c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
21027c478bd9Sstevel@tonic-gate 	}
21037c478bd9Sstevel@tonic-gate 	if (p != 0) {
21047c478bd9Sstevel@tonic-gate 		conv_i32_to_d32(d32r, prod, nlen);
21057c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)],
21067c478bd9Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
21077c478bd9Sstevel@tonic-gate 	}
21087c478bd9Sstevel@tonic-gate 	for (m = 0; m < l; m++) {
21097c478bd9Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
21107c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
21117c478bd9Sstevel@tonic-gate 	}
21127c478bd9Sstevel@tonic-gate 
2113*b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32)
2114*b60f2a0bSfr41279 	for (i = 0; i < nlen; i++) {
2115*b60f2a0bSfr41279 		result->value[i] = prod[i];
2116*b60f2a0bSfr41279 	}
2117*b60f2a0bSfr41279 	for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--)
2118*b60f2a0bSfr41279 		;
2119*b60f2a0bSfr41279 #else
2120*b60f2a0bSfr41279 	for (i = 0; i < nlen / 2; i++) {
2121*b60f2a0bSfr41279 		result->value[i] = (uint64_t)(prod[2 * i]) +
2122*b60f2a0bSfr41279 		    (((uint64_t)(prod[2 * i + 1])) << 32);
2123*b60f2a0bSfr41279 	}
2124*b60f2a0bSfr41279 	for (i = nlen / 2 - 1; (i > 0) && (result->value[i] == 0); i--)
2125*b60f2a0bSfr41279 		;
2126*b60f2a0bSfr41279 #endif
2127*b60f2a0bSfr41279 	result->len = i + 1;
2128*b60f2a0bSfr41279 
21297c478bd9Sstevel@tonic-gate ret:
21307c478bd9Sstevel@tonic-gate 	for (i = apowerssize - 1; i >= 0; i--) {
21317c478bd9Sstevel@tonic-gate 		if (apowers[i] != NULL)
21327c478bd9Sstevel@tonic-gate 			big_free(apowers[i], (2 * nlen + 1) * sizeof (double));
21337c478bd9Sstevel@tonic-gate 	}
2134*b60f2a0bSfr41279 	if (d32r != NULL) {
21357c478bd9Sstevel@tonic-gate 		big_free(d32r, nlen * sizeof (double));
2136*b60f2a0bSfr41279 	}
2137*b60f2a0bSfr41279 	if (d16r != NULL) {
21387c478bd9Sstevel@tonic-gate 		big_free(d16r, (2 * nlen + 1) * sizeof (double));
2139*b60f2a0bSfr41279 	}
2140*b60f2a0bSfr41279 	if (prod != NULL) {
21417c478bd9Sstevel@tonic-gate 		big_free(prod, (nlen + 1) * sizeof (uint32_t));
2142*b60f2a0bSfr41279 	}
2143*b60f2a0bSfr41279 	if (nint != NULL) {
21447c478bd9Sstevel@tonic-gate 		big_free(nint, nlen * sizeof (uint32_t));
2145*b60f2a0bSfr41279 	}
2146*b60f2a0bSfr41279 	if (dt != NULL) {
21477c478bd9Sstevel@tonic-gate 		big_free(dt, (4 * nlen + 2) * sizeof (double));
2148*b60f2a0bSfr41279 	}
2149*b60f2a0bSfr41279 	if (dn != NULL) {
21507c478bd9Sstevel@tonic-gate 		big_free(dn, nlen * sizeof (double));
21517c478bd9Sstevel@tonic-gate 	}
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate #ifdef _KERNEL
2154*b60f2a0bSfr41279 	big_restorefp(fpu);
21557c478bd9Sstevel@tonic-gate #endif
21567c478bd9Sstevel@tonic-gate 
21577c478bd9Sstevel@tonic-gate 	return (err);
21587c478bd9Sstevel@tonic-gate }
21597c478bd9Sstevel@tonic-gate 
21607c478bd9Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2164*b60f2a0bSfr41279 big_modexp_ext(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr,
2165*b60f2a0bSfr41279     big_modexp_ncp_info_t *info)
2166*b60f2a0bSfr41279 {
2167*b60f2a0bSfr41279 	BIGNUM		ma, tmp, rr;
2168*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	mavalue[BIGTMPSIZE];
2169*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
2170*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	rrvalue[BIGTMPSIZE];
2171*b60f2a0bSfr41279 	BIG_ERR_CODE	err;
2172*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	n0;
2173*b60f2a0bSfr41279 
2174*b60f2a0bSfr41279 	if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue)))	!=
2175*b60f2a0bSfr41279 	    BIG_OK) {
2176*b60f2a0bSfr41279 		return (err);
2177*b60f2a0bSfr41279 	}
2178*b60f2a0bSfr41279 	ma.len = 1;
2179*b60f2a0bSfr41279 	ma.value[0] = 0;
2180*b60f2a0bSfr41279 
2181*b60f2a0bSfr41279 	if ((err = big_init1(&tmp, 2 * n->len + 1,
2182*b60f2a0bSfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
2183*b60f2a0bSfr41279 		goto ret1;
2184*b60f2a0bSfr41279 	}
2185*b60f2a0bSfr41279 
2186*b60f2a0bSfr41279 	/* set the malloced bit to help cleanup */
2187*b60f2a0bSfr41279 	rr.malloced = 0;
2188*b60f2a0bSfr41279 	if (n_rr == NULL) {
2189*b60f2a0bSfr41279 		if ((err = big_init1(&rr, 2 * n->len + 1,
2190*b60f2a0bSfr41279 		    rrvalue, arraysize(rrvalue))) != BIG_OK) {
2191*b60f2a0bSfr41279 			goto ret2;
2192*b60f2a0bSfr41279 		}
2193*b60f2a0bSfr41279 		if (big_mont_rr(&rr, n) != BIG_OK) {
2194*b60f2a0bSfr41279 			goto ret;
2195*b60f2a0bSfr41279 		}
2196*b60f2a0bSfr41279 		n_rr = &rr;
2197*b60f2a0bSfr41279 	}
2198*b60f2a0bSfr41279 
2199*b60f2a0bSfr41279 	n0 = big_n0(n->value[0]);
2200*b60f2a0bSfr41279 
2201*b60f2a0bSfr41279 	if (big_cmp_abs(a, n) > 0) {
2202*b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK) {
2203*b60f2a0bSfr41279 			goto ret;
2204*b60f2a0bSfr41279 		}
2205*b60f2a0bSfr41279 		err = big_mont_conv(&ma, &ma, n, n0, n_rr);
2206*b60f2a0bSfr41279 	} else {
2207*b60f2a0bSfr41279 		err = big_mont_conv(&ma, a, n, n0, n_rr);
2208*b60f2a0bSfr41279 	}
2209*b60f2a0bSfr41279 	if (err != BIG_OK) {
2210*b60f2a0bSfr41279 		goto ret;
2211*b60f2a0bSfr41279 	}
2212*b60f2a0bSfr41279 
2213*b60f2a0bSfr41279 	tmp.len = 1;
2214*b60f2a0bSfr41279 	tmp.value[0] = 1;
2215*b60f2a0bSfr41279 	if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK) {
2216*b60f2a0bSfr41279 		goto ret;
2217*b60f2a0bSfr41279 	}
2218*b60f2a0bSfr41279 
2219*b60f2a0bSfr41279 	if ((info != NULL) && (info->func != NULL)) {
2220*b60f2a0bSfr41279 		err = (*(info->func))(&tmp, &ma, e, n, &tmp, n0,
2221*b60f2a0bSfr41279 		    info->ncp, info->reqp);
2222*b60f2a0bSfr41279 	} else {
2223*b60f2a0bSfr41279 		err = big_modexp_ncp_sw(&tmp, &ma, e, n, &tmp, n0);
2224*b60f2a0bSfr41279 	}
2225*b60f2a0bSfr41279 	if (err != BIG_OK) {
2226*b60f2a0bSfr41279 		goto ret;
2227*b60f2a0bSfr41279 	}
2228*b60f2a0bSfr41279 
2229*b60f2a0bSfr41279 	ma.value[0] = 1;
2230*b60f2a0bSfr41279 	ma.len = 1;
2231*b60f2a0bSfr41279 	if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK) {
2232*b60f2a0bSfr41279 		goto ret;
2233*b60f2a0bSfr41279 	}
2234*b60f2a0bSfr41279 	err = big_copy(result, &tmp);
2235*b60f2a0bSfr41279 
2236*b60f2a0bSfr41279 ret:
2237*b60f2a0bSfr41279 	if (rr.malloced) {
2238*b60f2a0bSfr41279 		big_finish(&rr);
2239*b60f2a0bSfr41279 	}
2240*b60f2a0bSfr41279 ret2:
2241*b60f2a0bSfr41279 	big_finish(&tmp);
2242*b60f2a0bSfr41279 ret1:
2243*b60f2a0bSfr41279 	big_finish(&ma);
2244*b60f2a0bSfr41279 
2245*b60f2a0bSfr41279 	return (err);
2246*b60f2a0bSfr41279 }
2247*b60f2a0bSfr41279 
2248*b60f2a0bSfr41279 BIG_ERR_CODE
2249*b60f2a0bSfr41279 big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
2250*b60f2a0bSfr41279 {
2251*b60f2a0bSfr41279 	return (big_modexp_ext(result, a, e, n, n_rr, NULL));
2252*b60f2a0bSfr41279 }
2253*b60f2a0bSfr41279 
2254*b60f2a0bSfr41279 
2255*b60f2a0bSfr41279 BIG_ERR_CODE
2256*b60f2a0bSfr41279 big_modexp_crt_ext(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
22577c478bd9Sstevel@tonic-gate     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
2258*b60f2a0bSfr41279     BIGNUM *p_rr, BIGNUM *q_rr, big_modexp_ncp_info_t *info)
22597c478bd9Sstevel@tonic-gate {
22607c478bd9Sstevel@tonic-gate 	BIGNUM		ap, aq, tmp;
22617c478bd9Sstevel@tonic-gate 	int		alen, biglen, sign;
22627c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
22637c478bd9Sstevel@tonic-gate 
2264*b60f2a0bSfr41279 	if (p->len > q->len) {
2265*b60f2a0bSfr41279 		biglen = p->len;
2266*b60f2a0bSfr41279 	} else {
2267*b60f2a0bSfr41279 		biglen = q->len;
2268*b60f2a0bSfr41279 	}
22697c478bd9Sstevel@tonic-gate 
2270*b60f2a0bSfr41279 	if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK) {
22717c478bd9Sstevel@tonic-gate 		return (err);
2272*b60f2a0bSfr41279 	}
2273*b60f2a0bSfr41279 	if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK) {
22747c478bd9Sstevel@tonic-gate 		goto ret1;
2275*b60f2a0bSfr41279 	}
2276*b60f2a0bSfr41279 	if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK) {
22777c478bd9Sstevel@tonic-gate 		goto ret2;
2278*b60f2a0bSfr41279 	}
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate 	/*
22817c478bd9Sstevel@tonic-gate 	 * check whether a is too short - to avoid timing attacks
22827c478bd9Sstevel@tonic-gate 	 */
22837c478bd9Sstevel@tonic-gate 	alen = a->len;
22847c478bd9Sstevel@tonic-gate 	while ((alen > p->len) && (a->value[alen - 1] == 0)) {
22857c478bd9Sstevel@tonic-gate 		alen--;
22867c478bd9Sstevel@tonic-gate 	}
22877c478bd9Sstevel@tonic-gate 	if (alen < p->len + q->len) {
22887c478bd9Sstevel@tonic-gate 		/*
22897c478bd9Sstevel@tonic-gate 		 * a is too short, add p*q to it before
22907c478bd9Sstevel@tonic-gate 		 * taking it modulo p and q
22917c478bd9Sstevel@tonic-gate 		 * this will also affect timing, but this difference
22927c478bd9Sstevel@tonic-gate 		 * does not depend on p or q, only on a
22937c478bd9Sstevel@tonic-gate 		 * (in "normal" operation, this path will never be
22947c478bd9Sstevel@tonic-gate 		 * taken, so it is not a performance penalty
22957c478bd9Sstevel@tonic-gate 		 */
2296*b60f2a0bSfr41279 		if ((err = big_mul(&tmp, p, q)) != BIG_OK) {
22977c478bd9Sstevel@tonic-gate 			goto ret;
22987c478bd9Sstevel@tonic-gate 		}
2299*b60f2a0bSfr41279 		if ((err = big_add(&tmp, &tmp, a)) != BIG_OK) {
2300*b60f2a0bSfr41279 			goto ret;
2301*b60f2a0bSfr41279 		}
2302*b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK) {
2303*b60f2a0bSfr41279 			goto ret;
2304*b60f2a0bSfr41279 		}
2305*b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) {
2306*b60f2a0bSfr41279 			goto ret;
2307*b60f2a0bSfr41279 		}
2308*b60f2a0bSfr41279 	} else {
2309*b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK) {
2310*b60f2a0bSfr41279 			goto ret;
2311*b60f2a0bSfr41279 		}
2312*b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK) {
2313*b60f2a0bSfr41279 			goto ret;
2314*b60f2a0bSfr41279 		}
2315*b60f2a0bSfr41279 	}
23167c478bd9Sstevel@tonic-gate 
2317*b60f2a0bSfr41279 	if ((err = big_modexp_ext(&ap, &ap, dmodpminus1, p, p_rr, info)) !=
2318*b60f2a0bSfr41279 	    BIG_OK) {
23197c478bd9Sstevel@tonic-gate 		goto ret;
2320*b60f2a0bSfr41279 	}
2321*b60f2a0bSfr41279 	if ((err = big_modexp_ext(&aq, &aq, dmodqminus1, q, q_rr, info)) !=
2322*b60f2a0bSfr41279 	    BIG_OK) {
23237c478bd9Sstevel@tonic-gate 		goto ret;
2324*b60f2a0bSfr41279 	}
2325*b60f2a0bSfr41279 	if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK) {
23267c478bd9Sstevel@tonic-gate 		goto ret;
2327*b60f2a0bSfr41279 	}
2328*b60f2a0bSfr41279 	if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK) {
23297c478bd9Sstevel@tonic-gate 		goto ret;
2330*b60f2a0bSfr41279 	}
23317c478bd9Sstevel@tonic-gate 	sign = tmp.sign;
23327c478bd9Sstevel@tonic-gate 	tmp.sign = 1;
2333*b60f2a0bSfr41279 	if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) {
23347c478bd9Sstevel@tonic-gate 		goto ret;
2335*b60f2a0bSfr41279 	}
23367c478bd9Sstevel@tonic-gate 	if ((sign == -1) && (!big_is_zero(&aq))) {
23377c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(&aq, q, &aq);
23387c478bd9Sstevel@tonic-gate 	}
2339*b60f2a0bSfr41279 	if ((err = big_mul(&tmp, &aq, p)) != BIG_OK) {
23407c478bd9Sstevel@tonic-gate 		goto ret;
2341*b60f2a0bSfr41279 	}
23427c478bd9Sstevel@tonic-gate 	err = big_add_abs(result, &ap, &tmp);
23437c478bd9Sstevel@tonic-gate 
23447c478bd9Sstevel@tonic-gate ret:
23457c478bd9Sstevel@tonic-gate 	big_finish(&tmp);
23467c478bd9Sstevel@tonic-gate ret2:
23477c478bd9Sstevel@tonic-gate 	big_finish(&aq);
23487c478bd9Sstevel@tonic-gate ret1:
23497c478bd9Sstevel@tonic-gate 	big_finish(&ap);
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate 	return (err);
23527c478bd9Sstevel@tonic-gate }
23537c478bd9Sstevel@tonic-gate 
23547c478bd9Sstevel@tonic-gate 
2355*b60f2a0bSfr41279 BIG_ERR_CODE
2356*b60f2a0bSfr41279 big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
2357*b60f2a0bSfr41279     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
2358*b60f2a0bSfr41279     BIGNUM *p_rr, BIGNUM *q_rr)
2359*b60f2a0bSfr41279 {
2360*b60f2a0bSfr41279 	return (big_modexp_crt_ext(result, a, dmodpminus1, dmodqminus1,
2361*b60f2a0bSfr41279 	    p, q, pinvmodq, p_rr, q_rr, NULL));
2362*b60f2a0bSfr41279 }
23637c478bd9Sstevel@tonic-gate 
23647c478bd9Sstevel@tonic-gate 
2365*b60f2a0bSfr41279 static BIG_CHUNK_TYPE onearr[1] = {(BIG_CHUNK_TYPE)1};
2366*b60f2a0bSfr41279 BIGNUM big_One = {1, 1, 1, 0, onearr};
2367*b60f2a0bSfr41279 
2368*b60f2a0bSfr41279 static BIG_CHUNK_TYPE twoarr[1] = {(BIG_CHUNK_TYPE)2};
2369*b60f2a0bSfr41279 BIGNUM big_Two = {1, 1, 1, 0, twoarr};
2370*b60f2a0bSfr41279 
2371*b60f2a0bSfr41279 static BIG_CHUNK_TYPE fourarr[1] = {(BIG_CHUNK_TYPE)4};
2372*b60f2a0bSfr41279 static BIGNUM big_Four = {1, 1, 1, 0, fourarr};
2373*b60f2a0bSfr41279 
23747c478bd9Sstevel@tonic-gate 
23757c478bd9Sstevel@tonic-gate BIG_ERR_CODE
23767c478bd9Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n)
23777c478bd9Sstevel@tonic-gate {
23787c478bd9Sstevel@tonic-gate 	BIGNUM		*high, *low, *mid, *t;
23797c478bd9Sstevel@tonic-gate 	BIGNUM		t1, t2, t3, prod;
2380*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
2381*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
2382*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
2383*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	prodvalue[BIGTMPSIZE];
23847c478bd9Sstevel@tonic-gate 	int		i, nbits, diff, nrootbits, highbits;
23857c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
23867c478bd9Sstevel@tonic-gate 
23877c478bd9Sstevel@tonic-gate 	nbits = big_numbits(n);
23887c478bd9Sstevel@tonic-gate 
23897c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, n->len + 1,
23907c478bd9Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
23917c478bd9Sstevel@tonic-gate 		return (err);
23927c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, n->len + 1,
23937c478bd9Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
23947c478bd9Sstevel@tonic-gate 		goto ret1;
23957c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, n->len + 1,
23967c478bd9Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
23977c478bd9Sstevel@tonic-gate 		goto ret2;
23987c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&prod, n->len + 1,
23997c478bd9Sstevel@tonic-gate 	    prodvalue, arraysize(prodvalue))) != BIG_OK)
24007c478bd9Sstevel@tonic-gate 		goto ret3;
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate 	nrootbits = (nbits + 1) / 2;
2403*b60f2a0bSfr41279 	t1.len = t2.len = t3.len = (nrootbits - 1) / BIG_CHUNK_SIZE + 1;
24047c478bd9Sstevel@tonic-gate 	for (i = 0; i < t1.len; i++) {
24057c478bd9Sstevel@tonic-gate 		t1.value[i] = 0;
2406*b60f2a0bSfr41279 		t2.value[i] = BIG_CHUNK_ALLBITS;
24077c478bd9Sstevel@tonic-gate 	}
2408*b60f2a0bSfr41279 	highbits = nrootbits - BIG_CHUNK_SIZE * (t1.len - 1);
2409*b60f2a0bSfr41279 	if (highbits == BIG_CHUNK_SIZE) {
2410*b60f2a0bSfr41279 		t1.value[t1.len - 1] = BIG_CHUNK_HIGHBIT;
2411*b60f2a0bSfr41279 		t2.value[t2.len - 1] = BIG_CHUNK_ALLBITS;
24127c478bd9Sstevel@tonic-gate 	} else {
2413*b60f2a0bSfr41279 		t1.value[t1.len - 1] = (BIG_CHUNK_TYPE)1 << (highbits - 1);
24147c478bd9Sstevel@tonic-gate 		t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1;
24157c478bd9Sstevel@tonic-gate 	}
2416*b60f2a0bSfr41279 
24177c478bd9Sstevel@tonic-gate 	high = &t2;
24187c478bd9Sstevel@tonic-gate 	low = &t1;
24197c478bd9Sstevel@tonic-gate 	mid = &t3;
24207c478bd9Sstevel@tonic-gate 
2421*b60f2a0bSfr41279 	if ((err = big_mul(&prod, high, high)) != BIG_OK) {
24227c478bd9Sstevel@tonic-gate 		goto ret;
2423*b60f2a0bSfr41279 	}
24247c478bd9Sstevel@tonic-gate 	diff = big_cmp_abs(&prod, n);
24257c478bd9Sstevel@tonic-gate 	if (diff <= 0) {
24267c478bd9Sstevel@tonic-gate 		err = big_copy(result, high);
24277c478bd9Sstevel@tonic-gate 		goto ret;
24287c478bd9Sstevel@tonic-gate 	}
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(mid, high, low);
2431*b60f2a0bSfr41279 	while (big_cmp_abs(&big_One, mid) != 0) {
24327c478bd9Sstevel@tonic-gate 		(void) big_add_abs(mid, high, low);
24337c478bd9Sstevel@tonic-gate 		(void) big_half_pos(mid, mid);
24347c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&prod, mid, mid)) != BIG_OK)
24357c478bd9Sstevel@tonic-gate 			goto ret;
24367c478bd9Sstevel@tonic-gate 		diff = big_cmp_abs(&prod, n);
24377c478bd9Sstevel@tonic-gate 		if (diff > 0) {
24387c478bd9Sstevel@tonic-gate 			t = high;
24397c478bd9Sstevel@tonic-gate 			high = mid;
24407c478bd9Sstevel@tonic-gate 			mid = t;
24417c478bd9Sstevel@tonic-gate 		} else if (diff < 0) {
24427c478bd9Sstevel@tonic-gate 			t = low;
24437c478bd9Sstevel@tonic-gate 			low = mid;
24447c478bd9Sstevel@tonic-gate 			mid = t;
24457c478bd9Sstevel@tonic-gate 		} else {
24467c478bd9Sstevel@tonic-gate 			err = big_copy(result, low);
24477c478bd9Sstevel@tonic-gate 			goto ret;
24487c478bd9Sstevel@tonic-gate 		}
24497c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(mid, high, low);
24507c478bd9Sstevel@tonic-gate 	}
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 	err = big_copy(result, low);
24537c478bd9Sstevel@tonic-gate ret:
24547c478bd9Sstevel@tonic-gate 	if (prod.malloced) big_finish(&prod);
24557c478bd9Sstevel@tonic-gate ret3:
24567c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
24577c478bd9Sstevel@tonic-gate ret2:
24587c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
24597c478bd9Sstevel@tonic-gate ret1:
24607c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate 	return (err);
24637c478bd9Sstevel@tonic-gate }
24647c478bd9Sstevel@tonic-gate 
24657c478bd9Sstevel@tonic-gate 
24667c478bd9Sstevel@tonic-gate BIG_ERR_CODE
24677c478bd9Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm)
24687c478bd9Sstevel@tonic-gate {
24697c478bd9Sstevel@tonic-gate 	BIGNUM		*t, *tmp2, *m, *n;
24707c478bd9Sstevel@tonic-gate 	BIGNUM		t1, t2, t3;
2471*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
2472*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
2473*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
24747c478bd9Sstevel@tonic-gate 	int		len, err;
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 	if (big_is_zero(nn) ||
24777c478bd9Sstevel@tonic-gate 	    (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) {
24787c478bd9Sstevel@tonic-gate 		*jac = 0;
24797c478bd9Sstevel@tonic-gate 		return (BIG_OK);
24807c478bd9Sstevel@tonic-gate 	}
24817c478bd9Sstevel@tonic-gate 
2482*b60f2a0bSfr41279 	if (nn->len > mm->len) {
2483*b60f2a0bSfr41279 		len = nn->len;
2484*b60f2a0bSfr41279 	} else {
2485*b60f2a0bSfr41279 		len = mm->len;
2486*b60f2a0bSfr41279 	}
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
2489*b60f2a0bSfr41279 	    t1value, arraysize(t1value))) != BIG_OK) {
24907c478bd9Sstevel@tonic-gate 		return (err);
2491*b60f2a0bSfr41279 	}
24927c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
2493*b60f2a0bSfr41279 	    t2value, arraysize(t2value))) != BIG_OK) {
24947c478bd9Sstevel@tonic-gate 		goto ret1;
2495*b60f2a0bSfr41279 	}
24967c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
2497*b60f2a0bSfr41279 	    t3value, arraysize(t3value))) != BIG_OK) {
24987c478bd9Sstevel@tonic-gate 		goto ret2;
2499*b60f2a0bSfr41279 	}
25007c478bd9Sstevel@tonic-gate 
25017c478bd9Sstevel@tonic-gate 	n = &t1;
25027c478bd9Sstevel@tonic-gate 	m = &t2;
25037c478bd9Sstevel@tonic-gate 	tmp2 = &t3;
25047c478bd9Sstevel@tonic-gate 
25057c478bd9Sstevel@tonic-gate 	(void) big_copy(n, nn);
25067c478bd9Sstevel@tonic-gate 	(void) big_copy(m, mm);
25077c478bd9Sstevel@tonic-gate 
25087c478bd9Sstevel@tonic-gate 	*jac = 1;
2509*b60f2a0bSfr41279 	while (big_cmp_abs(&big_One, m) != 0) {
25107c478bd9Sstevel@tonic-gate 		if (big_is_zero(n)) {
25117c478bd9Sstevel@tonic-gate 			*jac = 0;
25127c478bd9Sstevel@tonic-gate 			goto ret;
25137c478bd9Sstevel@tonic-gate 		}
25147c478bd9Sstevel@tonic-gate 		if ((m->value[0] & 1) == 0) {
25157c478bd9Sstevel@tonic-gate 			if (((n->value[0] & 7) == 3) ||
2516*b60f2a0bSfr41279 			    ((n->value[0] & 7) == 5))
2517*b60f2a0bSfr41279 				*jac = -*jac;
25187c478bd9Sstevel@tonic-gate 			(void) big_half_pos(m, m);
25197c478bd9Sstevel@tonic-gate 		} else if ((n->value[0] & 1) == 0) {
25207c478bd9Sstevel@tonic-gate 			if (((m->value[0] & 7) == 3) ||
2521*b60f2a0bSfr41279 			    ((m->value[0] & 7) == 5))
2522*b60f2a0bSfr41279 				*jac = -*jac;
25237c478bd9Sstevel@tonic-gate 			(void) big_half_pos(n, n);
25247c478bd9Sstevel@tonic-gate 		} else {
25257c478bd9Sstevel@tonic-gate 			if (((m->value[0] & 3) == 3) &&
25267c478bd9Sstevel@tonic-gate 			    ((n->value[0] & 3) == 3)) {
25277c478bd9Sstevel@tonic-gate 				*jac = -*jac;
25287c478bd9Sstevel@tonic-gate 			}
2529*b60f2a0bSfr41279 			if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK) {
25307c478bd9Sstevel@tonic-gate 				goto ret;
2531*b60f2a0bSfr41279 			}
25327c478bd9Sstevel@tonic-gate 			t = tmp2;
25337c478bd9Sstevel@tonic-gate 			tmp2 = m;
25347c478bd9Sstevel@tonic-gate 			m = n;
25357c478bd9Sstevel@tonic-gate 			n = t;
25367c478bd9Sstevel@tonic-gate 		}
25377c478bd9Sstevel@tonic-gate 	}
25387c478bd9Sstevel@tonic-gate 	err = BIG_OK;
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate ret:
25417c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
25427c478bd9Sstevel@tonic-gate ret2:
25437c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
25447c478bd9Sstevel@tonic-gate ret1:
25457c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 	return (err);
25487c478bd9Sstevel@tonic-gate }
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate 
25517c478bd9Sstevel@tonic-gate BIG_ERR_CODE
25527c478bd9Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n)
25537c478bd9Sstevel@tonic-gate {
25547c478bd9Sstevel@tonic-gate 	int		m, w, i;
2555*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	bit;
25567c478bd9Sstevel@tonic-gate 	BIGNUM		ki, tmp, tmp2;
2557*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	kivalue[BIGTMPSIZE];
2558*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
2559*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmp2value[BIGTMPSIZE];
25607c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
25617c478bd9Sstevel@tonic-gate 
2562*b60f2a0bSfr41279 	if (big_cmp_abs(k, &big_One) == 0) {
25637c478bd9Sstevel@tonic-gate 		(void) big_copy(Lk, p);
2564*b60f2a0bSfr41279 		(void) big_copy(Lkminus1, &big_Two);
25657c478bd9Sstevel@tonic-gate 		return (BIG_OK);
25667c478bd9Sstevel@tonic-gate 	}
25677c478bd9Sstevel@tonic-gate 
25687c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&ki, k->len + 1,
25697c478bd9Sstevel@tonic-gate 	    kivalue, arraysize(kivalue))) != BIG_OK)
25707c478bd9Sstevel@tonic-gate 		return (err);
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len +1,
25737c478bd9Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
25747c478bd9Sstevel@tonic-gate 		goto ret1;
25757c478bd9Sstevel@tonic-gate 
25767c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, n->len,
25777c478bd9Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
25787c478bd9Sstevel@tonic-gate 		goto ret2;
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate 	m = big_numbits(k);
2581*b60f2a0bSfr41279 	ki.len = (m - 1) / BIG_CHUNK_SIZE + 1;
2582*b60f2a0bSfr41279 	w = (m - 1) / BIG_CHUNK_SIZE;
2583*b60f2a0bSfr41279 	bit = (BIG_CHUNK_TYPE)1 << ((m - 1) % BIG_CHUNK_SIZE);
2584*b60f2a0bSfr41279 	for (i = 0; i < ki.len; i++) {
2585*b60f2a0bSfr41279 		ki.value[i] = 0;
2586*b60f2a0bSfr41279 	}
25877c478bd9Sstevel@tonic-gate 	ki.value[ki.len - 1] = bit;
2588*b60f2a0bSfr41279 	if (big_cmp_abs(k, &ki) != 0) {
25897c478bd9Sstevel@tonic-gate 		(void) big_double(&ki, &ki);
2590*b60f2a0bSfr41279 	}
25917c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(&ki, &ki, k);
25927c478bd9Sstevel@tonic-gate 
25937c478bd9Sstevel@tonic-gate 	(void) big_copy(Lk, p);
2594*b60f2a0bSfr41279 	(void) big_copy(Lkminus1, &big_Two);
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate 	for (i = 0; i < m; i++) {
2597*b60f2a0bSfr41279 		if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK) {
25987c478bd9Sstevel@tonic-gate 			goto ret;
2599*b60f2a0bSfr41279 		}
26007c478bd9Sstevel@tonic-gate 		(void) big_add_abs(&tmp, &tmp, n);
26017c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(&tmp, &tmp, p);
2602*b60f2a0bSfr41279 		if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK) {
26037c478bd9Sstevel@tonic-gate 			goto ret;
2604*b60f2a0bSfr41279 		}
26057c478bd9Sstevel@tonic-gate 		if ((ki.value[w] & bit) != 0) {
26067c478bd9Sstevel@tonic-gate 			if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) !=
2607*b60f2a0bSfr41279 			    BIG_OK) {
26087c478bd9Sstevel@tonic-gate 				goto ret;
2609*b60f2a0bSfr41279 			}
26107c478bd9Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
2611*b60f2a0bSfr41279 			(void) big_sub_pos(&tmp, &tmp, &big_Two);
26127c478bd9Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) !=
2613*b60f2a0bSfr41279 			    BIG_OK) {
26147c478bd9Sstevel@tonic-gate 				goto ret;
2615*b60f2a0bSfr41279 			}
26167c478bd9Sstevel@tonic-gate 			(void) big_copy(Lk, &tmp2);
26177c478bd9Sstevel@tonic-gate 		} else {
2618*b60f2a0bSfr41279 			if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK) {
26197c478bd9Sstevel@tonic-gate 				goto ret;
2620*b60f2a0bSfr41279 			}
26217c478bd9Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
2622*b60f2a0bSfr41279 			(void) big_sub_pos(&tmp, &tmp, &big_Two);
2623*b60f2a0bSfr41279 			if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK) {
26247c478bd9Sstevel@tonic-gate 				goto ret;
2625*b60f2a0bSfr41279 			}
26267c478bd9Sstevel@tonic-gate 			(void) big_copy(Lkminus1, &tmp2);
26277c478bd9Sstevel@tonic-gate 		}
26287c478bd9Sstevel@tonic-gate 		bit = bit >> 1;
26297c478bd9Sstevel@tonic-gate 		if (bit == 0) {
2630*b60f2a0bSfr41279 			bit = BIG_CHUNK_HIGHBIT;
26317c478bd9Sstevel@tonic-gate 			w--;
26327c478bd9Sstevel@tonic-gate 		}
26337c478bd9Sstevel@tonic-gate 	}
26347c478bd9Sstevel@tonic-gate 
26357c478bd9Sstevel@tonic-gate 	err = BIG_OK;
26367c478bd9Sstevel@tonic-gate 
26377c478bd9Sstevel@tonic-gate ret:
26387c478bd9Sstevel@tonic-gate 	if (tmp2.malloced) big_finish(&tmp2);
26397c478bd9Sstevel@tonic-gate ret2:
26407c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
26417c478bd9Sstevel@tonic-gate ret1:
26427c478bd9Sstevel@tonic-gate 	if (ki.malloced) big_finish(&ki);
26437c478bd9Sstevel@tonic-gate 
26447c478bd9Sstevel@tonic-gate 	return (err);
26457c478bd9Sstevel@tonic-gate }
26467c478bd9Sstevel@tonic-gate 
26477c478bd9Sstevel@tonic-gate 
26487c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2649*b60f2a0bSfr41279 big_isprime_pos_ext(BIGNUM *n, big_modexp_ncp_info_t *info)
26507c478bd9Sstevel@tonic-gate {
26517c478bd9Sstevel@tonic-gate 	BIGNUM		o, nminus1, tmp, Lkminus1, Lk;
2652*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	ovalue[BIGTMPSIZE];
2653*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	nminus1value[BIGTMPSIZE];
2654*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
2655*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	Lkminus1value[BIGTMPSIZE];
2656*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	Lkvalue[BIGTMPSIZE];
26577c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
26587c478bd9Sstevel@tonic-gate 	int		e, i, jac;
26597c478bd9Sstevel@tonic-gate 
2660*b60f2a0bSfr41279 	if (big_cmp_abs(n, &big_One) == 0) {
26617c478bd9Sstevel@tonic-gate 		return (BIG_FALSE);
2662*b60f2a0bSfr41279 	}
2663*b60f2a0bSfr41279 	if (big_cmp_abs(n, &big_Two) == 0) {
26647c478bd9Sstevel@tonic-gate 		return (BIG_TRUE);
2665*b60f2a0bSfr41279 	}
2666*b60f2a0bSfr41279 	if ((n->value[0] & 1) == 0) {
26677c478bd9Sstevel@tonic-gate 		return (BIG_FALSE);
2668*b60f2a0bSfr41279 	}
26697c478bd9Sstevel@tonic-gate 
2670*b60f2a0bSfr41279 	if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) !=
2671*b60f2a0bSfr41279 	    BIG_OK) {
26727c478bd9Sstevel@tonic-gate 		return (err);
2673*b60f2a0bSfr41279 	}
26747c478bd9Sstevel@tonic-gate 
26757c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&nminus1, n->len,
2676*b60f2a0bSfr41279 	    nminus1value, arraysize(nminus1value))) != BIG_OK) {
26777c478bd9Sstevel@tonic-gate 		goto ret1;
2678*b60f2a0bSfr41279 	}
26797c478bd9Sstevel@tonic-gate 
26807c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len,
2681*b60f2a0bSfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
26827c478bd9Sstevel@tonic-gate 		goto ret2;
2683*b60f2a0bSfr41279 	}
26847c478bd9Sstevel@tonic-gate 
26857c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&Lkminus1, n->len,
2686*b60f2a0bSfr41279 	    Lkminus1value, arraysize(Lkminus1value))) != BIG_OK) {
26877c478bd9Sstevel@tonic-gate 		goto ret3;
2688*b60f2a0bSfr41279 	}
26897c478bd9Sstevel@tonic-gate 
26907c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&Lk, n->len,
2691*b60f2a0bSfr41279 	    Lkvalue, arraysize(Lkvalue))) != BIG_OK) {
26927c478bd9Sstevel@tonic-gate 		goto ret4;
2693*b60f2a0bSfr41279 	}
26947c478bd9Sstevel@tonic-gate 
2695*b60f2a0bSfr41279 	(void) big_sub_pos(&o, n, &big_One); 	/* cannot fail */
26967c478bd9Sstevel@tonic-gate 	(void) big_copy(&nminus1, &o);		/* cannot fail */
26977c478bd9Sstevel@tonic-gate 	e = 0;
26987c478bd9Sstevel@tonic-gate 	while ((o.value[0] & 1) == 0) {
26997c478bd9Sstevel@tonic-gate 		e++;
27007c478bd9Sstevel@tonic-gate 		(void) big_half_pos(&o, &o);  /* cannot fail */
27017c478bd9Sstevel@tonic-gate 	}
2702*b60f2a0bSfr41279 	if ((err = big_modexp_ext(&tmp, &big_Two, &o, n, NULL, info)) !=
2703*b60f2a0bSfr41279 	    BIG_OK) {
27047c478bd9Sstevel@tonic-gate 		goto ret;
2705*b60f2a0bSfr41279 	}
2706*b60f2a0bSfr41279 
27077c478bd9Sstevel@tonic-gate 	i = 0;
27087c478bd9Sstevel@tonic-gate 	while ((i < e) &&
2709*b60f2a0bSfr41279 	    (big_cmp_abs(&tmp, &big_One) != 0) &&
27107c478bd9Sstevel@tonic-gate 	    (big_cmp_abs(&tmp, &nminus1) != 0)) {
2711*b60f2a0bSfr41279 		if ((err =
2712*b60f2a0bSfr41279 		    big_modexp_ext(&tmp, &tmp, &big_Two, n, NULL, info)) !=
2713*b60f2a0bSfr41279 		    BIG_OK)
27147c478bd9Sstevel@tonic-gate 			goto ret;
27157c478bd9Sstevel@tonic-gate 		i++;
27167c478bd9Sstevel@tonic-gate 	}
2717*b60f2a0bSfr41279 
27187c478bd9Sstevel@tonic-gate 	if (!((big_cmp_abs(&tmp, &nminus1) == 0) ||
2719*b60f2a0bSfr41279 	    ((i == 0) && (big_cmp_abs(&tmp, &big_One) == 0)))) {
27207c478bd9Sstevel@tonic-gate 		err = BIG_FALSE;
27217c478bd9Sstevel@tonic-gate 		goto ret;
27227c478bd9Sstevel@tonic-gate 	}
27237c478bd9Sstevel@tonic-gate 
2724*b60f2a0bSfr41279 	if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK) {
27257c478bd9Sstevel@tonic-gate 		goto ret;
2726*b60f2a0bSfr41279 	}
2727*b60f2a0bSfr41279 
2728*b60f2a0bSfr41279 	if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK) {
27297c478bd9Sstevel@tonic-gate 		goto ret;
2730*b60f2a0bSfr41279 	}
27317c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(&tmp, n) == 0) {
27327c478bd9Sstevel@tonic-gate 		err = BIG_FALSE;
27337c478bd9Sstevel@tonic-gate 		goto ret;
27347c478bd9Sstevel@tonic-gate 	}
27357c478bd9Sstevel@tonic-gate 
2736*b60f2a0bSfr41279 	(void) big_copy(&o, &big_Two);
27377c478bd9Sstevel@tonic-gate 	do {
2738*b60f2a0bSfr41279 		(void) big_add_abs(&o, &o, &big_One);
2739*b60f2a0bSfr41279 		if ((err = big_mul(&tmp, &o, &o)) != BIG_OK) {
27407c478bd9Sstevel@tonic-gate 			goto ret;
2741*b60f2a0bSfr41279 		}
2742*b60f2a0bSfr41279 		(void) big_sub_pos(&tmp, &tmp, &big_Four);
2743*b60f2a0bSfr41279 		if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK) {
27447c478bd9Sstevel@tonic-gate 			goto ret;
2745*b60f2a0bSfr41279 		}
27467c478bd9Sstevel@tonic-gate 	} while (jac != -1);
27477c478bd9Sstevel@tonic-gate 
2748*b60f2a0bSfr41279 	(void) big_add_abs(&tmp, n, &big_One);
2749*b60f2a0bSfr41279 	if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK) {
27507c478bd9Sstevel@tonic-gate 		goto ret;
2751*b60f2a0bSfr41279 	}
2752*b60f2a0bSfr41279 
2753*b60f2a0bSfr41279 	if ((big_cmp_abs(&Lkminus1, &o) == 0) &&
2754*b60f2a0bSfr41279 	    (big_cmp_abs(&Lk, &big_Two) == 0)) {
27557c478bd9Sstevel@tonic-gate 		err = BIG_TRUE;
2756*b60f2a0bSfr41279 	} else {
2757*b60f2a0bSfr41279 		err = BIG_FALSE;
2758*b60f2a0bSfr41279 	}
27597c478bd9Sstevel@tonic-gate 
27607c478bd9Sstevel@tonic-gate ret:
27617c478bd9Sstevel@tonic-gate 	if (Lk.malloced) big_finish(&Lk);
27627c478bd9Sstevel@tonic-gate ret4:
27637c478bd9Sstevel@tonic-gate 	if (Lkminus1.malloced) big_finish(&Lkminus1);
27647c478bd9Sstevel@tonic-gate ret3:
27657c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
27667c478bd9Sstevel@tonic-gate ret2:
27677c478bd9Sstevel@tonic-gate 	if (nminus1.malloced) big_finish(&nminus1);
27687c478bd9Sstevel@tonic-gate ret1:
27697c478bd9Sstevel@tonic-gate 	if (o.malloced) big_finish(&o);
27707c478bd9Sstevel@tonic-gate 
27717c478bd9Sstevel@tonic-gate 	return (err);
27727c478bd9Sstevel@tonic-gate }
27737c478bd9Sstevel@tonic-gate 
27747c478bd9Sstevel@tonic-gate 
2775*b60f2a0bSfr41279 BIG_ERR_CODE
2776*b60f2a0bSfr41279 big_isprime_pos(BIGNUM *n)
2777*b60f2a0bSfr41279 {
2778*b60f2a0bSfr41279 	return (big_isprime_pos_ext(n, NULL));
2779*b60f2a0bSfr41279 }
2780*b60f2a0bSfr41279 
2781*b60f2a0bSfr41279 
27827c478bd9Sstevel@tonic-gate #define	SIEVESIZE 1000
27837c478bd9Sstevel@tonic-gate 
27847c478bd9Sstevel@tonic-gate uint32_t smallprimes[] =
27857c478bd9Sstevel@tonic-gate {
27867c478bd9Sstevel@tonic-gate 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
27877c478bd9Sstevel@tonic-gate 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97
27887c478bd9Sstevel@tonic-gate };
27897c478bd9Sstevel@tonic-gate 
27907c478bd9Sstevel@tonic-gate 
27917c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2792*b60f2a0bSfr41279 big_nextprime_pos_ext(BIGNUM *result, BIGNUM *n, big_modexp_ncp_info_t *info)
27937c478bd9Sstevel@tonic-gate {
27947c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
27957c478bd9Sstevel@tonic-gate 	int		sieve[SIEVESIZE];
27967c478bd9Sstevel@tonic-gate 	int		i;
27977c478bd9Sstevel@tonic-gate 	uint32_t	off, p;
27987c478bd9Sstevel@tonic-gate 
2799*b60f2a0bSfr41279 	if ((err = big_copy(result, n)) != BIG_OK) {
28007c478bd9Sstevel@tonic-gate 		return (err);
2801*b60f2a0bSfr41279 	}
28027c478bd9Sstevel@tonic-gate 	result->value[0] |= 1;
2803f56c1286Srobinson 	/* CONSTCOND */
28047c478bd9Sstevel@tonic-gate 	while (1) {
28057c478bd9Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0;
28067c478bd9Sstevel@tonic-gate 		for (i = 0;
2807*b60f2a0bSfr41279 		    i < sizeof (smallprimes) / sizeof (smallprimes[0]); i++) {
28087c478bd9Sstevel@tonic-gate 			p = smallprimes[i];
2809*b60f2a0bSfr41279 			off = big_modhalf_pos(result, p);
28107c478bd9Sstevel@tonic-gate 			off = p - off;
2811*b60f2a0bSfr41279 			if ((off % 2) == 1) {
2812*b60f2a0bSfr41279 				off = off + p;
2813*b60f2a0bSfr41279 			}
28147c478bd9Sstevel@tonic-gate 			off = off / 2;
28157c478bd9Sstevel@tonic-gate 			while (off < SIEVESIZE) {
28167c478bd9Sstevel@tonic-gate 				sieve[off] = 1;
28177c478bd9Sstevel@tonic-gate 				off = off + p;
28187c478bd9Sstevel@tonic-gate 			}
28197c478bd9Sstevel@tonic-gate 		}
28207c478bd9Sstevel@tonic-gate 
28217c478bd9Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) {
28227c478bd9Sstevel@tonic-gate 			if (sieve[i] == 0) {
2823*b60f2a0bSfr41279 				err = big_isprime_pos_ext(result, info);
28247c478bd9Sstevel@tonic-gate 				if (err != BIG_FALSE) {
2825*b60f2a0bSfr41279 					if (err != BIG_TRUE) {
28267c478bd9Sstevel@tonic-gate 						return (err);
2827*b60f2a0bSfr41279 					} else {
2828*b60f2a0bSfr41279 						goto out;
2829*b60f2a0bSfr41279 					}
28307c478bd9Sstevel@tonic-gate 				}
28317c478bd9Sstevel@tonic-gate 
28327c478bd9Sstevel@tonic-gate 			}
2833*b60f2a0bSfr41279 			if ((err = big_add_abs(result, result, &big_Two)) !=
2834*b60f2a0bSfr41279 			    BIG_OK) {
28357c478bd9Sstevel@tonic-gate 				return (err);
28367c478bd9Sstevel@tonic-gate 			}
28377c478bd9Sstevel@tonic-gate 		}
2838*b60f2a0bSfr41279 	}
2839*b60f2a0bSfr41279 
2840*b60f2a0bSfr41279 out:
2841*b60f2a0bSfr41279 	return (BIG_OK);
2842*b60f2a0bSfr41279 }
2843*b60f2a0bSfr41279 
2844*b60f2a0bSfr41279 
2845*b60f2a0bSfr41279 BIG_ERR_CODE
2846*b60f2a0bSfr41279 big_nextprime_pos(BIGNUM *result, BIGNUM *n)
2847*b60f2a0bSfr41279 {
2848*b60f2a0bSfr41279 	return (big_nextprime_pos_ext(result, n, NULL));
28497c478bd9Sstevel@tonic-gate }
28507c478bd9Sstevel@tonic-gate 
28517c478bd9Sstevel@tonic-gate 
28527c478bd9Sstevel@tonic-gate BIG_ERR_CODE
28537c478bd9Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n)
28547c478bd9Sstevel@tonic-gate {
28557c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
28567c478bd9Sstevel@tonic-gate 
28577c478bd9Sstevel@tonic-gate 
28587c478bd9Sstevel@tonic-gate 	if ((err = big_copy(result, n)) != BIG_OK)
28597c478bd9Sstevel@tonic-gate 		return (err);
28607c478bd9Sstevel@tonic-gate 	result->value[0] |= 1;
2861*b60f2a0bSfr41279 	while ((err = big_isprime_pos_ext(result, NULL)) != BIG_TRUE) {
28627c478bd9Sstevel@tonic-gate 		if (err != BIG_FALSE)
28637c478bd9Sstevel@tonic-gate 			return (err);
2864*b60f2a0bSfr41279 		if ((err = big_add_abs(result, result, &big_Two)) != BIG_OK)
28657c478bd9Sstevel@tonic-gate 			return (err);
28667c478bd9Sstevel@tonic-gate 	}
28677c478bd9Sstevel@tonic-gate 	return (BIG_OK);
28687c478bd9Sstevel@tonic-gate }
28697c478bd9Sstevel@tonic-gate 
28707c478bd9Sstevel@tonic-gate 
28717c478bd9Sstevel@tonic-gate /*
28727c478bd9Sstevel@tonic-gate  * given m and e, computes the rest in the equation
28737c478bd9Sstevel@tonic-gate  * gcd(m, e) = cm * m + ce * e
28747c478bd9Sstevel@tonic-gate  */
28757c478bd9Sstevel@tonic-gate BIG_ERR_CODE
28767c478bd9Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e)
28777c478bd9Sstevel@tonic-gate {
2878*b60f2a0bSfr41279 	BIGNUM		*xi, *ri, *riminus1, *riminus2, *t;
2879*b60f2a0bSfr41279 	BIGNUM		*vmi, *vei, *vmiminus1, *veiminus1;
28807c478bd9Sstevel@tonic-gate 	BIGNUM		t1, t2, t3, t4, t5, t6, t7, t8, tmp;
2881*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t1value[BIGTMPSIZE];
2882*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t2value[BIGTMPSIZE];
2883*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t3value[BIGTMPSIZE];
2884*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t4value[BIGTMPSIZE];
2885*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t5value[BIGTMPSIZE];
2886*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t6value[BIGTMPSIZE];
2887*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t7value[BIGTMPSIZE];
2888*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	t8value[BIGTMPSIZE];
2889*b60f2a0bSfr41279 	BIG_CHUNK_TYPE	tmpvalue[BIGTMPSIZE];
28907c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE	err;
28917c478bd9Sstevel@tonic-gate 	int		len;
28927c478bd9Sstevel@tonic-gate 
2893*b60f2a0bSfr41279 	if (big_cmp_abs(m, e) >= 0) {
2894*b60f2a0bSfr41279 		len = m->len;
2895*b60f2a0bSfr41279 	} else {
2896*b60f2a0bSfr41279 		len = e->len;
2897*b60f2a0bSfr41279 	}
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
2900*b60f2a0bSfr41279 	    t1value, arraysize(t1value))) != BIG_OK) {
29017c478bd9Sstevel@tonic-gate 		return (err);
2902*b60f2a0bSfr41279 	}
29037c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
2904*b60f2a0bSfr41279 	    t2value, arraysize(t2value))) != BIG_OK) {
29057c478bd9Sstevel@tonic-gate 		goto ret1;
2906*b60f2a0bSfr41279 	}
29077c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
2908*b60f2a0bSfr41279 	    t3value, arraysize(t3value))) != BIG_OK) {
29097c478bd9Sstevel@tonic-gate 		goto ret2;
2910*b60f2a0bSfr41279 	}
29117c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t4, len,
2912*b60f2a0bSfr41279 	    t4value, arraysize(t3value))) != BIG_OK) {
29137c478bd9Sstevel@tonic-gate 		goto ret3;
2914*b60f2a0bSfr41279 	}
29157c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t5, len,
2916*b60f2a0bSfr41279 	    t5value, arraysize(t5value))) != BIG_OK) {
29177c478bd9Sstevel@tonic-gate 		goto ret4;
2918*b60f2a0bSfr41279 	}
29197c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t6, len,
2920*b60f2a0bSfr41279 	    t6value, arraysize(t6value))) != BIG_OK) {
29217c478bd9Sstevel@tonic-gate 		goto ret5;
2922*b60f2a0bSfr41279 	}
29237c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t7, len,
2924*b60f2a0bSfr41279 	    t7value, arraysize(t7value))) != BIG_OK) {
29257c478bd9Sstevel@tonic-gate 		goto ret6;
2926*b60f2a0bSfr41279 	}
29277c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t8, len,
2928*b60f2a0bSfr41279 	    t8value, arraysize(t8value))) != BIG_OK) {
29297c478bd9Sstevel@tonic-gate 		goto ret7;
2930*b60f2a0bSfr41279 	}
29317c478bd9Sstevel@tonic-gate 
29327c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * len,
2933*b60f2a0bSfr41279 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK) {
29347c478bd9Sstevel@tonic-gate 		goto ret8;
2935*b60f2a0bSfr41279 	}
29367c478bd9Sstevel@tonic-gate 
29377c478bd9Sstevel@tonic-gate 	ri = &t1;
29387c478bd9Sstevel@tonic-gate 	ri->value[0] = 1;
29397c478bd9Sstevel@tonic-gate 	ri->len = 1;
29407c478bd9Sstevel@tonic-gate 	xi = &t2;
29417c478bd9Sstevel@tonic-gate 	riminus1 = &t3;
29427c478bd9Sstevel@tonic-gate 	riminus2 = &t4;
29437c478bd9Sstevel@tonic-gate 	vmi = &t5;
29447c478bd9Sstevel@tonic-gate 	vei = &t6;
29457c478bd9Sstevel@tonic-gate 	vmiminus1 = &t7;
29467c478bd9Sstevel@tonic-gate 	veiminus1 = &t8;
29477c478bd9Sstevel@tonic-gate 
2948*b60f2a0bSfr41279 	(void) big_copy(vmiminus1, &big_One);
2949*b60f2a0bSfr41279 	(void) big_copy(vmi, &big_One);
2950*b60f2a0bSfr41279 	(void) big_copy(veiminus1, &big_One);
2951*b60f2a0bSfr41279 	(void) big_copy(xi, &big_One);
29527c478bd9Sstevel@tonic-gate 	vei->len = 1;
29537c478bd9Sstevel@tonic-gate 	vei->value[0] = 0;
29547c478bd9Sstevel@tonic-gate 
29557c478bd9Sstevel@tonic-gate 	(void) big_copy(riminus1, m);
29567c478bd9Sstevel@tonic-gate 	(void) big_copy(ri, e);
29577c478bd9Sstevel@tonic-gate 
29587c478bd9Sstevel@tonic-gate 	while (!big_is_zero(ri)) {
29597c478bd9Sstevel@tonic-gate 		t = riminus2;
29607c478bd9Sstevel@tonic-gate 		riminus2 = riminus1;
29617c478bd9Sstevel@tonic-gate 		riminus1 = ri;
29627c478bd9Sstevel@tonic-gate 		ri = t;
2963*b60f2a0bSfr41279 		if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK) {
29647c478bd9Sstevel@tonic-gate 			goto ret;
2965*b60f2a0bSfr41279 		}
2966*b60f2a0bSfr41279 		if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK) {
29677c478bd9Sstevel@tonic-gate 			goto ret;
2968*b60f2a0bSfr41279 		}
29697c478bd9Sstevel@tonic-gate 		t = vmiminus1;
29707c478bd9Sstevel@tonic-gate 		vmiminus1 = vmi;
29717c478bd9Sstevel@tonic-gate 		vmi = t;
2972*b60f2a0bSfr41279 		if ((err = big_mul(&tmp, vei, xi)) != BIG_OK) {
29737c478bd9Sstevel@tonic-gate 			goto ret;
2974*b60f2a0bSfr41279 		}
2975*b60f2a0bSfr41279 		if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK) {
29767c478bd9Sstevel@tonic-gate 			goto ret;
2977*b60f2a0bSfr41279 		}
29787c478bd9Sstevel@tonic-gate 		t = veiminus1;
29797c478bd9Sstevel@tonic-gate 		veiminus1 = vei;
29807c478bd9Sstevel@tonic-gate 		vei = t;
2981*b60f2a0bSfr41279 		if ((err = big_div_pos(xi, ri, riminus2, riminus1)) !=
2982*b60f2a0bSfr41279 		    BIG_OK) {
29837c478bd9Sstevel@tonic-gate 			goto ret;
29847c478bd9Sstevel@tonic-gate 		}
2985*b60f2a0bSfr41279 	}
2986*b60f2a0bSfr41279 	if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK)) {
29877c478bd9Sstevel@tonic-gate 		goto ret;
2988*b60f2a0bSfr41279 	}
2989*b60f2a0bSfr41279 	if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK)) {
29907c478bd9Sstevel@tonic-gate 		goto ret;
2991*b60f2a0bSfr41279 	}
2992*b60f2a0bSfr41279 	if (ce != NULL) {
29937c478bd9Sstevel@tonic-gate 		err = big_copy(ce, vei);
2994*b60f2a0bSfr41279 	}
29957c478bd9Sstevel@tonic-gate ret:
29967c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
29977c478bd9Sstevel@tonic-gate ret8:
29987c478bd9Sstevel@tonic-gate 	if (t8.malloced) big_finish(&t8);
29997c478bd9Sstevel@tonic-gate ret7:
30007c478bd9Sstevel@tonic-gate 	if (t7.malloced) big_finish(&t7);
30017c478bd9Sstevel@tonic-gate ret6:
30027c478bd9Sstevel@tonic-gate 	if (t6.malloced) big_finish(&t6);
30037c478bd9Sstevel@tonic-gate ret5:
30047c478bd9Sstevel@tonic-gate 	if (t5.malloced) big_finish(&t5);
30057c478bd9Sstevel@tonic-gate ret4:
30067c478bd9Sstevel@tonic-gate 	if (t4.malloced) big_finish(&t4);
30077c478bd9Sstevel@tonic-gate ret3:
30087c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
30097c478bd9Sstevel@tonic-gate ret2:
30107c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
30117c478bd9Sstevel@tonic-gate ret1:
30127c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
30137c478bd9Sstevel@tonic-gate 
30147c478bd9Sstevel@tonic-gate 	return (err);
30157c478bd9Sstevel@tonic-gate }
3016