xref: /titanic_50/usr/src/common/bignum/bignumimpl.c (revision f56c1286e5113aa46bd6e723da14d30c123153f2)
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
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #define	big_div_pos_fast big_div_pos
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include "bignum.h"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * Configuration guide
357c478bd9Sstevel@tonic-gate  * -------------------
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * There are 4 preprocessor symbols used to configure the bignum
387c478bd9Sstevel@tonic-gate  * implementation.  This file contains no logic to configure based on
397c478bd9Sstevel@tonic-gate  * processor; we leave that to the Makefiles to specify.
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * USE_FLOATING_POINT
427c478bd9Sstevel@tonic-gate  *   Meaning: There is support for a fast floating-point implementation of
437c478bd9Sstevel@tonic-gate  *   Montgomery multiply.
447c478bd9Sstevel@tonic-gate  *
457c478bd9Sstevel@tonic-gate  * PSR_MUL
467c478bd9Sstevel@tonic-gate  *   Meaning: There are processor-specific versions of the low level
477c478bd9Sstevel@tonic-gate  *   functions to implement big_mul.  Those functions are: big_mul_set_vec,
487c478bd9Sstevel@tonic-gate  *   big_mul_add_vec, big_mul_vec, and big_sqr_vec.  PSR_MUL implies support
497c478bd9Sstevel@tonic-gate  *   for all 4 functions.  You cannot pick and choose which subset of these
507c478bd9Sstevel@tonic-gate  *   functions to support; that would lead to a rat's nest of #ifdefs.
517c478bd9Sstevel@tonic-gate  *
527c478bd9Sstevel@tonic-gate  * HWCAP
537c478bd9Sstevel@tonic-gate  *   Meaning: Call multiply support functions through a function pointer.
547c478bd9Sstevel@tonic-gate  *   On x86, there are multiple implementations for differnt hardware
557c478bd9Sstevel@tonic-gate  *   capabilities, such as MMX, SSE2, etc.  Tests are made at run-time, when
567c478bd9Sstevel@tonic-gate  *   a function is first used.  So, the support functions are called through
577c478bd9Sstevel@tonic-gate  *   a function pointer.  There is no need for that on Sparc, because there
587c478bd9Sstevel@tonic-gate  *   is only one implementation; support functions are called directly.
597c478bd9Sstevel@tonic-gate  *   Later, if there were some new VIS instruction, or something, and a
607c478bd9Sstevel@tonic-gate  *   run-time test were needed, rather than variant kernel modules and
617c478bd9Sstevel@tonic-gate  *   libraries, then HWCAP would be defined for Sparc, as well.
627c478bd9Sstevel@tonic-gate  *
637c478bd9Sstevel@tonic-gate  * UMUL64
647c478bd9Sstevel@tonic-gate  *   Meaning: It is safe to use generic C code that assumes the existence
657c478bd9Sstevel@tonic-gate  *   of a 32 x 32 --> 64 bit unsigned multiply.  If this is not defined,
667c478bd9Sstevel@tonic-gate  *   then the generic code for big_mul_add_vec() must necessarily be very slow,
677c478bd9Sstevel@tonic-gate  *   because it must fall back to using 16 x 16 --> 32 bit multiplication.
687c478bd9Sstevel@tonic-gate  *
697c478bd9Sstevel@tonic-gate  */
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate #ifdef	_KERNEL
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate #include <sys/types.h>
757c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
767c478bd9Sstevel@tonic-gate #include <sys/param.h>
777c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate #define	big_malloc(size)	kmem_alloc(size, KM_NOSLEEP)
807c478bd9Sstevel@tonic-gate #define	big_free(ptr, size)	kmem_free(ptr, size)
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate void *
837c478bd9Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize)
847c478bd9Sstevel@tonic-gate {
857c478bd9Sstevel@tonic-gate 	void *rv;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	rv = kmem_alloc(newsize, KM_NOSLEEP);
887c478bd9Sstevel@tonic-gate 	if (rv != NULL)
897c478bd9Sstevel@tonic-gate 		bcopy(from, rv, oldsize);
907c478bd9Sstevel@tonic-gate 	kmem_free(from, oldsize);
917c478bd9Sstevel@tonic-gate 	return (rv);
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate #else	/* _KERNEL */
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate #include <stdlib.h>
977c478bd9Sstevel@tonic-gate #include <stdio.h>
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate #ifndef MALLOC_DEBUG
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate #define	big_malloc(size)	malloc(size)
1027c478bd9Sstevel@tonic-gate #define	big_free(ptr, size)	free(ptr)
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate #else
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate void
1077c478bd9Sstevel@tonic-gate big_free(void *ptr, size_t size)
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate 	printf("freed %d bytes at %p\n", size, ptr);
1107c478bd9Sstevel@tonic-gate 	free(ptr);
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate void *
1147c478bd9Sstevel@tonic-gate big_malloc(size_t size)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate 	void *rv;
1177c478bd9Sstevel@tonic-gate 	rv = malloc(size);
1187c478bd9Sstevel@tonic-gate 	printf("malloced %d bytes, addr:%p\n", size, rv);
1197c478bd9Sstevel@tonic-gate 	return (rv);
1207c478bd9Sstevel@tonic-gate }
1217c478bd9Sstevel@tonic-gate #endif /* MALLOC_DEBUG */
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate #define	big_realloc(x, y, z) realloc((x), (z))
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate void
1267c478bd9Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a)
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	int i;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	(void) printf("\n%s\n%d\n", aname, a->sign*a->len);
1317c478bd9Sstevel@tonic-gate 	for (i = a->len - 1; i >= 0; i--) {
1327c478bd9Sstevel@tonic-gate 		(void) printf("%08x ", a->value[i]);
1337c478bd9Sstevel@tonic-gate 		if ((i % 8 == 0) && (i != 0))
1347c478bd9Sstevel@tonic-gate 		    (void) printf("\n");
1357c478bd9Sstevel@tonic-gate 	}
1367c478bd9Sstevel@tonic-gate 	(void) printf("\n");
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate #endif	/* _KERNEL */
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate /* size in 32-bit words */
1437c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1447c478bd9Sstevel@tonic-gate big_init(BIGNUM *number, int size)
1457c478bd9Sstevel@tonic-gate {
1467c478bd9Sstevel@tonic-gate 	number->value = big_malloc(sizeof (uint32_t) * size);
1477c478bd9Sstevel@tonic-gate 	if (number->value == NULL) {
1487c478bd9Sstevel@tonic-gate 		return (BIG_NO_MEM);
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 	number->size = size;
1517c478bd9Sstevel@tonic-gate 	number->len = 0;
1527c478bd9Sstevel@tonic-gate 	number->sign = 1;
1537c478bd9Sstevel@tonic-gate 	number->malloced = 1;
1547c478bd9Sstevel@tonic-gate 	return (BIG_OK);
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate /* size in 32-bit words */
1587c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1597c478bd9Sstevel@tonic-gate big_init1(BIGNUM *number, int size, uint32_t *buf, int bufsize)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (size > bufsize)) {
1627c478bd9Sstevel@tonic-gate 		number->value = big_malloc(sizeof (uint32_t) * size);
1637c478bd9Sstevel@tonic-gate 		if (number->value == NULL) {
1647c478bd9Sstevel@tonic-gate 			return (BIG_NO_MEM);
1657c478bd9Sstevel@tonic-gate 		}
1667c478bd9Sstevel@tonic-gate 		number->size = size;
1677c478bd9Sstevel@tonic-gate 		number->malloced = 1;
1687c478bd9Sstevel@tonic-gate 	} else {
1697c478bd9Sstevel@tonic-gate 		number->value = buf;
1707c478bd9Sstevel@tonic-gate 		number->size = bufsize;
1717c478bd9Sstevel@tonic-gate 		number->malloced = 0;
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 		number->len = 0;
1747c478bd9Sstevel@tonic-gate 		number->sign = 1;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	return (BIG_OK);
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate void
1807c478bd9Sstevel@tonic-gate big_finish(BIGNUM *number)
1817c478bd9Sstevel@tonic-gate {
1827c478bd9Sstevel@tonic-gate 	if (number->malloced == 1) {
1837c478bd9Sstevel@tonic-gate 		big_free(number->value, sizeof (uint32_t) * number->size);
1847c478bd9Sstevel@tonic-gate 		number->malloced = 0;
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  *  bn->size should be at least (len + 3) / 4
1907c478bd9Sstevel@tonic-gate  * converts from byte-big-endian format to bignum format (words in
1917c478bd9Sstevel@tonic-gate  * little endian order, but bytes within the words big endian)
1927c478bd9Sstevel@tonic-gate  */
1937c478bd9Sstevel@tonic-gate void
1947c478bd9Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate 	int		i, j, offs;
1977c478bd9Sstevel@tonic-gate 	uint32_t	word;
1987c478bd9Sstevel@tonic-gate 	uchar_t		*knwordp;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate #ifdef	_LP64
2017c478bd9Sstevel@tonic-gate 	/* LINTED */
2027c478bd9Sstevel@tonic-gate 	offs = (uint32_t)len % sizeof (uint32_t);
2037c478bd9Sstevel@tonic-gate 	/* LINTED */
2047c478bd9Sstevel@tonic-gate 	bn->len = (uint32_t)len / sizeof (uint32_t);
2057c478bd9Sstevel@tonic-gate 	/* LINTED */
2067c478bd9Sstevel@tonic-gate 	for (i = 0; i < (uint32_t)len / sizeof (uint32_t); i++) {
2077c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
2087c478bd9Sstevel@tonic-gate 	offs = len % sizeof (uint32_t);
2097c478bd9Sstevel@tonic-gate 	bn->len = len / sizeof (uint32_t);
2107c478bd9Sstevel@tonic-gate 	for (i = 0; i < len / sizeof (uint32_t); i++) {
2117c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
2127c478bd9Sstevel@tonic-gate 		knwordp = &(kn[len - sizeof (uint32_t) * (i + 1)]);
2137c478bd9Sstevel@tonic-gate 		word = knwordp[0];
2147c478bd9Sstevel@tonic-gate 		for (j = 1; j < sizeof (uint32_t); j++) {
2157c478bd9Sstevel@tonic-gate 			word = (word << 8)+ knwordp[j];
2167c478bd9Sstevel@tonic-gate 		}
2177c478bd9Sstevel@tonic-gate 		bn->value[i] = word;
2187c478bd9Sstevel@tonic-gate 	}
2197c478bd9Sstevel@tonic-gate 	if (offs > 0) {
2207c478bd9Sstevel@tonic-gate 		word = kn[0];
2217c478bd9Sstevel@tonic-gate 		for (i = 1; i < offs; i++) word = (word << 8) + kn[i];
2227c478bd9Sstevel@tonic-gate 		bn->value[bn->len++] = word;
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 	while ((bn->len > 1) && (bn->value[bn->len-1] == 0)) {
2257c478bd9Sstevel@tonic-gate 		bn->len --;
2267c478bd9Sstevel@tonic-gate 	}
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate /*
2307c478bd9Sstevel@tonic-gate  * copies the least significant len bytes if
2317c478bd9Sstevel@tonic-gate  * len < bn->len * sizeof (uint32_t)
2327c478bd9Sstevel@tonic-gate  * converts from bignum format to byte-big-endian format.
2337c478bd9Sstevel@tonic-gate  * bignum format is words in little endian order,
2347c478bd9Sstevel@tonic-gate  * but bytes within words in native byte order.
2357c478bd9Sstevel@tonic-gate  */
2367c478bd9Sstevel@tonic-gate void
2377c478bd9Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len)
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate 	int		i, j, offs;
2407c478bd9Sstevel@tonic-gate 	uint32_t	word;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	if (len < sizeof (uint32_t) * bn->len) {
2437c478bd9Sstevel@tonic-gate #ifdef	_LP64
2447c478bd9Sstevel@tonic-gate 		/* LINTED */
2457c478bd9Sstevel@tonic-gate 		for (i = 0; i < (uint32_t)len / sizeof (uint32_t); i++) {
2467c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
2477c478bd9Sstevel@tonic-gate 		for (i = 0; i < len / sizeof (uint32_t); i++) {
2487c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
2497c478bd9Sstevel@tonic-gate 			word = bn->value[i];
2507c478bd9Sstevel@tonic-gate 			for (j = 0; j < sizeof (uint32_t); j++) {
2517c478bd9Sstevel@tonic-gate 				kn[len - sizeof (uint32_t) * i - j - 1] =
2527c478bd9Sstevel@tonic-gate 				    word & 0xff;
2537c478bd9Sstevel@tonic-gate 				word = word >> 8;
2547c478bd9Sstevel@tonic-gate 			}
2557c478bd9Sstevel@tonic-gate 		}
2567c478bd9Sstevel@tonic-gate #ifdef	_LP64
2577c478bd9Sstevel@tonic-gate 		/* LINTED */
2587c478bd9Sstevel@tonic-gate 		offs = (uint32_t)len % sizeof (uint32_t);
2597c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
2607c478bd9Sstevel@tonic-gate 		offs = len % sizeof (uint32_t);
2617c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
2627c478bd9Sstevel@tonic-gate 		if (offs > 0) {
2637c478bd9Sstevel@tonic-gate 			word = bn->value[len / sizeof (uint32_t)];
2647c478bd9Sstevel@tonic-gate #ifdef	_LP64
2657c478bd9Sstevel@tonic-gate 			    /* LINTED */
2667c478bd9Sstevel@tonic-gate 			    for (i =  (uint32_t)len % sizeof (uint32_t);
2677c478bd9Sstevel@tonic-gate 				i > 0; i --) {
2687c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
2697c478bd9Sstevel@tonic-gate 			    for (i = len % sizeof (uint32_t); i > 0; i --) {
2707c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
2717c478bd9Sstevel@tonic-gate 				    kn[i - 1] = word & 0xff;
2727c478bd9Sstevel@tonic-gate 				    word = word >> 8;
2737c478bd9Sstevel@tonic-gate 			    }
2747c478bd9Sstevel@tonic-gate 		}
2757c478bd9Sstevel@tonic-gate 	} else {
2767c478bd9Sstevel@tonic-gate 		for (i = 0; i < bn->len; i++) {
2777c478bd9Sstevel@tonic-gate 			word = bn->value[i];
2787c478bd9Sstevel@tonic-gate 			for (j = 0; j < sizeof (uint32_t); j++) {
2797c478bd9Sstevel@tonic-gate 				kn[len - sizeof (uint32_t) * i - j - 1] =
2807c478bd9Sstevel@tonic-gate 				    word & 0xff;
2817c478bd9Sstevel@tonic-gate 				word = word >> 8;
2827c478bd9Sstevel@tonic-gate 			}
2837c478bd9Sstevel@tonic-gate 		}
2847c478bd9Sstevel@tonic-gate #ifdef	_LP64
2857c478bd9Sstevel@tonic-gate 		/* LINTED */
2867c478bd9Sstevel@tonic-gate 		for (i = 0; i < (uint32_t)len - sizeof (uint32_t) * bn->len;
2877c478bd9Sstevel@tonic-gate 		    i++) {
2887c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
2897c478bd9Sstevel@tonic-gate 		for (i = 0; i < len - sizeof (uint32_t) * bn->len; i++) {
2907c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
2917c478bd9Sstevel@tonic-gate 			kn[i] = 0;
2927c478bd9Sstevel@tonic-gate 		}
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate int
2987c478bd9Sstevel@tonic-gate big_bitlength(BIGNUM *a)
2997c478bd9Sstevel@tonic-gate {
3007c478bd9Sstevel@tonic-gate 	int		l, b;
3017c478bd9Sstevel@tonic-gate 	uint32_t	c;
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	l = a->len - 1;
3047c478bd9Sstevel@tonic-gate 	while ((l > 0) && (a->value[l] == 0)) {
3057c478bd9Sstevel@tonic-gate 		l--;
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 	b = sizeof (uint32_t) * 8;
3087c478bd9Sstevel@tonic-gate 	c = a->value[l];
3097c478bd9Sstevel@tonic-gate 	while ((b > 1) && ((c & 0x80000000) == 0)) {
3107c478bd9Sstevel@tonic-gate 		c = c << 1;
3117c478bd9Sstevel@tonic-gate 		b--;
3127c478bd9Sstevel@tonic-gate 	}
3137c478bd9Sstevel@tonic-gate 	return (l * (int)sizeof (uint32_t) * 8 + b);
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate BIG_ERR_CODE
3187c478bd9Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src)
3197c478bd9Sstevel@tonic-gate {
3207c478bd9Sstevel@tonic-gate 	uint32_t *newptr;
3217c478bd9Sstevel@tonic-gate 	int i, len;
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	len = src->len;
3247c478bd9Sstevel@tonic-gate 	while ((len > 1) && (src->value[len - 1] == 0))
3257c478bd9Sstevel@tonic-gate 		len--;
3267c478bd9Sstevel@tonic-gate 	src->len = len;
3277c478bd9Sstevel@tonic-gate 	if (dest->size < len) {
3287c478bd9Sstevel@tonic-gate 		if (dest->malloced == 1) {
3297c478bd9Sstevel@tonic-gate 			newptr = (uint32_t *)big_realloc(dest->value,
3307c478bd9Sstevel@tonic-gate 			    sizeof (uint32_t) * dest->size,
3317c478bd9Sstevel@tonic-gate 			    sizeof (uint32_t) * len);
3327c478bd9Sstevel@tonic-gate 		} else {
3337c478bd9Sstevel@tonic-gate 			newptr = (uint32_t *)
3347c478bd9Sstevel@tonic-gate 			    big_malloc(sizeof (uint32_t) * len);
3357c478bd9Sstevel@tonic-gate 			if (newptr != NULL) dest->malloced = 1;
3367c478bd9Sstevel@tonic-gate 		}
3377c478bd9Sstevel@tonic-gate 		if (newptr == NULL)
3387c478bd9Sstevel@tonic-gate 			return (BIG_NO_MEM);
3397c478bd9Sstevel@tonic-gate 		dest->value = newptr;
3407c478bd9Sstevel@tonic-gate 		dest->size = len;
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate 	dest->len = len;
3437c478bd9Sstevel@tonic-gate 	dest->sign = src->sign;
3447c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) dest->value[i] = src->value[i];
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	return (BIG_OK);
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate BIG_ERR_CODE
3517c478bd9Sstevel@tonic-gate big_extend(BIGNUM *number, int size)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate 	uint32_t	*newptr;
3547c478bd9Sstevel@tonic-gate 	int		i;
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	if (number->size >= size)
3577c478bd9Sstevel@tonic-gate 		return (BIG_OK);
3587c478bd9Sstevel@tonic-gate 	if (number->malloced) {
3597c478bd9Sstevel@tonic-gate 		number->value =
3607c478bd9Sstevel@tonic-gate 		    big_realloc(number->value,
3617c478bd9Sstevel@tonic-gate 			sizeof (uint32_t) * number->size,
3627c478bd9Sstevel@tonic-gate 			sizeof (uint32_t) * size);
3637c478bd9Sstevel@tonic-gate 	} else {
3647c478bd9Sstevel@tonic-gate 		newptr = big_malloc(sizeof (uint32_t) * size);
3657c478bd9Sstevel@tonic-gate 		if (newptr != NULL) {
3667c478bd9Sstevel@tonic-gate 			for (i = 0; i < number->size; i++) {
3677c478bd9Sstevel@tonic-gate 				newptr[i] = number->value[i];
3687c478bd9Sstevel@tonic-gate 			}
3697c478bd9Sstevel@tonic-gate 		}
3707c478bd9Sstevel@tonic-gate 		number->value = newptr;
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	if (number->value == NULL)
3747c478bd9Sstevel@tonic-gate 		return (BIG_NO_MEM);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	number->size = size;
3777c478bd9Sstevel@tonic-gate 	number->malloced = 1;
3787c478bd9Sstevel@tonic-gate 	return (BIG_OK);
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate int
3837c478bd9Sstevel@tonic-gate big_is_zero(BIGNUM *n)
3847c478bd9Sstevel@tonic-gate {
3857c478bd9Sstevel@tonic-gate 	int i, result;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	result = 1;
3887c478bd9Sstevel@tonic-gate 	for (i = 0; i < n->len; i++)
3897c478bd9Sstevel@tonic-gate 		if (n->value[i] != 0) result = 0;
3907c478bd9Sstevel@tonic-gate 	return (result);
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate BIG_ERR_CODE
3957c478bd9Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
3967c478bd9Sstevel@tonic-gate {
3977c478bd9Sstevel@tonic-gate 	int i, shorter, longer;
3987c478bd9Sstevel@tonic-gate 	uint32_t cy, ai;
3997c478bd9Sstevel@tonic-gate 	uint32_t *r, *a, *b, *c;
4007c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	if (aa->len > bb->len) {
4037c478bd9Sstevel@tonic-gate 		shorter = bb->len;
4047c478bd9Sstevel@tonic-gate 		longer = aa->len;
4057c478bd9Sstevel@tonic-gate 		c = aa->value;
4067c478bd9Sstevel@tonic-gate 	} else {
4077c478bd9Sstevel@tonic-gate 		shorter = aa->len;
4087c478bd9Sstevel@tonic-gate 		longer = bb->len;
4097c478bd9Sstevel@tonic-gate 		c = bb->value;
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 	if (result->size < longer + 1) {
4127c478bd9Sstevel@tonic-gate 		err = big_extend(result, longer + 1);
4137c478bd9Sstevel@tonic-gate 		if (err != BIG_OK)
4147c478bd9Sstevel@tonic-gate 			return (err);
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	r = result->value;
4187c478bd9Sstevel@tonic-gate 	a = aa->value;
4197c478bd9Sstevel@tonic-gate 	b = bb->value;
4207c478bd9Sstevel@tonic-gate 	cy = 0;
4217c478bd9Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
4227c478bd9Sstevel@tonic-gate 		ai = a[i];
4237c478bd9Sstevel@tonic-gate 		r[i] = ai + b[i] + cy;
4247c478bd9Sstevel@tonic-gate 		if (r[i] > ai) cy = 0;
4257c478bd9Sstevel@tonic-gate 		else if (r[i] < ai) cy = 1;
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 	for (; i < longer; i++) {
4287c478bd9Sstevel@tonic-gate 		ai = c[i];
4297c478bd9Sstevel@tonic-gate 		r[i] = ai + cy;
4307c478bd9Sstevel@tonic-gate 		if (r[i] >= ai) cy = 0;
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate 	if (cy == 1) {
4337c478bd9Sstevel@tonic-gate 		r[i] = cy;
4347c478bd9Sstevel@tonic-gate 		result->len = longer + 1;
4357c478bd9Sstevel@tonic-gate 	} else {
4367c478bd9Sstevel@tonic-gate 		result->len = longer;
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 	result->sign = 1;
4397c478bd9Sstevel@tonic-gate 	return (BIG_OK);
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */
4447c478bd9Sstevel@tonic-gate void
4457c478bd9Sstevel@tonic-gate big_sub_vec(uint32_t *r, uint32_t *a, uint32_t *b, int len)
4467c478bd9Sstevel@tonic-gate {
4477c478bd9Sstevel@tonic-gate 	int i;
4487c478bd9Sstevel@tonic-gate 	uint32_t cy, ai;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	cy = 1;
4517c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
4527c478bd9Sstevel@tonic-gate 		ai = a[i];
4537c478bd9Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
4547c478bd9Sstevel@tonic-gate 		if (r[i] > ai) cy = 0;
4557c478bd9Sstevel@tonic-gate 		else if (r[i] < ai) cy = 1;
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate /* result=aa-bb  it is assumed that aa>=bb */
4617c478bd9Sstevel@tonic-gate BIG_ERR_CODE
4627c478bd9Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
4637c478bd9Sstevel@tonic-gate {
4647c478bd9Sstevel@tonic-gate 	int i, shorter;
4657c478bd9Sstevel@tonic-gate 	uint32_t cy, ai;
4667c478bd9Sstevel@tonic-gate 	uint32_t *r, *a, *b;
4677c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	if (aa->len > bb->len) shorter = bb->len;
4707c478bd9Sstevel@tonic-gate 	else shorter = aa->len;
4717c478bd9Sstevel@tonic-gate 	if (result->size < aa->len) {
4727c478bd9Sstevel@tonic-gate 		err = big_extend(result, aa->len);
4737c478bd9Sstevel@tonic-gate 		if (err != BIG_OK)
4747c478bd9Sstevel@tonic-gate 			return (err);
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	r = result->value;
4787c478bd9Sstevel@tonic-gate 	a = aa->value;
4797c478bd9Sstevel@tonic-gate 	b = bb->value;
4807c478bd9Sstevel@tonic-gate 	result->len = aa->len;
4817c478bd9Sstevel@tonic-gate 	cy = 1;
4827c478bd9Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
4837c478bd9Sstevel@tonic-gate 		ai = a[i];
4847c478bd9Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
4857c478bd9Sstevel@tonic-gate 		if (r[i] > ai) cy = 0;
4867c478bd9Sstevel@tonic-gate 		else if (r[i] < ai) cy = 1;
4877c478bd9Sstevel@tonic-gate 	}
4887c478bd9Sstevel@tonic-gate 	for (; i < aa->len; i++) {
4897c478bd9Sstevel@tonic-gate 		ai = a[i];
4907c478bd9Sstevel@tonic-gate 		r[i] = ai + (~0) + cy;
4917c478bd9Sstevel@tonic-gate 		if (r[i] < ai) cy = 1;
4927c478bd9Sstevel@tonic-gate 	}
4937c478bd9Sstevel@tonic-gate 	result->sign = 1;
4947c478bd9Sstevel@tonic-gate 	if (cy == 0)
4957c478bd9Sstevel@tonic-gate 		return (BIG_INVALID_ARGS);
4967c478bd9Sstevel@tonic-gate 	else
4977c478bd9Sstevel@tonic-gate 		return (BIG_OK);
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */
5027c478bd9Sstevel@tonic-gate int
5037c478bd9Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb)
5047c478bd9Sstevel@tonic-gate {
5057c478bd9Sstevel@tonic-gate 	int i;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	if (aa->len > bb->len) {
5087c478bd9Sstevel@tonic-gate 		for (i = aa->len - 1; i > bb->len - 1; i--) {
5097c478bd9Sstevel@tonic-gate 			if (aa->value[i] > 0)
5107c478bd9Sstevel@tonic-gate 				return (1);
5117c478bd9Sstevel@tonic-gate 		}
5127c478bd9Sstevel@tonic-gate 	} else if (aa->len < bb->len) {
5137c478bd9Sstevel@tonic-gate 		for (i = bb->len - 1; i > aa->len - 1; i--) {
5147c478bd9Sstevel@tonic-gate 			if (bb->value[i] > 0)
5157c478bd9Sstevel@tonic-gate 				return (-1);
5167c478bd9Sstevel@tonic-gate 		}
5177c478bd9Sstevel@tonic-gate 	} else i = aa->len-1;
5187c478bd9Sstevel@tonic-gate 	for (; i >= 0; i--) {
5197c478bd9Sstevel@tonic-gate 		if (aa->value[i] > bb->value[i])
5207c478bd9Sstevel@tonic-gate 			return (1);
5217c478bd9Sstevel@tonic-gate 		else if (aa->value[i] < bb->value[i])
5227c478bd9Sstevel@tonic-gate 			return (-1);
5237c478bd9Sstevel@tonic-gate 	}
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	return (0);
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate BIG_ERR_CODE
5307c478bd9Sstevel@tonic-gate big_sub(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == 1)) {
5357c478bd9Sstevel@tonic-gate 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK)
5367c478bd9Sstevel@tonic-gate 			return (err);
5377c478bd9Sstevel@tonic-gate 		result->sign = 1;
5387c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == -1) && (bb->sign == 1)) {
5397c478bd9Sstevel@tonic-gate 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK)
5407c478bd9Sstevel@tonic-gate 			return (err);
5417c478bd9Sstevel@tonic-gate 		result->sign = -1;
5427c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
5437c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
5447c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK)
5457c478bd9Sstevel@tonic-gate 				return (err);
5467c478bd9Sstevel@tonic-gate 			result->sign = 1;
5477c478bd9Sstevel@tonic-gate 		} else {
5487c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK)
5497c478bd9Sstevel@tonic-gate 				return (err);
5507c478bd9Sstevel@tonic-gate 			result->sign = -1;
5517c478bd9Sstevel@tonic-gate 		}
5527c478bd9Sstevel@tonic-gate 	} else {
5537c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
5547c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK)
5557c478bd9Sstevel@tonic-gate 				return (err);
5567c478bd9Sstevel@tonic-gate 			result->sign = -1;
5577c478bd9Sstevel@tonic-gate 		} else {
5587c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK)
5597c478bd9Sstevel@tonic-gate 				return (err);
5607c478bd9Sstevel@tonic-gate 			result->sign = 1;
5617c478bd9Sstevel@tonic-gate 		}
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate 	return (BIG_OK);
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate BIG_ERR_CODE
5697c478bd9Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
5707c478bd9Sstevel@tonic-gate {
5717c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == -1)) {
5747c478bd9Sstevel@tonic-gate 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK)
5757c478bd9Sstevel@tonic-gate 			return (err);
5767c478bd9Sstevel@tonic-gate 		result->sign = -1;
5777c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
5787c478bd9Sstevel@tonic-gate 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK)
5797c478bd9Sstevel@tonic-gate 			return (err);
5807c478bd9Sstevel@tonic-gate 		result->sign = 1;
5817c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == -1)) {
5827c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
5837c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK)
5847c478bd9Sstevel@tonic-gate 				return (err);
5857c478bd9Sstevel@tonic-gate 			result->sign = 1;
5867c478bd9Sstevel@tonic-gate 		} else {
5877c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK)
5887c478bd9Sstevel@tonic-gate 				return (err);
5897c478bd9Sstevel@tonic-gate 			result->sign = -1;
5907c478bd9Sstevel@tonic-gate 		}
5917c478bd9Sstevel@tonic-gate 	} else {
5927c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
5937c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK)
5947c478bd9Sstevel@tonic-gate 				return (err);
5957c478bd9Sstevel@tonic-gate 			result->sign = -1;
5967c478bd9Sstevel@tonic-gate 		} else {
5977c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK)
5987c478bd9Sstevel@tonic-gate 				return (err);
5997c478bd9Sstevel@tonic-gate 			result->sign = 1;
6007c478bd9Sstevel@tonic-gate 		}
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 	return (BIG_OK);
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate /* result = aa/2 aa must be positive */
6077c478bd9Sstevel@tonic-gate BIG_ERR_CODE
6087c478bd9Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
6117c478bd9Sstevel@tonic-gate 	int i;
6127c478bd9Sstevel@tonic-gate 	uint32_t cy, cy1;
6137c478bd9Sstevel@tonic-gate 	uint32_t *a, *r;
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	if (result->size < aa->len) {
6167c478bd9Sstevel@tonic-gate 		err = big_extend(result, aa->len);
6177c478bd9Sstevel@tonic-gate 		if (err != BIG_OK)
6187c478bd9Sstevel@tonic-gate 			return (err);
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	result->len = aa->len;
6227c478bd9Sstevel@tonic-gate 	a = aa->value;
6237c478bd9Sstevel@tonic-gate 	r = result->value;
6247c478bd9Sstevel@tonic-gate 	cy = 0;
6257c478bd9Sstevel@tonic-gate 	for (i = aa->len-1; i >= 0; i--) {
6267c478bd9Sstevel@tonic-gate 		cy1 = a[i] << 31;
6277c478bd9Sstevel@tonic-gate 		r[i] = (cy|(a[i] >> 1));
6287c478bd9Sstevel@tonic-gate 		cy = cy1;
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate 	if (r[result->len-1] == 0) result->len--;
6317c478bd9Sstevel@tonic-gate 	return (BIG_OK);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate /* result  =  aa*2 aa must be positive */
6357c478bd9Sstevel@tonic-gate BIG_ERR_CODE
6367c478bd9Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa)
6377c478bd9Sstevel@tonic-gate {
6387c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
6397c478bd9Sstevel@tonic-gate 	int i, rsize;
6407c478bd9Sstevel@tonic-gate 	uint32_t cy, cy1;
6417c478bd9Sstevel@tonic-gate 	uint32_t *a, *r;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	if ((aa->len > 0) && ((aa->value[aa->len - 1] & 0x80000000) != 0))
6447c478bd9Sstevel@tonic-gate 		rsize = aa->len + 1;
6457c478bd9Sstevel@tonic-gate 	else rsize = aa->len;
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	if (result->size < rsize) {
6487c478bd9Sstevel@tonic-gate 		err = big_extend(result, rsize);
6497c478bd9Sstevel@tonic-gate 		if (err != BIG_OK)
6507c478bd9Sstevel@tonic-gate 			return (err);
6517c478bd9Sstevel@tonic-gate 	}
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	a = aa->value;
6547c478bd9Sstevel@tonic-gate 	r = result->value;
6557c478bd9Sstevel@tonic-gate 	if (rsize == aa->len + 1) r[rsize - 1] = 1;
6567c478bd9Sstevel@tonic-gate 	cy = 0;
6577c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
6587c478bd9Sstevel@tonic-gate 		cy1 = a[i] >> 31;
6597c478bd9Sstevel@tonic-gate 		r[i] = (cy | (a[i] << 1));
6607c478bd9Sstevel@tonic-gate 		cy = cy1;
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 	result->len = rsize;
6637c478bd9Sstevel@tonic-gate 	return (BIG_OK);
6647c478bd9Sstevel@tonic-gate }
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate /* returns aa mod b, aa must be nonneg, b must be a max 16-bit integer */
6677c478bd9Sstevel@tonic-gate uint32_t
6687c478bd9Sstevel@tonic-gate big_mod16_pos(BIGNUM *aa, uint32_t b)
6697c478bd9Sstevel@tonic-gate {
6707c478bd9Sstevel@tonic-gate 	int i;
6717c478bd9Sstevel@tonic-gate 	uint32_t rem;
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	if (aa->len == 0)
6747c478bd9Sstevel@tonic-gate 		return (0);
6757c478bd9Sstevel@tonic-gate 	rem = aa->value[aa->len - 1] % b;
6767c478bd9Sstevel@tonic-gate 	for (i = aa->len - 2; i >= 0; i--) {
6777c478bd9Sstevel@tonic-gate 		rem = ((rem << 16) | (aa->value[i] >> 16)) % b;
6787c478bd9Sstevel@tonic-gate 		rem = ((rem << 16) | (aa->value[i] & 0xffff)) % b;
6797c478bd9Sstevel@tonic-gate 	}
6807c478bd9Sstevel@tonic-gate 	return (rem);
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate /*
6857c478bd9Sstevel@tonic-gate  * result = aa - (2^32)^lendiff * bb
6867c478bd9Sstevel@tonic-gate  * result->size should be at least aa->len at entry
6877c478bd9Sstevel@tonic-gate  * aa, bb, and result should be positive
6887c478bd9Sstevel@tonic-gate  */
6897c478bd9Sstevel@tonic-gate void
6907c478bd9Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
6917c478bd9Sstevel@tonic-gate {
6927c478bd9Sstevel@tonic-gate 	int i, lendiff;
6937c478bd9Sstevel@tonic-gate 	BIGNUM res1, aa1;
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
6967c478bd9Sstevel@tonic-gate 	res1.size = result->size - lendiff;
6977c478bd9Sstevel@tonic-gate 	res1.malloced = 0;
6987c478bd9Sstevel@tonic-gate 	res1.value = result->value + lendiff;
6997c478bd9Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
7007c478bd9Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
7017c478bd9Sstevel@tonic-gate 	aa1.len = bb->len;
7027c478bd9Sstevel@tonic-gate 	aa1.sign = 1;
7037c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(&res1, &aa1, bb);
7047c478bd9Sstevel@tonic-gate 	if (result->value != aa->value) {
7057c478bd9Sstevel@tonic-gate 		for (i = 0; i < lendiff; i++) {
7067c478bd9Sstevel@tonic-gate 			result->value[i] = aa->value[i];
7077c478bd9Sstevel@tonic-gate 		}
7087c478bd9Sstevel@tonic-gate 	}
7097c478bd9Sstevel@tonic-gate 	result->len = aa->len;
7107c478bd9Sstevel@tonic-gate }
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate /*
7147c478bd9Sstevel@tonic-gate  * returns 1, 0, or -1 depending on whether |aa| > , ==, or <
7157c478bd9Sstevel@tonic-gate  *							(2^32)^lendiff * |bb|
7167c478bd9Sstevel@tonic-gate  * aa->len should be >= bb->len
7177c478bd9Sstevel@tonic-gate  */
7187c478bd9Sstevel@tonic-gate int
7197c478bd9Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb)
7207c478bd9Sstevel@tonic-gate {
7217c478bd9Sstevel@tonic-gate 	int lendiff;
7227c478bd9Sstevel@tonic-gate 	BIGNUM aa1;
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
7257c478bd9Sstevel@tonic-gate 	aa1.len = bb->len;
7267c478bd9Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
7277c478bd9Sstevel@tonic-gate 	aa1.malloced = 0;
7287c478bd9Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
7297c478bd9Sstevel@tonic-gate 	return (big_cmp_abs(&aa1, bb));
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate /*
7347c478bd9Sstevel@tonic-gate  * result = aa * b where b is a max. 16-bit positive integer.
7357c478bd9Sstevel@tonic-gate  * result should have enough space allocated.
7367c478bd9Sstevel@tonic-gate  */
7377c478bd9Sstevel@tonic-gate void
7387c478bd9Sstevel@tonic-gate big_mul16_low(BIGNUM *result, BIGNUM *aa, uint32_t b)
7397c478bd9Sstevel@tonic-gate {
7407c478bd9Sstevel@tonic-gate 	int i;
7417c478bd9Sstevel@tonic-gate 	uint32_t t1, t2, ai, cy;
7427c478bd9Sstevel@tonic-gate 	uint32_t *a, *r;
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	a = aa->value;
7457c478bd9Sstevel@tonic-gate 	r = result->value;
7467c478bd9Sstevel@tonic-gate 	cy = 0;
7477c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
7487c478bd9Sstevel@tonic-gate 		ai = a[i];
7497c478bd9Sstevel@tonic-gate 		t1 = (ai & 0xffff) * b + cy;
7507c478bd9Sstevel@tonic-gate 		t2 = (ai >> 16) * b + (t1 >> 16);
7517c478bd9Sstevel@tonic-gate 		r[i] = (t1 & 0xffff) | (t2 << 16);
7527c478bd9Sstevel@tonic-gate 		cy = t2 >> 16;
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate 	r[i] = cy;
7557c478bd9Sstevel@tonic-gate 	result->len = aa->len + 1;
7567c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate /*
7617c478bd9Sstevel@tonic-gate  * result = aa * b * 2^16 where b is a max. 16-bit positive integer.
7627c478bd9Sstevel@tonic-gate  * result should have enough space allocated.
7637c478bd9Sstevel@tonic-gate  */
7647c478bd9Sstevel@tonic-gate void
7657c478bd9Sstevel@tonic-gate big_mul16_high(BIGNUM *result, BIGNUM *aa, uint32_t b)
7667c478bd9Sstevel@tonic-gate {
7677c478bd9Sstevel@tonic-gate 	int i;
7687c478bd9Sstevel@tonic-gate 	uint32_t t1, t2, ai, cy, ri;
7697c478bd9Sstevel@tonic-gate 	uint32_t *a, *r;
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	a = aa->value;
7727c478bd9Sstevel@tonic-gate 	r = result->value;
7737c478bd9Sstevel@tonic-gate 	cy = 0;
7747c478bd9Sstevel@tonic-gate 	ri = 0;
7757c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
7767c478bd9Sstevel@tonic-gate 		ai = a[i];
7777c478bd9Sstevel@tonic-gate 		t1 = (ai & 0xffff) * b + cy;
7787c478bd9Sstevel@tonic-gate 		t2 = (ai >> 16) * b + (t1 >> 16);
7797c478bd9Sstevel@tonic-gate 		r[i] = (t1 << 16) + ri;
7807c478bd9Sstevel@tonic-gate 		ri = t2 & 0xffff;
7817c478bd9Sstevel@tonic-gate 		cy = t2 >> 16;
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate 	r[i] = (cy << 16) + ri;
7847c478bd9Sstevel@tonic-gate 	result->len = aa->len + 1;
7857c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */
7897c478bd9Sstevel@tonic-gate void
7907c478bd9Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs)
7917c478bd9Sstevel@tonic-gate {
7927c478bd9Sstevel@tonic-gate 	int i;
7937c478bd9Sstevel@tonic-gate 	uint32_t cy, ai;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	if (offs == 0) {
7967c478bd9Sstevel@tonic-gate 		if (result != aa) {
7977c478bd9Sstevel@tonic-gate 			(void) big_copy(result, aa);
7987c478bd9Sstevel@tonic-gate 		}
7997c478bd9Sstevel@tonic-gate 		return;
8007c478bd9Sstevel@tonic-gate 	}
8017c478bd9Sstevel@tonic-gate 	cy = 0;
8027c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
8037c478bd9Sstevel@tonic-gate 		ai = aa->value[i];
8047c478bd9Sstevel@tonic-gate 		result->value[i] = (ai << offs) | cy;
8057c478bd9Sstevel@tonic-gate 		cy = ai >> (32 - offs);
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 	if (cy != 0) {
8087c478bd9Sstevel@tonic-gate 		result->len = aa->len + 1;
8097c478bd9Sstevel@tonic-gate 		result->value[result->len - 1] = cy;
8107c478bd9Sstevel@tonic-gate 	} else {
8117c478bd9Sstevel@tonic-gate 		result->len = aa->len;
8127c478bd9Sstevel@tonic-gate 	}
8137c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
8147c478bd9Sstevel@tonic-gate }
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */
8177c478bd9Sstevel@tonic-gate void
8187c478bd9Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs)
8197c478bd9Sstevel@tonic-gate {
8207c478bd9Sstevel@tonic-gate 	int i;
8217c478bd9Sstevel@tonic-gate 	uint32_t cy, ai;
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	if (offs == 0) {
8247c478bd9Sstevel@tonic-gate 		if (result != aa) {
8257c478bd9Sstevel@tonic-gate 			(void) big_copy(result, aa);
8267c478bd9Sstevel@tonic-gate 		}
8277c478bd9Sstevel@tonic-gate 		return;
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate 	cy = aa->value[0] >> offs;
8307c478bd9Sstevel@tonic-gate 	for (i = 1; i < aa->len; i++) {
8317c478bd9Sstevel@tonic-gate 		ai = aa->value[i];
8327c478bd9Sstevel@tonic-gate 		result->value[i-1] = (ai << (32 - offs)) | cy;
8337c478bd9Sstevel@tonic-gate 		cy = ai >> offs;
8347c478bd9Sstevel@tonic-gate 	}
8357c478bd9Sstevel@tonic-gate 	result->len = aa->len;
8367c478bd9Sstevel@tonic-gate 	result->value[result->len - 1] = cy;
8377c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
8387c478bd9Sstevel@tonic-gate }
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate /*
8427c478bd9Sstevel@tonic-gate  * result = aa/bb   remainder = aa mod bb
8437c478bd9Sstevel@tonic-gate  * it is assumed that aa and bb are positive
8447c478bd9Sstevel@tonic-gate  */
8457c478bd9Sstevel@tonic-gate BIG_ERR_CODE
8467c478bd9Sstevel@tonic-gate big_div_pos_fast(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb)
8477c478bd9Sstevel@tonic-gate {
8487c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
8497c478bd9Sstevel@tonic-gate 	int i, alen, blen, tlen, rlen, offs;
8507c478bd9Sstevel@tonic-gate 	uint32_t higha, highb, coeff;
8517c478bd9Sstevel@tonic-gate 	uint64_t highb64;
8527c478bd9Sstevel@tonic-gate 	uint32_t *a, *b;
8537c478bd9Sstevel@tonic-gate 	BIGNUM bbhigh, bblow, tresult, tmp1, tmp2;
8547c478bd9Sstevel@tonic-gate 	uint32_t tmp1value[BIGTMPSIZE];
8557c478bd9Sstevel@tonic-gate 	uint32_t tmp2value[BIGTMPSIZE];
8567c478bd9Sstevel@tonic-gate 	uint32_t tresultvalue[BIGTMPSIZE];
8577c478bd9Sstevel@tonic-gate 	uint32_t bblowvalue[BIGTMPSIZE];
8587c478bd9Sstevel@tonic-gate 	uint32_t bbhighvalue[BIGTMPSIZE];
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	a = aa->value;
8617c478bd9Sstevel@tonic-gate 	b = bb->value;
8627c478bd9Sstevel@tonic-gate 	alen = aa->len;
8637c478bd9Sstevel@tonic-gate 	blen = bb->len;
8647c478bd9Sstevel@tonic-gate 	while ((alen > 1) && (a[alen - 1] == 0)) alen = alen - 1;
8657c478bd9Sstevel@tonic-gate 	aa->len = alen;
8667c478bd9Sstevel@tonic-gate 	while ((blen > 1) && (b[blen - 1] == 0)) blen = blen - 1;
8677c478bd9Sstevel@tonic-gate 	bb->len = blen;
8687c478bd9Sstevel@tonic-gate 	if ((blen == 1) && (b[0] == 0))
8697c478bd9Sstevel@tonic-gate 		return (BIG_DIV_BY_0);
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(aa, bb) < 0) {
8727c478bd9Sstevel@tonic-gate 		if ((remainder != NULL) &&
8737c478bd9Sstevel@tonic-gate 		    ((err = big_copy(remainder, aa)) != BIG_OK))
8747c478bd9Sstevel@tonic-gate 			return (err);
8757c478bd9Sstevel@tonic-gate 		if (result != NULL) {
8767c478bd9Sstevel@tonic-gate 			result->len = 1;
8777c478bd9Sstevel@tonic-gate 			result->sign = 1;
8787c478bd9Sstevel@tonic-gate 			result->value[0] = 0;
8797c478bd9Sstevel@tonic-gate 		}
8807c478bd9Sstevel@tonic-gate 		return (BIG_OK);
8817c478bd9Sstevel@tonic-gate 	}
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&bblow, blen + 1,
8847c478bd9Sstevel@tonic-gate 	    bblowvalue, arraysize(bblowvalue))) != BIG_OK)
8857c478bd9Sstevel@tonic-gate 		return (err);
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&bbhigh, blen + 1,
8887c478bd9Sstevel@tonic-gate 	    bbhighvalue, arraysize(bbhighvalue))) != BIG_OK)
8897c478bd9Sstevel@tonic-gate 		goto ret1;
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp1, alen + 2,
8927c478bd9Sstevel@tonic-gate 	    tmp1value, arraysize(tmp1value))) != BIG_OK)
8937c478bd9Sstevel@tonic-gate 		goto ret2;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, blen + 2,
8967c478bd9Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
8977c478bd9Sstevel@tonic-gate 		goto ret3;
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tresult, alen - blen + 2,
9007c478bd9Sstevel@tonic-gate 	    tresultvalue, arraysize(tresultvalue))) != BIG_OK)
9017c478bd9Sstevel@tonic-gate 		goto ret4;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	offs = 0;
9047c478bd9Sstevel@tonic-gate 	if (blen > 1) {
9057c478bd9Sstevel@tonic-gate 		highb64 = (((uint64_t)(b[blen - 1])) << 32) |
9067c478bd9Sstevel@tonic-gate 		    ((uint64_t)(b[blen - 2]));
9077c478bd9Sstevel@tonic-gate 	} else {
9087c478bd9Sstevel@tonic-gate 		highb64 = (((uint64_t)(b[blen - 1])) << 32);
9097c478bd9Sstevel@tonic-gate 	}
9107c478bd9Sstevel@tonic-gate 	if (highb64 >= 0x1000000000000ull) {
9117c478bd9Sstevel@tonic-gate 		highb64 = highb64 >> 16;
9127c478bd9Sstevel@tonic-gate 		offs = 16;
9137c478bd9Sstevel@tonic-gate 	}
9147c478bd9Sstevel@tonic-gate 	while ((highb64 & 0x800000000000ull) == 0) {
9157c478bd9Sstevel@tonic-gate 		highb64 = highb64 << 1;
9167c478bd9Sstevel@tonic-gate 		offs++;
9177c478bd9Sstevel@tonic-gate 	}
9187c478bd9Sstevel@tonic-gate #ifdef	_LP64
9197c478bd9Sstevel@tonic-gate 	/* LINTED */
9207c478bd9Sstevel@tonic-gate 	highb = (highb64 >> 32) & 0xffffffff;
9217c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
9227c478bd9Sstevel@tonic-gate 	highb = highb64 >> 32;
9237c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	big_shiftleft(&bblow, bb, offs);
9267c478bd9Sstevel@tonic-gate 	if (offs <= 15) {
9277c478bd9Sstevel@tonic-gate 		big_shiftleft(&bbhigh, &bblow, 16);
9287c478bd9Sstevel@tonic-gate 	} else {
9297c478bd9Sstevel@tonic-gate 		big_shiftright(&bbhigh, &bblow, 16);
9307c478bd9Sstevel@tonic-gate 	}
9317c478bd9Sstevel@tonic-gate 	if (bbhigh.value[bbhigh.len - 1] == 0) {
9327c478bd9Sstevel@tonic-gate 		bbhigh.len--;
9337c478bd9Sstevel@tonic-gate 	} else {
9347c478bd9Sstevel@tonic-gate 		bbhigh.value[bbhigh.len] = 0;
9357c478bd9Sstevel@tonic-gate 	}
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	big_shiftleft(&tmp1, aa, offs);
9387c478bd9Sstevel@tonic-gate 	rlen = tmp1.len - bblow.len + 1;
9397c478bd9Sstevel@tonic-gate 	tresult.len = rlen;
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	tmp1.len++;
9427c478bd9Sstevel@tonic-gate 	tlen = tmp1.len;
9437c478bd9Sstevel@tonic-gate 	tmp1.value[tmp1.len - 1] = 0;
9447c478bd9Sstevel@tonic-gate 	for (i = 0; i < rlen; i++) {
9457c478bd9Sstevel@tonic-gate 		higha = (tmp1.value[tlen - 1] << 16) +
9467c478bd9Sstevel@tonic-gate 		    (tmp1.value[tlen - 2] >> 16);
9477c478bd9Sstevel@tonic-gate 		coeff = higha / (highb + 1);
9487c478bd9Sstevel@tonic-gate 		big_mul16_high(&tmp2, &bblow, coeff);
9497c478bd9Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
9507c478bd9Sstevel@tonic-gate 		bbhigh.len++;
9517c478bd9Sstevel@tonic-gate 		while (tmp1.value[tlen - 1] > 0) {
9527c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
9537c478bd9Sstevel@tonic-gate 			coeff++;
9547c478bd9Sstevel@tonic-gate 		}
9557c478bd9Sstevel@tonic-gate 		bbhigh.len--;
9567c478bd9Sstevel@tonic-gate 		tlen--;
9577c478bd9Sstevel@tonic-gate 		tmp1.len--;
9587c478bd9Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) {
9597c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
9607c478bd9Sstevel@tonic-gate 			coeff++;
9617c478bd9Sstevel@tonic-gate 		}
9627c478bd9Sstevel@tonic-gate 		tresult.value[rlen - i - 1] = coeff << 16;
9637c478bd9Sstevel@tonic-gate 		higha = tmp1.value[tlen - 1];
9647c478bd9Sstevel@tonic-gate 		coeff = higha / (highb + 1);
9657c478bd9Sstevel@tonic-gate 		big_mul16_low(&tmp2, &bblow, coeff);
9667c478bd9Sstevel@tonic-gate 		tmp2.len--;
9677c478bd9Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
9687c478bd9Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bblow) >= 0) {
9697c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bblow);
9707c478bd9Sstevel@tonic-gate 			coeff++;
9717c478bd9Sstevel@tonic-gate 		}
9727c478bd9Sstevel@tonic-gate 		tresult.value[rlen - i - 1] =
9737c478bd9Sstevel@tonic-gate 		    tresult.value[rlen - i - 1] + coeff;
9747c478bd9Sstevel@tonic-gate 	}
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	big_shiftright(&tmp1, &tmp1, offs);
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	err = BIG_OK;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	if ((remainder != NULL) &&
9817c478bd9Sstevel@tonic-gate 	    ((err = big_copy(remainder, &tmp1)) != BIG_OK))
9827c478bd9Sstevel@tonic-gate 		goto ret;
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	if (result != NULL)
9857c478bd9Sstevel@tonic-gate 		err = big_copy(result, &tresult);
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate ret:
9887c478bd9Sstevel@tonic-gate 	big_finish(&tresult);
9897c478bd9Sstevel@tonic-gate ret4:
9907c478bd9Sstevel@tonic-gate 	big_finish(&tmp1);
9917c478bd9Sstevel@tonic-gate ret3:
9927c478bd9Sstevel@tonic-gate 	big_finish(&tmp2);
9937c478bd9Sstevel@tonic-gate ret2:
9947c478bd9Sstevel@tonic-gate 	big_finish(&bbhigh);
9957c478bd9Sstevel@tonic-gate ret1:
9967c478bd9Sstevel@tonic-gate 	big_finish(&bblow);
9977c478bd9Sstevel@tonic-gate 	return (err);
9987c478bd9Sstevel@tonic-gate }
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate /*
10017c478bd9Sstevel@tonic-gate  * If there is no processor-specific integer implementation of
10027c478bd9Sstevel@tonic-gate  * the lower level multiply functions, then this code is provided
10037c478bd9Sstevel@tonic-gate  * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and
10047c478bd9Sstevel@tonic-gate  * big_sqr_vec().
10057c478bd9Sstevel@tonic-gate  *
10067c478bd9Sstevel@tonic-gate  * There are two generic implementations.  One that assumes that
10077c478bd9Sstevel@tonic-gate  * there is hardware and C compiler support for a 32 x 32 --> 64
10087c478bd9Sstevel@tonic-gate  * bit unsigned multiply, but otherwise is not specific to any
10097c478bd9Sstevel@tonic-gate  * processor, platform, or ISA.
10107c478bd9Sstevel@tonic-gate  *
10117c478bd9Sstevel@tonic-gate  * The other makes very few assumptions about hardware capabilities.
10127c478bd9Sstevel@tonic-gate  * It does not even assume that there is any implementation of a
10137c478bd9Sstevel@tonic-gate  * 32 x 32 --> 64 bit multiply that is accessible to C code and
10147c478bd9Sstevel@tonic-gate  * appropriate to use.  It falls constructs 32 x 32 --> 64 bit
10157c478bd9Sstevel@tonic-gate  * multiplies from 16 x 16 --> 32 bit multiplies.
10167c478bd9Sstevel@tonic-gate  *
10177c478bd9Sstevel@tonic-gate  */
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate #if !defined(PSR_MUL)
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate #ifdef UMUL64
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate #define	UNROLL8
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_PREFETCH(R) \
10267c478bd9Sstevel@tonic-gate 	p = pf * d; \
10277c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[R+1]; \
10287c478bd9Sstevel@tonic-gate 	t = p + cy; \
10297c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
10307c478bd9Sstevel@tonic-gate 	cy = t >> 32
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_NOPREFETCH(R) \
10337c478bd9Sstevel@tonic-gate 	p = pf * d; \
10347c478bd9Sstevel@tonic-gate 	t = p + cy; \
10357c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
10367c478bd9Sstevel@tonic-gate 	cy = t >> 32
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_PREFETCH(R) \
10397c478bd9Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
10407c478bd9Sstevel@tonic-gate 	p = pf * d; \
10417c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[R+1]; \
10427c478bd9Sstevel@tonic-gate 	t = p + t + cy; \
10437c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
10447c478bd9Sstevel@tonic-gate 	cy = t >> 32
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_NOPREFETCH(R) \
10477c478bd9Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
10487c478bd9Sstevel@tonic-gate 	p = pf * d; \
10497c478bd9Sstevel@tonic-gate 	t = p + t + cy; \
10507c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
10517c478bd9Sstevel@tonic-gate 	cy = t >> 32
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate #ifdef UNROLL8
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate #define	UNROLL 8
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate /*
10587c478bd9Sstevel@tonic-gate  * r = a * b
10597c478bd9Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
10607c478bd9Sstevel@tonic-gate  */
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate uint32_t
10637c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
10647c478bd9Sstevel@tonic-gate {
10657c478bd9Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	if (len == 0)
10687c478bd9Sstevel@tonic-gate 		return (0);
10697c478bd9Sstevel@tonic-gate 	cy = 0;
10707c478bd9Sstevel@tonic-gate 	d = (uint64_t)b;
10717c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[0];
10727c478bd9Sstevel@tonic-gate 	while (len > UNROLL) {
10737c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
10747c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
10757c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
10767c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
10777c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
10787c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
10797c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
10807c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(7);
10817c478bd9Sstevel@tonic-gate 		r += UNROLL;
10827c478bd9Sstevel@tonic-gate 		a += UNROLL;
10837c478bd9Sstevel@tonic-gate 		len -= UNROLL;
10847c478bd9Sstevel@tonic-gate 	}
10857c478bd9Sstevel@tonic-gate 	if (len == UNROLL) {
10867c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
10877c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
10887c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
10897c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
10907c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
10917c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
10927c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
10937c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(7);
10947c478bd9Sstevel@tonic-gate 		return ((uint32_t)cy);
10957c478bd9Sstevel@tonic-gate 	}
10967c478bd9Sstevel@tonic-gate 	while (len > 1) {
10977c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
10987c478bd9Sstevel@tonic-gate 		++r;
10997c478bd9Sstevel@tonic-gate 		++a;
11007c478bd9Sstevel@tonic-gate 		--len;
11017c478bd9Sstevel@tonic-gate 	}
11027c478bd9Sstevel@tonic-gate 	if (len > 0) {
11037c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(0);
11047c478bd9Sstevel@tonic-gate 	}
11057c478bd9Sstevel@tonic-gate 	return ((uint32_t)cy);
11067c478bd9Sstevel@tonic-gate }
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate /*
11097c478bd9Sstevel@tonic-gate  * r += a * b
11107c478bd9Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
11117c478bd9Sstevel@tonic-gate  */
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate uint32_t
11147c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
11157c478bd9Sstevel@tonic-gate {
11167c478bd9Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	if (len == 0)
11197c478bd9Sstevel@tonic-gate 		return (0);
11207c478bd9Sstevel@tonic-gate 	cy = 0;
11217c478bd9Sstevel@tonic-gate 	d = (uint64_t)b;
11227c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[0];
11237c478bd9Sstevel@tonic-gate 	while (len > 8) {
11247c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
11257c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
11267c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
11277c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
11287c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
11297c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
11307c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
11317c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(7);
11327c478bd9Sstevel@tonic-gate 		r += 8;
11337c478bd9Sstevel@tonic-gate 		a += 8;
11347c478bd9Sstevel@tonic-gate 		len -= 8;
11357c478bd9Sstevel@tonic-gate 	}
11367c478bd9Sstevel@tonic-gate 	if (len == 8) {
11377c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
11387c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
11397c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
11407c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
11417c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
11427c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
11437c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
11447c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(7);
11457c478bd9Sstevel@tonic-gate 		return ((uint32_t)cy);
11467c478bd9Sstevel@tonic-gate 	}
11477c478bd9Sstevel@tonic-gate 	while (len > 1) {
11487c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
11497c478bd9Sstevel@tonic-gate 		++r;
11507c478bd9Sstevel@tonic-gate 		++a;
11517c478bd9Sstevel@tonic-gate 		--len;
11527c478bd9Sstevel@tonic-gate 	}
11537c478bd9Sstevel@tonic-gate 	if (len > 0) {
11547c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(0);
11557c478bd9Sstevel@tonic-gate 	}
11567c478bd9Sstevel@tonic-gate 	return ((uint32_t)cy);
11577c478bd9Sstevel@tonic-gate }
11587c478bd9Sstevel@tonic-gate #endif /* UNROLL8 */
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate void
11617c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
11627c478bd9Sstevel@tonic-gate {
11637c478bd9Sstevel@tonic-gate 	uint32_t *tr, *ta;
11647c478bd9Sstevel@tonic-gate 	int tlen, row, col;
11657c478bd9Sstevel@tonic-gate 	uint64_t p, s, t, t2, cy;
11667c478bd9Sstevel@tonic-gate 	uint32_t d;
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	tr = r + 1;
11697c478bd9Sstevel@tonic-gate 	ta = a;
11707c478bd9Sstevel@tonic-gate 	tlen = len - 1;
11717c478bd9Sstevel@tonic-gate 	tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]);
11727c478bd9Sstevel@tonic-gate 	while (--tlen > 0) {
11737c478bd9Sstevel@tonic-gate 		tr += 2;
11747c478bd9Sstevel@tonic-gate 		++ta;
11757c478bd9Sstevel@tonic-gate 		tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]);
11767c478bd9Sstevel@tonic-gate 	}
11777c478bd9Sstevel@tonic-gate 	s = (uint64_t)a[0];
11787c478bd9Sstevel@tonic-gate 	s = s * s;
11797c478bd9Sstevel@tonic-gate 	r[0] = (uint32_t)s;
11807c478bd9Sstevel@tonic-gate 	cy = s >> 32;
11817c478bd9Sstevel@tonic-gate 	p = ((uint64_t)r[1] << 1) + cy;
11827c478bd9Sstevel@tonic-gate 	r[1] = (uint32_t)p;
11837c478bd9Sstevel@tonic-gate 	cy = p >> 32;
11847c478bd9Sstevel@tonic-gate 	row = 1;
11857c478bd9Sstevel@tonic-gate 	col = 2;
11867c478bd9Sstevel@tonic-gate 	while (row < len) {
11877c478bd9Sstevel@tonic-gate 		s = (uint64_t)a[row];
11887c478bd9Sstevel@tonic-gate 		s = s * s;
11897c478bd9Sstevel@tonic-gate 		p = (uint64_t)r[col] << 1;
11907c478bd9Sstevel@tonic-gate 		t = p + s;
11917c478bd9Sstevel@tonic-gate 		d = (uint32_t)t;
11927c478bd9Sstevel@tonic-gate 		t2 = (uint64_t)d + cy;
11937c478bd9Sstevel@tonic-gate 		r[col] = (uint32_t)t2;
11947c478bd9Sstevel@tonic-gate 		cy = (t >> 32) + (t2 >> 32);
11957c478bd9Sstevel@tonic-gate 		if (row == len - 1)
11967c478bd9Sstevel@tonic-gate 			break;
11977c478bd9Sstevel@tonic-gate 		p = ((uint64_t)r[col+1] << 1) + cy;
11987c478bd9Sstevel@tonic-gate 		r[col+1] = (uint32_t)p;
11997c478bd9Sstevel@tonic-gate 		cy = p >> 32;
12007c478bd9Sstevel@tonic-gate 		++row;
12017c478bd9Sstevel@tonic-gate 		col += 2;
12027c478bd9Sstevel@tonic-gate 	}
12037c478bd9Sstevel@tonic-gate 	r[col+1] = (uint32_t)cy;
12047c478bd9Sstevel@tonic-gate }
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate #else /* ! UMUL64 */
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate /*
12097c478bd9Sstevel@tonic-gate  * r = r + a * digit, r and a are vectors of length len
12107c478bd9Sstevel@tonic-gate  * returns the carry digit
12117c478bd9Sstevel@tonic-gate  */
12127c478bd9Sstevel@tonic-gate uint32_t
12137c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
12147c478bd9Sstevel@tonic-gate {
12157c478bd9Sstevel@tonic-gate 	uint32_t cy, cy1, retcy, dlow, dhigh;
12167c478bd9Sstevel@tonic-gate 	int i;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	cy1 = 0;
12197c478bd9Sstevel@tonic-gate 	dlow = digit & 0xffff;
12207c478bd9Sstevel@tonic-gate 	dhigh = digit >> 16;
12217c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
12227c478bd9Sstevel@tonic-gate 		cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff);
12237c478bd9Sstevel@tonic-gate 		cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16);
12247c478bd9Sstevel@tonic-gate 		r[i] = (cy & 0xffff) | (cy1 << 16);
12257c478bd9Sstevel@tonic-gate 	}
12267c478bd9Sstevel@tonic-gate 	retcy = cy1 >> 16;
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	cy1 = r[0] & 0xffff;
12297c478bd9Sstevel@tonic-gate 	for (i = 0; i < len - 1; i++) {
12307c478bd9Sstevel@tonic-gate 		cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16);
12317c478bd9Sstevel@tonic-gate 		r[i] = (cy1 & 0xffff) | (cy << 16);
12327c478bd9Sstevel@tonic-gate 		cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff);
12337c478bd9Sstevel@tonic-gate 	}
12347c478bd9Sstevel@tonic-gate 	cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16);
12357c478bd9Sstevel@tonic-gate 	r[len - 1] = (cy1 & 0xffff) | (cy << 16);
12367c478bd9Sstevel@tonic-gate 	retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy;
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	return (retcy);
12397c478bd9Sstevel@tonic-gate }
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate /*
12427c478bd9Sstevel@tonic-gate  * r = a * digit, r and a are vectors of length len
12437c478bd9Sstevel@tonic-gate  * returns the carry digit
12447c478bd9Sstevel@tonic-gate  */
12457c478bd9Sstevel@tonic-gate uint32_t
12467c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
12477c478bd9Sstevel@tonic-gate {
12487c478bd9Sstevel@tonic-gate 	return (big_mul_add_vec(r, a, len, digit));
12497c478bd9Sstevel@tonic-gate }
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate void
12527c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
12537c478bd9Sstevel@tonic-gate {
12547c478bd9Sstevel@tonic-gate 	int i;
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	r[len] = big_mul_set_vec(r, a, len, a[0]);
12577c478bd9Sstevel@tonic-gate 	for (i = 1; i < len; ++i)
12587c478bd9Sstevel@tonic-gate 		r[len + i] = big_mul_add_vec(r+i, a, len, a[i]);
12597c478bd9Sstevel@tonic-gate }
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate #endif /* UMUL64 */
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate void
12647c478bd9Sstevel@tonic-gate big_mul_vec(uint32_t *r, uint32_t *a, int alen, uint32_t *b, int blen)
12657c478bd9Sstevel@tonic-gate {
12667c478bd9Sstevel@tonic-gate 	int i;
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 	r[alen] = big_mul_set_vec(r, a, alen, b[0]);
12697c478bd9Sstevel@tonic-gate 	for (i = 1; i < blen; ++i)
12707c478bd9Sstevel@tonic-gate 		r[alen + i] = big_mul_add_vec(r+i, a, alen, b[i]);
12717c478bd9Sstevel@tonic-gate }
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate #endif /* ! PSR_MUL */
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate /*
12787c478bd9Sstevel@tonic-gate  * result = aa * bb  result->value should be big enough to hold the result
12797c478bd9Sstevel@tonic-gate  *
12807c478bd9Sstevel@tonic-gate  * Implementation: Standard grammar school algorithm
12817c478bd9Sstevel@tonic-gate  *
12827c478bd9Sstevel@tonic-gate  */
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate BIG_ERR_CODE
12857c478bd9Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
12867c478bd9Sstevel@tonic-gate {
12877c478bd9Sstevel@tonic-gate 	BIGNUM tmp1;
12887c478bd9Sstevel@tonic-gate 	uint32_t tmp1value[BIGTMPSIZE];
12897c478bd9Sstevel@tonic-gate 	uint32_t *r, *t, *a, *b;
12907c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
12917c478bd9Sstevel@tonic-gate 	int i, alen, blen, rsize, sign, diff;
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 	if (aa == bb) {
12947c478bd9Sstevel@tonic-gate 		diff = 0;
12957c478bd9Sstevel@tonic-gate 	} else {
12967c478bd9Sstevel@tonic-gate 		diff = big_cmp_abs(aa, bb);
12977c478bd9Sstevel@tonic-gate 		if (diff < 0) {
12987c478bd9Sstevel@tonic-gate 			BIGNUM *tt;
12997c478bd9Sstevel@tonic-gate 			tt = aa;
13007c478bd9Sstevel@tonic-gate 			aa = bb;
13017c478bd9Sstevel@tonic-gate 			bb = tt;
13027c478bd9Sstevel@tonic-gate 		}
13037c478bd9Sstevel@tonic-gate 	}
13047c478bd9Sstevel@tonic-gate 	a = aa->value;
13057c478bd9Sstevel@tonic-gate 	b = bb->value;
13067c478bd9Sstevel@tonic-gate 	alen = aa->len;
13077c478bd9Sstevel@tonic-gate 	blen = bb->len;
13087c478bd9Sstevel@tonic-gate 	while ((alen > 1) && (a[alen - 1] == 0)) alen--;
13097c478bd9Sstevel@tonic-gate 	aa->len = alen;
13107c478bd9Sstevel@tonic-gate 	while ((blen > 1) && (b[blen - 1] == 0)) blen--;
13117c478bd9Sstevel@tonic-gate 	bb->len = blen;
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 	rsize = alen + blen;
13147c478bd9Sstevel@tonic-gate 	if (result->size < rsize) {
13157c478bd9Sstevel@tonic-gate 		err = big_extend(result, rsize);
13167c478bd9Sstevel@tonic-gate 		if (err != BIG_OK)
13177c478bd9Sstevel@tonic-gate 			return (err);
13187c478bd9Sstevel@tonic-gate 		/* aa or bb might be an alias to result */
13197c478bd9Sstevel@tonic-gate 		a = aa->value;
13207c478bd9Sstevel@tonic-gate 		b = bb->value;
13217c478bd9Sstevel@tonic-gate 	}
13227c478bd9Sstevel@tonic-gate 	r = result->value;
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) {
13257c478bd9Sstevel@tonic-gate 		result->len = 1;
13267c478bd9Sstevel@tonic-gate 		result->sign = 1;
13277c478bd9Sstevel@tonic-gate 		r[0] = 0;
13287c478bd9Sstevel@tonic-gate 		return (BIG_OK);
13297c478bd9Sstevel@tonic-gate 	}
13307c478bd9Sstevel@tonic-gate 	sign = aa->sign * bb->sign;
13317c478bd9Sstevel@tonic-gate 	if ((alen == 1) && (a[0] == 1)) {
13327c478bd9Sstevel@tonic-gate 		for (i = 0; i < blen; i++) r[i] = b[i];
13337c478bd9Sstevel@tonic-gate 		result->len = blen;
13347c478bd9Sstevel@tonic-gate 		result->sign = sign;
13357c478bd9Sstevel@tonic-gate 		return (BIG_OK);
13367c478bd9Sstevel@tonic-gate 	}
13377c478bd9Sstevel@tonic-gate 	if ((blen == 1) && (b[0] == 1)) {
13387c478bd9Sstevel@tonic-gate 		for (i = 0; i < alen; i++) r[i] = a[i];
13397c478bd9Sstevel@tonic-gate 		result->len = alen;
13407c478bd9Sstevel@tonic-gate 		result->sign = sign;
13417c478bd9Sstevel@tonic-gate 		return (BIG_OK);
13427c478bd9Sstevel@tonic-gate 	}
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	err = big_init1(&tmp1, rsize, tmp1value, arraysize(tmp1value));
13457c478bd9Sstevel@tonic-gate 	if (err != BIG_OK)
13467c478bd9Sstevel@tonic-gate 		return (err);
13477c478bd9Sstevel@tonic-gate 	t = tmp1.value;
13487c478bd9Sstevel@tonic-gate 	for (i = 0; i < rsize; i++) t[i] = 0;
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 	if (diff == 0 && alen > 2)
13517c478bd9Sstevel@tonic-gate 		BIG_SQR_VEC(t, a, alen);
13527c478bd9Sstevel@tonic-gate 	else if (blen > 0)
13537c478bd9Sstevel@tonic-gate 		BIG_MUL_VEC(t, a, alen, b, blen);
13547c478bd9Sstevel@tonic-gate 	if (t[rsize - 1] == 0)
13557c478bd9Sstevel@tonic-gate 		--rsize;
13567c478bd9Sstevel@tonic-gate 	tmp1.len = rsize;
13577c478bd9Sstevel@tonic-gate 	if ((err = big_copy(result, &tmp1)) != BIG_OK)
13587c478bd9Sstevel@tonic-gate 		return (err);
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 	result->sign = sign;
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate 	if (tmp1.malloced) big_finish(&tmp1);
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 	return (BIG_OK);
13657c478bd9Sstevel@tonic-gate }
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate /*
13697c478bd9Sstevel@tonic-gate  * caller must ensure that  a < n,  b < n  and  ret->size >=  2 * n->len + 1
13707c478bd9Sstevel@tonic-gate  * and that ret is not n
13717c478bd9Sstevel@tonic-gate  */
13727c478bd9Sstevel@tonic-gate BIG_ERR_CODE
13737c478bd9Sstevel@tonic-gate big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, uint32_t n0)
13747c478bd9Sstevel@tonic-gate {
13757c478bd9Sstevel@tonic-gate 	int i, j, nlen, needsubtract;
13767c478bd9Sstevel@tonic-gate 	uint32_t *nn, *rr;
13777c478bd9Sstevel@tonic-gate 	uint32_t digit, c;
13787c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 	nlen = n->len;
13817c478bd9Sstevel@tonic-gate 	nn = n->value;
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	rr = ret->value;
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	if ((err = big_mul(ret, a, b)) != BIG_OK)
13867c478bd9Sstevel@tonic-gate 		return (err);
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 	rr = ret->value;
13897c478bd9Sstevel@tonic-gate 	for (i = ret->len; i < 2 * nlen + 1; i++) rr[i] = 0;
13907c478bd9Sstevel@tonic-gate 	for (i = 0; i < nlen; i++) {
13917c478bd9Sstevel@tonic-gate 		digit = rr[i];
13927c478bd9Sstevel@tonic-gate 		digit = digit * n0;
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 		c = BIG_MUL_ADD_VEC(rr + i, nn, nlen, digit);
13957c478bd9Sstevel@tonic-gate 		j = i + nlen;
13967c478bd9Sstevel@tonic-gate 		rr[j] += c;
13977c478bd9Sstevel@tonic-gate 		while (rr[j] < c) {
13987c478bd9Sstevel@tonic-gate 			rr[j + 1] += 1;
13997c478bd9Sstevel@tonic-gate 			j++;
14007c478bd9Sstevel@tonic-gate 			c = 1;
14017c478bd9Sstevel@tonic-gate 		}
14027c478bd9Sstevel@tonic-gate 	}
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate 	needsubtract = 0;
14057c478bd9Sstevel@tonic-gate 	if ((rr[2 * nlen]  != 0))
14067c478bd9Sstevel@tonic-gate 		needsubtract = 1;
14077c478bd9Sstevel@tonic-gate 	else {
14087c478bd9Sstevel@tonic-gate 		for (i = 2 * nlen - 1; i >= nlen; i--) {
14097c478bd9Sstevel@tonic-gate 			if (rr[i] > nn[i - nlen]) {
14107c478bd9Sstevel@tonic-gate 				needsubtract = 1;
14117c478bd9Sstevel@tonic-gate 				break;
14127c478bd9Sstevel@tonic-gate 			} else if (rr[i] < nn[i - nlen]) break;
14137c478bd9Sstevel@tonic-gate 		}
14147c478bd9Sstevel@tonic-gate 	}
14157c478bd9Sstevel@tonic-gate 	if (needsubtract)
14167c478bd9Sstevel@tonic-gate 		big_sub_vec(rr, rr + nlen, nn, nlen);
14177c478bd9Sstevel@tonic-gate 	else {
14187c478bd9Sstevel@tonic-gate 		for (i = 0; i < nlen; i++)
14197c478bd9Sstevel@tonic-gate 			rr[i] = rr[i + nlen];
14207c478bd9Sstevel@tonic-gate 	}
14217c478bd9Sstevel@tonic-gate 	for (i = nlen - 1; (i >= 0) && (rr[i] == 0); i--);
14227c478bd9Sstevel@tonic-gate 	ret->len = i+1;
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 	return (BIG_OK);
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate uint32_t
14287c478bd9Sstevel@tonic-gate big_n0(uint32_t n)
14297c478bd9Sstevel@tonic-gate {
14307c478bd9Sstevel@tonic-gate 	int i;
14317c478bd9Sstevel@tonic-gate 	uint32_t result, tmp;
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 	result = 0;
14347c478bd9Sstevel@tonic-gate 	tmp = 0xffffffff;
14357c478bd9Sstevel@tonic-gate 	for (i = 0; i < 32; i++) {
14367c478bd9Sstevel@tonic-gate 		if ((tmp & 1) == 1) {
14377c478bd9Sstevel@tonic-gate 			result = (result >> 1) | 0x80000000;
14387c478bd9Sstevel@tonic-gate 			tmp = tmp - n;
14397c478bd9Sstevel@tonic-gate 		} else  result = (result>>1);
14407c478bd9Sstevel@tonic-gate 		tmp = tmp >> 1;
14417c478bd9Sstevel@tonic-gate 	}
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 	return (result);
14447c478bd9Sstevel@tonic-gate }
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate int
14487c478bd9Sstevel@tonic-gate big_numbits(BIGNUM *n)
14497c478bd9Sstevel@tonic-gate {
14507c478bd9Sstevel@tonic-gate 	int i, j;
14517c478bd9Sstevel@tonic-gate 	uint32_t t;
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	for (i = n->len - 1; i > 0; i--)
14547c478bd9Sstevel@tonic-gate 		if (n->value[i] != 0) break;
14557c478bd9Sstevel@tonic-gate 	t = n->value[i];
14567c478bd9Sstevel@tonic-gate 	for (j = 32; j > 0; j--) {
14577c478bd9Sstevel@tonic-gate 		if ((t & 0x80000000) == 0)
14587c478bd9Sstevel@tonic-gate 			t = t << 1;
14597c478bd9Sstevel@tonic-gate 		else
14607c478bd9Sstevel@tonic-gate 			return (32 * i + j);
14617c478bd9Sstevel@tonic-gate 	}
14627c478bd9Sstevel@tonic-gate 	return (0);
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */
14667c478bd9Sstevel@tonic-gate BIG_ERR_CODE
14677c478bd9Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n)
14687c478bd9Sstevel@tonic-gate {
14697c478bd9Sstevel@tonic-gate 	BIGNUM rr;
14707c478bd9Sstevel@tonic-gate 	uint32_t rrvalue[BIGTMPSIZE];
14717c478bd9Sstevel@tonic-gate 	int len, i;
14727c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
14757c478bd9Sstevel@tonic-gate 	len = n->len;
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1,
14787c478bd9Sstevel@tonic-gate 	    rrvalue, arraysize(rrvalue))) != BIG_OK)
14797c478bd9Sstevel@tonic-gate 		return (err);
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	for (i = 0; i < 2 * len; i++) rr.value[i] = 0;
14827c478bd9Sstevel@tonic-gate 	rr.value[2 * len] = 1;
14837c478bd9Sstevel@tonic-gate 	rr.len = 2 * len + 1;
14847c478bd9Sstevel@tonic-gate 	if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK)
14857c478bd9Sstevel@tonic-gate 		goto ret;
14867c478bd9Sstevel@tonic-gate 	err = big_copy(result, &rr);
14877c478bd9Sstevel@tonic-gate ret:
14887c478bd9Sstevel@tonic-gate 	if (rr.malloced) big_finish(&rr);
14897c478bd9Sstevel@tonic-gate 	return (err);
14907c478bd9Sstevel@tonic-gate }
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */
14937c478bd9Sstevel@tonic-gate BIG_ERR_CODE
14947c478bd9Sstevel@tonic-gate big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, uint32_t n0, BIGNUM *n_rr)
14957c478bd9Sstevel@tonic-gate {
14967c478bd9Sstevel@tonic-gate 	BIGNUM rr;
14977c478bd9Sstevel@tonic-gate 	uint32_t rrvalue[BIGTMPSIZE];
14987c478bd9Sstevel@tonic-gate 	int len, i;
14997c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
15027c478bd9Sstevel@tonic-gate 	len = n->len;
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue)))
15057c478bd9Sstevel@tonic-gate 	    != BIG_OK)
15067c478bd9Sstevel@tonic-gate 			return (err);
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 	if (n_rr == NULL) {
15097c478bd9Sstevel@tonic-gate 		for (i = 0; i < 2 * len; i++) rr.value[i] = 0;
15107c478bd9Sstevel@tonic-gate 		rr.value[2 * len] = 1;
15117c478bd9Sstevel@tonic-gate 		rr.len = 2 * len + 1;
15127c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK)
15137c478bd9Sstevel@tonic-gate 			goto ret;
15147c478bd9Sstevel@tonic-gate 		n_rr = &rr;
15157c478bd9Sstevel@tonic-gate 	}
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 	if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK)
15187c478bd9Sstevel@tonic-gate 		goto ret;
15197c478bd9Sstevel@tonic-gate 	err = big_copy(result, &rr);
15207c478bd9Sstevel@tonic-gate ret:
15217c478bd9Sstevel@tonic-gate 	if (rr.malloced) big_finish(&rr);
15227c478bd9Sstevel@tonic-gate 	return (err);
15237c478bd9Sstevel@tonic-gate }
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate #define	MAX_EXP_BIT_GROUP_SIZE 6
15277c478bd9Sstevel@tonic-gate #define	APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1))
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate #ifdef USE_FLOATING_POINT
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate /*
15327c478bd9Sstevel@tonic-gate  * This version makes use of floating point for performance.
15337c478bd9Sstevel@tonic-gate  */
15347c478bd9Sstevel@tonic-gate static BIG_ERR_CODE
15357c478bd9Sstevel@tonic-gate _big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
15367c478bd9Sstevel@tonic-gate {
15377c478bd9Sstevel@tonic-gate 	BIGNUM ma, tmp, rr;
15387c478bd9Sstevel@tonic-gate 	uint32_t mavalue[BIGTMPSIZE];
15397c478bd9Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
15407c478bd9Sstevel@tonic-gate 	uint32_t rrvalue[BIGTMPSIZE];
15417c478bd9Sstevel@tonic-gate 	int i, j, k, l, m, p, bit, bitind, bitcount, nlen;
15427c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
15437c478bd9Sstevel@tonic-gate 	uint32_t n0;
15447c478bd9Sstevel@tonic-gate 	double dn0;
15457c478bd9Sstevel@tonic-gate 	double *dn, *dt, *d16r, *d32r;
15467c478bd9Sstevel@tonic-gate 	uint32_t *nint, *prod;
15477c478bd9Sstevel@tonic-gate 	double *apowers[APOWERS_MAX_SIZE];
15487c478bd9Sstevel@tonic-gate 	int nbits, groupbits, apowerssize;
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	nbits = big_numbits(e);
15517c478bd9Sstevel@tonic-gate 	if (nbits < 50) {
15527c478bd9Sstevel@tonic-gate 		groupbits = 1;
15537c478bd9Sstevel@tonic-gate 		apowerssize = 1;
15547c478bd9Sstevel@tonic-gate 	} else {
15557c478bd9Sstevel@tonic-gate 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
15567c478bd9Sstevel@tonic-gate 		apowerssize = 1 << (groupbits - 1);
15577c478bd9Sstevel@tonic-gate 	}
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue)))	!=
15607c478bd9Sstevel@tonic-gate 	    BIG_OK)
15617c478bd9Sstevel@tonic-gate 		return (err);
15627c478bd9Sstevel@tonic-gate 	ma.len = 1;
15637c478bd9Sstevel@tonic-gate 	ma.value[0] = 0;
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len + 1,
15667c478bd9Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
15677c478bd9Sstevel@tonic-gate 		goto ret1;
15687c478bd9Sstevel@tonic-gate 	tmp.len = 1;
15697c478bd9Sstevel@tonic-gate 	tmp.value[0] = 0;
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
15727c478bd9Sstevel@tonic-gate 	if (n_rr == NULL) {
15737c478bd9Sstevel@tonic-gate 		if ((err = big_init1(&rr, 2 * n->len + 1,
15747c478bd9Sstevel@tonic-gate 		    rrvalue, arraysize(rrvalue))) != BIG_OK)
15757c478bd9Sstevel@tonic-gate 			goto ret2;
15767c478bd9Sstevel@tonic-gate 		if (big_mont_rr(&rr, n) != BIG_OK)
15777c478bd9Sstevel@tonic-gate 			goto ret2;
15787c478bd9Sstevel@tonic-gate 		n_rr = &rr;
15797c478bd9Sstevel@tonic-gate 	}
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 	n0 = big_n0(n->value[0]);
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(a, n) > 0) {
15847c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK)
15857c478bd9Sstevel@tonic-gate 			goto ret2;
15867c478bd9Sstevel@tonic-gate 		err = big_mont_conv(&ma, &ma, n, n0, n_rr);
15877c478bd9Sstevel@tonic-gate 	} else {
15887c478bd9Sstevel@tonic-gate 		err = big_mont_conv(&ma, a, n, n0, n_rr);
15897c478bd9Sstevel@tonic-gate 	}
15907c478bd9Sstevel@tonic-gate 	if (err != BIG_OK)
15917c478bd9Sstevel@tonic-gate 		goto ret3;
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 	tmp.len = 1;
15947c478bd9Sstevel@tonic-gate 	tmp.value[0] = 1;
15957c478bd9Sstevel@tonic-gate 	if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK)
15967c478bd9Sstevel@tonic-gate 		goto ret3;
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 	nlen = n->len;
15997c478bd9Sstevel@tonic-gate 	dn0 = (double)(n0 & 0xffff);
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate 	dn = dt = d16r = d32r = NULL;
16027c478bd9Sstevel@tonic-gate 	nint = prod = NULL;
16037c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
16047c478bd9Sstevel@tonic-gate 		apowers[i] = NULL;
16057c478bd9Sstevel@tonic-gate 	}
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate 	if ((dn = big_malloc(nlen * sizeof (double))) == NULL) {
16087c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
16097c478bd9Sstevel@tonic-gate 		goto ret;
16107c478bd9Sstevel@tonic-gate 	}
16117c478bd9Sstevel@tonic-gate 	if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) {
16127c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
16137c478bd9Sstevel@tonic-gate 		goto ret;
16147c478bd9Sstevel@tonic-gate 	}
16157c478bd9Sstevel@tonic-gate 	if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) {
16167c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
16177c478bd9Sstevel@tonic-gate 		goto ret;
16187c478bd9Sstevel@tonic-gate 	}
16197c478bd9Sstevel@tonic-gate 	if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) {
16207c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
16217c478bd9Sstevel@tonic-gate 		goto ret;
16227c478bd9Sstevel@tonic-gate 	}
16237c478bd9Sstevel@tonic-gate 	if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) {
16247c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
16257c478bd9Sstevel@tonic-gate 		goto ret;
16267c478bd9Sstevel@tonic-gate 	}
16277c478bd9Sstevel@tonic-gate 	if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) {
16287c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
16297c478bd9Sstevel@tonic-gate 		goto ret;
16307c478bd9Sstevel@tonic-gate 	}
16317c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
16327c478bd9Sstevel@tonic-gate 		if ((apowers[i] = big_malloc((2 * nlen + 1) *
16337c478bd9Sstevel@tonic-gate 		    sizeof (double))) == NULL) {
16347c478bd9Sstevel@tonic-gate 			err = BIG_NO_MEM;
16357c478bd9Sstevel@tonic-gate 			goto ret;
16367c478bd9Sstevel@tonic-gate 		}
16377c478bd9Sstevel@tonic-gate 	}
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 	for (i = 0; i < ma.len; i++) nint[i] = ma.value[i];
16407c478bd9Sstevel@tonic-gate 	for (; i < nlen; i++) nint[i] = 0;
16417c478bd9Sstevel@tonic-gate 	conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen);
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 	for (i = 0; i < n->len; i++) nint[i] = n->value[i];
16447c478bd9Sstevel@tonic-gate 	for (; i < nlen; i++) nint[i] = 0;
16457c478bd9Sstevel@tonic-gate 	conv_i32_to_d32(dn, nint, nlen);
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0);
16487c478bd9Sstevel@tonic-gate 	conv_i32_to_d32(d32r, prod, nlen);
16497c478bd9Sstevel@tonic-gate 	for (i = 1; i < apowerssize; i++) {
16507c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[i - 1],
16517c478bd9Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
16527c478bd9Sstevel@tonic-gate 		conv_i32_to_d16(apowers[i], prod, nlen);
16537c478bd9Sstevel@tonic-gate 	}
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	for (i = 0; i < tmp.len; i++) prod[i] = tmp.value[i];
16567c478bd9Sstevel@tonic-gate 	for (; i < nlen + 1; i++) prod[i] = 0;
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	bitind = nbits % 32;
16597c478bd9Sstevel@tonic-gate 	k = 0;
16607c478bd9Sstevel@tonic-gate 	l = 0;
16617c478bd9Sstevel@tonic-gate 	p = 0;
16627c478bd9Sstevel@tonic-gate 	bitcount = 0;
16637c478bd9Sstevel@tonic-gate 	for (i = nbits / 32; i >= 0; i--) {
16647c478bd9Sstevel@tonic-gate 		for (j = bitind - 1; j >= 0; j--) {
16657c478bd9Sstevel@tonic-gate 			bit = (e->value[i] >> j) & 1;
16667c478bd9Sstevel@tonic-gate 			if ((bitcount == 0) && (bit == 0)) {
16677c478bd9Sstevel@tonic-gate 				conv_i32_to_d32_and_d16(d32r, d16r,
16687c478bd9Sstevel@tonic-gate 				    prod, nlen);
16697c478bd9Sstevel@tonic-gate 				mont_mulf_noconv(prod, d32r, d16r,
16707c478bd9Sstevel@tonic-gate 				    dt, dn, nint, nlen, dn0);
16717c478bd9Sstevel@tonic-gate 			} else {
16727c478bd9Sstevel@tonic-gate 				bitcount++;
16737c478bd9Sstevel@tonic-gate 				p = p * 2 + bit;
16747c478bd9Sstevel@tonic-gate 				if (bit == 1) {
16757c478bd9Sstevel@tonic-gate 					k = k + l + 1;
16767c478bd9Sstevel@tonic-gate 					l = 0;
16777c478bd9Sstevel@tonic-gate 				} else {
16787c478bd9Sstevel@tonic-gate 					l++;
16797c478bd9Sstevel@tonic-gate 				}
16807c478bd9Sstevel@tonic-gate 				if (bitcount == groupbits) {
16817c478bd9Sstevel@tonic-gate 					for (m = 0; m < k; m++) {
16827c478bd9Sstevel@tonic-gate 						conv_i32_to_d32_and_d16(
16837c478bd9Sstevel@tonic-gate 							d32r, d16r,
16847c478bd9Sstevel@tonic-gate 							prod, nlen);
16857c478bd9Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
16867c478bd9Sstevel@tonic-gate 						    d16r, dt, dn, nint,
16877c478bd9Sstevel@tonic-gate 						    nlen, dn0);
16887c478bd9Sstevel@tonic-gate 					}
16897c478bd9Sstevel@tonic-gate 					conv_i32_to_d32(d32r, prod, nlen);
16907c478bd9Sstevel@tonic-gate 					mont_mulf_noconv(prod, d32r,
16917c478bd9Sstevel@tonic-gate 					    apowers[p >> (l+1)],
16927c478bd9Sstevel@tonic-gate 					    dt, dn, nint, nlen, dn0);
16937c478bd9Sstevel@tonic-gate 					for (m = 0; m < l; m++) {
16947c478bd9Sstevel@tonic-gate 						conv_i32_to_d32_and_d16(
16957c478bd9Sstevel@tonic-gate 							d32r, d16r,
16967c478bd9Sstevel@tonic-gate 							prod, nlen);
16977c478bd9Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
16987c478bd9Sstevel@tonic-gate 						    d16r, dt, dn, nint,
16997c478bd9Sstevel@tonic-gate 						    nlen, dn0);
17007c478bd9Sstevel@tonic-gate 					}
17017c478bd9Sstevel@tonic-gate 					k = 0;
17027c478bd9Sstevel@tonic-gate 					l = 0;
17037c478bd9Sstevel@tonic-gate 					p = 0;
17047c478bd9Sstevel@tonic-gate 					bitcount = 0;
17057c478bd9Sstevel@tonic-gate 				}
17067c478bd9Sstevel@tonic-gate 			}
17077c478bd9Sstevel@tonic-gate 		}
17087c478bd9Sstevel@tonic-gate 		bitind = 32;
17097c478bd9Sstevel@tonic-gate 	}
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 	for (m = 0; m < k; m++) {
17127c478bd9Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
17137c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
17147c478bd9Sstevel@tonic-gate 	}
17157c478bd9Sstevel@tonic-gate 	if (p != 0) {
17167c478bd9Sstevel@tonic-gate 		conv_i32_to_d32(d32r, prod, nlen);
17177c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)],
17187c478bd9Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
17197c478bd9Sstevel@tonic-gate 	}
17207c478bd9Sstevel@tonic-gate 	for (m = 0; m < l; m++) {
17217c478bd9Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
17227c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
17237c478bd9Sstevel@tonic-gate 	}
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 	ma.value[0] = 1;
17267c478bd9Sstevel@tonic-gate 	ma.len = 1;
17277c478bd9Sstevel@tonic-gate 	for (i = 0; i < nlen; i++) tmp.value[i] = prod[i];
17287c478bd9Sstevel@tonic-gate 	for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--);
17297c478bd9Sstevel@tonic-gate 	tmp.len = i + 1;
17307c478bd9Sstevel@tonic-gate 	if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK)
17317c478bd9Sstevel@tonic-gate 		goto ret;
17327c478bd9Sstevel@tonic-gate 	err = big_copy(result, &tmp);
17337c478bd9Sstevel@tonic-gate ret:
17347c478bd9Sstevel@tonic-gate 	for (i = apowerssize - 1; i >= 0; i--) {
17357c478bd9Sstevel@tonic-gate 		if (apowers[i] != NULL)
17367c478bd9Sstevel@tonic-gate 			big_free(apowers[i], (2 * nlen + 1) * sizeof (double));
17377c478bd9Sstevel@tonic-gate 	}
17387c478bd9Sstevel@tonic-gate 	if (d32r != NULL)
17397c478bd9Sstevel@tonic-gate 		big_free(d32r, nlen * sizeof (double));
17407c478bd9Sstevel@tonic-gate 	if (d16r != NULL)
17417c478bd9Sstevel@tonic-gate 		big_free(d16r, (2 * nlen + 1) * sizeof (double));
17427c478bd9Sstevel@tonic-gate 	if (prod != NULL)
17437c478bd9Sstevel@tonic-gate 		big_free(prod, (nlen + 1) * sizeof (uint32_t));
17447c478bd9Sstevel@tonic-gate 	if (nint != NULL)
17457c478bd9Sstevel@tonic-gate 		big_free(nint, nlen * sizeof (uint32_t));
17467c478bd9Sstevel@tonic-gate 	if (dt != NULL)
17477c478bd9Sstevel@tonic-gate 		big_free(dt, (4 * nlen + 2) * sizeof (double));
17487c478bd9Sstevel@tonic-gate 	if (dn != NULL)
17497c478bd9Sstevel@tonic-gate 		big_free(dn, nlen * sizeof (double));
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate ret3:
17527c478bd9Sstevel@tonic-gate 	big_finish(&rr);
17537c478bd9Sstevel@tonic-gate ret2:
17547c478bd9Sstevel@tonic-gate 	big_finish(&tmp);
17557c478bd9Sstevel@tonic-gate ret1:
17567c478bd9Sstevel@tonic-gate 	big_finish(&ma);
17577c478bd9Sstevel@tonic-gate 	return (err);
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate }
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate #ifdef _KERNEL
17627c478bd9Sstevel@tonic-gate 
17637c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
17647c478bd9Sstevel@tonic-gate #include <sys/regset.h>
17657c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate /* the alignment for block stores to save fp registers */
17687c478bd9Sstevel@tonic-gate #define	FPR_ALIGN	(64)
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate extern void big_savefp(kfpu_t *);
17717c478bd9Sstevel@tonic-gate extern void big_restorefp(kfpu_t *);
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate BIG_ERR_CODE
17767c478bd9Sstevel@tonic-gate big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
17777c478bd9Sstevel@tonic-gate {
17787c478bd9Sstevel@tonic-gate #ifdef _KERNEL
17797c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE rv;
17807c478bd9Sstevel@tonic-gate 	uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN];
17817c478bd9Sstevel@tonic-gate 	kfpu_t *fpu;
17827c478bd9Sstevel@tonic-gate 
17837c478bd9Sstevel@tonic-gate #ifdef DEBUG
17847c478bd9Sstevel@tonic-gate 	if (!fpu_exists)
17857c478bd9Sstevel@tonic-gate 		return (BIG_GENERAL_ERR);
17867c478bd9Sstevel@tonic-gate #endif
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate 	fpu =  (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN);
17897c478bd9Sstevel@tonic-gate 	big_savefp(fpu);
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	rv = _big_modexp(result, a, e, n, n_rr);
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate 	big_restorefp(fpu);
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 	return (rv);
17967c478bd9Sstevel@tonic-gate #else
17977c478bd9Sstevel@tonic-gate 	return (_big_modexp(result, a, e, n, n_rr));
17987c478bd9Sstevel@tonic-gate #endif	/* _KERNEL */
17997c478bd9Sstevel@tonic-gate }
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate #else /* ! USE_FLOATING_POINT */
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate /*
18047c478bd9Sstevel@tonic-gate  * This version uses strictly integer math and is safe in the kernel
18057c478bd9Sstevel@tonic-gate  * for all platforms.
18067c478bd9Sstevel@tonic-gate  */
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate /*
18097c478bd9Sstevel@tonic-gate  * computes a^e mod n
18107c478bd9Sstevel@tonic-gate  * assumes a < n, n odd, result->value at least as long as n->value
18117c478bd9Sstevel@tonic-gate  */
18127c478bd9Sstevel@tonic-gate BIG_ERR_CODE
18137c478bd9Sstevel@tonic-gate big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
18147c478bd9Sstevel@tonic-gate {
18157c478bd9Sstevel@tonic-gate 	BIGNUM ma, tmp, rr;
18167c478bd9Sstevel@tonic-gate 	uint32_t mavalue[BIGTMPSIZE];
18177c478bd9Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
18187c478bd9Sstevel@tonic-gate 	uint32_t rrvalue[BIGTMPSIZE];
18197c478bd9Sstevel@tonic-gate 	BIGNUM apowers[APOWERS_MAX_SIZE];
18207c478bd9Sstevel@tonic-gate 	int i, j, k, l, m, p,
18217c478bd9Sstevel@tonic-gate 	    bit, bitind, bitcount, groupbits, apowerssize;
18227c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
18237c478bd9Sstevel@tonic-gate 	uint32_t n0;
18247c478bd9Sstevel@tonic-gate 
18257c478bd9Sstevel@tonic-gate 	int nbits;
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 	nbits = big_numbits(e);
18287c478bd9Sstevel@tonic-gate 	if (nbits < 50) {
18297c478bd9Sstevel@tonic-gate 		groupbits = 1;
18307c478bd9Sstevel@tonic-gate 		apowerssize = 1;
18317c478bd9Sstevel@tonic-gate 	} else {
18327c478bd9Sstevel@tonic-gate 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
18337c478bd9Sstevel@tonic-gate 		apowerssize = 1 << (groupbits - 1);
18347c478bd9Sstevel@tonic-gate 	}
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&ma, n->len,
18377c478bd9Sstevel@tonic-gate 	    mavalue, arraysize(mavalue))) != BIG_OK)
18387c478bd9Sstevel@tonic-gate 		return (err);
18397c478bd9Sstevel@tonic-gate 	ma.len = 1;
18407c478bd9Sstevel@tonic-gate 	ma.value[0] = 0;
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len + 1,
18437c478bd9Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
18447c478bd9Sstevel@tonic-gate 		goto ret1;
18457c478bd9Sstevel@tonic-gate 	tmp.len = 1;
18467c478bd9Sstevel@tonic-gate 	tmp.value[0] = 1;
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 	n0 = big_n0(n->value[0]);
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
18517c478bd9Sstevel@tonic-gate 	if (n_rr == NULL) {
18527c478bd9Sstevel@tonic-gate 		if ((err = big_init1(&rr, 2 * n->len + 1,
18537c478bd9Sstevel@tonic-gate 		    rrvalue, arraysize(rrvalue))) != BIG_OK)
18547c478bd9Sstevel@tonic-gate 			goto ret2;
18557c478bd9Sstevel@tonic-gate 
18567c478bd9Sstevel@tonic-gate 		if (big_mont_rr(&rr, n) != BIG_OK)
18577c478bd9Sstevel@tonic-gate 			goto ret3;
18587c478bd9Sstevel@tonic-gate 		n_rr = &rr;
18597c478bd9Sstevel@tonic-gate 	}
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) apowers[i].malloced = 0;
18627c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
18637c478bd9Sstevel@tonic-gate 		if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) !=
18647c478bd9Sstevel@tonic-gate 		    BIG_OK)
18657c478bd9Sstevel@tonic-gate 			goto ret;
18667c478bd9Sstevel@tonic-gate 	}
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(a, n) > 0) {
18697c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK)
18707c478bd9Sstevel@tonic-gate 			goto ret;
18717c478bd9Sstevel@tonic-gate 		err = big_mont_conv(&ma, &ma, n, n0, n_rr);
18727c478bd9Sstevel@tonic-gate 	} else {
18737c478bd9Sstevel@tonic-gate 		err = big_mont_conv(&ma, a, n, n0, n_rr);
18747c478bd9Sstevel@tonic-gate 	}
18757c478bd9Sstevel@tonic-gate 	if (err != BIG_OK) goto ret;
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 	(void) big_copy(&(apowers[0]), &ma);
18787c478bd9Sstevel@tonic-gate 	if ((err = big_mont_mul(&tmp, &ma, &ma, n, n0)) != BIG_OK)
18797c478bd9Sstevel@tonic-gate 		goto ret;
18807c478bd9Sstevel@tonic-gate 	(void) big_copy(&ma, &tmp);
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate 	for (i = 1; i < apowerssize; i++) {
18837c478bd9Sstevel@tonic-gate 		if ((err = big_mont_mul(&tmp, &ma,
18847c478bd9Sstevel@tonic-gate 		    &(apowers[i-1]), n, n0)) != BIG_OK)
18857c478bd9Sstevel@tonic-gate 			goto ret;
18867c478bd9Sstevel@tonic-gate 		(void) big_copy(&apowers[i], &tmp);
18877c478bd9Sstevel@tonic-gate 	}
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate 	tmp.len = 1;
18907c478bd9Sstevel@tonic-gate 	tmp.value[0] = 1;
18917c478bd9Sstevel@tonic-gate 	if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK)
18927c478bd9Sstevel@tonic-gate 		goto ret;
18937c478bd9Sstevel@tonic-gate 
18947c478bd9Sstevel@tonic-gate 	bitind = nbits % 32;
18957c478bd9Sstevel@tonic-gate 	k = 0;
18967c478bd9Sstevel@tonic-gate 	l = 0;
18977c478bd9Sstevel@tonic-gate 	p = 0;
18987c478bd9Sstevel@tonic-gate 	bitcount = 0;
18997c478bd9Sstevel@tonic-gate 	for (i = nbits / 32; i >= 0; i--) {
19007c478bd9Sstevel@tonic-gate 		for (j = bitind - 1; j >= 0; j--) {
19017c478bd9Sstevel@tonic-gate 			bit = (e->value[i] >> j) & 1;
19027c478bd9Sstevel@tonic-gate 			if ((bitcount == 0) && (bit == 0)) {
19037c478bd9Sstevel@tonic-gate 				if ((err = big_mont_mul(&tmp,
19047c478bd9Sstevel@tonic-gate 				    &tmp, &tmp, n, n0)) != BIG_OK)
19057c478bd9Sstevel@tonic-gate 					goto ret;
19067c478bd9Sstevel@tonic-gate 			} else {
19077c478bd9Sstevel@tonic-gate 				bitcount++;
19087c478bd9Sstevel@tonic-gate 				p = p * 2 + bit;
19097c478bd9Sstevel@tonic-gate 				if (bit == 1) {
19107c478bd9Sstevel@tonic-gate 					k = k + l + 1;
19117c478bd9Sstevel@tonic-gate 					l = 0;
19127c478bd9Sstevel@tonic-gate 				} else {
19137c478bd9Sstevel@tonic-gate 					l++;
19147c478bd9Sstevel@tonic-gate 				}
19157c478bd9Sstevel@tonic-gate 				if (bitcount == groupbits) {
19167c478bd9Sstevel@tonic-gate 					for (m = 0; m < k; m++) {
19177c478bd9Sstevel@tonic-gate 						if ((err = big_mont_mul(&tmp,
19187c478bd9Sstevel@tonic-gate 						    &tmp, &tmp, n, n0)) !=
19197c478bd9Sstevel@tonic-gate 						    BIG_OK)
19207c478bd9Sstevel@tonic-gate 							goto ret;
19217c478bd9Sstevel@tonic-gate 					}
19227c478bd9Sstevel@tonic-gate 					if ((err = big_mont_mul(&tmp, &tmp,
19237c478bd9Sstevel@tonic-gate 					    &(apowers[p >> (l + 1)]),
19247c478bd9Sstevel@tonic-gate 					    n, n0)) != BIG_OK)
19257c478bd9Sstevel@tonic-gate 						goto ret;
19267c478bd9Sstevel@tonic-gate 					for (m = 0; m < l; m++) {
19277c478bd9Sstevel@tonic-gate 						if ((err = big_mont_mul(&tmp,
19287c478bd9Sstevel@tonic-gate 						    &tmp, &tmp, n, n0)) !=
19297c478bd9Sstevel@tonic-gate 						    BIG_OK)
19307c478bd9Sstevel@tonic-gate 							goto ret;
19317c478bd9Sstevel@tonic-gate 					}
19327c478bd9Sstevel@tonic-gate 					k = 0;
19337c478bd9Sstevel@tonic-gate 					l = 0;
19347c478bd9Sstevel@tonic-gate 					p = 0;
19357c478bd9Sstevel@tonic-gate 					bitcount = 0;
19367c478bd9Sstevel@tonic-gate 				}
19377c478bd9Sstevel@tonic-gate 			}
19387c478bd9Sstevel@tonic-gate 		}
19397c478bd9Sstevel@tonic-gate 		bitind = 32;
19407c478bd9Sstevel@tonic-gate 	}
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 	for (m = 0; m < k; m++) {
19437c478bd9Sstevel@tonic-gate 		if ((err = big_mont_mul(&tmp, &tmp, &tmp, n, n0)) != BIG_OK)
19447c478bd9Sstevel@tonic-gate 			goto ret;
19457c478bd9Sstevel@tonic-gate 	}
19467c478bd9Sstevel@tonic-gate 	if (p != 0) {
19477c478bd9Sstevel@tonic-gate 		if ((err = big_mont_mul(&tmp, &tmp,
19487c478bd9Sstevel@tonic-gate 		    &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK)
19497c478bd9Sstevel@tonic-gate 			goto ret;
19507c478bd9Sstevel@tonic-gate 	}
19517c478bd9Sstevel@tonic-gate 	for (m = 0; m < l; m++) {
19527c478bd9Sstevel@tonic-gate 		if ((err = big_mont_mul(&tmp, &tmp, &tmp, n, n0)) != BIG_OK)
19537c478bd9Sstevel@tonic-gate 			goto ret;
19547c478bd9Sstevel@tonic-gate 	}
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 	ma.value[0] = 1;
19577c478bd9Sstevel@tonic-gate 	ma.len = 1;
19587c478bd9Sstevel@tonic-gate 	if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK)
19597c478bd9Sstevel@tonic-gate 		goto ret;
19607c478bd9Sstevel@tonic-gate 	err = big_copy(result, &tmp);
19617c478bd9Sstevel@tonic-gate ret:
19627c478bd9Sstevel@tonic-gate 	for (i = apowerssize - 1; i >= 0; i--) {
19637c478bd9Sstevel@tonic-gate 		big_finish(&(apowers[i]));
19647c478bd9Sstevel@tonic-gate 	}
19657c478bd9Sstevel@tonic-gate ret3:
19667c478bd9Sstevel@tonic-gate 	if (rr.malloced) big_finish(&rr);
19677c478bd9Sstevel@tonic-gate ret2:
19687c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
19697c478bd9Sstevel@tonic-gate ret1:
19707c478bd9Sstevel@tonic-gate 	if (ma.malloced) big_finish(&ma);
19717c478bd9Sstevel@tonic-gate 	return (err);
19727c478bd9Sstevel@tonic-gate }
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate BIG_ERR_CODE
19787c478bd9Sstevel@tonic-gate big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
19797c478bd9Sstevel@tonic-gate     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
19807c478bd9Sstevel@tonic-gate     BIGNUM *p_rr, BIGNUM *q_rr)
19817c478bd9Sstevel@tonic-gate {
19827c478bd9Sstevel@tonic-gate 	BIGNUM ap, aq, tmp;
19837c478bd9Sstevel@tonic-gate 	int alen, biglen, sign;
19847c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate 	if (p->len > q->len) biglen = p->len;
19877c478bd9Sstevel@tonic-gate 	else biglen = q->len;
19887c478bd9Sstevel@tonic-gate 
19897c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK)
19907c478bd9Sstevel@tonic-gate 		return (err);
19917c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK)
19927c478bd9Sstevel@tonic-gate 		goto ret1;
19937c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK)
19947c478bd9Sstevel@tonic-gate 		goto ret2;
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate 	/*
19977c478bd9Sstevel@tonic-gate 	 * check whether a is too short - to avoid timing attacks
19987c478bd9Sstevel@tonic-gate 	 */
19997c478bd9Sstevel@tonic-gate 	alen = a->len;
20007c478bd9Sstevel@tonic-gate 	while ((alen > p->len) && (a->value[alen - 1] == 0)) {
20017c478bd9Sstevel@tonic-gate 		alen--;
20027c478bd9Sstevel@tonic-gate 	}
20037c478bd9Sstevel@tonic-gate 	if (alen < p->len + q->len) {
20047c478bd9Sstevel@tonic-gate 		/*
20057c478bd9Sstevel@tonic-gate 		 * a is too short, add p*q to it before
20067c478bd9Sstevel@tonic-gate 		 * taking it modulo p and q
20077c478bd9Sstevel@tonic-gate 		 * this will also affect timing, but this difference
20087c478bd9Sstevel@tonic-gate 		 * does not depend on p or q, only on a
20097c478bd9Sstevel@tonic-gate 		 * (in "normal" operation, this path will never be
20107c478bd9Sstevel@tonic-gate 		 * taken, so it is not a performance penalty
20117c478bd9Sstevel@tonic-gate 		 */
20127c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&tmp, p, q)) != BIG_OK)
20137c478bd9Sstevel@tonic-gate 			goto ret;
20147c478bd9Sstevel@tonic-gate 		if ((err = big_add(&tmp, &tmp, a)) != BIG_OK)
20157c478bd9Sstevel@tonic-gate 			goto ret;
20167c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK)
20177c478bd9Sstevel@tonic-gate 			goto ret;
20187c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK)
20197c478bd9Sstevel@tonic-gate 			goto ret;
20207c478bd9Sstevel@tonic-gate 	} else {
20217c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK)
20227c478bd9Sstevel@tonic-gate 			goto ret;
20237c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK)
20247c478bd9Sstevel@tonic-gate 			goto ret;
20257c478bd9Sstevel@tonic-gate 	}
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate 	if ((err = big_modexp(&ap, &ap, dmodpminus1, p, p_rr)) != BIG_OK)
20287c478bd9Sstevel@tonic-gate 		goto ret;
20297c478bd9Sstevel@tonic-gate 	if ((err = big_modexp(&aq, &aq, dmodqminus1, q, q_rr)) != BIG_OK)
20307c478bd9Sstevel@tonic-gate 		goto ret;
20317c478bd9Sstevel@tonic-gate 	if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK)
20327c478bd9Sstevel@tonic-gate 		goto ret;
20337c478bd9Sstevel@tonic-gate 	if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK)
20347c478bd9Sstevel@tonic-gate 		goto ret;
20357c478bd9Sstevel@tonic-gate 	sign = tmp.sign;
20367c478bd9Sstevel@tonic-gate 	tmp.sign = 1;
20377c478bd9Sstevel@tonic-gate 	if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK)
20387c478bd9Sstevel@tonic-gate 		goto ret;
20397c478bd9Sstevel@tonic-gate 	if ((sign == -1) && (!big_is_zero(&aq))) {
20407c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(&aq, q, &aq);
20417c478bd9Sstevel@tonic-gate 	}
20427c478bd9Sstevel@tonic-gate 	if ((err = big_mul(&tmp, &aq, p)) != BIG_OK)
20437c478bd9Sstevel@tonic-gate 		goto ret;
20447c478bd9Sstevel@tonic-gate 	err = big_add_abs(result, &ap, &tmp);
20457c478bd9Sstevel@tonic-gate 
20467c478bd9Sstevel@tonic-gate ret:
20477c478bd9Sstevel@tonic-gate 	big_finish(&tmp);
20487c478bd9Sstevel@tonic-gate ret2:
20497c478bd9Sstevel@tonic-gate 	big_finish(&aq);
20507c478bd9Sstevel@tonic-gate ret1:
20517c478bd9Sstevel@tonic-gate 	big_finish(&ap);
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate 	return (err);
20547c478bd9Sstevel@tonic-gate }
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate uint32_t onearr[1] = {1};
20587c478bd9Sstevel@tonic-gate BIGNUM One = {1, 1, 1, 0, onearr};
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate uint32_t twoarr[1] = {2};
20617c478bd9Sstevel@tonic-gate BIGNUM Two = {1, 1, 1, 0, twoarr};
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate uint32_t fourarr[1] = {4};
20647c478bd9Sstevel@tonic-gate BIGNUM Four = {1, 1, 1, 0, fourarr};
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate BIG_ERR_CODE
20677c478bd9Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n)
20687c478bd9Sstevel@tonic-gate {
20697c478bd9Sstevel@tonic-gate 	BIGNUM *high, *low, *mid, *t;
20707c478bd9Sstevel@tonic-gate 	BIGNUM t1, t2, t3, prod;
20717c478bd9Sstevel@tonic-gate 	uint32_t t1value[BIGTMPSIZE];
20727c478bd9Sstevel@tonic-gate 	uint32_t t2value[BIGTMPSIZE];
20737c478bd9Sstevel@tonic-gate 	uint32_t t3value[BIGTMPSIZE];
20747c478bd9Sstevel@tonic-gate 	uint32_t prodvalue[BIGTMPSIZE];
20757c478bd9Sstevel@tonic-gate 	int i, nbits, diff, nrootbits, highbits;
20767c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 	nbits = big_numbits(n);
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, n->len + 1,
20817c478bd9Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
20827c478bd9Sstevel@tonic-gate 		return (err);
20837c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, n->len + 1,
20847c478bd9Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
20857c478bd9Sstevel@tonic-gate 		goto ret1;
20867c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, n->len + 1,
20877c478bd9Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
20887c478bd9Sstevel@tonic-gate 		goto ret2;
20897c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&prod, n->len + 1,
20907c478bd9Sstevel@tonic-gate 	    prodvalue, arraysize(prodvalue))) != BIG_OK)
20917c478bd9Sstevel@tonic-gate 		goto ret3;
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate 	nrootbits = (nbits + 1) / 2;
20947c478bd9Sstevel@tonic-gate 	t1.len = t2.len = t3.len = (nrootbits - 1) / 32 + 1;
20957c478bd9Sstevel@tonic-gate 	for (i = 0; i < t1.len; i++) {
20967c478bd9Sstevel@tonic-gate 		t1.value[i] = 0;
20977c478bd9Sstevel@tonic-gate 		t2.value[i] = 0xffffffff;
20987c478bd9Sstevel@tonic-gate 	}
20997c478bd9Sstevel@tonic-gate 	highbits = nrootbits - 32 * (t1.len - 1);
21007c478bd9Sstevel@tonic-gate 	if (highbits == 32) {
21017c478bd9Sstevel@tonic-gate 		t1.value[t1.len - 1] = 0x80000000;
21027c478bd9Sstevel@tonic-gate 		t2.value[t2.len - 1] = 0xffffffff;
21037c478bd9Sstevel@tonic-gate 	} else {
21047c478bd9Sstevel@tonic-gate 		t1.value[t1.len - 1] = 1 << (highbits - 1);
21057c478bd9Sstevel@tonic-gate 		t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1;
21067c478bd9Sstevel@tonic-gate 	}
21077c478bd9Sstevel@tonic-gate 	high = &t2;
21087c478bd9Sstevel@tonic-gate 	low = &t1;
21097c478bd9Sstevel@tonic-gate 	mid = &t3;
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 	if ((err = big_mul(&prod, high, high)) != BIG_OK)
21127c478bd9Sstevel@tonic-gate 		goto ret;
21137c478bd9Sstevel@tonic-gate 	diff = big_cmp_abs(&prod, n);
21147c478bd9Sstevel@tonic-gate 	if (diff <= 0) {
21157c478bd9Sstevel@tonic-gate 		err = big_copy(result, high);
21167c478bd9Sstevel@tonic-gate 		goto ret;
21177c478bd9Sstevel@tonic-gate 	}
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(mid, high, low);
21207c478bd9Sstevel@tonic-gate 	while (big_cmp_abs(&One, mid) != 0) {
21217c478bd9Sstevel@tonic-gate 		(void) big_add_abs(mid, high, low);
21227c478bd9Sstevel@tonic-gate 		(void) big_half_pos(mid, mid);
21237c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&prod, mid, mid)) != BIG_OK)
21247c478bd9Sstevel@tonic-gate 			goto ret;
21257c478bd9Sstevel@tonic-gate 		diff = big_cmp_abs(&prod, n);
21267c478bd9Sstevel@tonic-gate 		if (diff > 0) {
21277c478bd9Sstevel@tonic-gate 			t = high;
21287c478bd9Sstevel@tonic-gate 			high = mid;
21297c478bd9Sstevel@tonic-gate 			mid = t;
21307c478bd9Sstevel@tonic-gate 		} else if (diff < 0) {
21317c478bd9Sstevel@tonic-gate 			t = low;
21327c478bd9Sstevel@tonic-gate 			low = mid;
21337c478bd9Sstevel@tonic-gate 			mid = t;
21347c478bd9Sstevel@tonic-gate 		} else {
21357c478bd9Sstevel@tonic-gate 			err = big_copy(result, low);
21367c478bd9Sstevel@tonic-gate 			goto ret;
21377c478bd9Sstevel@tonic-gate 		}
21387c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(mid, high, low);
21397c478bd9Sstevel@tonic-gate 	}
21407c478bd9Sstevel@tonic-gate 
21417c478bd9Sstevel@tonic-gate 	err = big_copy(result, low);
21427c478bd9Sstevel@tonic-gate ret:
21437c478bd9Sstevel@tonic-gate 	if (prod.malloced) big_finish(&prod);
21447c478bd9Sstevel@tonic-gate ret3:
21457c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
21467c478bd9Sstevel@tonic-gate ret2:
21477c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
21487c478bd9Sstevel@tonic-gate ret1:
21497c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate 	return (err);
21527c478bd9Sstevel@tonic-gate }
21537c478bd9Sstevel@tonic-gate 
21547c478bd9Sstevel@tonic-gate 
21557c478bd9Sstevel@tonic-gate BIG_ERR_CODE
21567c478bd9Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm)
21577c478bd9Sstevel@tonic-gate {
21587c478bd9Sstevel@tonic-gate 	BIGNUM *t, *tmp2, *m, *n;
21597c478bd9Sstevel@tonic-gate 	BIGNUM t1, t2, t3;
21607c478bd9Sstevel@tonic-gate 	uint32_t t1value[BIGTMPSIZE];
21617c478bd9Sstevel@tonic-gate 	uint32_t t2value[BIGTMPSIZE];
21627c478bd9Sstevel@tonic-gate 	uint32_t t3value[BIGTMPSIZE];
21637c478bd9Sstevel@tonic-gate 	int len, err;
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate 	if (big_is_zero(nn) ||
21667c478bd9Sstevel@tonic-gate 	    (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) {
21677c478bd9Sstevel@tonic-gate 		*jac = 0;
21687c478bd9Sstevel@tonic-gate 		return (BIG_OK);
21697c478bd9Sstevel@tonic-gate 	}
21707c478bd9Sstevel@tonic-gate 
21717c478bd9Sstevel@tonic-gate 	if (nn->len > mm->len) len = nn->len;
21727c478bd9Sstevel@tonic-gate 	else len = mm->len;
21737c478bd9Sstevel@tonic-gate 
21747c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
21757c478bd9Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
21767c478bd9Sstevel@tonic-gate 		return (err);
21777c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
21787c478bd9Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
21797c478bd9Sstevel@tonic-gate 		goto ret1;
21807c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
21817c478bd9Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
21827c478bd9Sstevel@tonic-gate 		goto ret2;
21837c478bd9Sstevel@tonic-gate 
21847c478bd9Sstevel@tonic-gate 	n = &t1;
21857c478bd9Sstevel@tonic-gate 	m = &t2;
21867c478bd9Sstevel@tonic-gate 	tmp2 = &t3;
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 	(void) big_copy(n, nn);
21897c478bd9Sstevel@tonic-gate 	(void) big_copy(m, mm);
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate 	*jac = 1;
21927c478bd9Sstevel@tonic-gate 	while (big_cmp_abs(&One, m) != 0) {
21937c478bd9Sstevel@tonic-gate 		if (big_is_zero(n)) {
21947c478bd9Sstevel@tonic-gate 			*jac = 0;
21957c478bd9Sstevel@tonic-gate 			goto ret;
21967c478bd9Sstevel@tonic-gate 		}
21977c478bd9Sstevel@tonic-gate 		if ((m->value[0] & 1) == 0) {
21987c478bd9Sstevel@tonic-gate 			if (((n->value[0] & 7) == 3) ||
21997c478bd9Sstevel@tonic-gate 			    ((n->value[0] & 7) == 5)) *jac = -*jac;
22007c478bd9Sstevel@tonic-gate 			(void) big_half_pos(m, m);
22017c478bd9Sstevel@tonic-gate 		} else if ((n->value[0] & 1) == 0) {
22027c478bd9Sstevel@tonic-gate 			if (((m->value[0] & 7) == 3) ||
22037c478bd9Sstevel@tonic-gate 			    ((m->value[0] & 7) == 5)) *jac = -*jac;
22047c478bd9Sstevel@tonic-gate 			(void) big_half_pos(n, n);
22057c478bd9Sstevel@tonic-gate 		} else {
22067c478bd9Sstevel@tonic-gate 			if (((m->value[0] & 3) == 3) &&
22077c478bd9Sstevel@tonic-gate 			    ((n->value[0] & 3) == 3)) {
22087c478bd9Sstevel@tonic-gate 				*jac = -*jac;
22097c478bd9Sstevel@tonic-gate 			}
22107c478bd9Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK)
22117c478bd9Sstevel@tonic-gate 				goto ret;
22127c478bd9Sstevel@tonic-gate 			t = tmp2;
22137c478bd9Sstevel@tonic-gate 			tmp2 = m;
22147c478bd9Sstevel@tonic-gate 			m = n;
22157c478bd9Sstevel@tonic-gate 			n = t;
22167c478bd9Sstevel@tonic-gate 		}
22177c478bd9Sstevel@tonic-gate 	}
22187c478bd9Sstevel@tonic-gate 	err = BIG_OK;
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate ret:
22217c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
22227c478bd9Sstevel@tonic-gate ret2:
22237c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
22247c478bd9Sstevel@tonic-gate ret1:
22257c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
22267c478bd9Sstevel@tonic-gate 
22277c478bd9Sstevel@tonic-gate 	return (err);
22287c478bd9Sstevel@tonic-gate }
22297c478bd9Sstevel@tonic-gate 
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate BIG_ERR_CODE
22327c478bd9Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n)
22337c478bd9Sstevel@tonic-gate {
22347c478bd9Sstevel@tonic-gate 	int m, w, i;
22357c478bd9Sstevel@tonic-gate 	uint32_t bit;
22367c478bd9Sstevel@tonic-gate 	BIGNUM ki, tmp, tmp2;
22377c478bd9Sstevel@tonic-gate 	uint32_t kivalue[BIGTMPSIZE];
22387c478bd9Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
22397c478bd9Sstevel@tonic-gate 	uint32_t tmp2value[BIGTMPSIZE];
22407c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
22417c478bd9Sstevel@tonic-gate 
22427c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(k, &One) == 0) {
22437c478bd9Sstevel@tonic-gate 		(void) big_copy(Lk, p);
22447c478bd9Sstevel@tonic-gate 		(void) big_copy(Lkminus1, &Two);
22457c478bd9Sstevel@tonic-gate 		return (BIG_OK);
22467c478bd9Sstevel@tonic-gate 	}
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&ki, k->len + 1,
22497c478bd9Sstevel@tonic-gate 	    kivalue, arraysize(kivalue))) != BIG_OK)
22507c478bd9Sstevel@tonic-gate 		return (err);
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len +1,
22537c478bd9Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
22547c478bd9Sstevel@tonic-gate 		goto ret1;
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, n->len,
22577c478bd9Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
22587c478bd9Sstevel@tonic-gate 		goto ret2;
22597c478bd9Sstevel@tonic-gate 
22607c478bd9Sstevel@tonic-gate 	m = big_numbits(k);
22617c478bd9Sstevel@tonic-gate 	ki.len = (m - 1) / 32 + 1;
22627c478bd9Sstevel@tonic-gate 	w = (m - 1) / 32;
22637c478bd9Sstevel@tonic-gate 	bit = 1 << ((m - 1) % 32);
22647c478bd9Sstevel@tonic-gate 	for (i = 0; i < ki.len; i++) ki.value[i] = 0;
22657c478bd9Sstevel@tonic-gate 	ki.value[ki.len - 1] = bit;
22667c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(k, &ki) != 0)
22677c478bd9Sstevel@tonic-gate 		(void) big_double(&ki, &ki);
22687c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(&ki, &ki, k);
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate 	(void) big_copy(Lk, p);
22717c478bd9Sstevel@tonic-gate 	(void) big_copy(Lkminus1, &Two);
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 	for (i = 0; i < m; i++) {
22747c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK)
22757c478bd9Sstevel@tonic-gate 			goto ret;
22767c478bd9Sstevel@tonic-gate 		(void) big_add_abs(&tmp, &tmp, n);
22777c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(&tmp, &tmp, p);
22787c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK)
22797c478bd9Sstevel@tonic-gate 			goto ret;
22807c478bd9Sstevel@tonic-gate 
22817c478bd9Sstevel@tonic-gate 		if ((ki.value[w] & bit) != 0) {
22827c478bd9Sstevel@tonic-gate 			if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) !=
22837c478bd9Sstevel@tonic-gate 			    BIG_OK)
22847c478bd9Sstevel@tonic-gate 				goto ret;
22857c478bd9Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
22867c478bd9Sstevel@tonic-gate 			(void) big_sub_pos(&tmp, &tmp, &Two);
22877c478bd9Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) !=
22887c478bd9Sstevel@tonic-gate 			    BIG_OK)
22897c478bd9Sstevel@tonic-gate 				goto ret;
22907c478bd9Sstevel@tonic-gate 			(void) big_copy(Lk, &tmp2);
22917c478bd9Sstevel@tonic-gate 		} else {
22927c478bd9Sstevel@tonic-gate 			if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK)
22937c478bd9Sstevel@tonic-gate 				goto ret;
22947c478bd9Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
22957c478bd9Sstevel@tonic-gate 			(void) big_sub_pos(&tmp, &tmp, &Two);
22967c478bd9Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK)
22977c478bd9Sstevel@tonic-gate 				goto ret;
22987c478bd9Sstevel@tonic-gate 			(void) big_copy(Lkminus1, &tmp2);
22997c478bd9Sstevel@tonic-gate 		}
23007c478bd9Sstevel@tonic-gate 		bit = bit >> 1;
23017c478bd9Sstevel@tonic-gate 		if (bit == 0) {
23027c478bd9Sstevel@tonic-gate 			bit = 0x80000000;
23037c478bd9Sstevel@tonic-gate 			w--;
23047c478bd9Sstevel@tonic-gate 		}
23057c478bd9Sstevel@tonic-gate 	}
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate 	err = BIG_OK;
23087c478bd9Sstevel@tonic-gate 
23097c478bd9Sstevel@tonic-gate ret:
23107c478bd9Sstevel@tonic-gate 	if (tmp2.malloced) big_finish(&tmp2);
23117c478bd9Sstevel@tonic-gate ret2:
23127c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
23137c478bd9Sstevel@tonic-gate ret1:
23147c478bd9Sstevel@tonic-gate 	if (ki.malloced) big_finish(&ki);
23157c478bd9Sstevel@tonic-gate 
23167c478bd9Sstevel@tonic-gate 	return (err);
23177c478bd9Sstevel@tonic-gate }
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate BIG_ERR_CODE
23217c478bd9Sstevel@tonic-gate big_isprime_pos(BIGNUM *n)
23227c478bd9Sstevel@tonic-gate {
23237c478bd9Sstevel@tonic-gate 	BIGNUM o, nminus1, tmp, Lkminus1, Lk;
23247c478bd9Sstevel@tonic-gate 	uint32_t ovalue[BIGTMPSIZE];
23257c478bd9Sstevel@tonic-gate 	uint32_t nminus1value[BIGTMPSIZE];
23267c478bd9Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
23277c478bd9Sstevel@tonic-gate 	uint32_t Lkminus1value[BIGTMPSIZE];
23287c478bd9Sstevel@tonic-gate 	uint32_t Lkvalue[BIGTMPSIZE];
23297c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
23307c478bd9Sstevel@tonic-gate 	int e, i, jac;
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(n, &One) == 0)
23337c478bd9Sstevel@tonic-gate 		return (BIG_FALSE);
23347c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(n, &Two) == 0)
23357c478bd9Sstevel@tonic-gate 		return (BIG_TRUE);
23367c478bd9Sstevel@tonic-gate 	if ((n->value[0] & 1) == 0)
23377c478bd9Sstevel@tonic-gate 		return (BIG_FALSE);
23387c478bd9Sstevel@tonic-gate 
23397c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) != BIG_OK)
23407c478bd9Sstevel@tonic-gate 		return (err);
23417c478bd9Sstevel@tonic-gate 
23427c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&nminus1, n->len,
23437c478bd9Sstevel@tonic-gate 	    nminus1value, arraysize(nminus1value))) != BIG_OK)
23447c478bd9Sstevel@tonic-gate 		goto ret1;
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len,
23477c478bd9Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
23487c478bd9Sstevel@tonic-gate 		goto ret2;
23497c478bd9Sstevel@tonic-gate 
23507c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&Lkminus1, n->len,
23517c478bd9Sstevel@tonic-gate 	    Lkminus1value, arraysize(Lkminus1value))) != BIG_OK)
23527c478bd9Sstevel@tonic-gate 		goto ret3;
23537c478bd9Sstevel@tonic-gate 
23547c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&Lk, n->len,
23557c478bd9Sstevel@tonic-gate 	    Lkvalue, arraysize(Lkvalue))) != BIG_OK)
23567c478bd9Sstevel@tonic-gate 		goto ret4;
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(&o, n, &One); 	/* cannot fail */
23597c478bd9Sstevel@tonic-gate 	(void) big_copy(&nminus1, &o);		/* cannot fail */
23607c478bd9Sstevel@tonic-gate 	e = 0;
23617c478bd9Sstevel@tonic-gate 	while ((o.value[0] & 1) == 0) {
23627c478bd9Sstevel@tonic-gate 		e++;
23637c478bd9Sstevel@tonic-gate 		(void) big_half_pos(&o, &o);  /* cannot fail */
23647c478bd9Sstevel@tonic-gate 	}
23657c478bd9Sstevel@tonic-gate 	if ((err = big_modexp(&tmp, &Two, &o, n, NULL)) != BIG_OK)
23667c478bd9Sstevel@tonic-gate 		goto ret;
23677c478bd9Sstevel@tonic-gate 	i = 0;
23687c478bd9Sstevel@tonic-gate 	while ((i < e) &&
23697c478bd9Sstevel@tonic-gate 	    (big_cmp_abs(&tmp, &One) != 0) &&
23707c478bd9Sstevel@tonic-gate 	    (big_cmp_abs(&tmp, &nminus1) != 0)) {
23717c478bd9Sstevel@tonic-gate 		if ((err = big_modexp(&tmp, &tmp, &Two, n, NULL)) !=  BIG_OK)
23727c478bd9Sstevel@tonic-gate 			goto ret;
23737c478bd9Sstevel@tonic-gate 		i++;
23747c478bd9Sstevel@tonic-gate 	}
23757c478bd9Sstevel@tonic-gate 	if (!((big_cmp_abs(&tmp, &nminus1) == 0) ||
23767c478bd9Sstevel@tonic-gate 	    ((i == 0) && (big_cmp_abs(&tmp, &One) == 0)))) {
23777c478bd9Sstevel@tonic-gate 		err = BIG_FALSE;
23787c478bd9Sstevel@tonic-gate 		goto ret;
23797c478bd9Sstevel@tonic-gate 	}
23807c478bd9Sstevel@tonic-gate 
23817c478bd9Sstevel@tonic-gate 	if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK)
23827c478bd9Sstevel@tonic-gate 		goto ret;
23837c478bd9Sstevel@tonic-gate 	if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK)
23847c478bd9Sstevel@tonic-gate 		goto ret;
23857c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(&tmp, n) == 0) {
23867c478bd9Sstevel@tonic-gate 		err = BIG_FALSE;
23877c478bd9Sstevel@tonic-gate 		goto ret;
23887c478bd9Sstevel@tonic-gate 	}
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate 	(void) big_copy(&o, &Two);
23917c478bd9Sstevel@tonic-gate 	do {
23927c478bd9Sstevel@tonic-gate 		(void) big_add_abs(&o, &o, &One);
23937c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&tmp, &o, &o)) != BIG_OK)
23947c478bd9Sstevel@tonic-gate 			goto ret;
23957c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(&tmp, &tmp, &Four);
23967c478bd9Sstevel@tonic-gate 		if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK)
23977c478bd9Sstevel@tonic-gate 			goto ret;
23987c478bd9Sstevel@tonic-gate 	} while (jac != -1);
23997c478bd9Sstevel@tonic-gate 
24007c478bd9Sstevel@tonic-gate 	(void) big_add_abs(&tmp, n, &One);
24017c478bd9Sstevel@tonic-gate 	if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK)
24027c478bd9Sstevel@tonic-gate 		goto ret;
24037c478bd9Sstevel@tonic-gate 	if ((big_cmp_abs(&Lkminus1, &o) == 0) && (big_cmp_abs(&Lk, &Two) == 0))
24047c478bd9Sstevel@tonic-gate 		err = BIG_TRUE;
24057c478bd9Sstevel@tonic-gate 	else err = BIG_FALSE;
24067c478bd9Sstevel@tonic-gate 
24077c478bd9Sstevel@tonic-gate ret:
24087c478bd9Sstevel@tonic-gate 	if (Lk.malloced) big_finish(&Lk);
24097c478bd9Sstevel@tonic-gate ret4:
24107c478bd9Sstevel@tonic-gate 	if (Lkminus1.malloced) big_finish(&Lkminus1);
24117c478bd9Sstevel@tonic-gate ret3:
24127c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
24137c478bd9Sstevel@tonic-gate ret2:
24147c478bd9Sstevel@tonic-gate 	if (nminus1.malloced) big_finish(&nminus1);
24157c478bd9Sstevel@tonic-gate ret1:
24167c478bd9Sstevel@tonic-gate 	if (o.malloced) big_finish(&o);
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate 	return (err);
24197c478bd9Sstevel@tonic-gate }
24207c478bd9Sstevel@tonic-gate 
24217c478bd9Sstevel@tonic-gate 
24227c478bd9Sstevel@tonic-gate #define	SIEVESIZE 1000
24237c478bd9Sstevel@tonic-gate 
24247c478bd9Sstevel@tonic-gate uint32_t smallprimes[] =
24257c478bd9Sstevel@tonic-gate {
24267c478bd9Sstevel@tonic-gate 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
24277c478bd9Sstevel@tonic-gate 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97
24287c478bd9Sstevel@tonic-gate };
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate 
24317c478bd9Sstevel@tonic-gate BIG_ERR_CODE
24327c478bd9Sstevel@tonic-gate big_nextprime_pos(BIGNUM *result, BIGNUM *n)
24337c478bd9Sstevel@tonic-gate {
24347c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
24357c478bd9Sstevel@tonic-gate 	int sieve[SIEVESIZE];
24367c478bd9Sstevel@tonic-gate 	int i;
24377c478bd9Sstevel@tonic-gate 	uint32_t off, p;
24387c478bd9Sstevel@tonic-gate 
24397c478bd9Sstevel@tonic-gate 	if ((err = big_copy(result, n)) != BIG_OK)
24407c478bd9Sstevel@tonic-gate 		return (err);
24417c478bd9Sstevel@tonic-gate 	result->value[0] |= 1;
2442*f56c1286Srobinson 	/* CONSTCOND */
24437c478bd9Sstevel@tonic-gate 	while (1) {
24447c478bd9Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0;
24457c478bd9Sstevel@tonic-gate 		for (i = 0;
24467c478bd9Sstevel@tonic-gate 		    i < sizeof (smallprimes) / sizeof (uint32_t); i++) {
24477c478bd9Sstevel@tonic-gate 			p = smallprimes[i];
24487c478bd9Sstevel@tonic-gate 			off = big_mod16_pos(result, p);
24497c478bd9Sstevel@tonic-gate 			off = p - off;
24507c478bd9Sstevel@tonic-gate 			if ((off % 2) == 1) off = off + p;
24517c478bd9Sstevel@tonic-gate 			off = off/2;
24527c478bd9Sstevel@tonic-gate 			while (off < SIEVESIZE) {
24537c478bd9Sstevel@tonic-gate 				sieve[off] = 1;
24547c478bd9Sstevel@tonic-gate 				off = off + p;
24557c478bd9Sstevel@tonic-gate 			}
24567c478bd9Sstevel@tonic-gate 		}
24577c478bd9Sstevel@tonic-gate 
24587c478bd9Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) {
24597c478bd9Sstevel@tonic-gate 			if (sieve[i] == 0) {
24607c478bd9Sstevel@tonic-gate 				err = big_isprime_pos(result);
24617c478bd9Sstevel@tonic-gate 				if (err != BIG_FALSE) {
24627c478bd9Sstevel@tonic-gate 					if (err != BIG_TRUE)
24637c478bd9Sstevel@tonic-gate 						return (err);
24647c478bd9Sstevel@tonic-gate 					else
24657c478bd9Sstevel@tonic-gate 						return (BIG_OK);
24667c478bd9Sstevel@tonic-gate 				}
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate 			}
24697c478bd9Sstevel@tonic-gate 			if ((err = big_add_abs(result, result, &Two)) !=
24707c478bd9Sstevel@tonic-gate 			    BIG_OK)
24717c478bd9Sstevel@tonic-gate 				return (err);
24727c478bd9Sstevel@tonic-gate 		}
24737c478bd9Sstevel@tonic-gate 	}
2474*f56c1286Srobinson 	/* NOTREACHED */
24757c478bd9Sstevel@tonic-gate }
24767c478bd9Sstevel@tonic-gate 
24777c478bd9Sstevel@tonic-gate 
24787c478bd9Sstevel@tonic-gate BIG_ERR_CODE
24797c478bd9Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n)
24807c478bd9Sstevel@tonic-gate {
24817c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 	if ((err = big_copy(result, n)) != BIG_OK)
24857c478bd9Sstevel@tonic-gate 		return (err);
24867c478bd9Sstevel@tonic-gate 	result->value[0] |= 1;
24877c478bd9Sstevel@tonic-gate 	while ((err = big_isprime_pos(result)) != BIG_TRUE) {
24887c478bd9Sstevel@tonic-gate 		if (err != BIG_FALSE)
24897c478bd9Sstevel@tonic-gate 			return (err);
24907c478bd9Sstevel@tonic-gate 		if ((err = big_add_abs(result, result, &Two)) != BIG_OK)
24917c478bd9Sstevel@tonic-gate 			return (err);
24927c478bd9Sstevel@tonic-gate 	}
24937c478bd9Sstevel@tonic-gate 	return (BIG_OK);
24947c478bd9Sstevel@tonic-gate }
24957c478bd9Sstevel@tonic-gate 
24967c478bd9Sstevel@tonic-gate 
24977c478bd9Sstevel@tonic-gate /*
24987c478bd9Sstevel@tonic-gate  * given m and e, computes the rest in the equation
24997c478bd9Sstevel@tonic-gate  * gcd(m, e) = cm * m + ce * e
25007c478bd9Sstevel@tonic-gate  */
25017c478bd9Sstevel@tonic-gate BIG_ERR_CODE
25027c478bd9Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e)
25037c478bd9Sstevel@tonic-gate {
25047c478bd9Sstevel@tonic-gate 	BIGNUM *xi, *ri, *riminus1, *riminus2, *t,
25057c478bd9Sstevel@tonic-gate 	    *vmi, *vei, *vmiminus1, *veiminus1;
25067c478bd9Sstevel@tonic-gate 	BIGNUM t1, t2, t3, t4, t5, t6, t7, t8, tmp;
25077c478bd9Sstevel@tonic-gate 	uint32_t t1value[BIGTMPSIZE];
25087c478bd9Sstevel@tonic-gate 	uint32_t t2value[BIGTMPSIZE];
25097c478bd9Sstevel@tonic-gate 	uint32_t t3value[BIGTMPSIZE];
25107c478bd9Sstevel@tonic-gate 	uint32_t t4value[BIGTMPSIZE];
25117c478bd9Sstevel@tonic-gate 	uint32_t t5value[BIGTMPSIZE];
25127c478bd9Sstevel@tonic-gate 	uint32_t t6value[BIGTMPSIZE];
25137c478bd9Sstevel@tonic-gate 	uint32_t t7value[BIGTMPSIZE];
25147c478bd9Sstevel@tonic-gate 	uint32_t t8value[BIGTMPSIZE];
25157c478bd9Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
25167c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
25177c478bd9Sstevel@tonic-gate 	int len;
25187c478bd9Sstevel@tonic-gate 
25197c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(m, e) >= 0) len = m->len;
25207c478bd9Sstevel@tonic-gate 	else len = e->len;
25217c478bd9Sstevel@tonic-gate 
25227c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
25237c478bd9Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
25247c478bd9Sstevel@tonic-gate 		return (err);
25257c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
25267c478bd9Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
25277c478bd9Sstevel@tonic-gate 			goto ret1;
25287c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
25297c478bd9Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
25307c478bd9Sstevel@tonic-gate 			goto ret2;
25317c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t4, len,
25327c478bd9Sstevel@tonic-gate 	    t4value, arraysize(t3value))) != BIG_OK)
25337c478bd9Sstevel@tonic-gate 			goto ret3;
25347c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t5, len,
25357c478bd9Sstevel@tonic-gate 	    t5value, arraysize(t5value))) != BIG_OK)
25367c478bd9Sstevel@tonic-gate 			goto ret4;
25377c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t6, len,
25387c478bd9Sstevel@tonic-gate 	    t6value, arraysize(t6value))) != BIG_OK)
25397c478bd9Sstevel@tonic-gate 			goto ret5;
25407c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t7, len,
25417c478bd9Sstevel@tonic-gate 	    t7value, arraysize(t7value))) != BIG_OK)
25427c478bd9Sstevel@tonic-gate 			goto ret6;
25437c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t8, len,
25447c478bd9Sstevel@tonic-gate 	    t8value, arraysize(t8value))) != BIG_OK)
25457c478bd9Sstevel@tonic-gate 			goto ret7;
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * len,
25487c478bd9Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
25497c478bd9Sstevel@tonic-gate 		goto ret8;
25507c478bd9Sstevel@tonic-gate 
25517c478bd9Sstevel@tonic-gate 	ri = &t1;
25527c478bd9Sstevel@tonic-gate 	ri->value[0] = 1;
25537c478bd9Sstevel@tonic-gate 	ri->len = 1;
25547c478bd9Sstevel@tonic-gate 	xi = &t2;
25557c478bd9Sstevel@tonic-gate 	riminus1 = &t3;
25567c478bd9Sstevel@tonic-gate 	riminus2 = &t4;
25577c478bd9Sstevel@tonic-gate 	vmi = &t5;
25587c478bd9Sstevel@tonic-gate 	vei = &t6;
25597c478bd9Sstevel@tonic-gate 	vmiminus1 = &t7;
25607c478bd9Sstevel@tonic-gate 	veiminus1 = &t8;
25617c478bd9Sstevel@tonic-gate 
25627c478bd9Sstevel@tonic-gate 	(void) big_copy(vmiminus1, &One);
25637c478bd9Sstevel@tonic-gate 	(void) big_copy(vmi, &One);
25647c478bd9Sstevel@tonic-gate 	(void) big_copy(veiminus1, &One);
25657c478bd9Sstevel@tonic-gate 	(void) big_copy(xi, &One);
25667c478bd9Sstevel@tonic-gate 	vei->len = 1;
25677c478bd9Sstevel@tonic-gate 	vei->value[0] = 0;
25687c478bd9Sstevel@tonic-gate 
25697c478bd9Sstevel@tonic-gate 	(void) big_copy(riminus1, m);
25707c478bd9Sstevel@tonic-gate 	(void) big_copy(ri, e);
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate 	while (!big_is_zero(ri)) {
25737c478bd9Sstevel@tonic-gate 		t = riminus2;
25747c478bd9Sstevel@tonic-gate 		riminus2 = riminus1;
25757c478bd9Sstevel@tonic-gate 		riminus1 = ri;
25767c478bd9Sstevel@tonic-gate 		ri = t;
25777c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK)
25787c478bd9Sstevel@tonic-gate 			goto ret;
25797c478bd9Sstevel@tonic-gate 		if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK)
25807c478bd9Sstevel@tonic-gate 			goto ret;
25817c478bd9Sstevel@tonic-gate 		t = vmiminus1;
25827c478bd9Sstevel@tonic-gate 		vmiminus1 = vmi;
25837c478bd9Sstevel@tonic-gate 		vmi = t;
25847c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&tmp, vei, xi)) != BIG_OK)
25857c478bd9Sstevel@tonic-gate 			goto ret;
25867c478bd9Sstevel@tonic-gate 		if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK)
25877c478bd9Sstevel@tonic-gate 			goto ret;
25887c478bd9Sstevel@tonic-gate 		t = veiminus1;
25897c478bd9Sstevel@tonic-gate 		veiminus1 = vei;
25907c478bd9Sstevel@tonic-gate 		vei = t;
25917c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(xi, ri, riminus2, riminus1)) != BIG_OK)
25927c478bd9Sstevel@tonic-gate 			goto ret;
25937c478bd9Sstevel@tonic-gate 	}
25947c478bd9Sstevel@tonic-gate 	if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK))
25957c478bd9Sstevel@tonic-gate 		goto ret;
25967c478bd9Sstevel@tonic-gate 	if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK))
25977c478bd9Sstevel@tonic-gate 		goto ret;
25987c478bd9Sstevel@tonic-gate 	if (ce != NULL)
25997c478bd9Sstevel@tonic-gate 		err = big_copy(ce, vei);
26007c478bd9Sstevel@tonic-gate ret:
26017c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
26027c478bd9Sstevel@tonic-gate ret8:
26037c478bd9Sstevel@tonic-gate 	if (t8.malloced) big_finish(&t8);
26047c478bd9Sstevel@tonic-gate ret7:
26057c478bd9Sstevel@tonic-gate 	if (t7.malloced) big_finish(&t7);
26067c478bd9Sstevel@tonic-gate ret6:
26077c478bd9Sstevel@tonic-gate 	if (t6.malloced) big_finish(&t6);
26087c478bd9Sstevel@tonic-gate ret5:
26097c478bd9Sstevel@tonic-gate 	if (t5.malloced) big_finish(&t5);
26107c478bd9Sstevel@tonic-gate ret4:
26117c478bd9Sstevel@tonic-gate 	if (t4.malloced) big_finish(&t4);
26127c478bd9Sstevel@tonic-gate ret3:
26137c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
26147c478bd9Sstevel@tonic-gate ret2:
26157c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
26167c478bd9Sstevel@tonic-gate ret1:
26177c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
26187c478bd9Sstevel@tonic-gate 
26197c478bd9Sstevel@tonic-gate 	return (err);
26207c478bd9Sstevel@tonic-gate }
2621