xref: /titanic_44/usr/src/common/bignum/bignumimpl.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #define	big_div_pos_fast big_div_pos
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include "bignum.h"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate /*
34*7c478bd9Sstevel@tonic-gate  * Configuration guide
35*7c478bd9Sstevel@tonic-gate  * -------------------
36*7c478bd9Sstevel@tonic-gate  *
37*7c478bd9Sstevel@tonic-gate  * There are 4 preprocessor symbols used to configure the bignum
38*7c478bd9Sstevel@tonic-gate  * implementation.  This file contains no logic to configure based on
39*7c478bd9Sstevel@tonic-gate  * processor; we leave that to the Makefiles to specify.
40*7c478bd9Sstevel@tonic-gate  *
41*7c478bd9Sstevel@tonic-gate  * USE_FLOATING_POINT
42*7c478bd9Sstevel@tonic-gate  *   Meaning: There is support for a fast floating-point implementation of
43*7c478bd9Sstevel@tonic-gate  *   Montgomery multiply.
44*7c478bd9Sstevel@tonic-gate  *
45*7c478bd9Sstevel@tonic-gate  * PSR_MUL
46*7c478bd9Sstevel@tonic-gate  *   Meaning: There are processor-specific versions of the low level
47*7c478bd9Sstevel@tonic-gate  *   functions to implement big_mul.  Those functions are: big_mul_set_vec,
48*7c478bd9Sstevel@tonic-gate  *   big_mul_add_vec, big_mul_vec, and big_sqr_vec.  PSR_MUL implies support
49*7c478bd9Sstevel@tonic-gate  *   for all 4 functions.  You cannot pick and choose which subset of these
50*7c478bd9Sstevel@tonic-gate  *   functions to support; that would lead to a rat's nest of #ifdefs.
51*7c478bd9Sstevel@tonic-gate  *
52*7c478bd9Sstevel@tonic-gate  * HWCAP
53*7c478bd9Sstevel@tonic-gate  *   Meaning: Call multiply support functions through a function pointer.
54*7c478bd9Sstevel@tonic-gate  *   On x86, there are multiple implementations for differnt hardware
55*7c478bd9Sstevel@tonic-gate  *   capabilities, such as MMX, SSE2, etc.  Tests are made at run-time, when
56*7c478bd9Sstevel@tonic-gate  *   a function is first used.  So, the support functions are called through
57*7c478bd9Sstevel@tonic-gate  *   a function pointer.  There is no need for that on Sparc, because there
58*7c478bd9Sstevel@tonic-gate  *   is only one implementation; support functions are called directly.
59*7c478bd9Sstevel@tonic-gate  *   Later, if there were some new VIS instruction, or something, and a
60*7c478bd9Sstevel@tonic-gate  *   run-time test were needed, rather than variant kernel modules and
61*7c478bd9Sstevel@tonic-gate  *   libraries, then HWCAP would be defined for Sparc, as well.
62*7c478bd9Sstevel@tonic-gate  *
63*7c478bd9Sstevel@tonic-gate  * UMUL64
64*7c478bd9Sstevel@tonic-gate  *   Meaning: It is safe to use generic C code that assumes the existence
65*7c478bd9Sstevel@tonic-gate  *   of a 32 x 32 --> 64 bit unsigned multiply.  If this is not defined,
66*7c478bd9Sstevel@tonic-gate  *   then the generic code for big_mul_add_vec() must necessarily be very slow,
67*7c478bd9Sstevel@tonic-gate  *   because it must fall back to using 16 x 16 --> 32 bit multiplication.
68*7c478bd9Sstevel@tonic-gate  *
69*7c478bd9Sstevel@tonic-gate  */
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate #ifdef	_KERNEL
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
75*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
76*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
77*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate #define	big_malloc(size)	kmem_alloc(size, KM_NOSLEEP)
80*7c478bd9Sstevel@tonic-gate #define	big_free(ptr, size)	kmem_free(ptr, size)
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate void *
83*7c478bd9Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize)
84*7c478bd9Sstevel@tonic-gate {
85*7c478bd9Sstevel@tonic-gate 	void *rv;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 	rv = kmem_alloc(newsize, KM_NOSLEEP);
88*7c478bd9Sstevel@tonic-gate 	if (rv != NULL)
89*7c478bd9Sstevel@tonic-gate 		bcopy(from, rv, oldsize);
90*7c478bd9Sstevel@tonic-gate 	kmem_free(from, oldsize);
91*7c478bd9Sstevel@tonic-gate 	return (rv);
92*7c478bd9Sstevel@tonic-gate }
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate #else	/* _KERNEL */
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
97*7c478bd9Sstevel@tonic-gate #include <stdio.h>
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate #ifndef MALLOC_DEBUG
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate #define	big_malloc(size)	malloc(size)
102*7c478bd9Sstevel@tonic-gate #define	big_free(ptr, size)	free(ptr)
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate #else
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate void
107*7c478bd9Sstevel@tonic-gate big_free(void *ptr, size_t size)
108*7c478bd9Sstevel@tonic-gate {
109*7c478bd9Sstevel@tonic-gate 	printf("freed %d bytes at %p\n", size, ptr);
110*7c478bd9Sstevel@tonic-gate 	free(ptr);
111*7c478bd9Sstevel@tonic-gate }
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate void *
114*7c478bd9Sstevel@tonic-gate big_malloc(size_t size)
115*7c478bd9Sstevel@tonic-gate {
116*7c478bd9Sstevel@tonic-gate 	void *rv;
117*7c478bd9Sstevel@tonic-gate 	rv = malloc(size);
118*7c478bd9Sstevel@tonic-gate 	printf("malloced %d bytes, addr:%p\n", size, rv);
119*7c478bd9Sstevel@tonic-gate 	return (rv);
120*7c478bd9Sstevel@tonic-gate }
121*7c478bd9Sstevel@tonic-gate #endif /* MALLOC_DEBUG */
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate #define	big_realloc(x, y, z) realloc((x), (z))
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate void
126*7c478bd9Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a)
127*7c478bd9Sstevel@tonic-gate {
128*7c478bd9Sstevel@tonic-gate 	int i;
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	(void) printf("\n%s\n%d\n", aname, a->sign*a->len);
131*7c478bd9Sstevel@tonic-gate 	for (i = a->len - 1; i >= 0; i--) {
132*7c478bd9Sstevel@tonic-gate 		(void) printf("%08x ", a->value[i]);
133*7c478bd9Sstevel@tonic-gate 		if ((i % 8 == 0) && (i != 0))
134*7c478bd9Sstevel@tonic-gate 		    (void) printf("\n");
135*7c478bd9Sstevel@tonic-gate 	}
136*7c478bd9Sstevel@tonic-gate 	(void) printf("\n");
137*7c478bd9Sstevel@tonic-gate }
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate #endif	/* _KERNEL */
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate /* size in 32-bit words */
143*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
144*7c478bd9Sstevel@tonic-gate big_init(BIGNUM *number, int size)
145*7c478bd9Sstevel@tonic-gate {
146*7c478bd9Sstevel@tonic-gate 	number->value = big_malloc(sizeof (uint32_t) * size);
147*7c478bd9Sstevel@tonic-gate 	if (number->value == NULL) {
148*7c478bd9Sstevel@tonic-gate 		return (BIG_NO_MEM);
149*7c478bd9Sstevel@tonic-gate 	}
150*7c478bd9Sstevel@tonic-gate 	number->size = size;
151*7c478bd9Sstevel@tonic-gate 	number->len = 0;
152*7c478bd9Sstevel@tonic-gate 	number->sign = 1;
153*7c478bd9Sstevel@tonic-gate 	number->malloced = 1;
154*7c478bd9Sstevel@tonic-gate 	return (BIG_OK);
155*7c478bd9Sstevel@tonic-gate }
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate /* size in 32-bit words */
158*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
159*7c478bd9Sstevel@tonic-gate big_init1(BIGNUM *number, int size, uint32_t *buf, int bufsize)
160*7c478bd9Sstevel@tonic-gate {
161*7c478bd9Sstevel@tonic-gate 	if ((buf == NULL) || (size > bufsize)) {
162*7c478bd9Sstevel@tonic-gate 		number->value = big_malloc(sizeof (uint32_t) * size);
163*7c478bd9Sstevel@tonic-gate 		if (number->value == NULL) {
164*7c478bd9Sstevel@tonic-gate 			return (BIG_NO_MEM);
165*7c478bd9Sstevel@tonic-gate 		}
166*7c478bd9Sstevel@tonic-gate 		number->size = size;
167*7c478bd9Sstevel@tonic-gate 		number->malloced = 1;
168*7c478bd9Sstevel@tonic-gate 	} else {
169*7c478bd9Sstevel@tonic-gate 		number->value = buf;
170*7c478bd9Sstevel@tonic-gate 		number->size = bufsize;
171*7c478bd9Sstevel@tonic-gate 		number->malloced = 0;
172*7c478bd9Sstevel@tonic-gate 	}
173*7c478bd9Sstevel@tonic-gate 		number->len = 0;
174*7c478bd9Sstevel@tonic-gate 		number->sign = 1;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	return (BIG_OK);
177*7c478bd9Sstevel@tonic-gate }
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate void
180*7c478bd9Sstevel@tonic-gate big_finish(BIGNUM *number)
181*7c478bd9Sstevel@tonic-gate {
182*7c478bd9Sstevel@tonic-gate 	if (number->malloced == 1) {
183*7c478bd9Sstevel@tonic-gate 		big_free(number->value, sizeof (uint32_t) * number->size);
184*7c478bd9Sstevel@tonic-gate 		number->malloced = 0;
185*7c478bd9Sstevel@tonic-gate 	}
186*7c478bd9Sstevel@tonic-gate }
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate /*
189*7c478bd9Sstevel@tonic-gate  *  bn->size should be at least (len + 3) / 4
190*7c478bd9Sstevel@tonic-gate  * converts from byte-big-endian format to bignum format (words in
191*7c478bd9Sstevel@tonic-gate  * little endian order, but bytes within the words big endian)
192*7c478bd9Sstevel@tonic-gate  */
193*7c478bd9Sstevel@tonic-gate void
194*7c478bd9Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len)
195*7c478bd9Sstevel@tonic-gate {
196*7c478bd9Sstevel@tonic-gate 	int		i, j, offs;
197*7c478bd9Sstevel@tonic-gate 	uint32_t	word;
198*7c478bd9Sstevel@tonic-gate 	uchar_t		*knwordp;
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate #ifdef	_LP64
201*7c478bd9Sstevel@tonic-gate 	/* LINTED */
202*7c478bd9Sstevel@tonic-gate 	offs = (uint32_t)len % sizeof (uint32_t);
203*7c478bd9Sstevel@tonic-gate 	/* LINTED */
204*7c478bd9Sstevel@tonic-gate 	bn->len = (uint32_t)len / sizeof (uint32_t);
205*7c478bd9Sstevel@tonic-gate 	/* LINTED */
206*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < (uint32_t)len / sizeof (uint32_t); i++) {
207*7c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
208*7c478bd9Sstevel@tonic-gate 	offs = len % sizeof (uint32_t);
209*7c478bd9Sstevel@tonic-gate 	bn->len = len / sizeof (uint32_t);
210*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < len / sizeof (uint32_t); i++) {
211*7c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
212*7c478bd9Sstevel@tonic-gate 		knwordp = &(kn[len - sizeof (uint32_t) * (i + 1)]);
213*7c478bd9Sstevel@tonic-gate 		word = knwordp[0];
214*7c478bd9Sstevel@tonic-gate 		for (j = 1; j < sizeof (uint32_t); j++) {
215*7c478bd9Sstevel@tonic-gate 			word = (word << 8)+ knwordp[j];
216*7c478bd9Sstevel@tonic-gate 		}
217*7c478bd9Sstevel@tonic-gate 		bn->value[i] = word;
218*7c478bd9Sstevel@tonic-gate 	}
219*7c478bd9Sstevel@tonic-gate 	if (offs > 0) {
220*7c478bd9Sstevel@tonic-gate 		word = kn[0];
221*7c478bd9Sstevel@tonic-gate 		for (i = 1; i < offs; i++) word = (word << 8) + kn[i];
222*7c478bd9Sstevel@tonic-gate 		bn->value[bn->len++] = word;
223*7c478bd9Sstevel@tonic-gate 	}
224*7c478bd9Sstevel@tonic-gate 	while ((bn->len > 1) && (bn->value[bn->len-1] == 0)) {
225*7c478bd9Sstevel@tonic-gate 		bn->len --;
226*7c478bd9Sstevel@tonic-gate 	}
227*7c478bd9Sstevel@tonic-gate }
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate /*
230*7c478bd9Sstevel@tonic-gate  * copies the least significant len bytes if
231*7c478bd9Sstevel@tonic-gate  * len < bn->len * sizeof (uint32_t)
232*7c478bd9Sstevel@tonic-gate  * converts from bignum format to byte-big-endian format.
233*7c478bd9Sstevel@tonic-gate  * bignum format is words in little endian order,
234*7c478bd9Sstevel@tonic-gate  * but bytes within words in native byte order.
235*7c478bd9Sstevel@tonic-gate  */
236*7c478bd9Sstevel@tonic-gate void
237*7c478bd9Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len)
238*7c478bd9Sstevel@tonic-gate {
239*7c478bd9Sstevel@tonic-gate 	int		i, j, offs;
240*7c478bd9Sstevel@tonic-gate 	uint32_t	word;
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	if (len < sizeof (uint32_t) * bn->len) {
243*7c478bd9Sstevel@tonic-gate #ifdef	_LP64
244*7c478bd9Sstevel@tonic-gate 		/* LINTED */
245*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < (uint32_t)len / sizeof (uint32_t); i++) {
246*7c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
247*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < len / sizeof (uint32_t); i++) {
248*7c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
249*7c478bd9Sstevel@tonic-gate 			word = bn->value[i];
250*7c478bd9Sstevel@tonic-gate 			for (j = 0; j < sizeof (uint32_t); j++) {
251*7c478bd9Sstevel@tonic-gate 				kn[len - sizeof (uint32_t) * i - j - 1] =
252*7c478bd9Sstevel@tonic-gate 				    word & 0xff;
253*7c478bd9Sstevel@tonic-gate 				word = word >> 8;
254*7c478bd9Sstevel@tonic-gate 			}
255*7c478bd9Sstevel@tonic-gate 		}
256*7c478bd9Sstevel@tonic-gate #ifdef	_LP64
257*7c478bd9Sstevel@tonic-gate 		/* LINTED */
258*7c478bd9Sstevel@tonic-gate 		offs = (uint32_t)len % sizeof (uint32_t);
259*7c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
260*7c478bd9Sstevel@tonic-gate 		offs = len % sizeof (uint32_t);
261*7c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
262*7c478bd9Sstevel@tonic-gate 		if (offs > 0) {
263*7c478bd9Sstevel@tonic-gate 			word = bn->value[len / sizeof (uint32_t)];
264*7c478bd9Sstevel@tonic-gate #ifdef	_LP64
265*7c478bd9Sstevel@tonic-gate 			    /* LINTED */
266*7c478bd9Sstevel@tonic-gate 			    for (i =  (uint32_t)len % sizeof (uint32_t);
267*7c478bd9Sstevel@tonic-gate 				i > 0; i --) {
268*7c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
269*7c478bd9Sstevel@tonic-gate 			    for (i = len % sizeof (uint32_t); i > 0; i --) {
270*7c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
271*7c478bd9Sstevel@tonic-gate 				    kn[i - 1] = word & 0xff;
272*7c478bd9Sstevel@tonic-gate 				    word = word >> 8;
273*7c478bd9Sstevel@tonic-gate 			    }
274*7c478bd9Sstevel@tonic-gate 		}
275*7c478bd9Sstevel@tonic-gate 	} else {
276*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < bn->len; i++) {
277*7c478bd9Sstevel@tonic-gate 			word = bn->value[i];
278*7c478bd9Sstevel@tonic-gate 			for (j = 0; j < sizeof (uint32_t); j++) {
279*7c478bd9Sstevel@tonic-gate 				kn[len - sizeof (uint32_t) * i - j - 1] =
280*7c478bd9Sstevel@tonic-gate 				    word & 0xff;
281*7c478bd9Sstevel@tonic-gate 				word = word >> 8;
282*7c478bd9Sstevel@tonic-gate 			}
283*7c478bd9Sstevel@tonic-gate 		}
284*7c478bd9Sstevel@tonic-gate #ifdef	_LP64
285*7c478bd9Sstevel@tonic-gate 		/* LINTED */
286*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < (uint32_t)len - sizeof (uint32_t) * bn->len;
287*7c478bd9Sstevel@tonic-gate 		    i++) {
288*7c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
289*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < len - sizeof (uint32_t) * bn->len; i++) {
290*7c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
291*7c478bd9Sstevel@tonic-gate 			kn[i] = 0;
292*7c478bd9Sstevel@tonic-gate 		}
293*7c478bd9Sstevel@tonic-gate 	}
294*7c478bd9Sstevel@tonic-gate }
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate int
298*7c478bd9Sstevel@tonic-gate big_bitlength(BIGNUM *a)
299*7c478bd9Sstevel@tonic-gate {
300*7c478bd9Sstevel@tonic-gate 	int		l, b;
301*7c478bd9Sstevel@tonic-gate 	uint32_t	c;
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	l = a->len - 1;
304*7c478bd9Sstevel@tonic-gate 	while ((l > 0) && (a->value[l] == 0)) {
305*7c478bd9Sstevel@tonic-gate 		l--;
306*7c478bd9Sstevel@tonic-gate 	}
307*7c478bd9Sstevel@tonic-gate 	b = sizeof (uint32_t) * 8;
308*7c478bd9Sstevel@tonic-gate 	c = a->value[l];
309*7c478bd9Sstevel@tonic-gate 	while ((b > 1) && ((c & 0x80000000) == 0)) {
310*7c478bd9Sstevel@tonic-gate 		c = c << 1;
311*7c478bd9Sstevel@tonic-gate 		b--;
312*7c478bd9Sstevel@tonic-gate 	}
313*7c478bd9Sstevel@tonic-gate 	return (l * (int)sizeof (uint32_t) * 8 + b);
314*7c478bd9Sstevel@tonic-gate }
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
318*7c478bd9Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src)
319*7c478bd9Sstevel@tonic-gate {
320*7c478bd9Sstevel@tonic-gate 	uint32_t *newptr;
321*7c478bd9Sstevel@tonic-gate 	int i, len;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	len = src->len;
324*7c478bd9Sstevel@tonic-gate 	while ((len > 1) && (src->value[len - 1] == 0))
325*7c478bd9Sstevel@tonic-gate 		len--;
326*7c478bd9Sstevel@tonic-gate 	src->len = len;
327*7c478bd9Sstevel@tonic-gate 	if (dest->size < len) {
328*7c478bd9Sstevel@tonic-gate 		if (dest->malloced == 1) {
329*7c478bd9Sstevel@tonic-gate 			newptr = (uint32_t *)big_realloc(dest->value,
330*7c478bd9Sstevel@tonic-gate 			    sizeof (uint32_t) * dest->size,
331*7c478bd9Sstevel@tonic-gate 			    sizeof (uint32_t) * len);
332*7c478bd9Sstevel@tonic-gate 		} else {
333*7c478bd9Sstevel@tonic-gate 			newptr = (uint32_t *)
334*7c478bd9Sstevel@tonic-gate 			    big_malloc(sizeof (uint32_t) * len);
335*7c478bd9Sstevel@tonic-gate 			if (newptr != NULL) dest->malloced = 1;
336*7c478bd9Sstevel@tonic-gate 		}
337*7c478bd9Sstevel@tonic-gate 		if (newptr == NULL)
338*7c478bd9Sstevel@tonic-gate 			return (BIG_NO_MEM);
339*7c478bd9Sstevel@tonic-gate 		dest->value = newptr;
340*7c478bd9Sstevel@tonic-gate 		dest->size = len;
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate 	dest->len = len;
343*7c478bd9Sstevel@tonic-gate 	dest->sign = src->sign;
344*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) dest->value[i] = src->value[i];
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	return (BIG_OK);
347*7c478bd9Sstevel@tonic-gate }
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
351*7c478bd9Sstevel@tonic-gate big_extend(BIGNUM *number, int size)
352*7c478bd9Sstevel@tonic-gate {
353*7c478bd9Sstevel@tonic-gate 	uint32_t	*newptr;
354*7c478bd9Sstevel@tonic-gate 	int		i;
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	if (number->size >= size)
357*7c478bd9Sstevel@tonic-gate 		return (BIG_OK);
358*7c478bd9Sstevel@tonic-gate 	if (number->malloced) {
359*7c478bd9Sstevel@tonic-gate 		number->value =
360*7c478bd9Sstevel@tonic-gate 		    big_realloc(number->value,
361*7c478bd9Sstevel@tonic-gate 			sizeof (uint32_t) * number->size,
362*7c478bd9Sstevel@tonic-gate 			sizeof (uint32_t) * size);
363*7c478bd9Sstevel@tonic-gate 	} else {
364*7c478bd9Sstevel@tonic-gate 		newptr = big_malloc(sizeof (uint32_t) * size);
365*7c478bd9Sstevel@tonic-gate 		if (newptr != NULL) {
366*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < number->size; i++) {
367*7c478bd9Sstevel@tonic-gate 				newptr[i] = number->value[i];
368*7c478bd9Sstevel@tonic-gate 			}
369*7c478bd9Sstevel@tonic-gate 		}
370*7c478bd9Sstevel@tonic-gate 		number->value = newptr;
371*7c478bd9Sstevel@tonic-gate 	}
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	if (number->value == NULL)
374*7c478bd9Sstevel@tonic-gate 		return (BIG_NO_MEM);
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	number->size = size;
377*7c478bd9Sstevel@tonic-gate 	number->malloced = 1;
378*7c478bd9Sstevel@tonic-gate 	return (BIG_OK);
379*7c478bd9Sstevel@tonic-gate }
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate int
383*7c478bd9Sstevel@tonic-gate big_is_zero(BIGNUM *n)
384*7c478bd9Sstevel@tonic-gate {
385*7c478bd9Sstevel@tonic-gate 	int i, result;
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	result = 1;
388*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < n->len; i++)
389*7c478bd9Sstevel@tonic-gate 		if (n->value[i] != 0) result = 0;
390*7c478bd9Sstevel@tonic-gate 	return (result);
391*7c478bd9Sstevel@tonic-gate }
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
395*7c478bd9Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
396*7c478bd9Sstevel@tonic-gate {
397*7c478bd9Sstevel@tonic-gate 	int i, shorter, longer;
398*7c478bd9Sstevel@tonic-gate 	uint32_t cy, ai;
399*7c478bd9Sstevel@tonic-gate 	uint32_t *r, *a, *b, *c;
400*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 	if (aa->len > bb->len) {
403*7c478bd9Sstevel@tonic-gate 		shorter = bb->len;
404*7c478bd9Sstevel@tonic-gate 		longer = aa->len;
405*7c478bd9Sstevel@tonic-gate 		c = aa->value;
406*7c478bd9Sstevel@tonic-gate 	} else {
407*7c478bd9Sstevel@tonic-gate 		shorter = aa->len;
408*7c478bd9Sstevel@tonic-gate 		longer = bb->len;
409*7c478bd9Sstevel@tonic-gate 		c = bb->value;
410*7c478bd9Sstevel@tonic-gate 	}
411*7c478bd9Sstevel@tonic-gate 	if (result->size < longer + 1) {
412*7c478bd9Sstevel@tonic-gate 		err = big_extend(result, longer + 1);
413*7c478bd9Sstevel@tonic-gate 		if (err != BIG_OK)
414*7c478bd9Sstevel@tonic-gate 			return (err);
415*7c478bd9Sstevel@tonic-gate 	}
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	r = result->value;
418*7c478bd9Sstevel@tonic-gate 	a = aa->value;
419*7c478bd9Sstevel@tonic-gate 	b = bb->value;
420*7c478bd9Sstevel@tonic-gate 	cy = 0;
421*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
422*7c478bd9Sstevel@tonic-gate 		ai = a[i];
423*7c478bd9Sstevel@tonic-gate 		r[i] = ai + b[i] + cy;
424*7c478bd9Sstevel@tonic-gate 		if (r[i] > ai) cy = 0;
425*7c478bd9Sstevel@tonic-gate 		else if (r[i] < ai) cy = 1;
426*7c478bd9Sstevel@tonic-gate 	}
427*7c478bd9Sstevel@tonic-gate 	for (; i < longer; i++) {
428*7c478bd9Sstevel@tonic-gate 		ai = c[i];
429*7c478bd9Sstevel@tonic-gate 		r[i] = ai + cy;
430*7c478bd9Sstevel@tonic-gate 		if (r[i] >= ai) cy = 0;
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate 	if (cy == 1) {
433*7c478bd9Sstevel@tonic-gate 		r[i] = cy;
434*7c478bd9Sstevel@tonic-gate 		result->len = longer + 1;
435*7c478bd9Sstevel@tonic-gate 	} else {
436*7c478bd9Sstevel@tonic-gate 		result->len = longer;
437*7c478bd9Sstevel@tonic-gate 	}
438*7c478bd9Sstevel@tonic-gate 	result->sign = 1;
439*7c478bd9Sstevel@tonic-gate 	return (BIG_OK);
440*7c478bd9Sstevel@tonic-gate }
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */
444*7c478bd9Sstevel@tonic-gate void
445*7c478bd9Sstevel@tonic-gate big_sub_vec(uint32_t *r, uint32_t *a, uint32_t *b, int len)
446*7c478bd9Sstevel@tonic-gate {
447*7c478bd9Sstevel@tonic-gate 	int i;
448*7c478bd9Sstevel@tonic-gate 	uint32_t cy, ai;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	cy = 1;
451*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
452*7c478bd9Sstevel@tonic-gate 		ai = a[i];
453*7c478bd9Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
454*7c478bd9Sstevel@tonic-gate 		if (r[i] > ai) cy = 0;
455*7c478bd9Sstevel@tonic-gate 		else if (r[i] < ai) cy = 1;
456*7c478bd9Sstevel@tonic-gate 	}
457*7c478bd9Sstevel@tonic-gate }
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate /* result=aa-bb  it is assumed that aa>=bb */
461*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
462*7c478bd9Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
463*7c478bd9Sstevel@tonic-gate {
464*7c478bd9Sstevel@tonic-gate 	int i, shorter;
465*7c478bd9Sstevel@tonic-gate 	uint32_t cy, ai;
466*7c478bd9Sstevel@tonic-gate 	uint32_t *r, *a, *b;
467*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	if (aa->len > bb->len) shorter = bb->len;
470*7c478bd9Sstevel@tonic-gate 	else shorter = aa->len;
471*7c478bd9Sstevel@tonic-gate 	if (result->size < aa->len) {
472*7c478bd9Sstevel@tonic-gate 		err = big_extend(result, aa->len);
473*7c478bd9Sstevel@tonic-gate 		if (err != BIG_OK)
474*7c478bd9Sstevel@tonic-gate 			return (err);
475*7c478bd9Sstevel@tonic-gate 	}
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	r = result->value;
478*7c478bd9Sstevel@tonic-gate 	a = aa->value;
479*7c478bd9Sstevel@tonic-gate 	b = bb->value;
480*7c478bd9Sstevel@tonic-gate 	result->len = aa->len;
481*7c478bd9Sstevel@tonic-gate 	cy = 1;
482*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < shorter; i++) {
483*7c478bd9Sstevel@tonic-gate 		ai = a[i];
484*7c478bd9Sstevel@tonic-gate 		r[i] = ai + (~b[i]) + cy;
485*7c478bd9Sstevel@tonic-gate 		if (r[i] > ai) cy = 0;
486*7c478bd9Sstevel@tonic-gate 		else if (r[i] < ai) cy = 1;
487*7c478bd9Sstevel@tonic-gate 	}
488*7c478bd9Sstevel@tonic-gate 	for (; i < aa->len; i++) {
489*7c478bd9Sstevel@tonic-gate 		ai = a[i];
490*7c478bd9Sstevel@tonic-gate 		r[i] = ai + (~0) + cy;
491*7c478bd9Sstevel@tonic-gate 		if (r[i] < ai) cy = 1;
492*7c478bd9Sstevel@tonic-gate 	}
493*7c478bd9Sstevel@tonic-gate 	result->sign = 1;
494*7c478bd9Sstevel@tonic-gate 	if (cy == 0)
495*7c478bd9Sstevel@tonic-gate 		return (BIG_INVALID_ARGS);
496*7c478bd9Sstevel@tonic-gate 	else
497*7c478bd9Sstevel@tonic-gate 		return (BIG_OK);
498*7c478bd9Sstevel@tonic-gate }
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */
502*7c478bd9Sstevel@tonic-gate int
503*7c478bd9Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb)
504*7c478bd9Sstevel@tonic-gate {
505*7c478bd9Sstevel@tonic-gate 	int i;
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	if (aa->len > bb->len) {
508*7c478bd9Sstevel@tonic-gate 		for (i = aa->len - 1; i > bb->len - 1; i--) {
509*7c478bd9Sstevel@tonic-gate 			if (aa->value[i] > 0)
510*7c478bd9Sstevel@tonic-gate 				return (1);
511*7c478bd9Sstevel@tonic-gate 		}
512*7c478bd9Sstevel@tonic-gate 	} else if (aa->len < bb->len) {
513*7c478bd9Sstevel@tonic-gate 		for (i = bb->len - 1; i > aa->len - 1; i--) {
514*7c478bd9Sstevel@tonic-gate 			if (bb->value[i] > 0)
515*7c478bd9Sstevel@tonic-gate 				return (-1);
516*7c478bd9Sstevel@tonic-gate 		}
517*7c478bd9Sstevel@tonic-gate 	} else i = aa->len-1;
518*7c478bd9Sstevel@tonic-gate 	for (; i >= 0; i--) {
519*7c478bd9Sstevel@tonic-gate 		if (aa->value[i] > bb->value[i])
520*7c478bd9Sstevel@tonic-gate 			return (1);
521*7c478bd9Sstevel@tonic-gate 		else if (aa->value[i] < bb->value[i])
522*7c478bd9Sstevel@tonic-gate 			return (-1);
523*7c478bd9Sstevel@tonic-gate 	}
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 	return (0);
526*7c478bd9Sstevel@tonic-gate }
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
530*7c478bd9Sstevel@tonic-gate big_sub(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
531*7c478bd9Sstevel@tonic-gate {
532*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == 1)) {
535*7c478bd9Sstevel@tonic-gate 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK)
536*7c478bd9Sstevel@tonic-gate 			return (err);
537*7c478bd9Sstevel@tonic-gate 		result->sign = 1;
538*7c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == -1) && (bb->sign == 1)) {
539*7c478bd9Sstevel@tonic-gate 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK)
540*7c478bd9Sstevel@tonic-gate 			return (err);
541*7c478bd9Sstevel@tonic-gate 		result->sign = -1;
542*7c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
543*7c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
544*7c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK)
545*7c478bd9Sstevel@tonic-gate 				return (err);
546*7c478bd9Sstevel@tonic-gate 			result->sign = 1;
547*7c478bd9Sstevel@tonic-gate 		} else {
548*7c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK)
549*7c478bd9Sstevel@tonic-gate 				return (err);
550*7c478bd9Sstevel@tonic-gate 			result->sign = -1;
551*7c478bd9Sstevel@tonic-gate 		}
552*7c478bd9Sstevel@tonic-gate 	} else {
553*7c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
554*7c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK)
555*7c478bd9Sstevel@tonic-gate 				return (err);
556*7c478bd9Sstevel@tonic-gate 			result->sign = -1;
557*7c478bd9Sstevel@tonic-gate 		} else {
558*7c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK)
559*7c478bd9Sstevel@tonic-gate 				return (err);
560*7c478bd9Sstevel@tonic-gate 			result->sign = 1;
561*7c478bd9Sstevel@tonic-gate 		}
562*7c478bd9Sstevel@tonic-gate 	}
563*7c478bd9Sstevel@tonic-gate 	return (BIG_OK);
564*7c478bd9Sstevel@tonic-gate }
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
569*7c478bd9Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
570*7c478bd9Sstevel@tonic-gate {
571*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	if ((bb->sign == -1) && (aa->sign == -1)) {
574*7c478bd9Sstevel@tonic-gate 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK)
575*7c478bd9Sstevel@tonic-gate 			return (err);
576*7c478bd9Sstevel@tonic-gate 		result->sign = -1;
577*7c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == 1)) {
578*7c478bd9Sstevel@tonic-gate 		if ((err = big_add_abs(result, aa, bb)) != BIG_OK)
579*7c478bd9Sstevel@tonic-gate 			return (err);
580*7c478bd9Sstevel@tonic-gate 		result->sign = 1;
581*7c478bd9Sstevel@tonic-gate 	} else if ((aa->sign == 1) && (bb->sign == -1)) {
582*7c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
583*7c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK)
584*7c478bd9Sstevel@tonic-gate 				return (err);
585*7c478bd9Sstevel@tonic-gate 			result->sign = 1;
586*7c478bd9Sstevel@tonic-gate 		} else {
587*7c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK)
588*7c478bd9Sstevel@tonic-gate 				return (err);
589*7c478bd9Sstevel@tonic-gate 			result->sign = -1;
590*7c478bd9Sstevel@tonic-gate 		}
591*7c478bd9Sstevel@tonic-gate 	} else {
592*7c478bd9Sstevel@tonic-gate 		if (big_cmp_abs(aa, bb) >= 0) {
593*7c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, aa, bb)) != BIG_OK)
594*7c478bd9Sstevel@tonic-gate 				return (err);
595*7c478bd9Sstevel@tonic-gate 			result->sign = -1;
596*7c478bd9Sstevel@tonic-gate 		} else {
597*7c478bd9Sstevel@tonic-gate 			if ((err = big_sub_pos(result, bb, aa)) != BIG_OK)
598*7c478bd9Sstevel@tonic-gate 				return (err);
599*7c478bd9Sstevel@tonic-gate 			result->sign = 1;
600*7c478bd9Sstevel@tonic-gate 		}
601*7c478bd9Sstevel@tonic-gate 	}
602*7c478bd9Sstevel@tonic-gate 	return (BIG_OK);
603*7c478bd9Sstevel@tonic-gate }
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate /* result = aa/2 aa must be positive */
607*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
608*7c478bd9Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa)
609*7c478bd9Sstevel@tonic-gate {
610*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
611*7c478bd9Sstevel@tonic-gate 	int i;
612*7c478bd9Sstevel@tonic-gate 	uint32_t cy, cy1;
613*7c478bd9Sstevel@tonic-gate 	uint32_t *a, *r;
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	if (result->size < aa->len) {
616*7c478bd9Sstevel@tonic-gate 		err = big_extend(result, aa->len);
617*7c478bd9Sstevel@tonic-gate 		if (err != BIG_OK)
618*7c478bd9Sstevel@tonic-gate 			return (err);
619*7c478bd9Sstevel@tonic-gate 	}
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 	result->len = aa->len;
622*7c478bd9Sstevel@tonic-gate 	a = aa->value;
623*7c478bd9Sstevel@tonic-gate 	r = result->value;
624*7c478bd9Sstevel@tonic-gate 	cy = 0;
625*7c478bd9Sstevel@tonic-gate 	for (i = aa->len-1; i >= 0; i--) {
626*7c478bd9Sstevel@tonic-gate 		cy1 = a[i] << 31;
627*7c478bd9Sstevel@tonic-gate 		r[i] = (cy|(a[i] >> 1));
628*7c478bd9Sstevel@tonic-gate 		cy = cy1;
629*7c478bd9Sstevel@tonic-gate 	}
630*7c478bd9Sstevel@tonic-gate 	if (r[result->len-1] == 0) result->len--;
631*7c478bd9Sstevel@tonic-gate 	return (BIG_OK);
632*7c478bd9Sstevel@tonic-gate }
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate /* result  =  aa*2 aa must be positive */
635*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
636*7c478bd9Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa)
637*7c478bd9Sstevel@tonic-gate {
638*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
639*7c478bd9Sstevel@tonic-gate 	int i, rsize;
640*7c478bd9Sstevel@tonic-gate 	uint32_t cy, cy1;
641*7c478bd9Sstevel@tonic-gate 	uint32_t *a, *r;
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 	if ((aa->len > 0) && ((aa->value[aa->len - 1] & 0x80000000) != 0))
644*7c478bd9Sstevel@tonic-gate 		rsize = aa->len + 1;
645*7c478bd9Sstevel@tonic-gate 	else rsize = aa->len;
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 	if (result->size < rsize) {
648*7c478bd9Sstevel@tonic-gate 		err = big_extend(result, rsize);
649*7c478bd9Sstevel@tonic-gate 		if (err != BIG_OK)
650*7c478bd9Sstevel@tonic-gate 			return (err);
651*7c478bd9Sstevel@tonic-gate 	}
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 	a = aa->value;
654*7c478bd9Sstevel@tonic-gate 	r = result->value;
655*7c478bd9Sstevel@tonic-gate 	if (rsize == aa->len + 1) r[rsize - 1] = 1;
656*7c478bd9Sstevel@tonic-gate 	cy = 0;
657*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
658*7c478bd9Sstevel@tonic-gate 		cy1 = a[i] >> 31;
659*7c478bd9Sstevel@tonic-gate 		r[i] = (cy | (a[i] << 1));
660*7c478bd9Sstevel@tonic-gate 		cy = cy1;
661*7c478bd9Sstevel@tonic-gate 	}
662*7c478bd9Sstevel@tonic-gate 	result->len = rsize;
663*7c478bd9Sstevel@tonic-gate 	return (BIG_OK);
664*7c478bd9Sstevel@tonic-gate }
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate /* returns aa mod b, aa must be nonneg, b must be a max 16-bit integer */
667*7c478bd9Sstevel@tonic-gate uint32_t
668*7c478bd9Sstevel@tonic-gate big_mod16_pos(BIGNUM *aa, uint32_t b)
669*7c478bd9Sstevel@tonic-gate {
670*7c478bd9Sstevel@tonic-gate 	int i;
671*7c478bd9Sstevel@tonic-gate 	uint32_t rem;
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 	if (aa->len == 0)
674*7c478bd9Sstevel@tonic-gate 		return (0);
675*7c478bd9Sstevel@tonic-gate 	rem = aa->value[aa->len - 1] % b;
676*7c478bd9Sstevel@tonic-gate 	for (i = aa->len - 2; i >= 0; i--) {
677*7c478bd9Sstevel@tonic-gate 		rem = ((rem << 16) | (aa->value[i] >> 16)) % b;
678*7c478bd9Sstevel@tonic-gate 		rem = ((rem << 16) | (aa->value[i] & 0xffff)) % b;
679*7c478bd9Sstevel@tonic-gate 	}
680*7c478bd9Sstevel@tonic-gate 	return (rem);
681*7c478bd9Sstevel@tonic-gate }
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate /*
685*7c478bd9Sstevel@tonic-gate  * result = aa - (2^32)^lendiff * bb
686*7c478bd9Sstevel@tonic-gate  * result->size should be at least aa->len at entry
687*7c478bd9Sstevel@tonic-gate  * aa, bb, and result should be positive
688*7c478bd9Sstevel@tonic-gate  */
689*7c478bd9Sstevel@tonic-gate void
690*7c478bd9Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
691*7c478bd9Sstevel@tonic-gate {
692*7c478bd9Sstevel@tonic-gate 	int i, lendiff;
693*7c478bd9Sstevel@tonic-gate 	BIGNUM res1, aa1;
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
696*7c478bd9Sstevel@tonic-gate 	res1.size = result->size - lendiff;
697*7c478bd9Sstevel@tonic-gate 	res1.malloced = 0;
698*7c478bd9Sstevel@tonic-gate 	res1.value = result->value + lendiff;
699*7c478bd9Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
700*7c478bd9Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
701*7c478bd9Sstevel@tonic-gate 	aa1.len = bb->len;
702*7c478bd9Sstevel@tonic-gate 	aa1.sign = 1;
703*7c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(&res1, &aa1, bb);
704*7c478bd9Sstevel@tonic-gate 	if (result->value != aa->value) {
705*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < lendiff; i++) {
706*7c478bd9Sstevel@tonic-gate 			result->value[i] = aa->value[i];
707*7c478bd9Sstevel@tonic-gate 		}
708*7c478bd9Sstevel@tonic-gate 	}
709*7c478bd9Sstevel@tonic-gate 	result->len = aa->len;
710*7c478bd9Sstevel@tonic-gate }
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate /*
714*7c478bd9Sstevel@tonic-gate  * returns 1, 0, or -1 depending on whether |aa| > , ==, or <
715*7c478bd9Sstevel@tonic-gate  *							(2^32)^lendiff * |bb|
716*7c478bd9Sstevel@tonic-gate  * aa->len should be >= bb->len
717*7c478bd9Sstevel@tonic-gate  */
718*7c478bd9Sstevel@tonic-gate int
719*7c478bd9Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb)
720*7c478bd9Sstevel@tonic-gate {
721*7c478bd9Sstevel@tonic-gate 	int lendiff;
722*7c478bd9Sstevel@tonic-gate 	BIGNUM aa1;
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate 	lendiff = aa->len - bb->len;
725*7c478bd9Sstevel@tonic-gate 	aa1.len = bb->len;
726*7c478bd9Sstevel@tonic-gate 	aa1.size = aa->size - lendiff;
727*7c478bd9Sstevel@tonic-gate 	aa1.malloced = 0;
728*7c478bd9Sstevel@tonic-gate 	aa1.value = aa->value + lendiff;
729*7c478bd9Sstevel@tonic-gate 	return (big_cmp_abs(&aa1, bb));
730*7c478bd9Sstevel@tonic-gate }
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate /*
734*7c478bd9Sstevel@tonic-gate  * result = aa * b where b is a max. 16-bit positive integer.
735*7c478bd9Sstevel@tonic-gate  * result should have enough space allocated.
736*7c478bd9Sstevel@tonic-gate  */
737*7c478bd9Sstevel@tonic-gate void
738*7c478bd9Sstevel@tonic-gate big_mul16_low(BIGNUM *result, BIGNUM *aa, uint32_t b)
739*7c478bd9Sstevel@tonic-gate {
740*7c478bd9Sstevel@tonic-gate 	int i;
741*7c478bd9Sstevel@tonic-gate 	uint32_t t1, t2, ai, cy;
742*7c478bd9Sstevel@tonic-gate 	uint32_t *a, *r;
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 	a = aa->value;
745*7c478bd9Sstevel@tonic-gate 	r = result->value;
746*7c478bd9Sstevel@tonic-gate 	cy = 0;
747*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
748*7c478bd9Sstevel@tonic-gate 		ai = a[i];
749*7c478bd9Sstevel@tonic-gate 		t1 = (ai & 0xffff) * b + cy;
750*7c478bd9Sstevel@tonic-gate 		t2 = (ai >> 16) * b + (t1 >> 16);
751*7c478bd9Sstevel@tonic-gate 		r[i] = (t1 & 0xffff) | (t2 << 16);
752*7c478bd9Sstevel@tonic-gate 		cy = t2 >> 16;
753*7c478bd9Sstevel@tonic-gate 	}
754*7c478bd9Sstevel@tonic-gate 	r[i] = cy;
755*7c478bd9Sstevel@tonic-gate 	result->len = aa->len + 1;
756*7c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
757*7c478bd9Sstevel@tonic-gate }
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate /*
761*7c478bd9Sstevel@tonic-gate  * result = aa * b * 2^16 where b is a max. 16-bit positive integer.
762*7c478bd9Sstevel@tonic-gate  * result should have enough space allocated.
763*7c478bd9Sstevel@tonic-gate  */
764*7c478bd9Sstevel@tonic-gate void
765*7c478bd9Sstevel@tonic-gate big_mul16_high(BIGNUM *result, BIGNUM *aa, uint32_t b)
766*7c478bd9Sstevel@tonic-gate {
767*7c478bd9Sstevel@tonic-gate 	int i;
768*7c478bd9Sstevel@tonic-gate 	uint32_t t1, t2, ai, cy, ri;
769*7c478bd9Sstevel@tonic-gate 	uint32_t *a, *r;
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	a = aa->value;
772*7c478bd9Sstevel@tonic-gate 	r = result->value;
773*7c478bd9Sstevel@tonic-gate 	cy = 0;
774*7c478bd9Sstevel@tonic-gate 	ri = 0;
775*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
776*7c478bd9Sstevel@tonic-gate 		ai = a[i];
777*7c478bd9Sstevel@tonic-gate 		t1 = (ai & 0xffff) * b + cy;
778*7c478bd9Sstevel@tonic-gate 		t2 = (ai >> 16) * b + (t1 >> 16);
779*7c478bd9Sstevel@tonic-gate 		r[i] = (t1 << 16) + ri;
780*7c478bd9Sstevel@tonic-gate 		ri = t2 & 0xffff;
781*7c478bd9Sstevel@tonic-gate 		cy = t2 >> 16;
782*7c478bd9Sstevel@tonic-gate 	}
783*7c478bd9Sstevel@tonic-gate 	r[i] = (cy << 16) + ri;
784*7c478bd9Sstevel@tonic-gate 	result->len = aa->len + 1;
785*7c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
786*7c478bd9Sstevel@tonic-gate }
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */
789*7c478bd9Sstevel@tonic-gate void
790*7c478bd9Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs)
791*7c478bd9Sstevel@tonic-gate {
792*7c478bd9Sstevel@tonic-gate 	int i;
793*7c478bd9Sstevel@tonic-gate 	uint32_t cy, ai;
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 	if (offs == 0) {
796*7c478bd9Sstevel@tonic-gate 		if (result != aa) {
797*7c478bd9Sstevel@tonic-gate 			(void) big_copy(result, aa);
798*7c478bd9Sstevel@tonic-gate 		}
799*7c478bd9Sstevel@tonic-gate 		return;
800*7c478bd9Sstevel@tonic-gate 	}
801*7c478bd9Sstevel@tonic-gate 	cy = 0;
802*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < aa->len; i++) {
803*7c478bd9Sstevel@tonic-gate 		ai = aa->value[i];
804*7c478bd9Sstevel@tonic-gate 		result->value[i] = (ai << offs) | cy;
805*7c478bd9Sstevel@tonic-gate 		cy = ai >> (32 - offs);
806*7c478bd9Sstevel@tonic-gate 	}
807*7c478bd9Sstevel@tonic-gate 	if (cy != 0) {
808*7c478bd9Sstevel@tonic-gate 		result->len = aa->len + 1;
809*7c478bd9Sstevel@tonic-gate 		result->value[result->len - 1] = cy;
810*7c478bd9Sstevel@tonic-gate 	} else {
811*7c478bd9Sstevel@tonic-gate 		result->len = aa->len;
812*7c478bd9Sstevel@tonic-gate 	}
813*7c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
814*7c478bd9Sstevel@tonic-gate }
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */
817*7c478bd9Sstevel@tonic-gate void
818*7c478bd9Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs)
819*7c478bd9Sstevel@tonic-gate {
820*7c478bd9Sstevel@tonic-gate 	int i;
821*7c478bd9Sstevel@tonic-gate 	uint32_t cy, ai;
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate 	if (offs == 0) {
824*7c478bd9Sstevel@tonic-gate 		if (result != aa) {
825*7c478bd9Sstevel@tonic-gate 			(void) big_copy(result, aa);
826*7c478bd9Sstevel@tonic-gate 		}
827*7c478bd9Sstevel@tonic-gate 		return;
828*7c478bd9Sstevel@tonic-gate 	}
829*7c478bd9Sstevel@tonic-gate 	cy = aa->value[0] >> offs;
830*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < aa->len; i++) {
831*7c478bd9Sstevel@tonic-gate 		ai = aa->value[i];
832*7c478bd9Sstevel@tonic-gate 		result->value[i-1] = (ai << (32 - offs)) | cy;
833*7c478bd9Sstevel@tonic-gate 		cy = ai >> offs;
834*7c478bd9Sstevel@tonic-gate 	}
835*7c478bd9Sstevel@tonic-gate 	result->len = aa->len;
836*7c478bd9Sstevel@tonic-gate 	result->value[result->len - 1] = cy;
837*7c478bd9Sstevel@tonic-gate 	result->sign = aa->sign;
838*7c478bd9Sstevel@tonic-gate }
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate /*
842*7c478bd9Sstevel@tonic-gate  * result = aa/bb   remainder = aa mod bb
843*7c478bd9Sstevel@tonic-gate  * it is assumed that aa and bb are positive
844*7c478bd9Sstevel@tonic-gate  */
845*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
846*7c478bd9Sstevel@tonic-gate big_div_pos_fast(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb)
847*7c478bd9Sstevel@tonic-gate {
848*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
849*7c478bd9Sstevel@tonic-gate 	int i, alen, blen, tlen, rlen, offs;
850*7c478bd9Sstevel@tonic-gate 	uint32_t higha, highb, coeff;
851*7c478bd9Sstevel@tonic-gate 	uint64_t highb64;
852*7c478bd9Sstevel@tonic-gate 	uint32_t *a, *b;
853*7c478bd9Sstevel@tonic-gate 	BIGNUM bbhigh, bblow, tresult, tmp1, tmp2;
854*7c478bd9Sstevel@tonic-gate 	uint32_t tmp1value[BIGTMPSIZE];
855*7c478bd9Sstevel@tonic-gate 	uint32_t tmp2value[BIGTMPSIZE];
856*7c478bd9Sstevel@tonic-gate 	uint32_t tresultvalue[BIGTMPSIZE];
857*7c478bd9Sstevel@tonic-gate 	uint32_t bblowvalue[BIGTMPSIZE];
858*7c478bd9Sstevel@tonic-gate 	uint32_t bbhighvalue[BIGTMPSIZE];
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 	a = aa->value;
861*7c478bd9Sstevel@tonic-gate 	b = bb->value;
862*7c478bd9Sstevel@tonic-gate 	alen = aa->len;
863*7c478bd9Sstevel@tonic-gate 	blen = bb->len;
864*7c478bd9Sstevel@tonic-gate 	while ((alen > 1) && (a[alen - 1] == 0)) alen = alen - 1;
865*7c478bd9Sstevel@tonic-gate 	aa->len = alen;
866*7c478bd9Sstevel@tonic-gate 	while ((blen > 1) && (b[blen - 1] == 0)) blen = blen - 1;
867*7c478bd9Sstevel@tonic-gate 	bb->len = blen;
868*7c478bd9Sstevel@tonic-gate 	if ((blen == 1) && (b[0] == 0))
869*7c478bd9Sstevel@tonic-gate 		return (BIG_DIV_BY_0);
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(aa, bb) < 0) {
872*7c478bd9Sstevel@tonic-gate 		if ((remainder != NULL) &&
873*7c478bd9Sstevel@tonic-gate 		    ((err = big_copy(remainder, aa)) != BIG_OK))
874*7c478bd9Sstevel@tonic-gate 			return (err);
875*7c478bd9Sstevel@tonic-gate 		if (result != NULL) {
876*7c478bd9Sstevel@tonic-gate 			result->len = 1;
877*7c478bd9Sstevel@tonic-gate 			result->sign = 1;
878*7c478bd9Sstevel@tonic-gate 			result->value[0] = 0;
879*7c478bd9Sstevel@tonic-gate 		}
880*7c478bd9Sstevel@tonic-gate 		return (BIG_OK);
881*7c478bd9Sstevel@tonic-gate 	}
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&bblow, blen + 1,
884*7c478bd9Sstevel@tonic-gate 	    bblowvalue, arraysize(bblowvalue))) != BIG_OK)
885*7c478bd9Sstevel@tonic-gate 		return (err);
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&bbhigh, blen + 1,
888*7c478bd9Sstevel@tonic-gate 	    bbhighvalue, arraysize(bbhighvalue))) != BIG_OK)
889*7c478bd9Sstevel@tonic-gate 		goto ret1;
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp1, alen + 2,
892*7c478bd9Sstevel@tonic-gate 	    tmp1value, arraysize(tmp1value))) != BIG_OK)
893*7c478bd9Sstevel@tonic-gate 		goto ret2;
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, blen + 2,
896*7c478bd9Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
897*7c478bd9Sstevel@tonic-gate 		goto ret3;
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tresult, alen - blen + 2,
900*7c478bd9Sstevel@tonic-gate 	    tresultvalue, arraysize(tresultvalue))) != BIG_OK)
901*7c478bd9Sstevel@tonic-gate 		goto ret4;
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 	offs = 0;
904*7c478bd9Sstevel@tonic-gate 	if (blen > 1) {
905*7c478bd9Sstevel@tonic-gate 		highb64 = (((uint64_t)(b[blen - 1])) << 32) |
906*7c478bd9Sstevel@tonic-gate 		    ((uint64_t)(b[blen - 2]));
907*7c478bd9Sstevel@tonic-gate 	} else {
908*7c478bd9Sstevel@tonic-gate 		highb64 = (((uint64_t)(b[blen - 1])) << 32);
909*7c478bd9Sstevel@tonic-gate 	}
910*7c478bd9Sstevel@tonic-gate 	if (highb64 >= 0x1000000000000ull) {
911*7c478bd9Sstevel@tonic-gate 		highb64 = highb64 >> 16;
912*7c478bd9Sstevel@tonic-gate 		offs = 16;
913*7c478bd9Sstevel@tonic-gate 	}
914*7c478bd9Sstevel@tonic-gate 	while ((highb64 & 0x800000000000ull) == 0) {
915*7c478bd9Sstevel@tonic-gate 		highb64 = highb64 << 1;
916*7c478bd9Sstevel@tonic-gate 		offs++;
917*7c478bd9Sstevel@tonic-gate 	}
918*7c478bd9Sstevel@tonic-gate #ifdef	_LP64
919*7c478bd9Sstevel@tonic-gate 	/* LINTED */
920*7c478bd9Sstevel@tonic-gate 	highb = (highb64 >> 32) & 0xffffffff;
921*7c478bd9Sstevel@tonic-gate #else	/* !_LP64 */
922*7c478bd9Sstevel@tonic-gate 	highb = highb64 >> 32;
923*7c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 	big_shiftleft(&bblow, bb, offs);
926*7c478bd9Sstevel@tonic-gate 	if (offs <= 15) {
927*7c478bd9Sstevel@tonic-gate 		big_shiftleft(&bbhigh, &bblow, 16);
928*7c478bd9Sstevel@tonic-gate 	} else {
929*7c478bd9Sstevel@tonic-gate 		big_shiftright(&bbhigh, &bblow, 16);
930*7c478bd9Sstevel@tonic-gate 	}
931*7c478bd9Sstevel@tonic-gate 	if (bbhigh.value[bbhigh.len - 1] == 0) {
932*7c478bd9Sstevel@tonic-gate 		bbhigh.len--;
933*7c478bd9Sstevel@tonic-gate 	} else {
934*7c478bd9Sstevel@tonic-gate 		bbhigh.value[bbhigh.len] = 0;
935*7c478bd9Sstevel@tonic-gate 	}
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 	big_shiftleft(&tmp1, aa, offs);
938*7c478bd9Sstevel@tonic-gate 	rlen = tmp1.len - bblow.len + 1;
939*7c478bd9Sstevel@tonic-gate 	tresult.len = rlen;
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate 	tmp1.len++;
942*7c478bd9Sstevel@tonic-gate 	tlen = tmp1.len;
943*7c478bd9Sstevel@tonic-gate 	tmp1.value[tmp1.len - 1] = 0;
944*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < rlen; i++) {
945*7c478bd9Sstevel@tonic-gate 		higha = (tmp1.value[tlen - 1] << 16) +
946*7c478bd9Sstevel@tonic-gate 		    (tmp1.value[tlen - 2] >> 16);
947*7c478bd9Sstevel@tonic-gate 		coeff = higha / (highb + 1);
948*7c478bd9Sstevel@tonic-gate 		big_mul16_high(&tmp2, &bblow, coeff);
949*7c478bd9Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
950*7c478bd9Sstevel@tonic-gate 		bbhigh.len++;
951*7c478bd9Sstevel@tonic-gate 		while (tmp1.value[tlen - 1] > 0) {
952*7c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
953*7c478bd9Sstevel@tonic-gate 			coeff++;
954*7c478bd9Sstevel@tonic-gate 		}
955*7c478bd9Sstevel@tonic-gate 		bbhigh.len--;
956*7c478bd9Sstevel@tonic-gate 		tlen--;
957*7c478bd9Sstevel@tonic-gate 		tmp1.len--;
958*7c478bd9Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) {
959*7c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bbhigh);
960*7c478bd9Sstevel@tonic-gate 			coeff++;
961*7c478bd9Sstevel@tonic-gate 		}
962*7c478bd9Sstevel@tonic-gate 		tresult.value[rlen - i - 1] = coeff << 16;
963*7c478bd9Sstevel@tonic-gate 		higha = tmp1.value[tlen - 1];
964*7c478bd9Sstevel@tonic-gate 		coeff = higha / (highb + 1);
965*7c478bd9Sstevel@tonic-gate 		big_mul16_low(&tmp2, &bblow, coeff);
966*7c478bd9Sstevel@tonic-gate 		tmp2.len--;
967*7c478bd9Sstevel@tonic-gate 		big_sub_pos_high(&tmp1, &tmp1, &tmp2);
968*7c478bd9Sstevel@tonic-gate 		while (big_cmp_abs_high(&tmp1, &bblow) >= 0) {
969*7c478bd9Sstevel@tonic-gate 			big_sub_pos_high(&tmp1, &tmp1, &bblow);
970*7c478bd9Sstevel@tonic-gate 			coeff++;
971*7c478bd9Sstevel@tonic-gate 		}
972*7c478bd9Sstevel@tonic-gate 		tresult.value[rlen - i - 1] =
973*7c478bd9Sstevel@tonic-gate 		    tresult.value[rlen - i - 1] + coeff;
974*7c478bd9Sstevel@tonic-gate 	}
975*7c478bd9Sstevel@tonic-gate 
976*7c478bd9Sstevel@tonic-gate 	big_shiftright(&tmp1, &tmp1, offs);
977*7c478bd9Sstevel@tonic-gate 
978*7c478bd9Sstevel@tonic-gate 	err = BIG_OK;
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 	if ((remainder != NULL) &&
981*7c478bd9Sstevel@tonic-gate 	    ((err = big_copy(remainder, &tmp1)) != BIG_OK))
982*7c478bd9Sstevel@tonic-gate 		goto ret;
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate 	if (result != NULL)
985*7c478bd9Sstevel@tonic-gate 		err = big_copy(result, &tresult);
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate ret:
988*7c478bd9Sstevel@tonic-gate 	big_finish(&tresult);
989*7c478bd9Sstevel@tonic-gate ret4:
990*7c478bd9Sstevel@tonic-gate 	big_finish(&tmp1);
991*7c478bd9Sstevel@tonic-gate ret3:
992*7c478bd9Sstevel@tonic-gate 	big_finish(&tmp2);
993*7c478bd9Sstevel@tonic-gate ret2:
994*7c478bd9Sstevel@tonic-gate 	big_finish(&bbhigh);
995*7c478bd9Sstevel@tonic-gate ret1:
996*7c478bd9Sstevel@tonic-gate 	big_finish(&bblow);
997*7c478bd9Sstevel@tonic-gate 	return (err);
998*7c478bd9Sstevel@tonic-gate }
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate /*
1001*7c478bd9Sstevel@tonic-gate  * If there is no processor-specific integer implementation of
1002*7c478bd9Sstevel@tonic-gate  * the lower level multiply functions, then this code is provided
1003*7c478bd9Sstevel@tonic-gate  * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and
1004*7c478bd9Sstevel@tonic-gate  * big_sqr_vec().
1005*7c478bd9Sstevel@tonic-gate  *
1006*7c478bd9Sstevel@tonic-gate  * There are two generic implementations.  One that assumes that
1007*7c478bd9Sstevel@tonic-gate  * there is hardware and C compiler support for a 32 x 32 --> 64
1008*7c478bd9Sstevel@tonic-gate  * bit unsigned multiply, but otherwise is not specific to any
1009*7c478bd9Sstevel@tonic-gate  * processor, platform, or ISA.
1010*7c478bd9Sstevel@tonic-gate  *
1011*7c478bd9Sstevel@tonic-gate  * The other makes very few assumptions about hardware capabilities.
1012*7c478bd9Sstevel@tonic-gate  * It does not even assume that there is any implementation of a
1013*7c478bd9Sstevel@tonic-gate  * 32 x 32 --> 64 bit multiply that is accessible to C code and
1014*7c478bd9Sstevel@tonic-gate  * appropriate to use.  It falls constructs 32 x 32 --> 64 bit
1015*7c478bd9Sstevel@tonic-gate  * multiplies from 16 x 16 --> 32 bit multiplies.
1016*7c478bd9Sstevel@tonic-gate  *
1017*7c478bd9Sstevel@tonic-gate  */
1018*7c478bd9Sstevel@tonic-gate 
1019*7c478bd9Sstevel@tonic-gate #if !defined(PSR_MUL)
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate #ifdef UMUL64
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate #define	UNROLL8
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_PREFETCH(R) \
1026*7c478bd9Sstevel@tonic-gate 	p = pf * d; \
1027*7c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[R+1]; \
1028*7c478bd9Sstevel@tonic-gate 	t = p + cy; \
1029*7c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
1030*7c478bd9Sstevel@tonic-gate 	cy = t >> 32
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate #define	MUL_SET_VEC_ROUND_NOPREFETCH(R) \
1033*7c478bd9Sstevel@tonic-gate 	p = pf * d; \
1034*7c478bd9Sstevel@tonic-gate 	t = p + cy; \
1035*7c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
1036*7c478bd9Sstevel@tonic-gate 	cy = t >> 32
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_PREFETCH(R) \
1039*7c478bd9Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
1040*7c478bd9Sstevel@tonic-gate 	p = pf * d; \
1041*7c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[R+1]; \
1042*7c478bd9Sstevel@tonic-gate 	t = p + t + cy; \
1043*7c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
1044*7c478bd9Sstevel@tonic-gate 	cy = t >> 32
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate #define	MUL_ADD_VEC_ROUND_NOPREFETCH(R) \
1047*7c478bd9Sstevel@tonic-gate 	t = (uint64_t)r[R]; \
1048*7c478bd9Sstevel@tonic-gate 	p = pf * d; \
1049*7c478bd9Sstevel@tonic-gate 	t = p + t + cy; \
1050*7c478bd9Sstevel@tonic-gate 	r[R] = (uint32_t)t; \
1051*7c478bd9Sstevel@tonic-gate 	cy = t >> 32
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate #ifdef UNROLL8
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate #define	UNROLL 8
1056*7c478bd9Sstevel@tonic-gate 
1057*7c478bd9Sstevel@tonic-gate /*
1058*7c478bd9Sstevel@tonic-gate  * r = a * b
1059*7c478bd9Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
1060*7c478bd9Sstevel@tonic-gate  */
1061*7c478bd9Sstevel@tonic-gate 
1062*7c478bd9Sstevel@tonic-gate uint32_t
1063*7c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
1064*7c478bd9Sstevel@tonic-gate {
1065*7c478bd9Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate 	if (len == 0)
1068*7c478bd9Sstevel@tonic-gate 		return (0);
1069*7c478bd9Sstevel@tonic-gate 	cy = 0;
1070*7c478bd9Sstevel@tonic-gate 	d = (uint64_t)b;
1071*7c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[0];
1072*7c478bd9Sstevel@tonic-gate 	while (len > UNROLL) {
1073*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
1074*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
1075*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
1076*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
1077*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
1078*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
1079*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
1080*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(7);
1081*7c478bd9Sstevel@tonic-gate 		r += UNROLL;
1082*7c478bd9Sstevel@tonic-gate 		a += UNROLL;
1083*7c478bd9Sstevel@tonic-gate 		len -= UNROLL;
1084*7c478bd9Sstevel@tonic-gate 	}
1085*7c478bd9Sstevel@tonic-gate 	if (len == UNROLL) {
1086*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
1087*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(1);
1088*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(2);
1089*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(3);
1090*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(4);
1091*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(5);
1092*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(6);
1093*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(7);
1094*7c478bd9Sstevel@tonic-gate 		return ((uint32_t)cy);
1095*7c478bd9Sstevel@tonic-gate 	}
1096*7c478bd9Sstevel@tonic-gate 	while (len > 1) {
1097*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_PREFETCH(0);
1098*7c478bd9Sstevel@tonic-gate 		++r;
1099*7c478bd9Sstevel@tonic-gate 		++a;
1100*7c478bd9Sstevel@tonic-gate 		--len;
1101*7c478bd9Sstevel@tonic-gate 	}
1102*7c478bd9Sstevel@tonic-gate 	if (len > 0) {
1103*7c478bd9Sstevel@tonic-gate 		MUL_SET_VEC_ROUND_NOPREFETCH(0);
1104*7c478bd9Sstevel@tonic-gate 	}
1105*7c478bd9Sstevel@tonic-gate 	return ((uint32_t)cy);
1106*7c478bd9Sstevel@tonic-gate }
1107*7c478bd9Sstevel@tonic-gate 
1108*7c478bd9Sstevel@tonic-gate /*
1109*7c478bd9Sstevel@tonic-gate  * r += a * b
1110*7c478bd9Sstevel@tonic-gate  * where r and a are vectors; b is a single 32-bit digit
1111*7c478bd9Sstevel@tonic-gate  */
1112*7c478bd9Sstevel@tonic-gate 
1113*7c478bd9Sstevel@tonic-gate uint32_t
1114*7c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b)
1115*7c478bd9Sstevel@tonic-gate {
1116*7c478bd9Sstevel@tonic-gate 	uint64_t d, pf, p, t, cy;
1117*7c478bd9Sstevel@tonic-gate 
1118*7c478bd9Sstevel@tonic-gate 	if (len == 0)
1119*7c478bd9Sstevel@tonic-gate 		return (0);
1120*7c478bd9Sstevel@tonic-gate 	cy = 0;
1121*7c478bd9Sstevel@tonic-gate 	d = (uint64_t)b;
1122*7c478bd9Sstevel@tonic-gate 	pf = (uint64_t)a[0];
1123*7c478bd9Sstevel@tonic-gate 	while (len > 8) {
1124*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
1125*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
1126*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
1127*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
1128*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
1129*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
1130*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
1131*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(7);
1132*7c478bd9Sstevel@tonic-gate 		r += 8;
1133*7c478bd9Sstevel@tonic-gate 		a += 8;
1134*7c478bd9Sstevel@tonic-gate 		len -= 8;
1135*7c478bd9Sstevel@tonic-gate 	}
1136*7c478bd9Sstevel@tonic-gate 	if (len == 8) {
1137*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
1138*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(1);
1139*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(2);
1140*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(3);
1141*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(4);
1142*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(5);
1143*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(6);
1144*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(7);
1145*7c478bd9Sstevel@tonic-gate 		return ((uint32_t)cy);
1146*7c478bd9Sstevel@tonic-gate 	}
1147*7c478bd9Sstevel@tonic-gate 	while (len > 1) {
1148*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_PREFETCH(0);
1149*7c478bd9Sstevel@tonic-gate 		++r;
1150*7c478bd9Sstevel@tonic-gate 		++a;
1151*7c478bd9Sstevel@tonic-gate 		--len;
1152*7c478bd9Sstevel@tonic-gate 	}
1153*7c478bd9Sstevel@tonic-gate 	if (len > 0) {
1154*7c478bd9Sstevel@tonic-gate 		MUL_ADD_VEC_ROUND_NOPREFETCH(0);
1155*7c478bd9Sstevel@tonic-gate 	}
1156*7c478bd9Sstevel@tonic-gate 	return ((uint32_t)cy);
1157*7c478bd9Sstevel@tonic-gate }
1158*7c478bd9Sstevel@tonic-gate #endif /* UNROLL8 */
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate void
1161*7c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
1162*7c478bd9Sstevel@tonic-gate {
1163*7c478bd9Sstevel@tonic-gate 	uint32_t *tr, *ta;
1164*7c478bd9Sstevel@tonic-gate 	int tlen, row, col;
1165*7c478bd9Sstevel@tonic-gate 	uint64_t p, s, t, t2, cy;
1166*7c478bd9Sstevel@tonic-gate 	uint32_t d;
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate 	tr = r + 1;
1169*7c478bd9Sstevel@tonic-gate 	ta = a;
1170*7c478bd9Sstevel@tonic-gate 	tlen = len - 1;
1171*7c478bd9Sstevel@tonic-gate 	tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]);
1172*7c478bd9Sstevel@tonic-gate 	while (--tlen > 0) {
1173*7c478bd9Sstevel@tonic-gate 		tr += 2;
1174*7c478bd9Sstevel@tonic-gate 		++ta;
1175*7c478bd9Sstevel@tonic-gate 		tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]);
1176*7c478bd9Sstevel@tonic-gate 	}
1177*7c478bd9Sstevel@tonic-gate 	s = (uint64_t)a[0];
1178*7c478bd9Sstevel@tonic-gate 	s = s * s;
1179*7c478bd9Sstevel@tonic-gate 	r[0] = (uint32_t)s;
1180*7c478bd9Sstevel@tonic-gate 	cy = s >> 32;
1181*7c478bd9Sstevel@tonic-gate 	p = ((uint64_t)r[1] << 1) + cy;
1182*7c478bd9Sstevel@tonic-gate 	r[1] = (uint32_t)p;
1183*7c478bd9Sstevel@tonic-gate 	cy = p >> 32;
1184*7c478bd9Sstevel@tonic-gate 	row = 1;
1185*7c478bd9Sstevel@tonic-gate 	col = 2;
1186*7c478bd9Sstevel@tonic-gate 	while (row < len) {
1187*7c478bd9Sstevel@tonic-gate 		s = (uint64_t)a[row];
1188*7c478bd9Sstevel@tonic-gate 		s = s * s;
1189*7c478bd9Sstevel@tonic-gate 		p = (uint64_t)r[col] << 1;
1190*7c478bd9Sstevel@tonic-gate 		t = p + s;
1191*7c478bd9Sstevel@tonic-gate 		d = (uint32_t)t;
1192*7c478bd9Sstevel@tonic-gate 		t2 = (uint64_t)d + cy;
1193*7c478bd9Sstevel@tonic-gate 		r[col] = (uint32_t)t2;
1194*7c478bd9Sstevel@tonic-gate 		cy = (t >> 32) + (t2 >> 32);
1195*7c478bd9Sstevel@tonic-gate 		if (row == len - 1)
1196*7c478bd9Sstevel@tonic-gate 			break;
1197*7c478bd9Sstevel@tonic-gate 		p = ((uint64_t)r[col+1] << 1) + cy;
1198*7c478bd9Sstevel@tonic-gate 		r[col+1] = (uint32_t)p;
1199*7c478bd9Sstevel@tonic-gate 		cy = p >> 32;
1200*7c478bd9Sstevel@tonic-gate 		++row;
1201*7c478bd9Sstevel@tonic-gate 		col += 2;
1202*7c478bd9Sstevel@tonic-gate 	}
1203*7c478bd9Sstevel@tonic-gate 	r[col+1] = (uint32_t)cy;
1204*7c478bd9Sstevel@tonic-gate }
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate #else /* ! UMUL64 */
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate /*
1209*7c478bd9Sstevel@tonic-gate  * r = r + a * digit, r and a are vectors of length len
1210*7c478bd9Sstevel@tonic-gate  * returns the carry digit
1211*7c478bd9Sstevel@tonic-gate  */
1212*7c478bd9Sstevel@tonic-gate uint32_t
1213*7c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
1214*7c478bd9Sstevel@tonic-gate {
1215*7c478bd9Sstevel@tonic-gate 	uint32_t cy, cy1, retcy, dlow, dhigh;
1216*7c478bd9Sstevel@tonic-gate 	int i;
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate 	cy1 = 0;
1219*7c478bd9Sstevel@tonic-gate 	dlow = digit & 0xffff;
1220*7c478bd9Sstevel@tonic-gate 	dhigh = digit >> 16;
1221*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
1222*7c478bd9Sstevel@tonic-gate 		cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff);
1223*7c478bd9Sstevel@tonic-gate 		cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16);
1224*7c478bd9Sstevel@tonic-gate 		r[i] = (cy & 0xffff) | (cy1 << 16);
1225*7c478bd9Sstevel@tonic-gate 	}
1226*7c478bd9Sstevel@tonic-gate 	retcy = cy1 >> 16;
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 	cy1 = r[0] & 0xffff;
1229*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < len - 1; i++) {
1230*7c478bd9Sstevel@tonic-gate 		cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16);
1231*7c478bd9Sstevel@tonic-gate 		r[i] = (cy1 & 0xffff) | (cy << 16);
1232*7c478bd9Sstevel@tonic-gate 		cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff);
1233*7c478bd9Sstevel@tonic-gate 	}
1234*7c478bd9Sstevel@tonic-gate 	cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16);
1235*7c478bd9Sstevel@tonic-gate 	r[len - 1] = (cy1 & 0xffff) | (cy << 16);
1236*7c478bd9Sstevel@tonic-gate 	retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy;
1237*7c478bd9Sstevel@tonic-gate 
1238*7c478bd9Sstevel@tonic-gate 	return (retcy);
1239*7c478bd9Sstevel@tonic-gate }
1240*7c478bd9Sstevel@tonic-gate 
1241*7c478bd9Sstevel@tonic-gate /*
1242*7c478bd9Sstevel@tonic-gate  * r = a * digit, r and a are vectors of length len
1243*7c478bd9Sstevel@tonic-gate  * returns the carry digit
1244*7c478bd9Sstevel@tonic-gate  */
1245*7c478bd9Sstevel@tonic-gate uint32_t
1246*7c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit)
1247*7c478bd9Sstevel@tonic-gate {
1248*7c478bd9Sstevel@tonic-gate 	return (big_mul_add_vec(r, a, len, digit));
1249*7c478bd9Sstevel@tonic-gate }
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate void
1252*7c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len)
1253*7c478bd9Sstevel@tonic-gate {
1254*7c478bd9Sstevel@tonic-gate 	int i;
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate 	r[len] = big_mul_set_vec(r, a, len, a[0]);
1257*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < len; ++i)
1258*7c478bd9Sstevel@tonic-gate 		r[len + i] = big_mul_add_vec(r+i, a, len, a[i]);
1259*7c478bd9Sstevel@tonic-gate }
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate #endif /* UMUL64 */
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate void
1264*7c478bd9Sstevel@tonic-gate big_mul_vec(uint32_t *r, uint32_t *a, int alen, uint32_t *b, int blen)
1265*7c478bd9Sstevel@tonic-gate {
1266*7c478bd9Sstevel@tonic-gate 	int i;
1267*7c478bd9Sstevel@tonic-gate 
1268*7c478bd9Sstevel@tonic-gate 	r[alen] = big_mul_set_vec(r, a, alen, b[0]);
1269*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < blen; ++i)
1270*7c478bd9Sstevel@tonic-gate 		r[alen + i] = big_mul_add_vec(r+i, a, alen, b[i]);
1271*7c478bd9Sstevel@tonic-gate }
1272*7c478bd9Sstevel@tonic-gate 
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate #endif /* ! PSR_MUL */
1275*7c478bd9Sstevel@tonic-gate 
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate /*
1278*7c478bd9Sstevel@tonic-gate  * result = aa * bb  result->value should be big enough to hold the result
1279*7c478bd9Sstevel@tonic-gate  *
1280*7c478bd9Sstevel@tonic-gate  * Implementation: Standard grammar school algorithm
1281*7c478bd9Sstevel@tonic-gate  *
1282*7c478bd9Sstevel@tonic-gate  */
1283*7c478bd9Sstevel@tonic-gate 
1284*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1285*7c478bd9Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb)
1286*7c478bd9Sstevel@tonic-gate {
1287*7c478bd9Sstevel@tonic-gate 	BIGNUM tmp1;
1288*7c478bd9Sstevel@tonic-gate 	uint32_t tmp1value[BIGTMPSIZE];
1289*7c478bd9Sstevel@tonic-gate 	uint32_t *r, *t, *a, *b;
1290*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
1291*7c478bd9Sstevel@tonic-gate 	int i, alen, blen, rsize, sign, diff;
1292*7c478bd9Sstevel@tonic-gate 
1293*7c478bd9Sstevel@tonic-gate 	if (aa == bb) {
1294*7c478bd9Sstevel@tonic-gate 		diff = 0;
1295*7c478bd9Sstevel@tonic-gate 	} else {
1296*7c478bd9Sstevel@tonic-gate 		diff = big_cmp_abs(aa, bb);
1297*7c478bd9Sstevel@tonic-gate 		if (diff < 0) {
1298*7c478bd9Sstevel@tonic-gate 			BIGNUM *tt;
1299*7c478bd9Sstevel@tonic-gate 			tt = aa;
1300*7c478bd9Sstevel@tonic-gate 			aa = bb;
1301*7c478bd9Sstevel@tonic-gate 			bb = tt;
1302*7c478bd9Sstevel@tonic-gate 		}
1303*7c478bd9Sstevel@tonic-gate 	}
1304*7c478bd9Sstevel@tonic-gate 	a = aa->value;
1305*7c478bd9Sstevel@tonic-gate 	b = bb->value;
1306*7c478bd9Sstevel@tonic-gate 	alen = aa->len;
1307*7c478bd9Sstevel@tonic-gate 	blen = bb->len;
1308*7c478bd9Sstevel@tonic-gate 	while ((alen > 1) && (a[alen - 1] == 0)) alen--;
1309*7c478bd9Sstevel@tonic-gate 	aa->len = alen;
1310*7c478bd9Sstevel@tonic-gate 	while ((blen > 1) && (b[blen - 1] == 0)) blen--;
1311*7c478bd9Sstevel@tonic-gate 	bb->len = blen;
1312*7c478bd9Sstevel@tonic-gate 
1313*7c478bd9Sstevel@tonic-gate 	rsize = alen + blen;
1314*7c478bd9Sstevel@tonic-gate 	if (result->size < rsize) {
1315*7c478bd9Sstevel@tonic-gate 		err = big_extend(result, rsize);
1316*7c478bd9Sstevel@tonic-gate 		if (err != BIG_OK)
1317*7c478bd9Sstevel@tonic-gate 			return (err);
1318*7c478bd9Sstevel@tonic-gate 		/* aa or bb might be an alias to result */
1319*7c478bd9Sstevel@tonic-gate 		a = aa->value;
1320*7c478bd9Sstevel@tonic-gate 		b = bb->value;
1321*7c478bd9Sstevel@tonic-gate 	}
1322*7c478bd9Sstevel@tonic-gate 	r = result->value;
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 	if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) {
1325*7c478bd9Sstevel@tonic-gate 		result->len = 1;
1326*7c478bd9Sstevel@tonic-gate 		result->sign = 1;
1327*7c478bd9Sstevel@tonic-gate 		r[0] = 0;
1328*7c478bd9Sstevel@tonic-gate 		return (BIG_OK);
1329*7c478bd9Sstevel@tonic-gate 	}
1330*7c478bd9Sstevel@tonic-gate 	sign = aa->sign * bb->sign;
1331*7c478bd9Sstevel@tonic-gate 	if ((alen == 1) && (a[0] == 1)) {
1332*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < blen; i++) r[i] = b[i];
1333*7c478bd9Sstevel@tonic-gate 		result->len = blen;
1334*7c478bd9Sstevel@tonic-gate 		result->sign = sign;
1335*7c478bd9Sstevel@tonic-gate 		return (BIG_OK);
1336*7c478bd9Sstevel@tonic-gate 	}
1337*7c478bd9Sstevel@tonic-gate 	if ((blen == 1) && (b[0] == 1)) {
1338*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < alen; i++) r[i] = a[i];
1339*7c478bd9Sstevel@tonic-gate 		result->len = alen;
1340*7c478bd9Sstevel@tonic-gate 		result->sign = sign;
1341*7c478bd9Sstevel@tonic-gate 		return (BIG_OK);
1342*7c478bd9Sstevel@tonic-gate 	}
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate 	err = big_init1(&tmp1, rsize, tmp1value, arraysize(tmp1value));
1345*7c478bd9Sstevel@tonic-gate 	if (err != BIG_OK)
1346*7c478bd9Sstevel@tonic-gate 		return (err);
1347*7c478bd9Sstevel@tonic-gate 	t = tmp1.value;
1348*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < rsize; i++) t[i] = 0;
1349*7c478bd9Sstevel@tonic-gate 
1350*7c478bd9Sstevel@tonic-gate 	if (diff == 0 && alen > 2)
1351*7c478bd9Sstevel@tonic-gate 		BIG_SQR_VEC(t, a, alen);
1352*7c478bd9Sstevel@tonic-gate 	else if (blen > 0)
1353*7c478bd9Sstevel@tonic-gate 		BIG_MUL_VEC(t, a, alen, b, blen);
1354*7c478bd9Sstevel@tonic-gate 	if (t[rsize - 1] == 0)
1355*7c478bd9Sstevel@tonic-gate 		--rsize;
1356*7c478bd9Sstevel@tonic-gate 	tmp1.len = rsize;
1357*7c478bd9Sstevel@tonic-gate 	if ((err = big_copy(result, &tmp1)) != BIG_OK)
1358*7c478bd9Sstevel@tonic-gate 		return (err);
1359*7c478bd9Sstevel@tonic-gate 
1360*7c478bd9Sstevel@tonic-gate 	result->sign = sign;
1361*7c478bd9Sstevel@tonic-gate 
1362*7c478bd9Sstevel@tonic-gate 	if (tmp1.malloced) big_finish(&tmp1);
1363*7c478bd9Sstevel@tonic-gate 
1364*7c478bd9Sstevel@tonic-gate 	return (BIG_OK);
1365*7c478bd9Sstevel@tonic-gate }
1366*7c478bd9Sstevel@tonic-gate 
1367*7c478bd9Sstevel@tonic-gate 
1368*7c478bd9Sstevel@tonic-gate /*
1369*7c478bd9Sstevel@tonic-gate  * caller must ensure that  a < n,  b < n  and  ret->size >=  2 * n->len + 1
1370*7c478bd9Sstevel@tonic-gate  * and that ret is not n
1371*7c478bd9Sstevel@tonic-gate  */
1372*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1373*7c478bd9Sstevel@tonic-gate big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, uint32_t n0)
1374*7c478bd9Sstevel@tonic-gate {
1375*7c478bd9Sstevel@tonic-gate 	int i, j, nlen, needsubtract;
1376*7c478bd9Sstevel@tonic-gate 	uint32_t *nn, *rr;
1377*7c478bd9Sstevel@tonic-gate 	uint32_t digit, c;
1378*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
1379*7c478bd9Sstevel@tonic-gate 
1380*7c478bd9Sstevel@tonic-gate 	nlen = n->len;
1381*7c478bd9Sstevel@tonic-gate 	nn = n->value;
1382*7c478bd9Sstevel@tonic-gate 
1383*7c478bd9Sstevel@tonic-gate 	rr = ret->value;
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate 	if ((err = big_mul(ret, a, b)) != BIG_OK)
1386*7c478bd9Sstevel@tonic-gate 		return (err);
1387*7c478bd9Sstevel@tonic-gate 
1388*7c478bd9Sstevel@tonic-gate 	rr = ret->value;
1389*7c478bd9Sstevel@tonic-gate 	for (i = ret->len; i < 2 * nlen + 1; i++) rr[i] = 0;
1390*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nlen; i++) {
1391*7c478bd9Sstevel@tonic-gate 		digit = rr[i];
1392*7c478bd9Sstevel@tonic-gate 		digit = digit * n0;
1393*7c478bd9Sstevel@tonic-gate 
1394*7c478bd9Sstevel@tonic-gate 		c = BIG_MUL_ADD_VEC(rr + i, nn, nlen, digit);
1395*7c478bd9Sstevel@tonic-gate 		j = i + nlen;
1396*7c478bd9Sstevel@tonic-gate 		rr[j] += c;
1397*7c478bd9Sstevel@tonic-gate 		while (rr[j] < c) {
1398*7c478bd9Sstevel@tonic-gate 			rr[j + 1] += 1;
1399*7c478bd9Sstevel@tonic-gate 			j++;
1400*7c478bd9Sstevel@tonic-gate 			c = 1;
1401*7c478bd9Sstevel@tonic-gate 		}
1402*7c478bd9Sstevel@tonic-gate 	}
1403*7c478bd9Sstevel@tonic-gate 
1404*7c478bd9Sstevel@tonic-gate 	needsubtract = 0;
1405*7c478bd9Sstevel@tonic-gate 	if ((rr[2 * nlen]  != 0))
1406*7c478bd9Sstevel@tonic-gate 		needsubtract = 1;
1407*7c478bd9Sstevel@tonic-gate 	else {
1408*7c478bd9Sstevel@tonic-gate 		for (i = 2 * nlen - 1; i >= nlen; i--) {
1409*7c478bd9Sstevel@tonic-gate 			if (rr[i] > nn[i - nlen]) {
1410*7c478bd9Sstevel@tonic-gate 				needsubtract = 1;
1411*7c478bd9Sstevel@tonic-gate 				break;
1412*7c478bd9Sstevel@tonic-gate 			} else if (rr[i] < nn[i - nlen]) break;
1413*7c478bd9Sstevel@tonic-gate 		}
1414*7c478bd9Sstevel@tonic-gate 	}
1415*7c478bd9Sstevel@tonic-gate 	if (needsubtract)
1416*7c478bd9Sstevel@tonic-gate 		big_sub_vec(rr, rr + nlen, nn, nlen);
1417*7c478bd9Sstevel@tonic-gate 	else {
1418*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nlen; i++)
1419*7c478bd9Sstevel@tonic-gate 			rr[i] = rr[i + nlen];
1420*7c478bd9Sstevel@tonic-gate 	}
1421*7c478bd9Sstevel@tonic-gate 	for (i = nlen - 1; (i >= 0) && (rr[i] == 0); i--);
1422*7c478bd9Sstevel@tonic-gate 	ret->len = i+1;
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate 	return (BIG_OK);
1425*7c478bd9Sstevel@tonic-gate }
1426*7c478bd9Sstevel@tonic-gate 
1427*7c478bd9Sstevel@tonic-gate uint32_t
1428*7c478bd9Sstevel@tonic-gate big_n0(uint32_t n)
1429*7c478bd9Sstevel@tonic-gate {
1430*7c478bd9Sstevel@tonic-gate 	int i;
1431*7c478bd9Sstevel@tonic-gate 	uint32_t result, tmp;
1432*7c478bd9Sstevel@tonic-gate 
1433*7c478bd9Sstevel@tonic-gate 	result = 0;
1434*7c478bd9Sstevel@tonic-gate 	tmp = 0xffffffff;
1435*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 32; i++) {
1436*7c478bd9Sstevel@tonic-gate 		if ((tmp & 1) == 1) {
1437*7c478bd9Sstevel@tonic-gate 			result = (result >> 1) | 0x80000000;
1438*7c478bd9Sstevel@tonic-gate 			tmp = tmp - n;
1439*7c478bd9Sstevel@tonic-gate 		} else  result = (result>>1);
1440*7c478bd9Sstevel@tonic-gate 		tmp = tmp >> 1;
1441*7c478bd9Sstevel@tonic-gate 	}
1442*7c478bd9Sstevel@tonic-gate 
1443*7c478bd9Sstevel@tonic-gate 	return (result);
1444*7c478bd9Sstevel@tonic-gate }
1445*7c478bd9Sstevel@tonic-gate 
1446*7c478bd9Sstevel@tonic-gate 
1447*7c478bd9Sstevel@tonic-gate int
1448*7c478bd9Sstevel@tonic-gate big_numbits(BIGNUM *n)
1449*7c478bd9Sstevel@tonic-gate {
1450*7c478bd9Sstevel@tonic-gate 	int i, j;
1451*7c478bd9Sstevel@tonic-gate 	uint32_t t;
1452*7c478bd9Sstevel@tonic-gate 
1453*7c478bd9Sstevel@tonic-gate 	for (i = n->len - 1; i > 0; i--)
1454*7c478bd9Sstevel@tonic-gate 		if (n->value[i] != 0) break;
1455*7c478bd9Sstevel@tonic-gate 	t = n->value[i];
1456*7c478bd9Sstevel@tonic-gate 	for (j = 32; j > 0; j--) {
1457*7c478bd9Sstevel@tonic-gate 		if ((t & 0x80000000) == 0)
1458*7c478bd9Sstevel@tonic-gate 			t = t << 1;
1459*7c478bd9Sstevel@tonic-gate 		else
1460*7c478bd9Sstevel@tonic-gate 			return (32 * i + j);
1461*7c478bd9Sstevel@tonic-gate 	}
1462*7c478bd9Sstevel@tonic-gate 	return (0);
1463*7c478bd9Sstevel@tonic-gate }
1464*7c478bd9Sstevel@tonic-gate 
1465*7c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */
1466*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1467*7c478bd9Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n)
1468*7c478bd9Sstevel@tonic-gate {
1469*7c478bd9Sstevel@tonic-gate 	BIGNUM rr;
1470*7c478bd9Sstevel@tonic-gate 	uint32_t rrvalue[BIGTMPSIZE];
1471*7c478bd9Sstevel@tonic-gate 	int len, i;
1472*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
1473*7c478bd9Sstevel@tonic-gate 
1474*7c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
1475*7c478bd9Sstevel@tonic-gate 	len = n->len;
1476*7c478bd9Sstevel@tonic-gate 
1477*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1,
1478*7c478bd9Sstevel@tonic-gate 	    rrvalue, arraysize(rrvalue))) != BIG_OK)
1479*7c478bd9Sstevel@tonic-gate 		return (err);
1480*7c478bd9Sstevel@tonic-gate 
1481*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 2 * len; i++) rr.value[i] = 0;
1482*7c478bd9Sstevel@tonic-gate 	rr.value[2 * len] = 1;
1483*7c478bd9Sstevel@tonic-gate 	rr.len = 2 * len + 1;
1484*7c478bd9Sstevel@tonic-gate 	if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK)
1485*7c478bd9Sstevel@tonic-gate 		goto ret;
1486*7c478bd9Sstevel@tonic-gate 	err = big_copy(result, &rr);
1487*7c478bd9Sstevel@tonic-gate ret:
1488*7c478bd9Sstevel@tonic-gate 	if (rr.malloced) big_finish(&rr);
1489*7c478bd9Sstevel@tonic-gate 	return (err);
1490*7c478bd9Sstevel@tonic-gate }
1491*7c478bd9Sstevel@tonic-gate 
1492*7c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */
1493*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1494*7c478bd9Sstevel@tonic-gate big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, uint32_t n0, BIGNUM *n_rr)
1495*7c478bd9Sstevel@tonic-gate {
1496*7c478bd9Sstevel@tonic-gate 	BIGNUM rr;
1497*7c478bd9Sstevel@tonic-gate 	uint32_t rrvalue[BIGTMPSIZE];
1498*7c478bd9Sstevel@tonic-gate 	int len, i;
1499*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
1500*7c478bd9Sstevel@tonic-gate 
1501*7c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
1502*7c478bd9Sstevel@tonic-gate 	len = n->len;
1503*7c478bd9Sstevel@tonic-gate 
1504*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue)))
1505*7c478bd9Sstevel@tonic-gate 	    != BIG_OK)
1506*7c478bd9Sstevel@tonic-gate 			return (err);
1507*7c478bd9Sstevel@tonic-gate 
1508*7c478bd9Sstevel@tonic-gate 	if (n_rr == NULL) {
1509*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < 2 * len; i++) rr.value[i] = 0;
1510*7c478bd9Sstevel@tonic-gate 		rr.value[2 * len] = 1;
1511*7c478bd9Sstevel@tonic-gate 		rr.len = 2 * len + 1;
1512*7c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK)
1513*7c478bd9Sstevel@tonic-gate 			goto ret;
1514*7c478bd9Sstevel@tonic-gate 		n_rr = &rr;
1515*7c478bd9Sstevel@tonic-gate 	}
1516*7c478bd9Sstevel@tonic-gate 
1517*7c478bd9Sstevel@tonic-gate 	if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK)
1518*7c478bd9Sstevel@tonic-gate 		goto ret;
1519*7c478bd9Sstevel@tonic-gate 	err = big_copy(result, &rr);
1520*7c478bd9Sstevel@tonic-gate ret:
1521*7c478bd9Sstevel@tonic-gate 	if (rr.malloced) big_finish(&rr);
1522*7c478bd9Sstevel@tonic-gate 	return (err);
1523*7c478bd9Sstevel@tonic-gate }
1524*7c478bd9Sstevel@tonic-gate 
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate #define	MAX_EXP_BIT_GROUP_SIZE 6
1527*7c478bd9Sstevel@tonic-gate #define	APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1))
1528*7c478bd9Sstevel@tonic-gate 
1529*7c478bd9Sstevel@tonic-gate #ifdef USE_FLOATING_POINT
1530*7c478bd9Sstevel@tonic-gate 
1531*7c478bd9Sstevel@tonic-gate /*
1532*7c478bd9Sstevel@tonic-gate  * This version makes use of floating point for performance.
1533*7c478bd9Sstevel@tonic-gate  */
1534*7c478bd9Sstevel@tonic-gate static BIG_ERR_CODE
1535*7c478bd9Sstevel@tonic-gate _big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
1536*7c478bd9Sstevel@tonic-gate {
1537*7c478bd9Sstevel@tonic-gate 	BIGNUM ma, tmp, rr;
1538*7c478bd9Sstevel@tonic-gate 	uint32_t mavalue[BIGTMPSIZE];
1539*7c478bd9Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
1540*7c478bd9Sstevel@tonic-gate 	uint32_t rrvalue[BIGTMPSIZE];
1541*7c478bd9Sstevel@tonic-gate 	int i, j, k, l, m, p, bit, bitind, bitcount, nlen;
1542*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
1543*7c478bd9Sstevel@tonic-gate 	uint32_t n0;
1544*7c478bd9Sstevel@tonic-gate 	double dn0;
1545*7c478bd9Sstevel@tonic-gate 	double *dn, *dt, *d16r, *d32r;
1546*7c478bd9Sstevel@tonic-gate 	uint32_t *nint, *prod;
1547*7c478bd9Sstevel@tonic-gate 	double *apowers[APOWERS_MAX_SIZE];
1548*7c478bd9Sstevel@tonic-gate 	int nbits, groupbits, apowerssize;
1549*7c478bd9Sstevel@tonic-gate 
1550*7c478bd9Sstevel@tonic-gate 	nbits = big_numbits(e);
1551*7c478bd9Sstevel@tonic-gate 	if (nbits < 50) {
1552*7c478bd9Sstevel@tonic-gate 		groupbits = 1;
1553*7c478bd9Sstevel@tonic-gate 		apowerssize = 1;
1554*7c478bd9Sstevel@tonic-gate 	} else {
1555*7c478bd9Sstevel@tonic-gate 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
1556*7c478bd9Sstevel@tonic-gate 		apowerssize = 1 << (groupbits - 1);
1557*7c478bd9Sstevel@tonic-gate 	}
1558*7c478bd9Sstevel@tonic-gate 
1559*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue)))	!=
1560*7c478bd9Sstevel@tonic-gate 	    BIG_OK)
1561*7c478bd9Sstevel@tonic-gate 		return (err);
1562*7c478bd9Sstevel@tonic-gate 	ma.len = 1;
1563*7c478bd9Sstevel@tonic-gate 	ma.value[0] = 0;
1564*7c478bd9Sstevel@tonic-gate 
1565*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len + 1,
1566*7c478bd9Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
1567*7c478bd9Sstevel@tonic-gate 		goto ret1;
1568*7c478bd9Sstevel@tonic-gate 	tmp.len = 1;
1569*7c478bd9Sstevel@tonic-gate 	tmp.value[0] = 0;
1570*7c478bd9Sstevel@tonic-gate 
1571*7c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
1572*7c478bd9Sstevel@tonic-gate 	if (n_rr == NULL) {
1573*7c478bd9Sstevel@tonic-gate 		if ((err = big_init1(&rr, 2 * n->len + 1,
1574*7c478bd9Sstevel@tonic-gate 		    rrvalue, arraysize(rrvalue))) != BIG_OK)
1575*7c478bd9Sstevel@tonic-gate 			goto ret2;
1576*7c478bd9Sstevel@tonic-gate 		if (big_mont_rr(&rr, n) != BIG_OK)
1577*7c478bd9Sstevel@tonic-gate 			goto ret2;
1578*7c478bd9Sstevel@tonic-gate 		n_rr = &rr;
1579*7c478bd9Sstevel@tonic-gate 	}
1580*7c478bd9Sstevel@tonic-gate 
1581*7c478bd9Sstevel@tonic-gate 	n0 = big_n0(n->value[0]);
1582*7c478bd9Sstevel@tonic-gate 
1583*7c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(a, n) > 0) {
1584*7c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK)
1585*7c478bd9Sstevel@tonic-gate 			goto ret2;
1586*7c478bd9Sstevel@tonic-gate 		err = big_mont_conv(&ma, &ma, n, n0, n_rr);
1587*7c478bd9Sstevel@tonic-gate 	} else {
1588*7c478bd9Sstevel@tonic-gate 		err = big_mont_conv(&ma, a, n, n0, n_rr);
1589*7c478bd9Sstevel@tonic-gate 	}
1590*7c478bd9Sstevel@tonic-gate 	if (err != BIG_OK)
1591*7c478bd9Sstevel@tonic-gate 		goto ret3;
1592*7c478bd9Sstevel@tonic-gate 
1593*7c478bd9Sstevel@tonic-gate 	tmp.len = 1;
1594*7c478bd9Sstevel@tonic-gate 	tmp.value[0] = 1;
1595*7c478bd9Sstevel@tonic-gate 	if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK)
1596*7c478bd9Sstevel@tonic-gate 		goto ret3;
1597*7c478bd9Sstevel@tonic-gate 
1598*7c478bd9Sstevel@tonic-gate 	nlen = n->len;
1599*7c478bd9Sstevel@tonic-gate 	dn0 = (double)(n0 & 0xffff);
1600*7c478bd9Sstevel@tonic-gate 
1601*7c478bd9Sstevel@tonic-gate 	dn = dt = d16r = d32r = NULL;
1602*7c478bd9Sstevel@tonic-gate 	nint = prod = NULL;
1603*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
1604*7c478bd9Sstevel@tonic-gate 		apowers[i] = NULL;
1605*7c478bd9Sstevel@tonic-gate 	}
1606*7c478bd9Sstevel@tonic-gate 
1607*7c478bd9Sstevel@tonic-gate 	if ((dn = big_malloc(nlen * sizeof (double))) == NULL) {
1608*7c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
1609*7c478bd9Sstevel@tonic-gate 		goto ret;
1610*7c478bd9Sstevel@tonic-gate 	}
1611*7c478bd9Sstevel@tonic-gate 	if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) {
1612*7c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
1613*7c478bd9Sstevel@tonic-gate 		goto ret;
1614*7c478bd9Sstevel@tonic-gate 	}
1615*7c478bd9Sstevel@tonic-gate 	if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) {
1616*7c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
1617*7c478bd9Sstevel@tonic-gate 		goto ret;
1618*7c478bd9Sstevel@tonic-gate 	}
1619*7c478bd9Sstevel@tonic-gate 	if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) {
1620*7c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
1621*7c478bd9Sstevel@tonic-gate 		goto ret;
1622*7c478bd9Sstevel@tonic-gate 	}
1623*7c478bd9Sstevel@tonic-gate 	if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) {
1624*7c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
1625*7c478bd9Sstevel@tonic-gate 		goto ret;
1626*7c478bd9Sstevel@tonic-gate 	}
1627*7c478bd9Sstevel@tonic-gate 	if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) {
1628*7c478bd9Sstevel@tonic-gate 		err = BIG_NO_MEM;
1629*7c478bd9Sstevel@tonic-gate 		goto ret;
1630*7c478bd9Sstevel@tonic-gate 	}
1631*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
1632*7c478bd9Sstevel@tonic-gate 		if ((apowers[i] = big_malloc((2 * nlen + 1) *
1633*7c478bd9Sstevel@tonic-gate 		    sizeof (double))) == NULL) {
1634*7c478bd9Sstevel@tonic-gate 			err = BIG_NO_MEM;
1635*7c478bd9Sstevel@tonic-gate 			goto ret;
1636*7c478bd9Sstevel@tonic-gate 		}
1637*7c478bd9Sstevel@tonic-gate 	}
1638*7c478bd9Sstevel@tonic-gate 
1639*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ma.len; i++) nint[i] = ma.value[i];
1640*7c478bd9Sstevel@tonic-gate 	for (; i < nlen; i++) nint[i] = 0;
1641*7c478bd9Sstevel@tonic-gate 	conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen);
1642*7c478bd9Sstevel@tonic-gate 
1643*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < n->len; i++) nint[i] = n->value[i];
1644*7c478bd9Sstevel@tonic-gate 	for (; i < nlen; i++) nint[i] = 0;
1645*7c478bd9Sstevel@tonic-gate 	conv_i32_to_d32(dn, nint, nlen);
1646*7c478bd9Sstevel@tonic-gate 
1647*7c478bd9Sstevel@tonic-gate 	mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0);
1648*7c478bd9Sstevel@tonic-gate 	conv_i32_to_d32(d32r, prod, nlen);
1649*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < apowerssize; i++) {
1650*7c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[i - 1],
1651*7c478bd9Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
1652*7c478bd9Sstevel@tonic-gate 		conv_i32_to_d16(apowers[i], prod, nlen);
1653*7c478bd9Sstevel@tonic-gate 	}
1654*7c478bd9Sstevel@tonic-gate 
1655*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < tmp.len; i++) prod[i] = tmp.value[i];
1656*7c478bd9Sstevel@tonic-gate 	for (; i < nlen + 1; i++) prod[i] = 0;
1657*7c478bd9Sstevel@tonic-gate 
1658*7c478bd9Sstevel@tonic-gate 	bitind = nbits % 32;
1659*7c478bd9Sstevel@tonic-gate 	k = 0;
1660*7c478bd9Sstevel@tonic-gate 	l = 0;
1661*7c478bd9Sstevel@tonic-gate 	p = 0;
1662*7c478bd9Sstevel@tonic-gate 	bitcount = 0;
1663*7c478bd9Sstevel@tonic-gate 	for (i = nbits / 32; i >= 0; i--) {
1664*7c478bd9Sstevel@tonic-gate 		for (j = bitind - 1; j >= 0; j--) {
1665*7c478bd9Sstevel@tonic-gate 			bit = (e->value[i] >> j) & 1;
1666*7c478bd9Sstevel@tonic-gate 			if ((bitcount == 0) && (bit == 0)) {
1667*7c478bd9Sstevel@tonic-gate 				conv_i32_to_d32_and_d16(d32r, d16r,
1668*7c478bd9Sstevel@tonic-gate 				    prod, nlen);
1669*7c478bd9Sstevel@tonic-gate 				mont_mulf_noconv(prod, d32r, d16r,
1670*7c478bd9Sstevel@tonic-gate 				    dt, dn, nint, nlen, dn0);
1671*7c478bd9Sstevel@tonic-gate 			} else {
1672*7c478bd9Sstevel@tonic-gate 				bitcount++;
1673*7c478bd9Sstevel@tonic-gate 				p = p * 2 + bit;
1674*7c478bd9Sstevel@tonic-gate 				if (bit == 1) {
1675*7c478bd9Sstevel@tonic-gate 					k = k + l + 1;
1676*7c478bd9Sstevel@tonic-gate 					l = 0;
1677*7c478bd9Sstevel@tonic-gate 				} else {
1678*7c478bd9Sstevel@tonic-gate 					l++;
1679*7c478bd9Sstevel@tonic-gate 				}
1680*7c478bd9Sstevel@tonic-gate 				if (bitcount == groupbits) {
1681*7c478bd9Sstevel@tonic-gate 					for (m = 0; m < k; m++) {
1682*7c478bd9Sstevel@tonic-gate 						conv_i32_to_d32_and_d16(
1683*7c478bd9Sstevel@tonic-gate 							d32r, d16r,
1684*7c478bd9Sstevel@tonic-gate 							prod, nlen);
1685*7c478bd9Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
1686*7c478bd9Sstevel@tonic-gate 						    d16r, dt, dn, nint,
1687*7c478bd9Sstevel@tonic-gate 						    nlen, dn0);
1688*7c478bd9Sstevel@tonic-gate 					}
1689*7c478bd9Sstevel@tonic-gate 					conv_i32_to_d32(d32r, prod, nlen);
1690*7c478bd9Sstevel@tonic-gate 					mont_mulf_noconv(prod, d32r,
1691*7c478bd9Sstevel@tonic-gate 					    apowers[p >> (l+1)],
1692*7c478bd9Sstevel@tonic-gate 					    dt, dn, nint, nlen, dn0);
1693*7c478bd9Sstevel@tonic-gate 					for (m = 0; m < l; m++) {
1694*7c478bd9Sstevel@tonic-gate 						conv_i32_to_d32_and_d16(
1695*7c478bd9Sstevel@tonic-gate 							d32r, d16r,
1696*7c478bd9Sstevel@tonic-gate 							prod, nlen);
1697*7c478bd9Sstevel@tonic-gate 						mont_mulf_noconv(prod, d32r,
1698*7c478bd9Sstevel@tonic-gate 						    d16r, dt, dn, nint,
1699*7c478bd9Sstevel@tonic-gate 						    nlen, dn0);
1700*7c478bd9Sstevel@tonic-gate 					}
1701*7c478bd9Sstevel@tonic-gate 					k = 0;
1702*7c478bd9Sstevel@tonic-gate 					l = 0;
1703*7c478bd9Sstevel@tonic-gate 					p = 0;
1704*7c478bd9Sstevel@tonic-gate 					bitcount = 0;
1705*7c478bd9Sstevel@tonic-gate 				}
1706*7c478bd9Sstevel@tonic-gate 			}
1707*7c478bd9Sstevel@tonic-gate 		}
1708*7c478bd9Sstevel@tonic-gate 		bitind = 32;
1709*7c478bd9Sstevel@tonic-gate 	}
1710*7c478bd9Sstevel@tonic-gate 
1711*7c478bd9Sstevel@tonic-gate 	for (m = 0; m < k; m++) {
1712*7c478bd9Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
1713*7c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
1714*7c478bd9Sstevel@tonic-gate 	}
1715*7c478bd9Sstevel@tonic-gate 	if (p != 0) {
1716*7c478bd9Sstevel@tonic-gate 		conv_i32_to_d32(d32r, prod, nlen);
1717*7c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)],
1718*7c478bd9Sstevel@tonic-gate 		    dt, dn, nint, nlen, dn0);
1719*7c478bd9Sstevel@tonic-gate 	}
1720*7c478bd9Sstevel@tonic-gate 	for (m = 0; m < l; m++) {
1721*7c478bd9Sstevel@tonic-gate 		conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen);
1722*7c478bd9Sstevel@tonic-gate 		mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0);
1723*7c478bd9Sstevel@tonic-gate 	}
1724*7c478bd9Sstevel@tonic-gate 
1725*7c478bd9Sstevel@tonic-gate 	ma.value[0] = 1;
1726*7c478bd9Sstevel@tonic-gate 	ma.len = 1;
1727*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nlen; i++) tmp.value[i] = prod[i];
1728*7c478bd9Sstevel@tonic-gate 	for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--);
1729*7c478bd9Sstevel@tonic-gate 	tmp.len = i + 1;
1730*7c478bd9Sstevel@tonic-gate 	if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK)
1731*7c478bd9Sstevel@tonic-gate 		goto ret;
1732*7c478bd9Sstevel@tonic-gate 	err = big_copy(result, &tmp);
1733*7c478bd9Sstevel@tonic-gate ret:
1734*7c478bd9Sstevel@tonic-gate 	for (i = apowerssize - 1; i >= 0; i--) {
1735*7c478bd9Sstevel@tonic-gate 		if (apowers[i] != NULL)
1736*7c478bd9Sstevel@tonic-gate 			big_free(apowers[i], (2 * nlen + 1) * sizeof (double));
1737*7c478bd9Sstevel@tonic-gate 	}
1738*7c478bd9Sstevel@tonic-gate 	if (d32r != NULL)
1739*7c478bd9Sstevel@tonic-gate 		big_free(d32r, nlen * sizeof (double));
1740*7c478bd9Sstevel@tonic-gate 	if (d16r != NULL)
1741*7c478bd9Sstevel@tonic-gate 		big_free(d16r, (2 * nlen + 1) * sizeof (double));
1742*7c478bd9Sstevel@tonic-gate 	if (prod != NULL)
1743*7c478bd9Sstevel@tonic-gate 		big_free(prod, (nlen + 1) * sizeof (uint32_t));
1744*7c478bd9Sstevel@tonic-gate 	if (nint != NULL)
1745*7c478bd9Sstevel@tonic-gate 		big_free(nint, nlen * sizeof (uint32_t));
1746*7c478bd9Sstevel@tonic-gate 	if (dt != NULL)
1747*7c478bd9Sstevel@tonic-gate 		big_free(dt, (4 * nlen + 2) * sizeof (double));
1748*7c478bd9Sstevel@tonic-gate 	if (dn != NULL)
1749*7c478bd9Sstevel@tonic-gate 		big_free(dn, nlen * sizeof (double));
1750*7c478bd9Sstevel@tonic-gate 
1751*7c478bd9Sstevel@tonic-gate ret3:
1752*7c478bd9Sstevel@tonic-gate 	big_finish(&rr);
1753*7c478bd9Sstevel@tonic-gate ret2:
1754*7c478bd9Sstevel@tonic-gate 	big_finish(&tmp);
1755*7c478bd9Sstevel@tonic-gate ret1:
1756*7c478bd9Sstevel@tonic-gate 	big_finish(&ma);
1757*7c478bd9Sstevel@tonic-gate 	return (err);
1758*7c478bd9Sstevel@tonic-gate 
1759*7c478bd9Sstevel@tonic-gate }
1760*7c478bd9Sstevel@tonic-gate 
1761*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
1762*7c478bd9Sstevel@tonic-gate 
1763*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
1764*7c478bd9Sstevel@tonic-gate #include <sys/regset.h>
1765*7c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
1766*7c478bd9Sstevel@tonic-gate 
1767*7c478bd9Sstevel@tonic-gate /* the alignment for block stores to save fp registers */
1768*7c478bd9Sstevel@tonic-gate #define	FPR_ALIGN	(64)
1769*7c478bd9Sstevel@tonic-gate 
1770*7c478bd9Sstevel@tonic-gate extern void big_savefp(kfpu_t *);
1771*7c478bd9Sstevel@tonic-gate extern void big_restorefp(kfpu_t *);
1772*7c478bd9Sstevel@tonic-gate 
1773*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
1774*7c478bd9Sstevel@tonic-gate 
1775*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1776*7c478bd9Sstevel@tonic-gate big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
1777*7c478bd9Sstevel@tonic-gate {
1778*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
1779*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE rv;
1780*7c478bd9Sstevel@tonic-gate 	uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN];
1781*7c478bd9Sstevel@tonic-gate 	kfpu_t *fpu;
1782*7c478bd9Sstevel@tonic-gate 
1783*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1784*7c478bd9Sstevel@tonic-gate 	if (!fpu_exists)
1785*7c478bd9Sstevel@tonic-gate 		return (BIG_GENERAL_ERR);
1786*7c478bd9Sstevel@tonic-gate #endif
1787*7c478bd9Sstevel@tonic-gate 
1788*7c478bd9Sstevel@tonic-gate 	fpu =  (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN);
1789*7c478bd9Sstevel@tonic-gate 	big_savefp(fpu);
1790*7c478bd9Sstevel@tonic-gate 
1791*7c478bd9Sstevel@tonic-gate 	rv = _big_modexp(result, a, e, n, n_rr);
1792*7c478bd9Sstevel@tonic-gate 
1793*7c478bd9Sstevel@tonic-gate 	big_restorefp(fpu);
1794*7c478bd9Sstevel@tonic-gate 
1795*7c478bd9Sstevel@tonic-gate 	return (rv);
1796*7c478bd9Sstevel@tonic-gate #else
1797*7c478bd9Sstevel@tonic-gate 	return (_big_modexp(result, a, e, n, n_rr));
1798*7c478bd9Sstevel@tonic-gate #endif	/* _KERNEL */
1799*7c478bd9Sstevel@tonic-gate }
1800*7c478bd9Sstevel@tonic-gate 
1801*7c478bd9Sstevel@tonic-gate #else /* ! USE_FLOATING_POINT */
1802*7c478bd9Sstevel@tonic-gate 
1803*7c478bd9Sstevel@tonic-gate /*
1804*7c478bd9Sstevel@tonic-gate  * This version uses strictly integer math and is safe in the kernel
1805*7c478bd9Sstevel@tonic-gate  * for all platforms.
1806*7c478bd9Sstevel@tonic-gate  */
1807*7c478bd9Sstevel@tonic-gate 
1808*7c478bd9Sstevel@tonic-gate /*
1809*7c478bd9Sstevel@tonic-gate  * computes a^e mod n
1810*7c478bd9Sstevel@tonic-gate  * assumes a < n, n odd, result->value at least as long as n->value
1811*7c478bd9Sstevel@tonic-gate  */
1812*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1813*7c478bd9Sstevel@tonic-gate big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr)
1814*7c478bd9Sstevel@tonic-gate {
1815*7c478bd9Sstevel@tonic-gate 	BIGNUM ma, tmp, rr;
1816*7c478bd9Sstevel@tonic-gate 	uint32_t mavalue[BIGTMPSIZE];
1817*7c478bd9Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
1818*7c478bd9Sstevel@tonic-gate 	uint32_t rrvalue[BIGTMPSIZE];
1819*7c478bd9Sstevel@tonic-gate 	BIGNUM apowers[APOWERS_MAX_SIZE];
1820*7c478bd9Sstevel@tonic-gate 	int i, j, k, l, m, p,
1821*7c478bd9Sstevel@tonic-gate 	    bit, bitind, bitcount, groupbits, apowerssize;
1822*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
1823*7c478bd9Sstevel@tonic-gate 	uint32_t n0;
1824*7c478bd9Sstevel@tonic-gate 
1825*7c478bd9Sstevel@tonic-gate 	int nbits;
1826*7c478bd9Sstevel@tonic-gate 
1827*7c478bd9Sstevel@tonic-gate 	nbits = big_numbits(e);
1828*7c478bd9Sstevel@tonic-gate 	if (nbits < 50) {
1829*7c478bd9Sstevel@tonic-gate 		groupbits = 1;
1830*7c478bd9Sstevel@tonic-gate 		apowerssize = 1;
1831*7c478bd9Sstevel@tonic-gate 	} else {
1832*7c478bd9Sstevel@tonic-gate 		groupbits = MAX_EXP_BIT_GROUP_SIZE;
1833*7c478bd9Sstevel@tonic-gate 		apowerssize = 1 << (groupbits - 1);
1834*7c478bd9Sstevel@tonic-gate 	}
1835*7c478bd9Sstevel@tonic-gate 
1836*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&ma, n->len,
1837*7c478bd9Sstevel@tonic-gate 	    mavalue, arraysize(mavalue))) != BIG_OK)
1838*7c478bd9Sstevel@tonic-gate 		return (err);
1839*7c478bd9Sstevel@tonic-gate 	ma.len = 1;
1840*7c478bd9Sstevel@tonic-gate 	ma.value[0] = 0;
1841*7c478bd9Sstevel@tonic-gate 
1842*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len + 1,
1843*7c478bd9Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
1844*7c478bd9Sstevel@tonic-gate 		goto ret1;
1845*7c478bd9Sstevel@tonic-gate 	tmp.len = 1;
1846*7c478bd9Sstevel@tonic-gate 	tmp.value[0] = 1;
1847*7c478bd9Sstevel@tonic-gate 
1848*7c478bd9Sstevel@tonic-gate 	n0 = big_n0(n->value[0]);
1849*7c478bd9Sstevel@tonic-gate 
1850*7c478bd9Sstevel@tonic-gate 	rr.malloced = 0;
1851*7c478bd9Sstevel@tonic-gate 	if (n_rr == NULL) {
1852*7c478bd9Sstevel@tonic-gate 		if ((err = big_init1(&rr, 2 * n->len + 1,
1853*7c478bd9Sstevel@tonic-gate 		    rrvalue, arraysize(rrvalue))) != BIG_OK)
1854*7c478bd9Sstevel@tonic-gate 			goto ret2;
1855*7c478bd9Sstevel@tonic-gate 
1856*7c478bd9Sstevel@tonic-gate 		if (big_mont_rr(&rr, n) != BIG_OK)
1857*7c478bd9Sstevel@tonic-gate 			goto ret3;
1858*7c478bd9Sstevel@tonic-gate 		n_rr = &rr;
1859*7c478bd9Sstevel@tonic-gate 	}
1860*7c478bd9Sstevel@tonic-gate 
1861*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) apowers[i].malloced = 0;
1862*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < apowerssize; i++) {
1863*7c478bd9Sstevel@tonic-gate 		if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) !=
1864*7c478bd9Sstevel@tonic-gate 		    BIG_OK)
1865*7c478bd9Sstevel@tonic-gate 			goto ret;
1866*7c478bd9Sstevel@tonic-gate 	}
1867*7c478bd9Sstevel@tonic-gate 
1868*7c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(a, n) > 0) {
1869*7c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK)
1870*7c478bd9Sstevel@tonic-gate 			goto ret;
1871*7c478bd9Sstevel@tonic-gate 		err = big_mont_conv(&ma, &ma, n, n0, n_rr);
1872*7c478bd9Sstevel@tonic-gate 	} else {
1873*7c478bd9Sstevel@tonic-gate 		err = big_mont_conv(&ma, a, n, n0, n_rr);
1874*7c478bd9Sstevel@tonic-gate 	}
1875*7c478bd9Sstevel@tonic-gate 	if (err != BIG_OK) goto ret;
1876*7c478bd9Sstevel@tonic-gate 
1877*7c478bd9Sstevel@tonic-gate 	(void) big_copy(&(apowers[0]), &ma);
1878*7c478bd9Sstevel@tonic-gate 	if ((err = big_mont_mul(&tmp, &ma, &ma, n, n0)) != BIG_OK)
1879*7c478bd9Sstevel@tonic-gate 		goto ret;
1880*7c478bd9Sstevel@tonic-gate 	(void) big_copy(&ma, &tmp);
1881*7c478bd9Sstevel@tonic-gate 
1882*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < apowerssize; i++) {
1883*7c478bd9Sstevel@tonic-gate 		if ((err = big_mont_mul(&tmp, &ma,
1884*7c478bd9Sstevel@tonic-gate 		    &(apowers[i-1]), n, n0)) != BIG_OK)
1885*7c478bd9Sstevel@tonic-gate 			goto ret;
1886*7c478bd9Sstevel@tonic-gate 		(void) big_copy(&apowers[i], &tmp);
1887*7c478bd9Sstevel@tonic-gate 	}
1888*7c478bd9Sstevel@tonic-gate 
1889*7c478bd9Sstevel@tonic-gate 	tmp.len = 1;
1890*7c478bd9Sstevel@tonic-gate 	tmp.value[0] = 1;
1891*7c478bd9Sstevel@tonic-gate 	if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK)
1892*7c478bd9Sstevel@tonic-gate 		goto ret;
1893*7c478bd9Sstevel@tonic-gate 
1894*7c478bd9Sstevel@tonic-gate 	bitind = nbits % 32;
1895*7c478bd9Sstevel@tonic-gate 	k = 0;
1896*7c478bd9Sstevel@tonic-gate 	l = 0;
1897*7c478bd9Sstevel@tonic-gate 	p = 0;
1898*7c478bd9Sstevel@tonic-gate 	bitcount = 0;
1899*7c478bd9Sstevel@tonic-gate 	for (i = nbits / 32; i >= 0; i--) {
1900*7c478bd9Sstevel@tonic-gate 		for (j = bitind - 1; j >= 0; j--) {
1901*7c478bd9Sstevel@tonic-gate 			bit = (e->value[i] >> j) & 1;
1902*7c478bd9Sstevel@tonic-gate 			if ((bitcount == 0) && (bit == 0)) {
1903*7c478bd9Sstevel@tonic-gate 				if ((err = big_mont_mul(&tmp,
1904*7c478bd9Sstevel@tonic-gate 				    &tmp, &tmp, n, n0)) != BIG_OK)
1905*7c478bd9Sstevel@tonic-gate 					goto ret;
1906*7c478bd9Sstevel@tonic-gate 			} else {
1907*7c478bd9Sstevel@tonic-gate 				bitcount++;
1908*7c478bd9Sstevel@tonic-gate 				p = p * 2 + bit;
1909*7c478bd9Sstevel@tonic-gate 				if (bit == 1) {
1910*7c478bd9Sstevel@tonic-gate 					k = k + l + 1;
1911*7c478bd9Sstevel@tonic-gate 					l = 0;
1912*7c478bd9Sstevel@tonic-gate 				} else {
1913*7c478bd9Sstevel@tonic-gate 					l++;
1914*7c478bd9Sstevel@tonic-gate 				}
1915*7c478bd9Sstevel@tonic-gate 				if (bitcount == groupbits) {
1916*7c478bd9Sstevel@tonic-gate 					for (m = 0; m < k; m++) {
1917*7c478bd9Sstevel@tonic-gate 						if ((err = big_mont_mul(&tmp,
1918*7c478bd9Sstevel@tonic-gate 						    &tmp, &tmp, n, n0)) !=
1919*7c478bd9Sstevel@tonic-gate 						    BIG_OK)
1920*7c478bd9Sstevel@tonic-gate 							goto ret;
1921*7c478bd9Sstevel@tonic-gate 					}
1922*7c478bd9Sstevel@tonic-gate 					if ((err = big_mont_mul(&tmp, &tmp,
1923*7c478bd9Sstevel@tonic-gate 					    &(apowers[p >> (l + 1)]),
1924*7c478bd9Sstevel@tonic-gate 					    n, n0)) != BIG_OK)
1925*7c478bd9Sstevel@tonic-gate 						goto ret;
1926*7c478bd9Sstevel@tonic-gate 					for (m = 0; m < l; m++) {
1927*7c478bd9Sstevel@tonic-gate 						if ((err = big_mont_mul(&tmp,
1928*7c478bd9Sstevel@tonic-gate 						    &tmp, &tmp, n, n0)) !=
1929*7c478bd9Sstevel@tonic-gate 						    BIG_OK)
1930*7c478bd9Sstevel@tonic-gate 							goto ret;
1931*7c478bd9Sstevel@tonic-gate 					}
1932*7c478bd9Sstevel@tonic-gate 					k = 0;
1933*7c478bd9Sstevel@tonic-gate 					l = 0;
1934*7c478bd9Sstevel@tonic-gate 					p = 0;
1935*7c478bd9Sstevel@tonic-gate 					bitcount = 0;
1936*7c478bd9Sstevel@tonic-gate 				}
1937*7c478bd9Sstevel@tonic-gate 			}
1938*7c478bd9Sstevel@tonic-gate 		}
1939*7c478bd9Sstevel@tonic-gate 		bitind = 32;
1940*7c478bd9Sstevel@tonic-gate 	}
1941*7c478bd9Sstevel@tonic-gate 
1942*7c478bd9Sstevel@tonic-gate 	for (m = 0; m < k; m++) {
1943*7c478bd9Sstevel@tonic-gate 		if ((err = big_mont_mul(&tmp, &tmp, &tmp, n, n0)) != BIG_OK)
1944*7c478bd9Sstevel@tonic-gate 			goto ret;
1945*7c478bd9Sstevel@tonic-gate 	}
1946*7c478bd9Sstevel@tonic-gate 	if (p != 0) {
1947*7c478bd9Sstevel@tonic-gate 		if ((err = big_mont_mul(&tmp, &tmp,
1948*7c478bd9Sstevel@tonic-gate 		    &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK)
1949*7c478bd9Sstevel@tonic-gate 			goto ret;
1950*7c478bd9Sstevel@tonic-gate 	}
1951*7c478bd9Sstevel@tonic-gate 	for (m = 0; m < l; m++) {
1952*7c478bd9Sstevel@tonic-gate 		if ((err = big_mont_mul(&tmp, &tmp, &tmp, n, n0)) != BIG_OK)
1953*7c478bd9Sstevel@tonic-gate 			goto ret;
1954*7c478bd9Sstevel@tonic-gate 	}
1955*7c478bd9Sstevel@tonic-gate 
1956*7c478bd9Sstevel@tonic-gate 	ma.value[0] = 1;
1957*7c478bd9Sstevel@tonic-gate 	ma.len = 1;
1958*7c478bd9Sstevel@tonic-gate 	if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK)
1959*7c478bd9Sstevel@tonic-gate 		goto ret;
1960*7c478bd9Sstevel@tonic-gate 	err = big_copy(result, &tmp);
1961*7c478bd9Sstevel@tonic-gate ret:
1962*7c478bd9Sstevel@tonic-gate 	for (i = apowerssize - 1; i >= 0; i--) {
1963*7c478bd9Sstevel@tonic-gate 		big_finish(&(apowers[i]));
1964*7c478bd9Sstevel@tonic-gate 	}
1965*7c478bd9Sstevel@tonic-gate ret3:
1966*7c478bd9Sstevel@tonic-gate 	if (rr.malloced) big_finish(&rr);
1967*7c478bd9Sstevel@tonic-gate ret2:
1968*7c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
1969*7c478bd9Sstevel@tonic-gate ret1:
1970*7c478bd9Sstevel@tonic-gate 	if (ma.malloced) big_finish(&ma);
1971*7c478bd9Sstevel@tonic-gate 	return (err);
1972*7c478bd9Sstevel@tonic-gate }
1973*7c478bd9Sstevel@tonic-gate 
1974*7c478bd9Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */
1975*7c478bd9Sstevel@tonic-gate 
1976*7c478bd9Sstevel@tonic-gate 
1977*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
1978*7c478bd9Sstevel@tonic-gate big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1,
1979*7c478bd9Sstevel@tonic-gate     BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq,
1980*7c478bd9Sstevel@tonic-gate     BIGNUM *p_rr, BIGNUM *q_rr)
1981*7c478bd9Sstevel@tonic-gate {
1982*7c478bd9Sstevel@tonic-gate 	BIGNUM ap, aq, tmp;
1983*7c478bd9Sstevel@tonic-gate 	int alen, biglen, sign;
1984*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
1985*7c478bd9Sstevel@tonic-gate 
1986*7c478bd9Sstevel@tonic-gate 	if (p->len > q->len) biglen = p->len;
1987*7c478bd9Sstevel@tonic-gate 	else biglen = q->len;
1988*7c478bd9Sstevel@tonic-gate 
1989*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK)
1990*7c478bd9Sstevel@tonic-gate 		return (err);
1991*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK)
1992*7c478bd9Sstevel@tonic-gate 		goto ret1;
1993*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK)
1994*7c478bd9Sstevel@tonic-gate 		goto ret2;
1995*7c478bd9Sstevel@tonic-gate 
1996*7c478bd9Sstevel@tonic-gate 	/*
1997*7c478bd9Sstevel@tonic-gate 	 * check whether a is too short - to avoid timing attacks
1998*7c478bd9Sstevel@tonic-gate 	 */
1999*7c478bd9Sstevel@tonic-gate 	alen = a->len;
2000*7c478bd9Sstevel@tonic-gate 	while ((alen > p->len) && (a->value[alen - 1] == 0)) {
2001*7c478bd9Sstevel@tonic-gate 		alen--;
2002*7c478bd9Sstevel@tonic-gate 	}
2003*7c478bd9Sstevel@tonic-gate 	if (alen < p->len + q->len) {
2004*7c478bd9Sstevel@tonic-gate 		/*
2005*7c478bd9Sstevel@tonic-gate 		 * a is too short, add p*q to it before
2006*7c478bd9Sstevel@tonic-gate 		 * taking it modulo p and q
2007*7c478bd9Sstevel@tonic-gate 		 * this will also affect timing, but this difference
2008*7c478bd9Sstevel@tonic-gate 		 * does not depend on p or q, only on a
2009*7c478bd9Sstevel@tonic-gate 		 * (in "normal" operation, this path will never be
2010*7c478bd9Sstevel@tonic-gate 		 * taken, so it is not a performance penalty
2011*7c478bd9Sstevel@tonic-gate 		 */
2012*7c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&tmp, p, q)) != BIG_OK)
2013*7c478bd9Sstevel@tonic-gate 			goto ret;
2014*7c478bd9Sstevel@tonic-gate 		if ((err = big_add(&tmp, &tmp, a)) != BIG_OK)
2015*7c478bd9Sstevel@tonic-gate 			goto ret;
2016*7c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK)
2017*7c478bd9Sstevel@tonic-gate 			goto ret;
2018*7c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK)
2019*7c478bd9Sstevel@tonic-gate 			goto ret;
2020*7c478bd9Sstevel@tonic-gate 	} else {
2021*7c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK)
2022*7c478bd9Sstevel@tonic-gate 			goto ret;
2023*7c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK)
2024*7c478bd9Sstevel@tonic-gate 			goto ret;
2025*7c478bd9Sstevel@tonic-gate 	}
2026*7c478bd9Sstevel@tonic-gate 
2027*7c478bd9Sstevel@tonic-gate 	if ((err = big_modexp(&ap, &ap, dmodpminus1, p, p_rr)) != BIG_OK)
2028*7c478bd9Sstevel@tonic-gate 		goto ret;
2029*7c478bd9Sstevel@tonic-gate 	if ((err = big_modexp(&aq, &aq, dmodqminus1, q, q_rr)) != BIG_OK)
2030*7c478bd9Sstevel@tonic-gate 		goto ret;
2031*7c478bd9Sstevel@tonic-gate 	if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK)
2032*7c478bd9Sstevel@tonic-gate 		goto ret;
2033*7c478bd9Sstevel@tonic-gate 	if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK)
2034*7c478bd9Sstevel@tonic-gate 		goto ret;
2035*7c478bd9Sstevel@tonic-gate 	sign = tmp.sign;
2036*7c478bd9Sstevel@tonic-gate 	tmp.sign = 1;
2037*7c478bd9Sstevel@tonic-gate 	if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK)
2038*7c478bd9Sstevel@tonic-gate 		goto ret;
2039*7c478bd9Sstevel@tonic-gate 	if ((sign == -1) && (!big_is_zero(&aq))) {
2040*7c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(&aq, q, &aq);
2041*7c478bd9Sstevel@tonic-gate 	}
2042*7c478bd9Sstevel@tonic-gate 	if ((err = big_mul(&tmp, &aq, p)) != BIG_OK)
2043*7c478bd9Sstevel@tonic-gate 		goto ret;
2044*7c478bd9Sstevel@tonic-gate 	err = big_add_abs(result, &ap, &tmp);
2045*7c478bd9Sstevel@tonic-gate 
2046*7c478bd9Sstevel@tonic-gate ret:
2047*7c478bd9Sstevel@tonic-gate 	big_finish(&tmp);
2048*7c478bd9Sstevel@tonic-gate ret2:
2049*7c478bd9Sstevel@tonic-gate 	big_finish(&aq);
2050*7c478bd9Sstevel@tonic-gate ret1:
2051*7c478bd9Sstevel@tonic-gate 	big_finish(&ap);
2052*7c478bd9Sstevel@tonic-gate 
2053*7c478bd9Sstevel@tonic-gate 	return (err);
2054*7c478bd9Sstevel@tonic-gate }
2055*7c478bd9Sstevel@tonic-gate 
2056*7c478bd9Sstevel@tonic-gate 
2057*7c478bd9Sstevel@tonic-gate uint32_t onearr[1] = {1};
2058*7c478bd9Sstevel@tonic-gate BIGNUM One = {1, 1, 1, 0, onearr};
2059*7c478bd9Sstevel@tonic-gate 
2060*7c478bd9Sstevel@tonic-gate uint32_t twoarr[1] = {2};
2061*7c478bd9Sstevel@tonic-gate BIGNUM Two = {1, 1, 1, 0, twoarr};
2062*7c478bd9Sstevel@tonic-gate 
2063*7c478bd9Sstevel@tonic-gate uint32_t fourarr[1] = {4};
2064*7c478bd9Sstevel@tonic-gate BIGNUM Four = {1, 1, 1, 0, fourarr};
2065*7c478bd9Sstevel@tonic-gate 
2066*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2067*7c478bd9Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n)
2068*7c478bd9Sstevel@tonic-gate {
2069*7c478bd9Sstevel@tonic-gate 	BIGNUM *high, *low, *mid, *t;
2070*7c478bd9Sstevel@tonic-gate 	BIGNUM t1, t2, t3, prod;
2071*7c478bd9Sstevel@tonic-gate 	uint32_t t1value[BIGTMPSIZE];
2072*7c478bd9Sstevel@tonic-gate 	uint32_t t2value[BIGTMPSIZE];
2073*7c478bd9Sstevel@tonic-gate 	uint32_t t3value[BIGTMPSIZE];
2074*7c478bd9Sstevel@tonic-gate 	uint32_t prodvalue[BIGTMPSIZE];
2075*7c478bd9Sstevel@tonic-gate 	int i, nbits, diff, nrootbits, highbits;
2076*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
2077*7c478bd9Sstevel@tonic-gate 
2078*7c478bd9Sstevel@tonic-gate 	nbits = big_numbits(n);
2079*7c478bd9Sstevel@tonic-gate 
2080*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, n->len + 1,
2081*7c478bd9Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
2082*7c478bd9Sstevel@tonic-gate 		return (err);
2083*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, n->len + 1,
2084*7c478bd9Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
2085*7c478bd9Sstevel@tonic-gate 		goto ret1;
2086*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, n->len + 1,
2087*7c478bd9Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
2088*7c478bd9Sstevel@tonic-gate 		goto ret2;
2089*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&prod, n->len + 1,
2090*7c478bd9Sstevel@tonic-gate 	    prodvalue, arraysize(prodvalue))) != BIG_OK)
2091*7c478bd9Sstevel@tonic-gate 		goto ret3;
2092*7c478bd9Sstevel@tonic-gate 
2093*7c478bd9Sstevel@tonic-gate 	nrootbits = (nbits + 1) / 2;
2094*7c478bd9Sstevel@tonic-gate 	t1.len = t2.len = t3.len = (nrootbits - 1) / 32 + 1;
2095*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < t1.len; i++) {
2096*7c478bd9Sstevel@tonic-gate 		t1.value[i] = 0;
2097*7c478bd9Sstevel@tonic-gate 		t2.value[i] = 0xffffffff;
2098*7c478bd9Sstevel@tonic-gate 	}
2099*7c478bd9Sstevel@tonic-gate 	highbits = nrootbits - 32 * (t1.len - 1);
2100*7c478bd9Sstevel@tonic-gate 	if (highbits == 32) {
2101*7c478bd9Sstevel@tonic-gate 		t1.value[t1.len - 1] = 0x80000000;
2102*7c478bd9Sstevel@tonic-gate 		t2.value[t2.len - 1] = 0xffffffff;
2103*7c478bd9Sstevel@tonic-gate 	} else {
2104*7c478bd9Sstevel@tonic-gate 		t1.value[t1.len - 1] = 1 << (highbits - 1);
2105*7c478bd9Sstevel@tonic-gate 		t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1;
2106*7c478bd9Sstevel@tonic-gate 	}
2107*7c478bd9Sstevel@tonic-gate 	high = &t2;
2108*7c478bd9Sstevel@tonic-gate 	low = &t1;
2109*7c478bd9Sstevel@tonic-gate 	mid = &t3;
2110*7c478bd9Sstevel@tonic-gate 
2111*7c478bd9Sstevel@tonic-gate 	if ((err = big_mul(&prod, high, high)) != BIG_OK)
2112*7c478bd9Sstevel@tonic-gate 		goto ret;
2113*7c478bd9Sstevel@tonic-gate 	diff = big_cmp_abs(&prod, n);
2114*7c478bd9Sstevel@tonic-gate 	if (diff <= 0) {
2115*7c478bd9Sstevel@tonic-gate 		err = big_copy(result, high);
2116*7c478bd9Sstevel@tonic-gate 		goto ret;
2117*7c478bd9Sstevel@tonic-gate 	}
2118*7c478bd9Sstevel@tonic-gate 
2119*7c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(mid, high, low);
2120*7c478bd9Sstevel@tonic-gate 	while (big_cmp_abs(&One, mid) != 0) {
2121*7c478bd9Sstevel@tonic-gate 		(void) big_add_abs(mid, high, low);
2122*7c478bd9Sstevel@tonic-gate 		(void) big_half_pos(mid, mid);
2123*7c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&prod, mid, mid)) != BIG_OK)
2124*7c478bd9Sstevel@tonic-gate 			goto ret;
2125*7c478bd9Sstevel@tonic-gate 		diff = big_cmp_abs(&prod, n);
2126*7c478bd9Sstevel@tonic-gate 		if (diff > 0) {
2127*7c478bd9Sstevel@tonic-gate 			t = high;
2128*7c478bd9Sstevel@tonic-gate 			high = mid;
2129*7c478bd9Sstevel@tonic-gate 			mid = t;
2130*7c478bd9Sstevel@tonic-gate 		} else if (diff < 0) {
2131*7c478bd9Sstevel@tonic-gate 			t = low;
2132*7c478bd9Sstevel@tonic-gate 			low = mid;
2133*7c478bd9Sstevel@tonic-gate 			mid = t;
2134*7c478bd9Sstevel@tonic-gate 		} else {
2135*7c478bd9Sstevel@tonic-gate 			err = big_copy(result, low);
2136*7c478bd9Sstevel@tonic-gate 			goto ret;
2137*7c478bd9Sstevel@tonic-gate 		}
2138*7c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(mid, high, low);
2139*7c478bd9Sstevel@tonic-gate 	}
2140*7c478bd9Sstevel@tonic-gate 
2141*7c478bd9Sstevel@tonic-gate 	err = big_copy(result, low);
2142*7c478bd9Sstevel@tonic-gate ret:
2143*7c478bd9Sstevel@tonic-gate 	if (prod.malloced) big_finish(&prod);
2144*7c478bd9Sstevel@tonic-gate ret3:
2145*7c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
2146*7c478bd9Sstevel@tonic-gate ret2:
2147*7c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
2148*7c478bd9Sstevel@tonic-gate ret1:
2149*7c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
2150*7c478bd9Sstevel@tonic-gate 
2151*7c478bd9Sstevel@tonic-gate 	return (err);
2152*7c478bd9Sstevel@tonic-gate }
2153*7c478bd9Sstevel@tonic-gate 
2154*7c478bd9Sstevel@tonic-gate 
2155*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2156*7c478bd9Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm)
2157*7c478bd9Sstevel@tonic-gate {
2158*7c478bd9Sstevel@tonic-gate 	BIGNUM *t, *tmp2, *m, *n;
2159*7c478bd9Sstevel@tonic-gate 	BIGNUM t1, t2, t3;
2160*7c478bd9Sstevel@tonic-gate 	uint32_t t1value[BIGTMPSIZE];
2161*7c478bd9Sstevel@tonic-gate 	uint32_t t2value[BIGTMPSIZE];
2162*7c478bd9Sstevel@tonic-gate 	uint32_t t3value[BIGTMPSIZE];
2163*7c478bd9Sstevel@tonic-gate 	int len, err;
2164*7c478bd9Sstevel@tonic-gate 
2165*7c478bd9Sstevel@tonic-gate 	if (big_is_zero(nn) ||
2166*7c478bd9Sstevel@tonic-gate 	    (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) {
2167*7c478bd9Sstevel@tonic-gate 		*jac = 0;
2168*7c478bd9Sstevel@tonic-gate 		return (BIG_OK);
2169*7c478bd9Sstevel@tonic-gate 	}
2170*7c478bd9Sstevel@tonic-gate 
2171*7c478bd9Sstevel@tonic-gate 	if (nn->len > mm->len) len = nn->len;
2172*7c478bd9Sstevel@tonic-gate 	else len = mm->len;
2173*7c478bd9Sstevel@tonic-gate 
2174*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
2175*7c478bd9Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
2176*7c478bd9Sstevel@tonic-gate 		return (err);
2177*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
2178*7c478bd9Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
2179*7c478bd9Sstevel@tonic-gate 		goto ret1;
2180*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
2181*7c478bd9Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
2182*7c478bd9Sstevel@tonic-gate 		goto ret2;
2183*7c478bd9Sstevel@tonic-gate 
2184*7c478bd9Sstevel@tonic-gate 	n = &t1;
2185*7c478bd9Sstevel@tonic-gate 	m = &t2;
2186*7c478bd9Sstevel@tonic-gate 	tmp2 = &t3;
2187*7c478bd9Sstevel@tonic-gate 
2188*7c478bd9Sstevel@tonic-gate 	(void) big_copy(n, nn);
2189*7c478bd9Sstevel@tonic-gate 	(void) big_copy(m, mm);
2190*7c478bd9Sstevel@tonic-gate 
2191*7c478bd9Sstevel@tonic-gate 	*jac = 1;
2192*7c478bd9Sstevel@tonic-gate 	while (big_cmp_abs(&One, m) != 0) {
2193*7c478bd9Sstevel@tonic-gate 		if (big_is_zero(n)) {
2194*7c478bd9Sstevel@tonic-gate 			*jac = 0;
2195*7c478bd9Sstevel@tonic-gate 			goto ret;
2196*7c478bd9Sstevel@tonic-gate 		}
2197*7c478bd9Sstevel@tonic-gate 		if ((m->value[0] & 1) == 0) {
2198*7c478bd9Sstevel@tonic-gate 			if (((n->value[0] & 7) == 3) ||
2199*7c478bd9Sstevel@tonic-gate 			    ((n->value[0] & 7) == 5)) *jac = -*jac;
2200*7c478bd9Sstevel@tonic-gate 			(void) big_half_pos(m, m);
2201*7c478bd9Sstevel@tonic-gate 		} else if ((n->value[0] & 1) == 0) {
2202*7c478bd9Sstevel@tonic-gate 			if (((m->value[0] & 7) == 3) ||
2203*7c478bd9Sstevel@tonic-gate 			    ((m->value[0] & 7) == 5)) *jac = -*jac;
2204*7c478bd9Sstevel@tonic-gate 			(void) big_half_pos(n, n);
2205*7c478bd9Sstevel@tonic-gate 		} else {
2206*7c478bd9Sstevel@tonic-gate 			if (((m->value[0] & 3) == 3) &&
2207*7c478bd9Sstevel@tonic-gate 			    ((n->value[0] & 3) == 3)) {
2208*7c478bd9Sstevel@tonic-gate 				*jac = -*jac;
2209*7c478bd9Sstevel@tonic-gate 			}
2210*7c478bd9Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK)
2211*7c478bd9Sstevel@tonic-gate 				goto ret;
2212*7c478bd9Sstevel@tonic-gate 			t = tmp2;
2213*7c478bd9Sstevel@tonic-gate 			tmp2 = m;
2214*7c478bd9Sstevel@tonic-gate 			m = n;
2215*7c478bd9Sstevel@tonic-gate 			n = t;
2216*7c478bd9Sstevel@tonic-gate 		}
2217*7c478bd9Sstevel@tonic-gate 	}
2218*7c478bd9Sstevel@tonic-gate 	err = BIG_OK;
2219*7c478bd9Sstevel@tonic-gate 
2220*7c478bd9Sstevel@tonic-gate ret:
2221*7c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
2222*7c478bd9Sstevel@tonic-gate ret2:
2223*7c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
2224*7c478bd9Sstevel@tonic-gate ret1:
2225*7c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
2226*7c478bd9Sstevel@tonic-gate 
2227*7c478bd9Sstevel@tonic-gate 	return (err);
2228*7c478bd9Sstevel@tonic-gate }
2229*7c478bd9Sstevel@tonic-gate 
2230*7c478bd9Sstevel@tonic-gate 
2231*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2232*7c478bd9Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n)
2233*7c478bd9Sstevel@tonic-gate {
2234*7c478bd9Sstevel@tonic-gate 	int m, w, i;
2235*7c478bd9Sstevel@tonic-gate 	uint32_t bit;
2236*7c478bd9Sstevel@tonic-gate 	BIGNUM ki, tmp, tmp2;
2237*7c478bd9Sstevel@tonic-gate 	uint32_t kivalue[BIGTMPSIZE];
2238*7c478bd9Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
2239*7c478bd9Sstevel@tonic-gate 	uint32_t tmp2value[BIGTMPSIZE];
2240*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
2241*7c478bd9Sstevel@tonic-gate 
2242*7c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(k, &One) == 0) {
2243*7c478bd9Sstevel@tonic-gate 		(void) big_copy(Lk, p);
2244*7c478bd9Sstevel@tonic-gate 		(void) big_copy(Lkminus1, &Two);
2245*7c478bd9Sstevel@tonic-gate 		return (BIG_OK);
2246*7c478bd9Sstevel@tonic-gate 	}
2247*7c478bd9Sstevel@tonic-gate 
2248*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&ki, k->len + 1,
2249*7c478bd9Sstevel@tonic-gate 	    kivalue, arraysize(kivalue))) != BIG_OK)
2250*7c478bd9Sstevel@tonic-gate 		return (err);
2251*7c478bd9Sstevel@tonic-gate 
2252*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len +1,
2253*7c478bd9Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
2254*7c478bd9Sstevel@tonic-gate 		goto ret1;
2255*7c478bd9Sstevel@tonic-gate 
2256*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp2, n->len,
2257*7c478bd9Sstevel@tonic-gate 	    tmp2value, arraysize(tmp2value))) != BIG_OK)
2258*7c478bd9Sstevel@tonic-gate 		goto ret2;
2259*7c478bd9Sstevel@tonic-gate 
2260*7c478bd9Sstevel@tonic-gate 	m = big_numbits(k);
2261*7c478bd9Sstevel@tonic-gate 	ki.len = (m - 1) / 32 + 1;
2262*7c478bd9Sstevel@tonic-gate 	w = (m - 1) / 32;
2263*7c478bd9Sstevel@tonic-gate 	bit = 1 << ((m - 1) % 32);
2264*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ki.len; i++) ki.value[i] = 0;
2265*7c478bd9Sstevel@tonic-gate 	ki.value[ki.len - 1] = bit;
2266*7c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(k, &ki) != 0)
2267*7c478bd9Sstevel@tonic-gate 		(void) big_double(&ki, &ki);
2268*7c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(&ki, &ki, k);
2269*7c478bd9Sstevel@tonic-gate 
2270*7c478bd9Sstevel@tonic-gate 	(void) big_copy(Lk, p);
2271*7c478bd9Sstevel@tonic-gate 	(void) big_copy(Lkminus1, &Two);
2272*7c478bd9Sstevel@tonic-gate 
2273*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < m; i++) {
2274*7c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK)
2275*7c478bd9Sstevel@tonic-gate 			goto ret;
2276*7c478bd9Sstevel@tonic-gate 		(void) big_add_abs(&tmp, &tmp, n);
2277*7c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(&tmp, &tmp, p);
2278*7c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK)
2279*7c478bd9Sstevel@tonic-gate 			goto ret;
2280*7c478bd9Sstevel@tonic-gate 
2281*7c478bd9Sstevel@tonic-gate 		if ((ki.value[w] & bit) != 0) {
2282*7c478bd9Sstevel@tonic-gate 			if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) !=
2283*7c478bd9Sstevel@tonic-gate 			    BIG_OK)
2284*7c478bd9Sstevel@tonic-gate 				goto ret;
2285*7c478bd9Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
2286*7c478bd9Sstevel@tonic-gate 			(void) big_sub_pos(&tmp, &tmp, &Two);
2287*7c478bd9Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) !=
2288*7c478bd9Sstevel@tonic-gate 			    BIG_OK)
2289*7c478bd9Sstevel@tonic-gate 				goto ret;
2290*7c478bd9Sstevel@tonic-gate 			(void) big_copy(Lk, &tmp2);
2291*7c478bd9Sstevel@tonic-gate 		} else {
2292*7c478bd9Sstevel@tonic-gate 			if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK)
2293*7c478bd9Sstevel@tonic-gate 				goto ret;
2294*7c478bd9Sstevel@tonic-gate 			(void) big_add_abs(&tmp, &tmp, n);
2295*7c478bd9Sstevel@tonic-gate 			(void) big_sub_pos(&tmp, &tmp, &Two);
2296*7c478bd9Sstevel@tonic-gate 			if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK)
2297*7c478bd9Sstevel@tonic-gate 				goto ret;
2298*7c478bd9Sstevel@tonic-gate 			(void) big_copy(Lkminus1, &tmp2);
2299*7c478bd9Sstevel@tonic-gate 		}
2300*7c478bd9Sstevel@tonic-gate 		bit = bit >> 1;
2301*7c478bd9Sstevel@tonic-gate 		if (bit == 0) {
2302*7c478bd9Sstevel@tonic-gate 			bit = 0x80000000;
2303*7c478bd9Sstevel@tonic-gate 			w--;
2304*7c478bd9Sstevel@tonic-gate 		}
2305*7c478bd9Sstevel@tonic-gate 	}
2306*7c478bd9Sstevel@tonic-gate 
2307*7c478bd9Sstevel@tonic-gate 	err = BIG_OK;
2308*7c478bd9Sstevel@tonic-gate 
2309*7c478bd9Sstevel@tonic-gate ret:
2310*7c478bd9Sstevel@tonic-gate 	if (tmp2.malloced) big_finish(&tmp2);
2311*7c478bd9Sstevel@tonic-gate ret2:
2312*7c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
2313*7c478bd9Sstevel@tonic-gate ret1:
2314*7c478bd9Sstevel@tonic-gate 	if (ki.malloced) big_finish(&ki);
2315*7c478bd9Sstevel@tonic-gate 
2316*7c478bd9Sstevel@tonic-gate 	return (err);
2317*7c478bd9Sstevel@tonic-gate }
2318*7c478bd9Sstevel@tonic-gate 
2319*7c478bd9Sstevel@tonic-gate 
2320*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2321*7c478bd9Sstevel@tonic-gate big_isprime_pos(BIGNUM *n)
2322*7c478bd9Sstevel@tonic-gate {
2323*7c478bd9Sstevel@tonic-gate 	BIGNUM o, nminus1, tmp, Lkminus1, Lk;
2324*7c478bd9Sstevel@tonic-gate 	uint32_t ovalue[BIGTMPSIZE];
2325*7c478bd9Sstevel@tonic-gate 	uint32_t nminus1value[BIGTMPSIZE];
2326*7c478bd9Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
2327*7c478bd9Sstevel@tonic-gate 	uint32_t Lkminus1value[BIGTMPSIZE];
2328*7c478bd9Sstevel@tonic-gate 	uint32_t Lkvalue[BIGTMPSIZE];
2329*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
2330*7c478bd9Sstevel@tonic-gate 	int e, i, jac;
2331*7c478bd9Sstevel@tonic-gate 
2332*7c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(n, &One) == 0)
2333*7c478bd9Sstevel@tonic-gate 		return (BIG_FALSE);
2334*7c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(n, &Two) == 0)
2335*7c478bd9Sstevel@tonic-gate 		return (BIG_TRUE);
2336*7c478bd9Sstevel@tonic-gate 	if ((n->value[0] & 1) == 0)
2337*7c478bd9Sstevel@tonic-gate 		return (BIG_FALSE);
2338*7c478bd9Sstevel@tonic-gate 
2339*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) != BIG_OK)
2340*7c478bd9Sstevel@tonic-gate 		return (err);
2341*7c478bd9Sstevel@tonic-gate 
2342*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&nminus1, n->len,
2343*7c478bd9Sstevel@tonic-gate 	    nminus1value, arraysize(nminus1value))) != BIG_OK)
2344*7c478bd9Sstevel@tonic-gate 		goto ret1;
2345*7c478bd9Sstevel@tonic-gate 
2346*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * n->len,
2347*7c478bd9Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
2348*7c478bd9Sstevel@tonic-gate 		goto ret2;
2349*7c478bd9Sstevel@tonic-gate 
2350*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&Lkminus1, n->len,
2351*7c478bd9Sstevel@tonic-gate 	    Lkminus1value, arraysize(Lkminus1value))) != BIG_OK)
2352*7c478bd9Sstevel@tonic-gate 		goto ret3;
2353*7c478bd9Sstevel@tonic-gate 
2354*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&Lk, n->len,
2355*7c478bd9Sstevel@tonic-gate 	    Lkvalue, arraysize(Lkvalue))) != BIG_OK)
2356*7c478bd9Sstevel@tonic-gate 		goto ret4;
2357*7c478bd9Sstevel@tonic-gate 
2358*7c478bd9Sstevel@tonic-gate 	(void) big_sub_pos(&o, n, &One); 	/* cannot fail */
2359*7c478bd9Sstevel@tonic-gate 	(void) big_copy(&nminus1, &o);		/* cannot fail */
2360*7c478bd9Sstevel@tonic-gate 	e = 0;
2361*7c478bd9Sstevel@tonic-gate 	while ((o.value[0] & 1) == 0) {
2362*7c478bd9Sstevel@tonic-gate 		e++;
2363*7c478bd9Sstevel@tonic-gate 		(void) big_half_pos(&o, &o);  /* cannot fail */
2364*7c478bd9Sstevel@tonic-gate 	}
2365*7c478bd9Sstevel@tonic-gate 	if ((err = big_modexp(&tmp, &Two, &o, n, NULL)) != BIG_OK)
2366*7c478bd9Sstevel@tonic-gate 		goto ret;
2367*7c478bd9Sstevel@tonic-gate 	i = 0;
2368*7c478bd9Sstevel@tonic-gate 	while ((i < e) &&
2369*7c478bd9Sstevel@tonic-gate 	    (big_cmp_abs(&tmp, &One) != 0) &&
2370*7c478bd9Sstevel@tonic-gate 	    (big_cmp_abs(&tmp, &nminus1) != 0)) {
2371*7c478bd9Sstevel@tonic-gate 		if ((err = big_modexp(&tmp, &tmp, &Two, n, NULL)) !=  BIG_OK)
2372*7c478bd9Sstevel@tonic-gate 			goto ret;
2373*7c478bd9Sstevel@tonic-gate 		i++;
2374*7c478bd9Sstevel@tonic-gate 	}
2375*7c478bd9Sstevel@tonic-gate 	if (!((big_cmp_abs(&tmp, &nminus1) == 0) ||
2376*7c478bd9Sstevel@tonic-gate 	    ((i == 0) && (big_cmp_abs(&tmp, &One) == 0)))) {
2377*7c478bd9Sstevel@tonic-gate 		err = BIG_FALSE;
2378*7c478bd9Sstevel@tonic-gate 		goto ret;
2379*7c478bd9Sstevel@tonic-gate 	}
2380*7c478bd9Sstevel@tonic-gate 
2381*7c478bd9Sstevel@tonic-gate 	if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK)
2382*7c478bd9Sstevel@tonic-gate 		goto ret;
2383*7c478bd9Sstevel@tonic-gate 	if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK)
2384*7c478bd9Sstevel@tonic-gate 		goto ret;
2385*7c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(&tmp, n) == 0) {
2386*7c478bd9Sstevel@tonic-gate 		err = BIG_FALSE;
2387*7c478bd9Sstevel@tonic-gate 		goto ret;
2388*7c478bd9Sstevel@tonic-gate 	}
2389*7c478bd9Sstevel@tonic-gate 
2390*7c478bd9Sstevel@tonic-gate 	(void) big_copy(&o, &Two);
2391*7c478bd9Sstevel@tonic-gate 	do {
2392*7c478bd9Sstevel@tonic-gate 		(void) big_add_abs(&o, &o, &One);
2393*7c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&tmp, &o, &o)) != BIG_OK)
2394*7c478bd9Sstevel@tonic-gate 			goto ret;
2395*7c478bd9Sstevel@tonic-gate 		(void) big_sub_pos(&tmp, &tmp, &Four);
2396*7c478bd9Sstevel@tonic-gate 		if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK)
2397*7c478bd9Sstevel@tonic-gate 			goto ret;
2398*7c478bd9Sstevel@tonic-gate 	} while (jac != -1);
2399*7c478bd9Sstevel@tonic-gate 
2400*7c478bd9Sstevel@tonic-gate 	(void) big_add_abs(&tmp, n, &One);
2401*7c478bd9Sstevel@tonic-gate 	if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK)
2402*7c478bd9Sstevel@tonic-gate 		goto ret;
2403*7c478bd9Sstevel@tonic-gate 	if ((big_cmp_abs(&Lkminus1, &o) == 0) && (big_cmp_abs(&Lk, &Two) == 0))
2404*7c478bd9Sstevel@tonic-gate 		err = BIG_TRUE;
2405*7c478bd9Sstevel@tonic-gate 	else err = BIG_FALSE;
2406*7c478bd9Sstevel@tonic-gate 
2407*7c478bd9Sstevel@tonic-gate ret:
2408*7c478bd9Sstevel@tonic-gate 	if (Lk.malloced) big_finish(&Lk);
2409*7c478bd9Sstevel@tonic-gate ret4:
2410*7c478bd9Sstevel@tonic-gate 	if (Lkminus1.malloced) big_finish(&Lkminus1);
2411*7c478bd9Sstevel@tonic-gate ret3:
2412*7c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
2413*7c478bd9Sstevel@tonic-gate ret2:
2414*7c478bd9Sstevel@tonic-gate 	if (nminus1.malloced) big_finish(&nminus1);
2415*7c478bd9Sstevel@tonic-gate ret1:
2416*7c478bd9Sstevel@tonic-gate 	if (o.malloced) big_finish(&o);
2417*7c478bd9Sstevel@tonic-gate 
2418*7c478bd9Sstevel@tonic-gate 	return (err);
2419*7c478bd9Sstevel@tonic-gate }
2420*7c478bd9Sstevel@tonic-gate 
2421*7c478bd9Sstevel@tonic-gate 
2422*7c478bd9Sstevel@tonic-gate #define	SIEVESIZE 1000
2423*7c478bd9Sstevel@tonic-gate 
2424*7c478bd9Sstevel@tonic-gate uint32_t smallprimes[] =
2425*7c478bd9Sstevel@tonic-gate {
2426*7c478bd9Sstevel@tonic-gate 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
2427*7c478bd9Sstevel@tonic-gate 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97
2428*7c478bd9Sstevel@tonic-gate };
2429*7c478bd9Sstevel@tonic-gate 
2430*7c478bd9Sstevel@tonic-gate 
2431*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2432*7c478bd9Sstevel@tonic-gate big_nextprime_pos(BIGNUM *result, BIGNUM *n)
2433*7c478bd9Sstevel@tonic-gate {
2434*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
2435*7c478bd9Sstevel@tonic-gate 	int sieve[SIEVESIZE];
2436*7c478bd9Sstevel@tonic-gate 	int i;
2437*7c478bd9Sstevel@tonic-gate 	uint32_t off, p;
2438*7c478bd9Sstevel@tonic-gate 
2439*7c478bd9Sstevel@tonic-gate 	if ((err = big_copy(result, n)) != BIG_OK)
2440*7c478bd9Sstevel@tonic-gate 		return (err);
2441*7c478bd9Sstevel@tonic-gate 	result->value[0] |= 1;
2442*7c478bd9Sstevel@tonic-gate 	/* LINTED */
2443*7c478bd9Sstevel@tonic-gate 	while (1) {
2444*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0;
2445*7c478bd9Sstevel@tonic-gate 		for (i = 0;
2446*7c478bd9Sstevel@tonic-gate 		    i < sizeof (smallprimes) / sizeof (uint32_t); i++) {
2447*7c478bd9Sstevel@tonic-gate 			p = smallprimes[i];
2448*7c478bd9Sstevel@tonic-gate 			off = big_mod16_pos(result, p);
2449*7c478bd9Sstevel@tonic-gate 			off = p - off;
2450*7c478bd9Sstevel@tonic-gate 			if ((off % 2) == 1) off = off + p;
2451*7c478bd9Sstevel@tonic-gate 			off = off/2;
2452*7c478bd9Sstevel@tonic-gate 			while (off < SIEVESIZE) {
2453*7c478bd9Sstevel@tonic-gate 				sieve[off] = 1;
2454*7c478bd9Sstevel@tonic-gate 				off = off + p;
2455*7c478bd9Sstevel@tonic-gate 			}
2456*7c478bd9Sstevel@tonic-gate 		}
2457*7c478bd9Sstevel@tonic-gate 
2458*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < SIEVESIZE; i++) {
2459*7c478bd9Sstevel@tonic-gate 			if (sieve[i] == 0) {
2460*7c478bd9Sstevel@tonic-gate 				err = big_isprime_pos(result);
2461*7c478bd9Sstevel@tonic-gate 				if (err != BIG_FALSE) {
2462*7c478bd9Sstevel@tonic-gate 					if (err != BIG_TRUE)
2463*7c478bd9Sstevel@tonic-gate 						return (err);
2464*7c478bd9Sstevel@tonic-gate 					else
2465*7c478bd9Sstevel@tonic-gate 						return (BIG_OK);
2466*7c478bd9Sstevel@tonic-gate 				}
2467*7c478bd9Sstevel@tonic-gate 
2468*7c478bd9Sstevel@tonic-gate 			}
2469*7c478bd9Sstevel@tonic-gate 			if ((err = big_add_abs(result, result, &Two)) !=
2470*7c478bd9Sstevel@tonic-gate 			    BIG_OK)
2471*7c478bd9Sstevel@tonic-gate 				return (err);
2472*7c478bd9Sstevel@tonic-gate 		}
2473*7c478bd9Sstevel@tonic-gate 	}
2474*7c478bd9Sstevel@tonic-gate 	return (BIG_OK);
2475*7c478bd9Sstevel@tonic-gate }
2476*7c478bd9Sstevel@tonic-gate 
2477*7c478bd9Sstevel@tonic-gate 
2478*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2479*7c478bd9Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n)
2480*7c478bd9Sstevel@tonic-gate {
2481*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
2482*7c478bd9Sstevel@tonic-gate 
2483*7c478bd9Sstevel@tonic-gate 
2484*7c478bd9Sstevel@tonic-gate 	if ((err = big_copy(result, n)) != BIG_OK)
2485*7c478bd9Sstevel@tonic-gate 		return (err);
2486*7c478bd9Sstevel@tonic-gate 	result->value[0] |= 1;
2487*7c478bd9Sstevel@tonic-gate 	while ((err = big_isprime_pos(result)) != BIG_TRUE) {
2488*7c478bd9Sstevel@tonic-gate 		if (err != BIG_FALSE)
2489*7c478bd9Sstevel@tonic-gate 			return (err);
2490*7c478bd9Sstevel@tonic-gate 		if ((err = big_add_abs(result, result, &Two)) != BIG_OK)
2491*7c478bd9Sstevel@tonic-gate 			return (err);
2492*7c478bd9Sstevel@tonic-gate 	}
2493*7c478bd9Sstevel@tonic-gate 	return (BIG_OK);
2494*7c478bd9Sstevel@tonic-gate }
2495*7c478bd9Sstevel@tonic-gate 
2496*7c478bd9Sstevel@tonic-gate 
2497*7c478bd9Sstevel@tonic-gate /*
2498*7c478bd9Sstevel@tonic-gate  * given m and e, computes the rest in the equation
2499*7c478bd9Sstevel@tonic-gate  * gcd(m, e) = cm * m + ce * e
2500*7c478bd9Sstevel@tonic-gate  */
2501*7c478bd9Sstevel@tonic-gate BIG_ERR_CODE
2502*7c478bd9Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e)
2503*7c478bd9Sstevel@tonic-gate {
2504*7c478bd9Sstevel@tonic-gate 	BIGNUM *xi, *ri, *riminus1, *riminus2, *t,
2505*7c478bd9Sstevel@tonic-gate 	    *vmi, *vei, *vmiminus1, *veiminus1;
2506*7c478bd9Sstevel@tonic-gate 	BIGNUM t1, t2, t3, t4, t5, t6, t7, t8, tmp;
2507*7c478bd9Sstevel@tonic-gate 	uint32_t t1value[BIGTMPSIZE];
2508*7c478bd9Sstevel@tonic-gate 	uint32_t t2value[BIGTMPSIZE];
2509*7c478bd9Sstevel@tonic-gate 	uint32_t t3value[BIGTMPSIZE];
2510*7c478bd9Sstevel@tonic-gate 	uint32_t t4value[BIGTMPSIZE];
2511*7c478bd9Sstevel@tonic-gate 	uint32_t t5value[BIGTMPSIZE];
2512*7c478bd9Sstevel@tonic-gate 	uint32_t t6value[BIGTMPSIZE];
2513*7c478bd9Sstevel@tonic-gate 	uint32_t t7value[BIGTMPSIZE];
2514*7c478bd9Sstevel@tonic-gate 	uint32_t t8value[BIGTMPSIZE];
2515*7c478bd9Sstevel@tonic-gate 	uint32_t tmpvalue[BIGTMPSIZE];
2516*7c478bd9Sstevel@tonic-gate 	BIG_ERR_CODE err;
2517*7c478bd9Sstevel@tonic-gate 	int len;
2518*7c478bd9Sstevel@tonic-gate 
2519*7c478bd9Sstevel@tonic-gate 	if (big_cmp_abs(m, e) >= 0) len = m->len;
2520*7c478bd9Sstevel@tonic-gate 	else len = e->len;
2521*7c478bd9Sstevel@tonic-gate 
2522*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t1, len,
2523*7c478bd9Sstevel@tonic-gate 	    t1value, arraysize(t1value))) != BIG_OK)
2524*7c478bd9Sstevel@tonic-gate 		return (err);
2525*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t2, len,
2526*7c478bd9Sstevel@tonic-gate 	    t2value, arraysize(t2value))) != BIG_OK)
2527*7c478bd9Sstevel@tonic-gate 			goto ret1;
2528*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t3, len,
2529*7c478bd9Sstevel@tonic-gate 	    t3value, arraysize(t3value))) != BIG_OK)
2530*7c478bd9Sstevel@tonic-gate 			goto ret2;
2531*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t4, len,
2532*7c478bd9Sstevel@tonic-gate 	    t4value, arraysize(t3value))) != BIG_OK)
2533*7c478bd9Sstevel@tonic-gate 			goto ret3;
2534*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t5, len,
2535*7c478bd9Sstevel@tonic-gate 	    t5value, arraysize(t5value))) != BIG_OK)
2536*7c478bd9Sstevel@tonic-gate 			goto ret4;
2537*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t6, len,
2538*7c478bd9Sstevel@tonic-gate 	    t6value, arraysize(t6value))) != BIG_OK)
2539*7c478bd9Sstevel@tonic-gate 			goto ret5;
2540*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t7, len,
2541*7c478bd9Sstevel@tonic-gate 	    t7value, arraysize(t7value))) != BIG_OK)
2542*7c478bd9Sstevel@tonic-gate 			goto ret6;
2543*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&t8, len,
2544*7c478bd9Sstevel@tonic-gate 	    t8value, arraysize(t8value))) != BIG_OK)
2545*7c478bd9Sstevel@tonic-gate 			goto ret7;
2546*7c478bd9Sstevel@tonic-gate 
2547*7c478bd9Sstevel@tonic-gate 	if ((err = big_init1(&tmp, 2 * len,
2548*7c478bd9Sstevel@tonic-gate 	    tmpvalue, arraysize(tmpvalue))) != BIG_OK)
2549*7c478bd9Sstevel@tonic-gate 		goto ret8;
2550*7c478bd9Sstevel@tonic-gate 
2551*7c478bd9Sstevel@tonic-gate 	ri = &t1;
2552*7c478bd9Sstevel@tonic-gate 	ri->value[0] = 1;
2553*7c478bd9Sstevel@tonic-gate 	ri->len = 1;
2554*7c478bd9Sstevel@tonic-gate 	xi = &t2;
2555*7c478bd9Sstevel@tonic-gate 	riminus1 = &t3;
2556*7c478bd9Sstevel@tonic-gate 	riminus2 = &t4;
2557*7c478bd9Sstevel@tonic-gate 	vmi = &t5;
2558*7c478bd9Sstevel@tonic-gate 	vei = &t6;
2559*7c478bd9Sstevel@tonic-gate 	vmiminus1 = &t7;
2560*7c478bd9Sstevel@tonic-gate 	veiminus1 = &t8;
2561*7c478bd9Sstevel@tonic-gate 
2562*7c478bd9Sstevel@tonic-gate 	(void) big_copy(vmiminus1, &One);
2563*7c478bd9Sstevel@tonic-gate 	(void) big_copy(vmi, &One);
2564*7c478bd9Sstevel@tonic-gate 	(void) big_copy(veiminus1, &One);
2565*7c478bd9Sstevel@tonic-gate 	(void) big_copy(xi, &One);
2566*7c478bd9Sstevel@tonic-gate 	vei->len = 1;
2567*7c478bd9Sstevel@tonic-gate 	vei->value[0] = 0;
2568*7c478bd9Sstevel@tonic-gate 
2569*7c478bd9Sstevel@tonic-gate 	(void) big_copy(riminus1, m);
2570*7c478bd9Sstevel@tonic-gate 	(void) big_copy(ri, e);
2571*7c478bd9Sstevel@tonic-gate 
2572*7c478bd9Sstevel@tonic-gate 	while (!big_is_zero(ri)) {
2573*7c478bd9Sstevel@tonic-gate 		t = riminus2;
2574*7c478bd9Sstevel@tonic-gate 		riminus2 = riminus1;
2575*7c478bd9Sstevel@tonic-gate 		riminus1 = ri;
2576*7c478bd9Sstevel@tonic-gate 		ri = t;
2577*7c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK)
2578*7c478bd9Sstevel@tonic-gate 			goto ret;
2579*7c478bd9Sstevel@tonic-gate 		if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK)
2580*7c478bd9Sstevel@tonic-gate 			goto ret;
2581*7c478bd9Sstevel@tonic-gate 		t = vmiminus1;
2582*7c478bd9Sstevel@tonic-gate 		vmiminus1 = vmi;
2583*7c478bd9Sstevel@tonic-gate 		vmi = t;
2584*7c478bd9Sstevel@tonic-gate 		if ((err = big_mul(&tmp, vei, xi)) != BIG_OK)
2585*7c478bd9Sstevel@tonic-gate 			goto ret;
2586*7c478bd9Sstevel@tonic-gate 		if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK)
2587*7c478bd9Sstevel@tonic-gate 			goto ret;
2588*7c478bd9Sstevel@tonic-gate 		t = veiminus1;
2589*7c478bd9Sstevel@tonic-gate 		veiminus1 = vei;
2590*7c478bd9Sstevel@tonic-gate 		vei = t;
2591*7c478bd9Sstevel@tonic-gate 		if ((err = big_div_pos(xi, ri, riminus2, riminus1)) != BIG_OK)
2592*7c478bd9Sstevel@tonic-gate 			goto ret;
2593*7c478bd9Sstevel@tonic-gate 	}
2594*7c478bd9Sstevel@tonic-gate 	if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK))
2595*7c478bd9Sstevel@tonic-gate 		goto ret;
2596*7c478bd9Sstevel@tonic-gate 	if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK))
2597*7c478bd9Sstevel@tonic-gate 		goto ret;
2598*7c478bd9Sstevel@tonic-gate 	if (ce != NULL)
2599*7c478bd9Sstevel@tonic-gate 		err = big_copy(ce, vei);
2600*7c478bd9Sstevel@tonic-gate ret:
2601*7c478bd9Sstevel@tonic-gate 	if (tmp.malloced) big_finish(&tmp);
2602*7c478bd9Sstevel@tonic-gate ret8:
2603*7c478bd9Sstevel@tonic-gate 	if (t8.malloced) big_finish(&t8);
2604*7c478bd9Sstevel@tonic-gate ret7:
2605*7c478bd9Sstevel@tonic-gate 	if (t7.malloced) big_finish(&t7);
2606*7c478bd9Sstevel@tonic-gate ret6:
2607*7c478bd9Sstevel@tonic-gate 	if (t6.malloced) big_finish(&t6);
2608*7c478bd9Sstevel@tonic-gate ret5:
2609*7c478bd9Sstevel@tonic-gate 	if (t5.malloced) big_finish(&t5);
2610*7c478bd9Sstevel@tonic-gate ret4:
2611*7c478bd9Sstevel@tonic-gate 	if (t4.malloced) big_finish(&t4);
2612*7c478bd9Sstevel@tonic-gate ret3:
2613*7c478bd9Sstevel@tonic-gate 	if (t3.malloced) big_finish(&t3);
2614*7c478bd9Sstevel@tonic-gate ret2:
2615*7c478bd9Sstevel@tonic-gate 	if (t2.malloced) big_finish(&t2);
2616*7c478bd9Sstevel@tonic-gate ret1:
2617*7c478bd9Sstevel@tonic-gate 	if (t1.malloced) big_finish(&t1);
2618*7c478bd9Sstevel@tonic-gate 
2619*7c478bd9Sstevel@tonic-gate 	return (err);
2620*7c478bd9Sstevel@tonic-gate }
2621