10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 56557Sfr41279 * Common Development and Distribution License (the "License"). 66557Sfr41279 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*8933Sopensolaris@drydog.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * Configuration guide 280Sstevel@tonic-gate * ------------------- 290Sstevel@tonic-gate * 300Sstevel@tonic-gate * There are 4 preprocessor symbols used to configure the bignum 310Sstevel@tonic-gate * implementation. This file contains no logic to configure based on 320Sstevel@tonic-gate * processor; we leave that to the Makefiles to specify. 330Sstevel@tonic-gate * 340Sstevel@tonic-gate * USE_FLOATING_POINT 350Sstevel@tonic-gate * Meaning: There is support for a fast floating-point implementation of 360Sstevel@tonic-gate * Montgomery multiply. 370Sstevel@tonic-gate * 380Sstevel@tonic-gate * PSR_MUL 390Sstevel@tonic-gate * Meaning: There are processor-specific versions of the low level 400Sstevel@tonic-gate * functions to implement big_mul. Those functions are: big_mul_set_vec, 410Sstevel@tonic-gate * big_mul_add_vec, big_mul_vec, and big_sqr_vec. PSR_MUL implies support 420Sstevel@tonic-gate * for all 4 functions. You cannot pick and choose which subset of these 430Sstevel@tonic-gate * functions to support; that would lead to a rat's nest of #ifdefs. 440Sstevel@tonic-gate * 450Sstevel@tonic-gate * HWCAP 460Sstevel@tonic-gate * Meaning: Call multiply support functions through a function pointer. 47*8933Sopensolaris@drydog.com * On x86, there are multiple implementations for different hardware 480Sstevel@tonic-gate * capabilities, such as MMX, SSE2, etc. Tests are made at run-time, when 490Sstevel@tonic-gate * a function is first used. So, the support functions are called through 500Sstevel@tonic-gate * a function pointer. There is no need for that on Sparc, because there 510Sstevel@tonic-gate * is only one implementation; support functions are called directly. 520Sstevel@tonic-gate * Later, if there were some new VIS instruction, or something, and a 530Sstevel@tonic-gate * run-time test were needed, rather than variant kernel modules and 540Sstevel@tonic-gate * libraries, then HWCAP would be defined for Sparc, as well. 550Sstevel@tonic-gate * 560Sstevel@tonic-gate * UMUL64 570Sstevel@tonic-gate * Meaning: It is safe to use generic C code that assumes the existence 580Sstevel@tonic-gate * of a 32 x 32 --> 64 bit unsigned multiply. If this is not defined, 590Sstevel@tonic-gate * then the generic code for big_mul_add_vec() must necessarily be very slow, 600Sstevel@tonic-gate * because it must fall back to using 16 x 16 --> 32 bit multiplication. 610Sstevel@tonic-gate * 620Sstevel@tonic-gate */ 630Sstevel@tonic-gate 640Sstevel@tonic-gate 65*8933Sopensolaris@drydog.com #include <sys/types.h> 66*8933Sopensolaris@drydog.com #include "bignum.h" 67*8933Sopensolaris@drydog.com 680Sstevel@tonic-gate #ifdef _KERNEL 696557Sfr41279 #include <sys/ddi.h> 706557Sfr41279 #include <sys/mdesc.h> 716557Sfr41279 #include <sys/crypto/common.h> 720Sstevel@tonic-gate 730Sstevel@tonic-gate #include <sys/kmem.h> 740Sstevel@tonic-gate #include <sys/param.h> 750Sstevel@tonic-gate #include <sys/sunddi.h> 760Sstevel@tonic-gate 77*8933Sopensolaris@drydog.com #else 78*8933Sopensolaris@drydog.com #include <stdlib.h> 79*8933Sopensolaris@drydog.com #include <stdio.h> 80*8933Sopensolaris@drydog.com #include <assert.h> 81*8933Sopensolaris@drydog.com #define ASSERT assert 82*8933Sopensolaris@drydog.com #endif /* _KERNEL */ 83*8933Sopensolaris@drydog.com 84*8933Sopensolaris@drydog.com #ifdef _LP64 /* truncate 64-bit size_t to 32-bits */ 85*8933Sopensolaris@drydog.com #define UI32(ui) ((uint32_t)ui) 86*8933Sopensolaris@drydog.com #else /* size_t already 32-bits */ 87*8933Sopensolaris@drydog.com #define UI32(ui) (ui) 88*8933Sopensolaris@drydog.com #endif 89*8933Sopensolaris@drydog.com 90*8933Sopensolaris@drydog.com 91*8933Sopensolaris@drydog.com #ifdef _KERNEL 920Sstevel@tonic-gate #define big_malloc(size) kmem_alloc(size, KM_NOSLEEP) 930Sstevel@tonic-gate #define big_free(ptr, size) kmem_free(ptr, size) 940Sstevel@tonic-gate 950Sstevel@tonic-gate void * 960Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize) 970Sstevel@tonic-gate { 980Sstevel@tonic-gate void *rv; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate rv = kmem_alloc(newsize, KM_NOSLEEP); 1010Sstevel@tonic-gate if (rv != NULL) 1020Sstevel@tonic-gate bcopy(from, rv, oldsize); 1030Sstevel@tonic-gate kmem_free(from, oldsize); 1040Sstevel@tonic-gate return (rv); 1050Sstevel@tonic-gate } 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate #else /* _KERNEL */ 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate #ifndef MALLOC_DEBUG 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate #define big_malloc(size) malloc(size) 1120Sstevel@tonic-gate #define big_free(ptr, size) free(ptr) 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate #else 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate void 1170Sstevel@tonic-gate big_free(void *ptr, size_t size) 1180Sstevel@tonic-gate { 1190Sstevel@tonic-gate printf("freed %d bytes at %p\n", size, ptr); 1200Sstevel@tonic-gate free(ptr); 1210Sstevel@tonic-gate } 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate void * 1240Sstevel@tonic-gate big_malloc(size_t size) 1250Sstevel@tonic-gate { 1260Sstevel@tonic-gate void *rv; 1270Sstevel@tonic-gate rv = malloc(size); 1280Sstevel@tonic-gate printf("malloced %d bytes, addr:%p\n", size, rv); 1290Sstevel@tonic-gate return (rv); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate #endif /* MALLOC_DEBUG */ 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate #define big_realloc(x, y, z) realloc((x), (z)) 1340Sstevel@tonic-gate 135*8933Sopensolaris@drydog.com 136*8933Sopensolaris@drydog.com /* 137*8933Sopensolaris@drydog.com * printbignum() 138*8933Sopensolaris@drydog.com * Print a BIGNUM type to stdout. 139*8933Sopensolaris@drydog.com */ 1400Sstevel@tonic-gate void 1410Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a) 1420Sstevel@tonic-gate { 1430Sstevel@tonic-gate int i; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate (void) printf("\n%s\n%d\n", aname, a->sign*a->len); 1460Sstevel@tonic-gate for (i = a->len - 1; i >= 0; i--) { 1476557Sfr41279 #ifdef BIGNUM_CHUNK_32 1480Sstevel@tonic-gate (void) printf("%08x ", a->value[i]); 149*8933Sopensolaris@drydog.com if (((i & (BITSINBYTE - 1)) == 0) && (i != 0)) { 1506557Sfr41279 (void) printf("\n"); 1516557Sfr41279 } 1526557Sfr41279 #else 1536557Sfr41279 (void) printf("%08x %08x ", (uint32_t)((a->value[i]) >> 32), 1546557Sfr41279 (uint32_t)((a->value[i]) & 0xffffffff)); 155*8933Sopensolaris@drydog.com if (((i & 3) == 0) && (i != 0)) { /* end of this chunk */ 1566557Sfr41279 (void) printf("\n"); 1576557Sfr41279 } 1586557Sfr41279 #endif 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate (void) printf("\n"); 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate #endif /* _KERNEL */ 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate 166*8933Sopensolaris@drydog.com /* 167*8933Sopensolaris@drydog.com * big_init() 168*8933Sopensolaris@drydog.com * Initialize and allocate memory for a BIGNUM type. 169*8933Sopensolaris@drydog.com * 170*8933Sopensolaris@drydog.com * big_init(number, size) is equivalent to big_init1(number, size, NULL, 0) 171*8933Sopensolaris@drydog.com * 172*8933Sopensolaris@drydog.com * Note: call big_finish() to free memory allocated by big_init(). 173*8933Sopensolaris@drydog.com * 174*8933Sopensolaris@drydog.com * Input: 175*8933Sopensolaris@drydog.com * number Uninitialized memory for BIGNUM 176*8933Sopensolaris@drydog.com * size Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM 177*8933Sopensolaris@drydog.com * 178*8933Sopensolaris@drydog.com * Output: 179*8933Sopensolaris@drydog.com * number Initialized BIGNUM 180*8933Sopensolaris@drydog.com * 181*8933Sopensolaris@drydog.com * Return BIG_OK on success or BIG_NO_MEM for an allocation error. 182*8933Sopensolaris@drydog.com */ 1830Sstevel@tonic-gate BIG_ERR_CODE 1840Sstevel@tonic-gate big_init(BIGNUM *number, int size) 1850Sstevel@tonic-gate { 186*8933Sopensolaris@drydog.com number->value = big_malloc(BIGNUM_WORDSIZE * size); 1870Sstevel@tonic-gate if (number->value == NULL) { 1880Sstevel@tonic-gate return (BIG_NO_MEM); 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate number->size = size; 1910Sstevel@tonic-gate number->len = 0; 1920Sstevel@tonic-gate number->sign = 1; 1930Sstevel@tonic-gate number->malloced = 1; 1940Sstevel@tonic-gate return (BIG_OK); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 197*8933Sopensolaris@drydog.com 198*8933Sopensolaris@drydog.com /* 199*8933Sopensolaris@drydog.com * big_init1() 200*8933Sopensolaris@drydog.com * Initialize and, if needed, allocate memory for a BIGNUM type. 201*8933Sopensolaris@drydog.com * Use the buffer passed, buf, if any, instad of allocating memory 202*8933Sopensolaris@drydog.com * if it's at least "size" bytes. 203*8933Sopensolaris@drydog.com * 204*8933Sopensolaris@drydog.com * Note: call big_finish() to free memory allocated by big_init(). 205*8933Sopensolaris@drydog.com * 206*8933Sopensolaris@drydog.com * Input: 207*8933Sopensolaris@drydog.com * number Uninitialized memory for BIGNUM 208*8933Sopensolaris@drydog.com * size Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM 209*8933Sopensolaris@drydog.com * buf Buffer for storing a BIGNUM. 210*8933Sopensolaris@drydog.com * If NULL, big_init1() will allocate a buffer 211*8933Sopensolaris@drydog.com * bufsize Size, in BIG_CHUNK_SIZE_bit words, of buf 212*8933Sopensolaris@drydog.com * 213*8933Sopensolaris@drydog.com * Output: 214*8933Sopensolaris@drydog.com * number Initialized BIGNUM 215*8933Sopensolaris@drydog.com * 216*8933Sopensolaris@drydog.com * Return BIG_OK on success or BIG_NO_MEM for an allocation error. 217*8933Sopensolaris@drydog.com */ 2180Sstevel@tonic-gate BIG_ERR_CODE 2196557Sfr41279 big_init1(BIGNUM *number, int size, BIG_CHUNK_TYPE *buf, int bufsize) 2200Sstevel@tonic-gate { 2210Sstevel@tonic-gate if ((buf == NULL) || (size > bufsize)) { 222*8933Sopensolaris@drydog.com number->value = big_malloc(BIGNUM_WORDSIZE * size); 2230Sstevel@tonic-gate if (number->value == NULL) { 2240Sstevel@tonic-gate return (BIG_NO_MEM); 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate number->size = size; 2270Sstevel@tonic-gate number->malloced = 1; 2280Sstevel@tonic-gate } else { 2290Sstevel@tonic-gate number->value = buf; 2300Sstevel@tonic-gate number->size = bufsize; 2310Sstevel@tonic-gate number->malloced = 0; 2320Sstevel@tonic-gate } 233*8933Sopensolaris@drydog.com number->len = 0; 234*8933Sopensolaris@drydog.com number->sign = 1; 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate return (BIG_OK); 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate 239*8933Sopensolaris@drydog.com 240*8933Sopensolaris@drydog.com /* 241*8933Sopensolaris@drydog.com * big_finish() 242*8933Sopensolaris@drydog.com * Free memory, if any, allocated by big_init() or big_init1(). 243*8933Sopensolaris@drydog.com */ 2440Sstevel@tonic-gate void 2450Sstevel@tonic-gate big_finish(BIGNUM *number) 2460Sstevel@tonic-gate { 2470Sstevel@tonic-gate if (number->malloced == 1) { 248*8933Sopensolaris@drydog.com big_free(number->value, BIGNUM_WORDSIZE * number->size); 2490Sstevel@tonic-gate number->malloced = 0; 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate 2536557Sfr41279 2540Sstevel@tonic-gate /* 255*8933Sopensolaris@drydog.com * bn->size should be at least 256*8933Sopensolaris@drydog.com * (len + BIGNUM_WORDSIZE - 1) / BIGNUM_WORDSIZE bytes 2570Sstevel@tonic-gate * converts from byte-big-endian format to bignum format (words in 2580Sstevel@tonic-gate * little endian order, but bytes within the words big endian) 2590Sstevel@tonic-gate */ 2600Sstevel@tonic-gate void 2610Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len) 2620Sstevel@tonic-gate { 263*8933Sopensolaris@drydog.com int i, j; 264*8933Sopensolaris@drydog.com uint32_t offs; 265*8933Sopensolaris@drydog.com const uint32_t slen = UI32(len); 2666557Sfr41279 BIG_CHUNK_TYPE word; 2670Sstevel@tonic-gate uchar_t *knwordp; 2680Sstevel@tonic-gate 269*8933Sopensolaris@drydog.com if (slen == 0) { 270*8933Sopensolaris@drydog.com bn->len = 1; 271*8933Sopensolaris@drydog.com bn->value[0] = 0; 272*8933Sopensolaris@drydog.com return; 273*8933Sopensolaris@drydog.com } 274*8933Sopensolaris@drydog.com 275*8933Sopensolaris@drydog.com offs = slen % BIGNUM_WORDSIZE; 276*8933Sopensolaris@drydog.com bn->len = slen / BIGNUM_WORDSIZE; 277*8933Sopensolaris@drydog.com 278*8933Sopensolaris@drydog.com for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) { 279*8933Sopensolaris@drydog.com knwordp = &(kn[slen - BIGNUM_WORDSIZE * (i + 1)]); 2800Sstevel@tonic-gate word = knwordp[0]; 281*8933Sopensolaris@drydog.com for (j = 1; j < BIGNUM_WORDSIZE; j++) { 282*8933Sopensolaris@drydog.com word = (word << BITSINBYTE) + knwordp[j]; 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate bn->value[i] = word; 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate if (offs > 0) { 2870Sstevel@tonic-gate word = kn[0]; 288*8933Sopensolaris@drydog.com for (i = 1; i < offs; i++) word = (word << BITSINBYTE) + kn[i]; 2890Sstevel@tonic-gate bn->value[bn->len++] = word; 2900Sstevel@tonic-gate } 291*8933Sopensolaris@drydog.com while ((bn->len > 1) && (bn->value[bn->len - 1] == 0)) { 2920Sstevel@tonic-gate bn->len --; 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 296*8933Sopensolaris@drydog.com 2970Sstevel@tonic-gate /* 2980Sstevel@tonic-gate * copies the least significant len bytes if 299*8933Sopensolaris@drydog.com * len < bn->len * BIGNUM_WORDSIZE 3000Sstevel@tonic-gate * converts from bignum format to byte-big-endian format. 3016557Sfr41279 * bignum format is words of type BIG_CHUNK_TYPE in little endian order. 3020Sstevel@tonic-gate */ 3030Sstevel@tonic-gate void 3040Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len) 3050Sstevel@tonic-gate { 306*8933Sopensolaris@drydog.com int i, j; 307*8933Sopensolaris@drydog.com uint32_t offs; 308*8933Sopensolaris@drydog.com const uint32_t slen = UI32(len); 3096557Sfr41279 BIG_CHUNK_TYPE word; 3106557Sfr41279 311*8933Sopensolaris@drydog.com if (len < BIGNUM_WORDSIZE * bn->len) { 312*8933Sopensolaris@drydog.com for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) { 3130Sstevel@tonic-gate word = bn->value[i]; 314*8933Sopensolaris@drydog.com for (j = 0; j < BIGNUM_WORDSIZE; j++) { 315*8933Sopensolaris@drydog.com kn[slen - BIGNUM_WORDSIZE * i - j - 1] = 3160Sstevel@tonic-gate word & 0xff; 317*8933Sopensolaris@drydog.com word = word >> BITSINBYTE; 3180Sstevel@tonic-gate } 3190Sstevel@tonic-gate } 320*8933Sopensolaris@drydog.com offs = slen % BIGNUM_WORDSIZE; 3210Sstevel@tonic-gate if (offs > 0) { 322*8933Sopensolaris@drydog.com word = bn->value[slen / BIGNUM_WORDSIZE]; 323*8933Sopensolaris@drydog.com for (i = slen % BIGNUM_WORDSIZE; i > 0; i --) { 3246557Sfr41279 kn[i - 1] = word & 0xff; 325*8933Sopensolaris@drydog.com word = word >> BITSINBYTE; 3266557Sfr41279 } 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate } else { 3290Sstevel@tonic-gate for (i = 0; i < bn->len; i++) { 3300Sstevel@tonic-gate word = bn->value[i]; 331*8933Sopensolaris@drydog.com for (j = 0; j < BIGNUM_WORDSIZE; j++) { 332*8933Sopensolaris@drydog.com kn[slen - BIGNUM_WORDSIZE * i - j - 1] = 3330Sstevel@tonic-gate word & 0xff; 334*8933Sopensolaris@drydog.com word = word >> BITSINBYTE; 3350Sstevel@tonic-gate } 3360Sstevel@tonic-gate } 337*8933Sopensolaris@drydog.com for (i = 0; i < slen - BIGNUM_WORDSIZE * bn->len; i++) { 3380Sstevel@tonic-gate kn[i] = 0; 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate int 3450Sstevel@tonic-gate big_bitlength(BIGNUM *a) 3460Sstevel@tonic-gate { 3476557Sfr41279 int l = 0, b = 0; 3486557Sfr41279 BIG_CHUNK_TYPE c; 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate l = a->len - 1; 3510Sstevel@tonic-gate while ((l > 0) && (a->value[l] == 0)) { 3520Sstevel@tonic-gate l--; 3530Sstevel@tonic-gate } 354*8933Sopensolaris@drydog.com b = BIG_CHUNK_SIZE; 3550Sstevel@tonic-gate c = a->value[l]; 3566557Sfr41279 while ((b > 1) && ((c & BIG_CHUNK_HIGHBIT) == 0)) { 3570Sstevel@tonic-gate c = c << 1; 3580Sstevel@tonic-gate b--; 3590Sstevel@tonic-gate } 3606557Sfr41279 361*8933Sopensolaris@drydog.com return (l * BIG_CHUNK_SIZE + b); 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate BIG_ERR_CODE 3660Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src) 3670Sstevel@tonic-gate { 3686557Sfr41279 BIG_CHUNK_TYPE *newptr; 3696557Sfr41279 int i, len; 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate len = src->len; 3726557Sfr41279 while ((len > 1) && (src->value[len - 1] == 0)) { 3730Sstevel@tonic-gate len--; 3746557Sfr41279 } 3750Sstevel@tonic-gate src->len = len; 3760Sstevel@tonic-gate if (dest->size < len) { 3770Sstevel@tonic-gate if (dest->malloced == 1) { 3786557Sfr41279 newptr = (BIG_CHUNK_TYPE *)big_realloc(dest->value, 379*8933Sopensolaris@drydog.com BIGNUM_WORDSIZE * dest->size, 380*8933Sopensolaris@drydog.com BIGNUM_WORDSIZE * len); 3810Sstevel@tonic-gate } else { 3826557Sfr41279 newptr = (BIG_CHUNK_TYPE *) 383*8933Sopensolaris@drydog.com big_malloc(BIGNUM_WORDSIZE * len); 3846557Sfr41279 if (newptr != NULL) { 3856557Sfr41279 dest->malloced = 1; 3866557Sfr41279 } 3870Sstevel@tonic-gate } 3886557Sfr41279 if (newptr == NULL) { 3890Sstevel@tonic-gate return (BIG_NO_MEM); 3906557Sfr41279 } 3910Sstevel@tonic-gate dest->value = newptr; 3920Sstevel@tonic-gate dest->size = len; 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate dest->len = len; 3950Sstevel@tonic-gate dest->sign = src->sign; 3966557Sfr41279 for (i = 0; i < len; i++) { 3976557Sfr41279 dest->value[i] = src->value[i]; 3986557Sfr41279 } 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate return (BIG_OK); 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate BIG_ERR_CODE 4050Sstevel@tonic-gate big_extend(BIGNUM *number, int size) 4060Sstevel@tonic-gate { 4076557Sfr41279 BIG_CHUNK_TYPE *newptr; 4080Sstevel@tonic-gate int i; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate if (number->size >= size) 4110Sstevel@tonic-gate return (BIG_OK); 4120Sstevel@tonic-gate if (number->malloced) { 4136557Sfr41279 number->value = big_realloc(number->value, 414*8933Sopensolaris@drydog.com BIGNUM_WORDSIZE * number->size, 415*8933Sopensolaris@drydog.com BIGNUM_WORDSIZE * size); 4160Sstevel@tonic-gate } else { 417*8933Sopensolaris@drydog.com newptr = big_malloc(BIGNUM_WORDSIZE * size); 4180Sstevel@tonic-gate if (newptr != NULL) { 4190Sstevel@tonic-gate for (i = 0; i < number->size; i++) { 4200Sstevel@tonic-gate newptr[i] = number->value[i]; 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate } 4230Sstevel@tonic-gate number->value = newptr; 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate 4266557Sfr41279 if (number->value == NULL) { 4270Sstevel@tonic-gate return (BIG_NO_MEM); 4286557Sfr41279 } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate number->size = size; 4310Sstevel@tonic-gate number->malloced = 1; 4320Sstevel@tonic-gate return (BIG_OK); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate 4366557Sfr41279 /* returns 1 if n == 0 */ 4370Sstevel@tonic-gate int 4380Sstevel@tonic-gate big_is_zero(BIGNUM *n) 4390Sstevel@tonic-gate { 4406557Sfr41279 int i, result; 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate result = 1; 4436557Sfr41279 for (i = 0; i < n->len; i++) { 4446557Sfr41279 if (n->value[i] != 0) { 4456557Sfr41279 result = 0; 4466557Sfr41279 } 4476557Sfr41279 } 4480Sstevel@tonic-gate return (result); 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate BIG_ERR_CODE 4530Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 4540Sstevel@tonic-gate { 4556557Sfr41279 int i, shorter, longer; 4566557Sfr41279 BIG_CHUNK_TYPE cy, ai; 4576557Sfr41279 BIG_CHUNK_TYPE *r, *a, *b, *c; 4586557Sfr41279 BIG_ERR_CODE err; 4596557Sfr41279 BIGNUM *longerarg; 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate if (aa->len > bb->len) { 4620Sstevel@tonic-gate shorter = bb->len; 4630Sstevel@tonic-gate longer = aa->len; 4646557Sfr41279 longerarg = aa; 4650Sstevel@tonic-gate } else { 4660Sstevel@tonic-gate shorter = aa->len; 4670Sstevel@tonic-gate longer = bb->len; 4686557Sfr41279 longerarg = bb; 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate if (result->size < longer + 1) { 4710Sstevel@tonic-gate err = big_extend(result, longer + 1); 4726557Sfr41279 if (err != BIG_OK) { 4730Sstevel@tonic-gate return (err); 4746557Sfr41279 } 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate r = result->value; 4780Sstevel@tonic-gate a = aa->value; 4790Sstevel@tonic-gate b = bb->value; 4806557Sfr41279 c = longerarg->value; 4810Sstevel@tonic-gate cy = 0; 4820Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 4830Sstevel@tonic-gate ai = a[i]; 4840Sstevel@tonic-gate r[i] = ai + b[i] + cy; 4856557Sfr41279 if (r[i] > ai) { 4866557Sfr41279 cy = 0; 4876557Sfr41279 } else if (r[i] < ai) { 4886557Sfr41279 cy = 1; 4896557Sfr41279 } 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate for (; i < longer; i++) { 4920Sstevel@tonic-gate ai = c[i]; 4930Sstevel@tonic-gate r[i] = ai + cy; 4946557Sfr41279 if (r[i] >= ai) { 4956557Sfr41279 cy = 0; 4966557Sfr41279 } 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate if (cy == 1) { 4990Sstevel@tonic-gate r[i] = cy; 5000Sstevel@tonic-gate result->len = longer + 1; 5010Sstevel@tonic-gate } else { 5020Sstevel@tonic-gate result->len = longer; 5030Sstevel@tonic-gate } 5040Sstevel@tonic-gate result->sign = 1; 5050Sstevel@tonic-gate return (BIG_OK); 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */ 5100Sstevel@tonic-gate void 5116557Sfr41279 big_sub_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, BIG_CHUNK_TYPE *b, int len) 5120Sstevel@tonic-gate { 5136557Sfr41279 int i; 5146557Sfr41279 BIG_CHUNK_TYPE cy, ai; 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate cy = 1; 5170Sstevel@tonic-gate for (i = 0; i < len; i++) { 5180Sstevel@tonic-gate ai = a[i]; 5190Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 5206557Sfr41279 if (r[i] > ai) { 5216557Sfr41279 cy = 0; 5226557Sfr41279 } else if (r[i] < ai) { 5236557Sfr41279 cy = 1; 5246557Sfr41279 } 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate /* result=aa-bb it is assumed that aa>=bb */ 5300Sstevel@tonic-gate BIG_ERR_CODE 5310Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 5320Sstevel@tonic-gate { 5336557Sfr41279 int i, shorter; 5346557Sfr41279 BIG_CHUNK_TYPE cy = 1, ai; 5356557Sfr41279 BIG_CHUNK_TYPE *r, *a, *b; 5366557Sfr41279 BIG_ERR_CODE err = BIG_OK; 5376557Sfr41279 5386557Sfr41279 if (aa->len > bb->len) { 5396557Sfr41279 shorter = bb->len; 5406557Sfr41279 } else { 5416557Sfr41279 shorter = aa->len; 5426557Sfr41279 } 5430Sstevel@tonic-gate if (result->size < aa->len) { 5440Sstevel@tonic-gate err = big_extend(result, aa->len); 5456557Sfr41279 if (err != BIG_OK) { 5460Sstevel@tonic-gate return (err); 5476557Sfr41279 } 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate r = result->value; 5510Sstevel@tonic-gate a = aa->value; 5520Sstevel@tonic-gate b = bb->value; 5530Sstevel@tonic-gate result->len = aa->len; 5540Sstevel@tonic-gate cy = 1; 5550Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 5560Sstevel@tonic-gate ai = a[i]; 5570Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 5586557Sfr41279 if (r[i] > ai) { 5596557Sfr41279 cy = 0; 5606557Sfr41279 } else if (r[i] < ai) { 5616557Sfr41279 cy = 1; 5626557Sfr41279 } 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate for (; i < aa->len; i++) { 5650Sstevel@tonic-gate ai = a[i]; 5660Sstevel@tonic-gate r[i] = ai + (~0) + cy; 5676557Sfr41279 if (r[i] < ai) { 5686557Sfr41279 cy = 1; 5696557Sfr41279 } 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate result->sign = 1; 5726557Sfr41279 5736557Sfr41279 if (cy == 0) { 5740Sstevel@tonic-gate return (BIG_INVALID_ARGS); 5756557Sfr41279 } else { 5760Sstevel@tonic-gate return (BIG_OK); 5776557Sfr41279 } 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */ 5820Sstevel@tonic-gate int 5830Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb) 5840Sstevel@tonic-gate { 5856557Sfr41279 int i; 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate if (aa->len > bb->len) { 5880Sstevel@tonic-gate for (i = aa->len - 1; i > bb->len - 1; i--) { 5896557Sfr41279 if (aa->value[i] > 0) { 5900Sstevel@tonic-gate return (1); 5916557Sfr41279 } 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate } else if (aa->len < bb->len) { 5940Sstevel@tonic-gate for (i = bb->len - 1; i > aa->len - 1; i--) { 5956557Sfr41279 if (bb->value[i] > 0) { 5960Sstevel@tonic-gate return (-1); 5976557Sfr41279 } 5980Sstevel@tonic-gate } 5996557Sfr41279 } else { 600*8933Sopensolaris@drydog.com i = aa->len - 1; 6016557Sfr41279 } 6020Sstevel@tonic-gate for (; i >= 0; i--) { 6036557Sfr41279 if (aa->value[i] > bb->value[i]) { 6040Sstevel@tonic-gate return (1); 6056557Sfr41279 } else if (aa->value[i] < bb->value[i]) { 6060Sstevel@tonic-gate return (-1); 6076557Sfr41279 } 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate return (0); 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate BIG_ERR_CODE 6150Sstevel@tonic-gate big_sub(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 6160Sstevel@tonic-gate { 6176557Sfr41279 BIG_ERR_CODE err; 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate if ((bb->sign == -1) && (aa->sign == 1)) { 6206557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6210Sstevel@tonic-gate return (err); 6226557Sfr41279 } 6230Sstevel@tonic-gate result->sign = 1; 6240Sstevel@tonic-gate } else if ((aa->sign == -1) && (bb->sign == 1)) { 6256557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6260Sstevel@tonic-gate return (err); 6276557Sfr41279 } 6280Sstevel@tonic-gate result->sign = -1; 6290Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == 1)) { 6300Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 6316557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6320Sstevel@tonic-gate return (err); 6336557Sfr41279 } 6340Sstevel@tonic-gate result->sign = 1; 6350Sstevel@tonic-gate } else { 6366557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6370Sstevel@tonic-gate return (err); 6386557Sfr41279 } 6390Sstevel@tonic-gate result->sign = -1; 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate } else { 6420Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 6436557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6440Sstevel@tonic-gate return (err); 6456557Sfr41279 } 6460Sstevel@tonic-gate result->sign = -1; 6470Sstevel@tonic-gate } else { 6486557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6490Sstevel@tonic-gate return (err); 6506557Sfr41279 } 6510Sstevel@tonic-gate result->sign = 1; 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate } 6540Sstevel@tonic-gate return (BIG_OK); 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate BIG_ERR_CODE 6590Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 6600Sstevel@tonic-gate { 6616557Sfr41279 BIG_ERR_CODE err; 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate if ((bb->sign == -1) && (aa->sign == -1)) { 6646557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6650Sstevel@tonic-gate return (err); 6666557Sfr41279 } 6670Sstevel@tonic-gate result->sign = -1; 6680Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == 1)) { 6696557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6700Sstevel@tonic-gate return (err); 6716557Sfr41279 } 6720Sstevel@tonic-gate result->sign = 1; 6730Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == -1)) { 6740Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 6756557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6760Sstevel@tonic-gate return (err); 6776557Sfr41279 } 6780Sstevel@tonic-gate result->sign = 1; 6790Sstevel@tonic-gate } else { 6806557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6810Sstevel@tonic-gate return (err); 6826557Sfr41279 } 6830Sstevel@tonic-gate result->sign = -1; 6840Sstevel@tonic-gate } 6850Sstevel@tonic-gate } else { 6860Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 6876557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6880Sstevel@tonic-gate return (err); 6896557Sfr41279 } 6900Sstevel@tonic-gate result->sign = -1; 6910Sstevel@tonic-gate } else { 6926557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6930Sstevel@tonic-gate return (err); 6946557Sfr41279 } 6950Sstevel@tonic-gate result->sign = 1; 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate return (BIG_OK); 6990Sstevel@tonic-gate } 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate 7026557Sfr41279 /* result = aa/2 */ 7030Sstevel@tonic-gate BIG_ERR_CODE 7040Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa) 7050Sstevel@tonic-gate { 7066557Sfr41279 BIG_ERR_CODE err; 7076557Sfr41279 int i; 7086557Sfr41279 BIG_CHUNK_TYPE cy, cy1; 7096557Sfr41279 BIG_CHUNK_TYPE *a, *r; 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate if (result->size < aa->len) { 7120Sstevel@tonic-gate err = big_extend(result, aa->len); 7136557Sfr41279 if (err != BIG_OK) { 7140Sstevel@tonic-gate return (err); 7156557Sfr41279 } 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate result->len = aa->len; 7190Sstevel@tonic-gate a = aa->value; 7200Sstevel@tonic-gate r = result->value; 7210Sstevel@tonic-gate cy = 0; 7226557Sfr41279 for (i = aa->len - 1; i >= 0; i--) { 7236557Sfr41279 cy1 = a[i] << (BIG_CHUNK_SIZE - 1); 7246557Sfr41279 r[i] = (cy | (a[i] >> 1)); 7250Sstevel@tonic-gate cy = cy1; 7260Sstevel@tonic-gate } 7276557Sfr41279 if (r[result->len - 1] == 0) { 7286557Sfr41279 result->len--; 7296557Sfr41279 } 7306557Sfr41279 7310Sstevel@tonic-gate return (BIG_OK); 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate 7346557Sfr41279 /* result = aa*2 */ 7350Sstevel@tonic-gate BIG_ERR_CODE 7360Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa) 7370Sstevel@tonic-gate { 7386557Sfr41279 BIG_ERR_CODE err; 7396557Sfr41279 int i, rsize; 7406557Sfr41279 BIG_CHUNK_TYPE cy, cy1; 7416557Sfr41279 BIG_CHUNK_TYPE *a, *r; 7426557Sfr41279 7436557Sfr41279 if ((aa->len > 0) && 7446557Sfr41279 ((aa->value[aa->len - 1] & BIG_CHUNK_HIGHBIT) != 0)) { 7450Sstevel@tonic-gate rsize = aa->len + 1; 7466557Sfr41279 } else { 7476557Sfr41279 rsize = aa->len; 7486557Sfr41279 } 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate if (result->size < rsize) { 7510Sstevel@tonic-gate err = big_extend(result, rsize); 7520Sstevel@tonic-gate if (err != BIG_OK) 7530Sstevel@tonic-gate return (err); 7540Sstevel@tonic-gate } 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate a = aa->value; 7570Sstevel@tonic-gate r = result->value; 7586557Sfr41279 if (rsize == aa->len + 1) { 7596557Sfr41279 r[rsize - 1] = 1; 7606557Sfr41279 } 7610Sstevel@tonic-gate cy = 0; 7620Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 7636557Sfr41279 cy1 = a[i] >> (BIG_CHUNK_SIZE - 1); 7640Sstevel@tonic-gate r[i] = (cy | (a[i] << 1)); 7650Sstevel@tonic-gate cy = cy1; 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate result->len = rsize; 7680Sstevel@tonic-gate return (BIG_OK); 7690Sstevel@tonic-gate } 7700Sstevel@tonic-gate 7716557Sfr41279 7726557Sfr41279 /* 7736557Sfr41279 * returns aa mod b, aa must be nonneg, b must be a max 7746557Sfr41279 * (BIG_CHUNK_SIZE / 2)-bit integer 7756557Sfr41279 */ 7766557Sfr41279 static uint32_t 7776557Sfr41279 big_modhalf_pos(BIGNUM *aa, uint32_t b) 7780Sstevel@tonic-gate { 7796557Sfr41279 int i; 7806557Sfr41279 BIG_CHUNK_TYPE rem; 7816557Sfr41279 7826557Sfr41279 if (aa->len == 0) { 7830Sstevel@tonic-gate return (0); 7846557Sfr41279 } 7850Sstevel@tonic-gate rem = aa->value[aa->len - 1] % b; 7860Sstevel@tonic-gate for (i = aa->len - 2; i >= 0; i--) { 7876557Sfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 7886557Sfr41279 (aa->value[i] >> (BIG_CHUNK_SIZE / 2))) % b; 7896557Sfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 7906557Sfr41279 (aa->value[i] & BIG_CHUNK_LOWHALFBITS)) % b; 7910Sstevel@tonic-gate } 7926557Sfr41279 7936557Sfr41279 return ((uint32_t)rem); 7940Sstevel@tonic-gate } 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate /* 7986557Sfr41279 * result = aa - (2^BIG_CHUNK_SIZE)^lendiff * bb 7990Sstevel@tonic-gate * result->size should be at least aa->len at entry 8000Sstevel@tonic-gate * aa, bb, and result should be positive 8010Sstevel@tonic-gate */ 8020Sstevel@tonic-gate void 8030Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 8040Sstevel@tonic-gate { 8050Sstevel@tonic-gate int i, lendiff; 8060Sstevel@tonic-gate BIGNUM res1, aa1; 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate lendiff = aa->len - bb->len; 8090Sstevel@tonic-gate res1.size = result->size - lendiff; 8100Sstevel@tonic-gate res1.malloced = 0; 8110Sstevel@tonic-gate res1.value = result->value + lendiff; 8120Sstevel@tonic-gate aa1.size = aa->size - lendiff; 8130Sstevel@tonic-gate aa1.value = aa->value + lendiff; 8140Sstevel@tonic-gate aa1.len = bb->len; 8150Sstevel@tonic-gate aa1.sign = 1; 8160Sstevel@tonic-gate (void) big_sub_pos(&res1, &aa1, bb); 8170Sstevel@tonic-gate if (result->value != aa->value) { 8180Sstevel@tonic-gate for (i = 0; i < lendiff; i++) { 8190Sstevel@tonic-gate result->value[i] = aa->value[i]; 8200Sstevel@tonic-gate } 8210Sstevel@tonic-gate } 8220Sstevel@tonic-gate result->len = aa->len; 8230Sstevel@tonic-gate } 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate /* 8270Sstevel@tonic-gate * returns 1, 0, or -1 depending on whether |aa| > , ==, or < 8286557Sfr41279 * (2^BIG_CHUNK_SIZE)^lendiff * |bb| 8290Sstevel@tonic-gate * aa->len should be >= bb->len 8300Sstevel@tonic-gate */ 8310Sstevel@tonic-gate int 8320Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb) 8330Sstevel@tonic-gate { 834*8933Sopensolaris@drydog.com int lendiff; 835*8933Sopensolaris@drydog.com BIGNUM aa1; 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate lendiff = aa->len - bb->len; 8380Sstevel@tonic-gate aa1.len = bb->len; 8390Sstevel@tonic-gate aa1.size = aa->size - lendiff; 8400Sstevel@tonic-gate aa1.malloced = 0; 8410Sstevel@tonic-gate aa1.value = aa->value + lendiff; 8420Sstevel@tonic-gate return (big_cmp_abs(&aa1, bb)); 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate /* 8476557Sfr41279 * result = aa * b where b is a max. (BIG_CHUNK_SIZE / 2)-bit positive integer. 8480Sstevel@tonic-gate * result should have enough space allocated. 8490Sstevel@tonic-gate */ 8506557Sfr41279 static void 8516557Sfr41279 big_mulhalf_low(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 8520Sstevel@tonic-gate { 8536557Sfr41279 int i; 8546557Sfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy; 8556557Sfr41279 BIG_CHUNK_TYPE *a, *r; 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate a = aa->value; 8580Sstevel@tonic-gate r = result->value; 8590Sstevel@tonic-gate cy = 0; 8600Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 8610Sstevel@tonic-gate ai = a[i]; 8626557Sfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 8636557Sfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 8646557Sfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 8656557Sfr41279 r[i] = (t1 & BIG_CHUNK_LOWHALFBITS) | 8666557Sfr41279 (t2 << (BIG_CHUNK_SIZE / 2)); 8676557Sfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 8680Sstevel@tonic-gate } 8690Sstevel@tonic-gate r[i] = cy; 8700Sstevel@tonic-gate result->len = aa->len + 1; 8710Sstevel@tonic-gate result->sign = aa->sign; 8720Sstevel@tonic-gate } 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate /* 8766557Sfr41279 * result = aa * b * 2^(BIG_CHUNK_SIZE / 2) where b is a max. 8776557Sfr41279 * (BIG_CHUNK_SIZE / 2)-bit positive integer. 8780Sstevel@tonic-gate * result should have enough space allocated. 8790Sstevel@tonic-gate */ 8806557Sfr41279 static void 8816557Sfr41279 big_mulhalf_high(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 8820Sstevel@tonic-gate { 8836557Sfr41279 int i; 8846557Sfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy, ri; 8856557Sfr41279 BIG_CHUNK_TYPE *a, *r; 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate a = aa->value; 8880Sstevel@tonic-gate r = result->value; 8890Sstevel@tonic-gate cy = 0; 8900Sstevel@tonic-gate ri = 0; 8910Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 8920Sstevel@tonic-gate ai = a[i]; 8936557Sfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 8946557Sfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 8956557Sfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 8966557Sfr41279 r[i] = (t1 << (BIG_CHUNK_SIZE / 2)) + ri; 8976557Sfr41279 ri = t2 & BIG_CHUNK_LOWHALFBITS; 8986557Sfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 8990Sstevel@tonic-gate } 9006557Sfr41279 r[i] = (cy << (BIG_CHUNK_SIZE / 2)) + ri; 9010Sstevel@tonic-gate result->len = aa->len + 1; 9020Sstevel@tonic-gate result->sign = aa->sign; 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate 9056557Sfr41279 9060Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 9070Sstevel@tonic-gate void 9080Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs) 9090Sstevel@tonic-gate { 9106557Sfr41279 int i; 9116557Sfr41279 BIG_CHUNK_TYPE cy, ai; 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate if (offs == 0) { 9140Sstevel@tonic-gate if (result != aa) { 9150Sstevel@tonic-gate (void) big_copy(result, aa); 9160Sstevel@tonic-gate } 9170Sstevel@tonic-gate return; 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate cy = 0; 9200Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 9210Sstevel@tonic-gate ai = aa->value[i]; 9220Sstevel@tonic-gate result->value[i] = (ai << offs) | cy; 9236557Sfr41279 cy = ai >> (BIG_CHUNK_SIZE - offs); 9240Sstevel@tonic-gate } 9250Sstevel@tonic-gate if (cy != 0) { 9260Sstevel@tonic-gate result->len = aa->len + 1; 9270Sstevel@tonic-gate result->value[result->len - 1] = cy; 9280Sstevel@tonic-gate } else { 9290Sstevel@tonic-gate result->len = aa->len; 9300Sstevel@tonic-gate } 9310Sstevel@tonic-gate result->sign = aa->sign; 9320Sstevel@tonic-gate } 9330Sstevel@tonic-gate 9346557Sfr41279 9350Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 9360Sstevel@tonic-gate void 9370Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs) 9380Sstevel@tonic-gate { 9396557Sfr41279 int i; 9406557Sfr41279 BIG_CHUNK_TYPE cy, ai; 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate if (offs == 0) { 9430Sstevel@tonic-gate if (result != aa) { 9440Sstevel@tonic-gate (void) big_copy(result, aa); 9450Sstevel@tonic-gate } 9460Sstevel@tonic-gate return; 9470Sstevel@tonic-gate } 9480Sstevel@tonic-gate cy = aa->value[0] >> offs; 9490Sstevel@tonic-gate for (i = 1; i < aa->len; i++) { 9500Sstevel@tonic-gate ai = aa->value[i]; 951*8933Sopensolaris@drydog.com result->value[i - 1] = (ai << (BIG_CHUNK_SIZE - offs)) | cy; 9520Sstevel@tonic-gate cy = ai >> offs; 9530Sstevel@tonic-gate } 9540Sstevel@tonic-gate result->len = aa->len; 9550Sstevel@tonic-gate result->value[result->len - 1] = cy; 9560Sstevel@tonic-gate result->sign = aa->sign; 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate /* 9610Sstevel@tonic-gate * result = aa/bb remainder = aa mod bb 9620Sstevel@tonic-gate * it is assumed that aa and bb are positive 9630Sstevel@tonic-gate */ 9640Sstevel@tonic-gate BIG_ERR_CODE 965*8933Sopensolaris@drydog.com big_div_pos(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb) 9660Sstevel@tonic-gate { 9676557Sfr41279 BIG_ERR_CODE err = BIG_OK; 9686557Sfr41279 int i, alen, blen, tlen, rlen, offs; 9696557Sfr41279 BIG_CHUNK_TYPE higha, highb, coeff; 9706557Sfr41279 BIG_CHUNK_TYPE *a, *b; 9716557Sfr41279 BIGNUM bbhigh, bblow, tresult, tmp1, tmp2; 9726557Sfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 9736557Sfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 9746557Sfr41279 BIG_CHUNK_TYPE tresultvalue[BIGTMPSIZE]; 9756557Sfr41279 BIG_CHUNK_TYPE bblowvalue[BIGTMPSIZE]; 9766557Sfr41279 BIG_CHUNK_TYPE bbhighvalue[BIGTMPSIZE]; 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate a = aa->value; 9790Sstevel@tonic-gate b = bb->value; 9800Sstevel@tonic-gate alen = aa->len; 9810Sstevel@tonic-gate blen = bb->len; 9826557Sfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 9836557Sfr41279 alen = alen - 1; 9846557Sfr41279 } 9850Sstevel@tonic-gate aa->len = alen; 9866557Sfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 9876557Sfr41279 blen = blen - 1; 9886557Sfr41279 } 9890Sstevel@tonic-gate bb->len = blen; 9906557Sfr41279 if ((blen == 1) && (b[0] == 0)) { 9910Sstevel@tonic-gate return (BIG_DIV_BY_0); 9926557Sfr41279 } 9930Sstevel@tonic-gate 9940Sstevel@tonic-gate if (big_cmp_abs(aa, bb) < 0) { 9950Sstevel@tonic-gate if ((remainder != NULL) && 9966557Sfr41279 ((err = big_copy(remainder, aa)) != BIG_OK)) { 9970Sstevel@tonic-gate return (err); 9986557Sfr41279 } 9990Sstevel@tonic-gate if (result != NULL) { 10000Sstevel@tonic-gate result->len = 1; 10010Sstevel@tonic-gate result->sign = 1; 10020Sstevel@tonic-gate result->value[0] = 0; 10030Sstevel@tonic-gate } 10040Sstevel@tonic-gate return (BIG_OK); 10050Sstevel@tonic-gate } 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate if ((err = big_init1(&bblow, blen + 1, 10080Sstevel@tonic-gate bblowvalue, arraysize(bblowvalue))) != BIG_OK) 10090Sstevel@tonic-gate return (err); 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate if ((err = big_init1(&bbhigh, blen + 1, 10120Sstevel@tonic-gate bbhighvalue, arraysize(bbhighvalue))) != BIG_OK) 10130Sstevel@tonic-gate goto ret1; 10140Sstevel@tonic-gate 10150Sstevel@tonic-gate if ((err = big_init1(&tmp1, alen + 2, 10160Sstevel@tonic-gate tmp1value, arraysize(tmp1value))) != BIG_OK) 10170Sstevel@tonic-gate goto ret2; 10180Sstevel@tonic-gate 10190Sstevel@tonic-gate if ((err = big_init1(&tmp2, blen + 2, 10200Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 10210Sstevel@tonic-gate goto ret3; 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate if ((err = big_init1(&tresult, alen - blen + 2, 10240Sstevel@tonic-gate tresultvalue, arraysize(tresultvalue))) != BIG_OK) 10250Sstevel@tonic-gate goto ret4; 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate offs = 0; 10286557Sfr41279 highb = b[blen - 1]; 10296557Sfr41279 if (highb >= (BIG_CHUNK_HALF_HIGHBIT << 1)) { 10306557Sfr41279 highb = highb >> (BIG_CHUNK_SIZE / 2); 10316557Sfr41279 offs = (BIG_CHUNK_SIZE / 2); 10320Sstevel@tonic-gate } 10336557Sfr41279 while ((highb & BIG_CHUNK_HALF_HIGHBIT) == 0) { 10346557Sfr41279 highb = highb << 1; 10350Sstevel@tonic-gate offs++; 10360Sstevel@tonic-gate } 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate big_shiftleft(&bblow, bb, offs); 10396557Sfr41279 10406557Sfr41279 if (offs <= (BIG_CHUNK_SIZE / 2 - 1)) { 10416557Sfr41279 big_shiftleft(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10420Sstevel@tonic-gate } else { 10436557Sfr41279 big_shiftright(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10440Sstevel@tonic-gate } 10450Sstevel@tonic-gate if (bbhigh.value[bbhigh.len - 1] == 0) { 10460Sstevel@tonic-gate bbhigh.len--; 10470Sstevel@tonic-gate } else { 10480Sstevel@tonic-gate bbhigh.value[bbhigh.len] = 0; 10490Sstevel@tonic-gate } 10500Sstevel@tonic-gate 10516557Sfr41279 highb = bblow.value[bblow.len - 1]; 10526557Sfr41279 10530Sstevel@tonic-gate big_shiftleft(&tmp1, aa, offs); 10540Sstevel@tonic-gate rlen = tmp1.len - bblow.len + 1; 10550Sstevel@tonic-gate tresult.len = rlen; 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate tmp1.len++; 10580Sstevel@tonic-gate tlen = tmp1.len; 10590Sstevel@tonic-gate tmp1.value[tmp1.len - 1] = 0; 10600Sstevel@tonic-gate for (i = 0; i < rlen; i++) { 10616557Sfr41279 higha = (tmp1.value[tlen - 1] << (BIG_CHUNK_SIZE / 2)) + 10626557Sfr41279 (tmp1.value[tlen - 2] >> (BIG_CHUNK_SIZE / 2)); 10630Sstevel@tonic-gate coeff = higha / (highb + 1); 10646557Sfr41279 big_mulhalf_high(&tmp2, &bblow, coeff); 10650Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 10660Sstevel@tonic-gate bbhigh.len++; 10670Sstevel@tonic-gate while (tmp1.value[tlen - 1] > 0) { 10680Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 10690Sstevel@tonic-gate coeff++; 10700Sstevel@tonic-gate } 10710Sstevel@tonic-gate bbhigh.len--; 10720Sstevel@tonic-gate tlen--; 10730Sstevel@tonic-gate tmp1.len--; 10740Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) { 10750Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 10760Sstevel@tonic-gate coeff++; 10770Sstevel@tonic-gate } 10786557Sfr41279 tresult.value[rlen - i - 1] = coeff << (BIG_CHUNK_SIZE / 2); 10790Sstevel@tonic-gate higha = tmp1.value[tlen - 1]; 10800Sstevel@tonic-gate coeff = higha / (highb + 1); 10816557Sfr41279 big_mulhalf_low(&tmp2, &bblow, coeff); 10820Sstevel@tonic-gate tmp2.len--; 10830Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 10840Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bblow) >= 0) { 10850Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bblow); 10860Sstevel@tonic-gate coeff++; 10870Sstevel@tonic-gate } 10880Sstevel@tonic-gate tresult.value[rlen - i - 1] = 10890Sstevel@tonic-gate tresult.value[rlen - i - 1] + coeff; 10900Sstevel@tonic-gate } 10910Sstevel@tonic-gate 10920Sstevel@tonic-gate big_shiftright(&tmp1, &tmp1, offs); 10930Sstevel@tonic-gate 10940Sstevel@tonic-gate err = BIG_OK; 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate if ((remainder != NULL) && 10970Sstevel@tonic-gate ((err = big_copy(remainder, &tmp1)) != BIG_OK)) 10980Sstevel@tonic-gate goto ret; 10990Sstevel@tonic-gate 11000Sstevel@tonic-gate if (result != NULL) 11010Sstevel@tonic-gate err = big_copy(result, &tresult); 11020Sstevel@tonic-gate 11030Sstevel@tonic-gate ret: 11040Sstevel@tonic-gate big_finish(&tresult); 11050Sstevel@tonic-gate ret4: 11060Sstevel@tonic-gate big_finish(&tmp1); 11070Sstevel@tonic-gate ret3: 11080Sstevel@tonic-gate big_finish(&tmp2); 11090Sstevel@tonic-gate ret2: 11100Sstevel@tonic-gate big_finish(&bbhigh); 11110Sstevel@tonic-gate ret1: 11120Sstevel@tonic-gate big_finish(&bblow); 11130Sstevel@tonic-gate return (err); 11140Sstevel@tonic-gate } 11150Sstevel@tonic-gate 1116*8933Sopensolaris@drydog.com 11170Sstevel@tonic-gate /* 11180Sstevel@tonic-gate * If there is no processor-specific integer implementation of 11190Sstevel@tonic-gate * the lower level multiply functions, then this code is provided 11200Sstevel@tonic-gate * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and 11210Sstevel@tonic-gate * big_sqr_vec(). 11220Sstevel@tonic-gate * 11230Sstevel@tonic-gate * There are two generic implementations. One that assumes that 11240Sstevel@tonic-gate * there is hardware and C compiler support for a 32 x 32 --> 64 11250Sstevel@tonic-gate * bit unsigned multiply, but otherwise is not specific to any 11260Sstevel@tonic-gate * processor, platform, or ISA. 11270Sstevel@tonic-gate * 11280Sstevel@tonic-gate * The other makes very few assumptions about hardware capabilities. 11290Sstevel@tonic-gate * It does not even assume that there is any implementation of a 11300Sstevel@tonic-gate * 32 x 32 --> 64 bit multiply that is accessible to C code and 11310Sstevel@tonic-gate * appropriate to use. It falls constructs 32 x 32 --> 64 bit 11320Sstevel@tonic-gate * multiplies from 16 x 16 --> 32 bit multiplies. 11330Sstevel@tonic-gate * 11340Sstevel@tonic-gate */ 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate #if !defined(PSR_MUL) 11370Sstevel@tonic-gate 11380Sstevel@tonic-gate #ifdef UMUL64 11390Sstevel@tonic-gate 11406557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 11416557Sfr41279 11420Sstevel@tonic-gate #define UNROLL8 11430Sstevel@tonic-gate 11440Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_PREFETCH(R) \ 11450Sstevel@tonic-gate p = pf * d; \ 1146*8933Sopensolaris@drydog.com pf = (uint64_t)a[R + 1]; \ 11470Sstevel@tonic-gate t = p + cy; \ 11480Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11490Sstevel@tonic-gate cy = t >> 32 11500Sstevel@tonic-gate 11510Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_NOPREFETCH(R) \ 11520Sstevel@tonic-gate p = pf * d; \ 11530Sstevel@tonic-gate t = p + cy; \ 11540Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11550Sstevel@tonic-gate cy = t >> 32 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_PREFETCH(R) \ 11580Sstevel@tonic-gate t = (uint64_t)r[R]; \ 11590Sstevel@tonic-gate p = pf * d; \ 1160*8933Sopensolaris@drydog.com pf = (uint64_t)a[R + 1]; \ 11610Sstevel@tonic-gate t = p + t + cy; \ 11620Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11630Sstevel@tonic-gate cy = t >> 32 11640Sstevel@tonic-gate 11650Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_NOPREFETCH(R) \ 11660Sstevel@tonic-gate t = (uint64_t)r[R]; \ 11670Sstevel@tonic-gate p = pf * d; \ 11680Sstevel@tonic-gate t = p + t + cy; \ 11690Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11700Sstevel@tonic-gate cy = t >> 32 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate #ifdef UNROLL8 11730Sstevel@tonic-gate 11740Sstevel@tonic-gate #define UNROLL 8 11750Sstevel@tonic-gate 11760Sstevel@tonic-gate /* 11770Sstevel@tonic-gate * r = a * b 11780Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 11790Sstevel@tonic-gate */ 11800Sstevel@tonic-gate 11810Sstevel@tonic-gate uint32_t 11820Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 11830Sstevel@tonic-gate { 11840Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate if (len == 0) 11870Sstevel@tonic-gate return (0); 11880Sstevel@tonic-gate cy = 0; 11890Sstevel@tonic-gate d = (uint64_t)b; 11900Sstevel@tonic-gate pf = (uint64_t)a[0]; 11910Sstevel@tonic-gate while (len > UNROLL) { 11920Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 11930Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 11940Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 11950Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 11960Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 11970Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 11980Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 11990Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(7); 12000Sstevel@tonic-gate r += UNROLL; 12010Sstevel@tonic-gate a += UNROLL; 12020Sstevel@tonic-gate len -= UNROLL; 12030Sstevel@tonic-gate } 12040Sstevel@tonic-gate if (len == UNROLL) { 12050Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 12060Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 12070Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 12080Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 12090Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 12100Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 12110Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 12120Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(7); 12130Sstevel@tonic-gate return ((uint32_t)cy); 12140Sstevel@tonic-gate } 12150Sstevel@tonic-gate while (len > 1) { 12160Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 12170Sstevel@tonic-gate ++r; 12180Sstevel@tonic-gate ++a; 12190Sstevel@tonic-gate --len; 12200Sstevel@tonic-gate } 12210Sstevel@tonic-gate if (len > 0) { 12220Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(0); 12230Sstevel@tonic-gate } 12240Sstevel@tonic-gate return ((uint32_t)cy); 12250Sstevel@tonic-gate } 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate /* 12280Sstevel@tonic-gate * r += a * b 12290Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 12300Sstevel@tonic-gate */ 12310Sstevel@tonic-gate 12320Sstevel@tonic-gate uint32_t 12330Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 12340Sstevel@tonic-gate { 12350Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate if (len == 0) 12380Sstevel@tonic-gate return (0); 12390Sstevel@tonic-gate cy = 0; 12400Sstevel@tonic-gate d = (uint64_t)b; 12410Sstevel@tonic-gate pf = (uint64_t)a[0]; 12420Sstevel@tonic-gate while (len > 8) { 12430Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12440Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 12450Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 12460Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 12470Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 12480Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 12490Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 12500Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(7); 12510Sstevel@tonic-gate r += 8; 12520Sstevel@tonic-gate a += 8; 12530Sstevel@tonic-gate len -= 8; 12540Sstevel@tonic-gate } 12550Sstevel@tonic-gate if (len == 8) { 12560Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12570Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 12580Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 12590Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 12600Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 12610Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 12620Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 12630Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(7); 12640Sstevel@tonic-gate return ((uint32_t)cy); 12650Sstevel@tonic-gate } 12660Sstevel@tonic-gate while (len > 1) { 12670Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12680Sstevel@tonic-gate ++r; 12690Sstevel@tonic-gate ++a; 12700Sstevel@tonic-gate --len; 12710Sstevel@tonic-gate } 12720Sstevel@tonic-gate if (len > 0) { 12730Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(0); 12740Sstevel@tonic-gate } 12750Sstevel@tonic-gate return ((uint32_t)cy); 12760Sstevel@tonic-gate } 12770Sstevel@tonic-gate #endif /* UNROLL8 */ 12780Sstevel@tonic-gate 12790Sstevel@tonic-gate void 12800Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 12810Sstevel@tonic-gate { 1282*8933Sopensolaris@drydog.com uint32_t *tr, *ta; 1283*8933Sopensolaris@drydog.com int tlen, row, col; 1284*8933Sopensolaris@drydog.com uint64_t p, s, t, t2, cy; 1285*8933Sopensolaris@drydog.com uint32_t d; 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate tr = r + 1; 12880Sstevel@tonic-gate ta = a; 12890Sstevel@tonic-gate tlen = len - 1; 12900Sstevel@tonic-gate tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]); 12910Sstevel@tonic-gate while (--tlen > 0) { 12920Sstevel@tonic-gate tr += 2; 12930Sstevel@tonic-gate ++ta; 12940Sstevel@tonic-gate tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]); 12950Sstevel@tonic-gate } 12960Sstevel@tonic-gate s = (uint64_t)a[0]; 12970Sstevel@tonic-gate s = s * s; 12980Sstevel@tonic-gate r[0] = (uint32_t)s; 12990Sstevel@tonic-gate cy = s >> 32; 13000Sstevel@tonic-gate p = ((uint64_t)r[1] << 1) + cy; 13010Sstevel@tonic-gate r[1] = (uint32_t)p; 13020Sstevel@tonic-gate cy = p >> 32; 13030Sstevel@tonic-gate row = 1; 13040Sstevel@tonic-gate col = 2; 13050Sstevel@tonic-gate while (row < len) { 13060Sstevel@tonic-gate s = (uint64_t)a[row]; 13070Sstevel@tonic-gate s = s * s; 13080Sstevel@tonic-gate p = (uint64_t)r[col] << 1; 13090Sstevel@tonic-gate t = p + s; 13100Sstevel@tonic-gate d = (uint32_t)t; 13110Sstevel@tonic-gate t2 = (uint64_t)d + cy; 13120Sstevel@tonic-gate r[col] = (uint32_t)t2; 13130Sstevel@tonic-gate cy = (t >> 32) + (t2 >> 32); 13140Sstevel@tonic-gate if (row == len - 1) 13150Sstevel@tonic-gate break; 1316*8933Sopensolaris@drydog.com p = ((uint64_t)r[col + 1] << 1) + cy; 1317*8933Sopensolaris@drydog.com r[col + 1] = (uint32_t)p; 13180Sstevel@tonic-gate cy = p >> 32; 13190Sstevel@tonic-gate ++row; 13200Sstevel@tonic-gate col += 2; 13210Sstevel@tonic-gate } 1322*8933Sopensolaris@drydog.com r[col + 1] = (uint32_t)cy; 13230Sstevel@tonic-gate } 13240Sstevel@tonic-gate 13256557Sfr41279 #else /* BIG_CHUNK_SIZE == 64 */ 13266557Sfr41279 13276557Sfr41279 /* 13286557Sfr41279 * r = r + a * digit, r and a are vectors of length len 13296557Sfr41279 * returns the carry digit 13306557Sfr41279 */ 13316557Sfr41279 BIG_CHUNK_TYPE 13326557Sfr41279 big_mul_add_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 13336557Sfr41279 BIG_CHUNK_TYPE digit) 13346557Sfr41279 { 13356557Sfr41279 BIG_CHUNK_TYPE cy, cy1, retcy, dlow, dhigh; 13366557Sfr41279 int i; 13376557Sfr41279 13386557Sfr41279 cy1 = 0; 13396557Sfr41279 dlow = digit & BIG_CHUNK_LOWHALFBITS; 13406557Sfr41279 dhigh = digit >> (BIG_CHUNK_SIZE / 2); 13416557Sfr41279 for (i = 0; i < len; i++) { 13426557Sfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 13436557Sfr41279 dlow * (a[i] & BIG_CHUNK_LOWHALFBITS) + 13446557Sfr41279 (r[i] & BIG_CHUNK_LOWHALFBITS); 13456557Sfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 13466557Sfr41279 dlow * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 13476557Sfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 13486557Sfr41279 r[i] = (cy & BIG_CHUNK_LOWHALFBITS) | 13496557Sfr41279 (cy1 << (BIG_CHUNK_SIZE / 2)); 13506557Sfr41279 } 13516557Sfr41279 retcy = cy1 >> (BIG_CHUNK_SIZE / 2); 13526557Sfr41279 13536557Sfr41279 cy1 = r[0] & BIG_CHUNK_LOWHALFBITS; 13546557Sfr41279 for (i = 0; i < len - 1; i++) { 13556557Sfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 13566557Sfr41279 dhigh * (a[i] & BIG_CHUNK_LOWHALFBITS) + 13576557Sfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 13586557Sfr41279 r[i] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 13596557Sfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 13606557Sfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 13616557Sfr41279 dhigh * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 13626557Sfr41279 (r[i + 1] & BIG_CHUNK_LOWHALFBITS); 13636557Sfr41279 } 13646557Sfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 13656557Sfr41279 dhigh * (a[len - 1] & BIG_CHUNK_LOWHALFBITS) + 13666557Sfr41279 (r[len - 1] >> (BIG_CHUNK_SIZE / 2)); 13676557Sfr41279 r[len - 1] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 13686557Sfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 13696557Sfr41279 retcy = (cy >> (BIG_CHUNK_SIZE / 2)) + 13706557Sfr41279 dhigh * (a[len - 1] >> (BIG_CHUNK_SIZE / 2)) + retcy; 13716557Sfr41279 13726557Sfr41279 return (retcy); 13736557Sfr41279 } 13746557Sfr41279 13756557Sfr41279 13766557Sfr41279 /* 13776557Sfr41279 * r = a * digit, r and a are vectors of length len 13786557Sfr41279 * returns the carry digit 13796557Sfr41279 */ 13806557Sfr41279 BIG_CHUNK_TYPE 13816557Sfr41279 big_mul_set_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 13826557Sfr41279 BIG_CHUNK_TYPE digit) 13836557Sfr41279 { 13846557Sfr41279 int i; 13856557Sfr41279 13866557Sfr41279 ASSERT(r != a); 13876557Sfr41279 for (i = 0; i < len; i++) { 13886557Sfr41279 r[i] = 0; 13896557Sfr41279 } 13906557Sfr41279 return (big_mul_add_vec(r, a, len, digit)); 13916557Sfr41279 } 13926557Sfr41279 13936557Sfr41279 void 13946557Sfr41279 big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len) 13956557Sfr41279 { 13966557Sfr41279 int i; 13976557Sfr41279 13986557Sfr41279 ASSERT(r != a); 13996557Sfr41279 r[len] = big_mul_set_vec(r, a, len, a[0]); 14006557Sfr41279 for (i = 1; i < len; ++i) 1401*8933Sopensolaris@drydog.com r[len + i] = big_mul_add_vec(r + i, a, len, a[i]); 14026557Sfr41279 } 14036557Sfr41279 14046557Sfr41279 #endif /* BIG_CHUNK_SIZE == 32/64 */ 14056557Sfr41279 1406*8933Sopensolaris@drydog.com 14070Sstevel@tonic-gate #else /* ! UMUL64 */ 14080Sstevel@tonic-gate 14096557Sfr41279 #if (BIG_CHUNK_SIZE != 32) 14106557Sfr41279 #error Don't use 64-bit chunks without defining UMUL64 14116557Sfr41279 #endif 14126557Sfr41279 14136557Sfr41279 14140Sstevel@tonic-gate /* 14150Sstevel@tonic-gate * r = r + a * digit, r and a are vectors of length len 14160Sstevel@tonic-gate * returns the carry digit 14170Sstevel@tonic-gate */ 14180Sstevel@tonic-gate uint32_t 14190Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 14200Sstevel@tonic-gate { 14210Sstevel@tonic-gate uint32_t cy, cy1, retcy, dlow, dhigh; 14220Sstevel@tonic-gate int i; 14230Sstevel@tonic-gate 14240Sstevel@tonic-gate cy1 = 0; 14250Sstevel@tonic-gate dlow = digit & 0xffff; 14260Sstevel@tonic-gate dhigh = digit >> 16; 14270Sstevel@tonic-gate for (i = 0; i < len; i++) { 14280Sstevel@tonic-gate cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff); 14290Sstevel@tonic-gate cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16); 14300Sstevel@tonic-gate r[i] = (cy & 0xffff) | (cy1 << 16); 14310Sstevel@tonic-gate } 14320Sstevel@tonic-gate retcy = cy1 >> 16; 14330Sstevel@tonic-gate 14340Sstevel@tonic-gate cy1 = r[0] & 0xffff; 14350Sstevel@tonic-gate for (i = 0; i < len - 1; i++) { 14360Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16); 14370Sstevel@tonic-gate r[i] = (cy1 & 0xffff) | (cy << 16); 14380Sstevel@tonic-gate cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff); 14390Sstevel@tonic-gate } 14400Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16); 14410Sstevel@tonic-gate r[len - 1] = (cy1 & 0xffff) | (cy << 16); 14420Sstevel@tonic-gate retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy; 14430Sstevel@tonic-gate 14440Sstevel@tonic-gate return (retcy); 14450Sstevel@tonic-gate } 14460Sstevel@tonic-gate 14476557Sfr41279 14480Sstevel@tonic-gate /* 14490Sstevel@tonic-gate * r = a * digit, r and a are vectors of length len 14500Sstevel@tonic-gate * returns the carry digit 14510Sstevel@tonic-gate */ 14520Sstevel@tonic-gate uint32_t 14530Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 14540Sstevel@tonic-gate { 14556557Sfr41279 int i; 14566557Sfr41279 14576557Sfr41279 ASSERT(r != a); 14586557Sfr41279 for (i = 0; i < len; i++) { 14596557Sfr41279 r[i] = 0; 14606557Sfr41279 } 14616557Sfr41279 14620Sstevel@tonic-gate return (big_mul_add_vec(r, a, len, digit)); 14630Sstevel@tonic-gate } 14640Sstevel@tonic-gate 14650Sstevel@tonic-gate void 14660Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 14670Sstevel@tonic-gate { 14680Sstevel@tonic-gate int i; 14690Sstevel@tonic-gate 14706557Sfr41279 ASSERT(r != a); 14710Sstevel@tonic-gate r[len] = big_mul_set_vec(r, a, len, a[0]); 14720Sstevel@tonic-gate for (i = 1; i < len; ++i) 1473*8933Sopensolaris@drydog.com r[len + i] = big_mul_add_vec(r + i, a, len, a[i]); 14740Sstevel@tonic-gate } 14750Sstevel@tonic-gate 14760Sstevel@tonic-gate #endif /* UMUL64 */ 14770Sstevel@tonic-gate 14780Sstevel@tonic-gate void 14796557Sfr41279 big_mul_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int alen, 14806557Sfr41279 BIG_CHUNK_TYPE *b, int blen) 14810Sstevel@tonic-gate { 14820Sstevel@tonic-gate int i; 14830Sstevel@tonic-gate 14840Sstevel@tonic-gate r[alen] = big_mul_set_vec(r, a, alen, b[0]); 14850Sstevel@tonic-gate for (i = 1; i < blen; ++i) 1486*8933Sopensolaris@drydog.com r[alen + i] = big_mul_add_vec(r + i, a, alen, b[i]); 14870Sstevel@tonic-gate } 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate 14900Sstevel@tonic-gate #endif /* ! PSR_MUL */ 14910Sstevel@tonic-gate 14920Sstevel@tonic-gate 14930Sstevel@tonic-gate /* 14940Sstevel@tonic-gate * result = aa * bb result->value should be big enough to hold the result 14950Sstevel@tonic-gate * 14960Sstevel@tonic-gate * Implementation: Standard grammar school algorithm 14970Sstevel@tonic-gate * 14980Sstevel@tonic-gate */ 14990Sstevel@tonic-gate BIG_ERR_CODE 15000Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 15010Sstevel@tonic-gate { 15026557Sfr41279 BIGNUM tmp1; 15036557Sfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 15046557Sfr41279 BIG_CHUNK_TYPE *r, *t, *a, *b; 15056557Sfr41279 BIG_ERR_CODE err; 15066557Sfr41279 int i, alen, blen, rsize, sign, diff; 15070Sstevel@tonic-gate 15080Sstevel@tonic-gate if (aa == bb) { 15090Sstevel@tonic-gate diff = 0; 15100Sstevel@tonic-gate } else { 15110Sstevel@tonic-gate diff = big_cmp_abs(aa, bb); 15120Sstevel@tonic-gate if (diff < 0) { 15130Sstevel@tonic-gate BIGNUM *tt; 15140Sstevel@tonic-gate tt = aa; 15150Sstevel@tonic-gate aa = bb; 15160Sstevel@tonic-gate bb = tt; 15170Sstevel@tonic-gate } 15180Sstevel@tonic-gate } 15190Sstevel@tonic-gate a = aa->value; 15200Sstevel@tonic-gate b = bb->value; 15210Sstevel@tonic-gate alen = aa->len; 15220Sstevel@tonic-gate blen = bb->len; 15236557Sfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 15246557Sfr41279 alen--; 15256557Sfr41279 } 15260Sstevel@tonic-gate aa->len = alen; 15276557Sfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 15286557Sfr41279 blen--; 15296557Sfr41279 } 15300Sstevel@tonic-gate bb->len = blen; 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate rsize = alen + blen; 1533*8933Sopensolaris@drydog.com ASSERT(rsize > 0); 15340Sstevel@tonic-gate if (result->size < rsize) { 15350Sstevel@tonic-gate err = big_extend(result, rsize); 15366557Sfr41279 if (err != BIG_OK) { 15370Sstevel@tonic-gate return (err); 15386557Sfr41279 } 15390Sstevel@tonic-gate /* aa or bb might be an alias to result */ 15400Sstevel@tonic-gate a = aa->value; 15410Sstevel@tonic-gate b = bb->value; 15420Sstevel@tonic-gate } 15430Sstevel@tonic-gate r = result->value; 15440Sstevel@tonic-gate 15450Sstevel@tonic-gate if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) { 15460Sstevel@tonic-gate result->len = 1; 15470Sstevel@tonic-gate result->sign = 1; 15480Sstevel@tonic-gate r[0] = 0; 15490Sstevel@tonic-gate return (BIG_OK); 15500Sstevel@tonic-gate } 15510Sstevel@tonic-gate sign = aa->sign * bb->sign; 15520Sstevel@tonic-gate if ((alen == 1) && (a[0] == 1)) { 15536557Sfr41279 for (i = 0; i < blen; i++) { 15546557Sfr41279 r[i] = b[i]; 15556557Sfr41279 } 15560Sstevel@tonic-gate result->len = blen; 15570Sstevel@tonic-gate result->sign = sign; 15580Sstevel@tonic-gate return (BIG_OK); 15590Sstevel@tonic-gate } 15600Sstevel@tonic-gate if ((blen == 1) && (b[0] == 1)) { 15616557Sfr41279 for (i = 0; i < alen; i++) { 15626557Sfr41279 r[i] = a[i]; 15636557Sfr41279 } 15640Sstevel@tonic-gate result->len = alen; 15650Sstevel@tonic-gate result->sign = sign; 15660Sstevel@tonic-gate return (BIG_OK); 15670Sstevel@tonic-gate } 15680Sstevel@tonic-gate 15696557Sfr41279 if ((err = big_init1(&tmp1, rsize, 15706557Sfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 15710Sstevel@tonic-gate return (err); 15726557Sfr41279 } 15736557Sfr41279 (void) big_copy(&tmp1, aa); 15740Sstevel@tonic-gate t = tmp1.value; 15756557Sfr41279 15766557Sfr41279 for (i = 0; i < rsize; i++) { 15776557Sfr41279 t[i] = 0; 15786557Sfr41279 } 15796557Sfr41279 15806557Sfr41279 if (diff == 0 && alen > 2) { 15810Sstevel@tonic-gate BIG_SQR_VEC(t, a, alen); 15826557Sfr41279 } else if (blen > 0) { 15830Sstevel@tonic-gate BIG_MUL_VEC(t, a, alen, b, blen); 15846557Sfr41279 } 15856557Sfr41279 15866557Sfr41279 if (t[rsize - 1] == 0) { 15876557Sfr41279 tmp1.len = rsize - 1; 15886557Sfr41279 } else { 15896557Sfr41279 tmp1.len = rsize; 15906557Sfr41279 } 1591*8933Sopensolaris@drydog.com 1592*8933Sopensolaris@drydog.com err = big_copy(result, &tmp1); 1593*8933Sopensolaris@drydog.com 15940Sstevel@tonic-gate result->sign = sign; 15950Sstevel@tonic-gate 15966557Sfr41279 big_finish(&tmp1); 15970Sstevel@tonic-gate 1598*8933Sopensolaris@drydog.com return (err); 15990Sstevel@tonic-gate } 16000Sstevel@tonic-gate 16010Sstevel@tonic-gate 16020Sstevel@tonic-gate /* 16030Sstevel@tonic-gate * caller must ensure that a < n, b < n and ret->size >= 2 * n->len + 1 16040Sstevel@tonic-gate * and that ret is not n 16050Sstevel@tonic-gate */ 16060Sstevel@tonic-gate BIG_ERR_CODE 16076557Sfr41279 big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, BIG_CHUNK_TYPE n0) 16080Sstevel@tonic-gate { 16096557Sfr41279 int i, j, nlen, needsubtract; 16106557Sfr41279 BIG_CHUNK_TYPE *nn, *rr; 16116557Sfr41279 BIG_CHUNK_TYPE digit, c; 16126557Sfr41279 BIG_ERR_CODE err; 16130Sstevel@tonic-gate 16140Sstevel@tonic-gate nlen = n->len; 16150Sstevel@tonic-gate nn = n->value; 16160Sstevel@tonic-gate 16170Sstevel@tonic-gate rr = ret->value; 16180Sstevel@tonic-gate 16196557Sfr41279 if ((err = big_mul(ret, a, b)) != BIG_OK) { 16200Sstevel@tonic-gate return (err); 16216557Sfr41279 } 16220Sstevel@tonic-gate 16230Sstevel@tonic-gate rr = ret->value; 16246557Sfr41279 for (i = ret->len; i < 2 * nlen + 1; i++) { 16256557Sfr41279 rr[i] = 0; 16266557Sfr41279 } 16270Sstevel@tonic-gate for (i = 0; i < nlen; i++) { 16280Sstevel@tonic-gate digit = rr[i]; 16290Sstevel@tonic-gate digit = digit * n0; 16300Sstevel@tonic-gate 16310Sstevel@tonic-gate c = BIG_MUL_ADD_VEC(rr + i, nn, nlen, digit); 16320Sstevel@tonic-gate j = i + nlen; 16330Sstevel@tonic-gate rr[j] += c; 16340Sstevel@tonic-gate while (rr[j] < c) { 16350Sstevel@tonic-gate rr[j + 1] += 1; 16360Sstevel@tonic-gate j++; 16370Sstevel@tonic-gate c = 1; 16380Sstevel@tonic-gate } 16390Sstevel@tonic-gate } 16400Sstevel@tonic-gate 16410Sstevel@tonic-gate needsubtract = 0; 16420Sstevel@tonic-gate if ((rr[2 * nlen] != 0)) 16430Sstevel@tonic-gate needsubtract = 1; 16440Sstevel@tonic-gate else { 16450Sstevel@tonic-gate for (i = 2 * nlen - 1; i >= nlen; i--) { 16460Sstevel@tonic-gate if (rr[i] > nn[i - nlen]) { 16470Sstevel@tonic-gate needsubtract = 1; 16480Sstevel@tonic-gate break; 16496557Sfr41279 } else if (rr[i] < nn[i - nlen]) { 16506557Sfr41279 break; 16516557Sfr41279 } 16520Sstevel@tonic-gate } 16530Sstevel@tonic-gate } 16540Sstevel@tonic-gate if (needsubtract) 16550Sstevel@tonic-gate big_sub_vec(rr, rr + nlen, nn, nlen); 16560Sstevel@tonic-gate else { 16576557Sfr41279 for (i = 0; i < nlen; i++) { 16580Sstevel@tonic-gate rr[i] = rr[i + nlen]; 16596557Sfr41279 } 16600Sstevel@tonic-gate } 1661*8933Sopensolaris@drydog.com 1662*8933Sopensolaris@drydog.com /* Remove leading zeros, but keep at least 1 digit: */ 1663*8933Sopensolaris@drydog.com for (i = nlen - 1; (i > 0) && (rr[i] == 0); i--) 16646557Sfr41279 ; 1665*8933Sopensolaris@drydog.com ret->len = i + 1; 16660Sstevel@tonic-gate 16670Sstevel@tonic-gate return (BIG_OK); 16680Sstevel@tonic-gate } 16690Sstevel@tonic-gate 16706557Sfr41279 16716557Sfr41279 BIG_CHUNK_TYPE 16726557Sfr41279 big_n0(BIG_CHUNK_TYPE n) 16730Sstevel@tonic-gate { 16746557Sfr41279 int i; 16756557Sfr41279 BIG_CHUNK_TYPE result, tmp; 16760Sstevel@tonic-gate 16770Sstevel@tonic-gate result = 0; 16786557Sfr41279 tmp = BIG_CHUNK_ALLBITS; 16796557Sfr41279 for (i = 0; i < BIG_CHUNK_SIZE; i++) { 16800Sstevel@tonic-gate if ((tmp & 1) == 1) { 16816557Sfr41279 result = (result >> 1) | BIG_CHUNK_HIGHBIT; 16820Sstevel@tonic-gate tmp = tmp - n; 16836557Sfr41279 } else { 16846557Sfr41279 result = (result >> 1); 16856557Sfr41279 } 16860Sstevel@tonic-gate tmp = tmp >> 1; 16870Sstevel@tonic-gate } 16880Sstevel@tonic-gate 16890Sstevel@tonic-gate return (result); 16900Sstevel@tonic-gate } 16910Sstevel@tonic-gate 16920Sstevel@tonic-gate 16930Sstevel@tonic-gate int 16940Sstevel@tonic-gate big_numbits(BIGNUM *n) 16950Sstevel@tonic-gate { 16966557Sfr41279 int i, j; 16976557Sfr41279 BIG_CHUNK_TYPE t; 16986557Sfr41279 16996557Sfr41279 for (i = n->len - 1; i > 0; i--) { 17006557Sfr41279 if (n->value[i] != 0) { 17016557Sfr41279 break; 17026557Sfr41279 } 17036557Sfr41279 } 17040Sstevel@tonic-gate t = n->value[i]; 17056557Sfr41279 for (j = BIG_CHUNK_SIZE; j > 0; j--) { 17066557Sfr41279 if ((t & BIG_CHUNK_HIGHBIT) == 0) { 17070Sstevel@tonic-gate t = t << 1; 17086557Sfr41279 } else { 17096557Sfr41279 return (BIG_CHUNK_SIZE * i + j); 17106557Sfr41279 } 17110Sstevel@tonic-gate } 17120Sstevel@tonic-gate return (0); 17130Sstevel@tonic-gate } 17140Sstevel@tonic-gate 17156557Sfr41279 17160Sstevel@tonic-gate /* caller must make sure that a < n */ 17170Sstevel@tonic-gate BIG_ERR_CODE 17180Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n) 17190Sstevel@tonic-gate { 17206557Sfr41279 BIGNUM rr; 17216557Sfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 17226557Sfr41279 int len, i; 17236557Sfr41279 BIG_ERR_CODE err; 17240Sstevel@tonic-gate 17250Sstevel@tonic-gate rr.malloced = 0; 17260Sstevel@tonic-gate len = n->len; 17270Sstevel@tonic-gate 17280Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, 17296557Sfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 17300Sstevel@tonic-gate return (err); 17316557Sfr41279 } 17326557Sfr41279 17336557Sfr41279 for (i = 0; i < 2 * len; i++) { 17346557Sfr41279 rr.value[i] = 0; 17356557Sfr41279 } 17360Sstevel@tonic-gate rr.value[2 * len] = 1; 17370Sstevel@tonic-gate rr.len = 2 * len + 1; 17386557Sfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 17390Sstevel@tonic-gate goto ret; 17406557Sfr41279 } 17410Sstevel@tonic-gate err = big_copy(result, &rr); 17420Sstevel@tonic-gate ret: 17436557Sfr41279 big_finish(&rr); 17440Sstevel@tonic-gate return (err); 17450Sstevel@tonic-gate } 17460Sstevel@tonic-gate 17476557Sfr41279 17480Sstevel@tonic-gate /* caller must make sure that a < n */ 17490Sstevel@tonic-gate BIG_ERR_CODE 17506557Sfr41279 big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, BIG_CHUNK_TYPE n0, 17516557Sfr41279 BIGNUM *n_rr) 17520Sstevel@tonic-gate { 17536557Sfr41279 BIGNUM rr; 17546557Sfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 17556557Sfr41279 int len, i; 17566557Sfr41279 BIG_ERR_CODE err; 17570Sstevel@tonic-gate 17580Sstevel@tonic-gate rr.malloced = 0; 17590Sstevel@tonic-gate len = n->len; 17600Sstevel@tonic-gate 17610Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue))) 17626557Sfr41279 != BIG_OK) { 17636557Sfr41279 return (err); 17646557Sfr41279 } 17650Sstevel@tonic-gate 17660Sstevel@tonic-gate if (n_rr == NULL) { 17676557Sfr41279 for (i = 0; i < 2 * len; i++) { 17686557Sfr41279 rr.value[i] = 0; 17696557Sfr41279 } 17700Sstevel@tonic-gate rr.value[2 * len] = 1; 17710Sstevel@tonic-gate rr.len = 2 * len + 1; 17726557Sfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 17730Sstevel@tonic-gate goto ret; 17746557Sfr41279 } 17750Sstevel@tonic-gate n_rr = &rr; 17760Sstevel@tonic-gate } 17770Sstevel@tonic-gate 17786557Sfr41279 if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK) { 17790Sstevel@tonic-gate goto ret; 17806557Sfr41279 } 17810Sstevel@tonic-gate err = big_copy(result, &rr); 17826557Sfr41279 17830Sstevel@tonic-gate ret: 17846557Sfr41279 big_finish(&rr); 17850Sstevel@tonic-gate return (err); 17860Sstevel@tonic-gate } 17870Sstevel@tonic-gate 17880Sstevel@tonic-gate 17896557Sfr41279 #ifdef USE_FLOATING_POINT 17906557Sfr41279 #define big_modexp_ncp_float big_modexp_ncp_sw 17916557Sfr41279 #else 17926557Sfr41279 #define big_modexp_ncp_int big_modexp_ncp_sw 17936557Sfr41279 #endif 17946557Sfr41279 17950Sstevel@tonic-gate #define MAX_EXP_BIT_GROUP_SIZE 6 17960Sstevel@tonic-gate #define APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1)) 17970Sstevel@tonic-gate 17986557Sfr41279 /* ARGSUSED */ 17990Sstevel@tonic-gate static BIG_ERR_CODE 18006557Sfr41279 big_modexp_ncp_int(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 18016557Sfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 18026557Sfr41279 18030Sstevel@tonic-gate { 18046557Sfr41279 BIGNUM apowers[APOWERS_MAX_SIZE]; 18056557Sfr41279 BIGNUM tmp1; 18066557Sfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 18076557Sfr41279 int i, j, k, l, m, p; 1808*8933Sopensolaris@drydog.com uint32_t bit, bitind, bitcount, groupbits, apowerssize; 1809*8933Sopensolaris@drydog.com uint32_t nbits; 18106557Sfr41279 BIG_ERR_CODE err; 18110Sstevel@tonic-gate 18120Sstevel@tonic-gate nbits = big_numbits(e); 18130Sstevel@tonic-gate if (nbits < 50) { 18140Sstevel@tonic-gate groupbits = 1; 18150Sstevel@tonic-gate apowerssize = 1; 18160Sstevel@tonic-gate } else { 18170Sstevel@tonic-gate groupbits = MAX_EXP_BIT_GROUP_SIZE; 18180Sstevel@tonic-gate apowerssize = 1 << (groupbits - 1); 18190Sstevel@tonic-gate } 18200Sstevel@tonic-gate 18216557Sfr41279 18226557Sfr41279 if ((err = big_init1(&tmp1, 2 * n->len + 1, 18236557Sfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 18240Sstevel@tonic-gate return (err); 18256557Sfr41279 } 18266557Sfr41279 1827*8933Sopensolaris@drydog.com /* clear the malloced bit to help cleanup */ 18286557Sfr41279 for (i = 0; i < apowerssize; i++) { 18296557Sfr41279 apowers[i].malloced = 0; 18306557Sfr41279 } 1831*8933Sopensolaris@drydog.com 18326557Sfr41279 for (i = 0; i < apowerssize; i++) { 18336557Sfr41279 if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) != 18346557Sfr41279 BIG_OK) { 18356557Sfr41279 goto ret; 18366557Sfr41279 } 18376557Sfr41279 } 18386557Sfr41279 18396557Sfr41279 (void) big_copy(&(apowers[0]), ma); 18406557Sfr41279 18416557Sfr41279 if ((err = big_mont_mul(&tmp1, ma, ma, n, n0)) != BIG_OK) { 18426557Sfr41279 goto ret; 18436557Sfr41279 } 18446557Sfr41279 (void) big_copy(ma, &tmp1); 18456557Sfr41279 18466557Sfr41279 for (i = 1; i < apowerssize; i++) { 18476557Sfr41279 if ((err = big_mont_mul(&tmp1, ma, 1848*8933Sopensolaris@drydog.com &(apowers[i - 1]), n, n0)) != BIG_OK) { 18496557Sfr41279 goto ret; 18506557Sfr41279 } 18516557Sfr41279 (void) big_copy(&apowers[i], &tmp1); 18526557Sfr41279 } 18536557Sfr41279 18546557Sfr41279 bitind = nbits % BIG_CHUNK_SIZE; 18556557Sfr41279 k = 0; 18566557Sfr41279 l = 0; 18576557Sfr41279 p = 0; 18586557Sfr41279 bitcount = 0; 18596557Sfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 18606557Sfr41279 for (j = bitind - 1; j >= 0; j--) { 18616557Sfr41279 bit = (e->value[i] >> j) & 1; 18626557Sfr41279 if ((bitcount == 0) && (bit == 0)) { 18636557Sfr41279 if ((err = big_mont_mul(tmp, 18646557Sfr41279 tmp, tmp, n, n0)) != BIG_OK) { 18656557Sfr41279 goto ret; 18666557Sfr41279 } 18676557Sfr41279 } else { 18686557Sfr41279 bitcount++; 18696557Sfr41279 p = p * 2 + bit; 18706557Sfr41279 if (bit == 1) { 18716557Sfr41279 k = k + l + 1; 18726557Sfr41279 l = 0; 18736557Sfr41279 } else { 18746557Sfr41279 l++; 18756557Sfr41279 } 18766557Sfr41279 if (bitcount == groupbits) { 18776557Sfr41279 for (m = 0; m < k; m++) { 18786557Sfr41279 if ((err = big_mont_mul(tmp, 18796557Sfr41279 tmp, tmp, n, n0)) != 18806557Sfr41279 BIG_OK) { 18816557Sfr41279 goto ret; 18826557Sfr41279 } 18836557Sfr41279 } 18846557Sfr41279 if ((err = big_mont_mul(tmp, tmp, 18856557Sfr41279 &(apowers[p >> (l + 1)]), 18866557Sfr41279 n, n0)) != BIG_OK) { 18876557Sfr41279 goto ret; 18886557Sfr41279 } 18896557Sfr41279 for (m = 0; m < l; m++) { 18906557Sfr41279 if ((err = big_mont_mul(tmp, 18916557Sfr41279 tmp, tmp, n, n0)) != 18926557Sfr41279 BIG_OK) { 18936557Sfr41279 goto ret; 18946557Sfr41279 } 18956557Sfr41279 } 18966557Sfr41279 k = 0; 18976557Sfr41279 l = 0; 18986557Sfr41279 p = 0; 18996557Sfr41279 bitcount = 0; 19006557Sfr41279 } 19016557Sfr41279 } 19026557Sfr41279 } 19036557Sfr41279 bitind = BIG_CHUNK_SIZE; 19040Sstevel@tonic-gate } 19050Sstevel@tonic-gate 19066557Sfr41279 for (m = 0; m < k; m++) { 19076557Sfr41279 if ((err = big_mont_mul(tmp, tmp, tmp, n, n0)) != BIG_OK) { 19086557Sfr41279 goto ret; 19096557Sfr41279 } 19106557Sfr41279 } 19116557Sfr41279 if (p != 0) { 19126557Sfr41279 if ((err = big_mont_mul(tmp, tmp, 19136557Sfr41279 &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK) { 19146557Sfr41279 goto ret; 19156557Sfr41279 } 19166557Sfr41279 } 19176557Sfr41279 for (m = 0; m < l; m++) { 19186557Sfr41279 if ((err = big_mont_mul(result, tmp, tmp, n, n0)) != BIG_OK) { 19196557Sfr41279 goto ret; 19206557Sfr41279 } 19216557Sfr41279 } 19226557Sfr41279 19236557Sfr41279 ret: 19246557Sfr41279 for (i = apowerssize - 1; i >= 0; i--) { 19256557Sfr41279 big_finish(&(apowers[i])); 19260Sstevel@tonic-gate } 19276557Sfr41279 big_finish(&tmp1); 19286557Sfr41279 19296557Sfr41279 return (err); 19306557Sfr41279 } 19316557Sfr41279 19326557Sfr41279 19336557Sfr41279 #ifdef USE_FLOATING_POINT 19346557Sfr41279 19356557Sfr41279 #ifdef _KERNEL 19366557Sfr41279 19376557Sfr41279 #include <sys/sysmacros.h> 19386557Sfr41279 #include <sys/regset.h> 19396557Sfr41279 #include <sys/fpu/fpusystm.h> 19406557Sfr41279 19416557Sfr41279 /* the alignment for block stores to save fp registers */ 19426557Sfr41279 #define FPR_ALIGN (64) 19436557Sfr41279 19446557Sfr41279 extern void big_savefp(kfpu_t *); 19456557Sfr41279 extern void big_restorefp(kfpu_t *); 19466557Sfr41279 19476557Sfr41279 #endif /* _KERNEL */ 19486557Sfr41279 19496557Sfr41279 /* 19506557Sfr41279 * This version makes use of floating point for performance 19516557Sfr41279 */ 19526557Sfr41279 static BIG_ERR_CODE 19536557Sfr41279 big_modexp_ncp_float(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 19546557Sfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 19556557Sfr41279 { 19566557Sfr41279 1957*8933Sopensolaris@drydog.com int i, j, k, l, m, p; 1958*8933Sopensolaris@drydog.com uint32_t bit, bitind, bitcount, nlen; 19596557Sfr41279 double dn0; 19606557Sfr41279 double *dn, *dt, *d16r, *d32r; 19616557Sfr41279 uint32_t *nint, *prod; 19626557Sfr41279 double *apowers[APOWERS_MAX_SIZE]; 1963*8933Sopensolaris@drydog.com uint32_t nbits, groupbits, apowerssize; 19646557Sfr41279 BIG_ERR_CODE err = BIG_OK; 19656557Sfr41279 19666557Sfr41279 #ifdef _KERNEL 19676557Sfr41279 uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN]; 19686557Sfr41279 kfpu_t *fpu; 19696557Sfr41279 19706557Sfr41279 #ifdef DEBUG 19716557Sfr41279 if (!fpu_exists) 19726557Sfr41279 return (BIG_GENERAL_ERR); 19736557Sfr41279 #endif 19746557Sfr41279 19756557Sfr41279 fpu = (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN); 19766557Sfr41279 big_savefp(fpu); 19776557Sfr41279 19786557Sfr41279 #endif /* _KERNEL */ 19796557Sfr41279 19806557Sfr41279 nbits = big_numbits(e); 19816557Sfr41279 if (nbits < 50) { 19826557Sfr41279 groupbits = 1; 19836557Sfr41279 apowerssize = 1; 19846557Sfr41279 } else { 19856557Sfr41279 groupbits = MAX_EXP_BIT_GROUP_SIZE; 19866557Sfr41279 apowerssize = 1 << (groupbits - 1); 19876557Sfr41279 } 19886557Sfr41279 19896557Sfr41279 nlen = (BIG_CHUNK_SIZE / 32) * n->len; 19900Sstevel@tonic-gate dn0 = (double)(n0 & 0xffff); 19910Sstevel@tonic-gate 19920Sstevel@tonic-gate dn = dt = d16r = d32r = NULL; 19930Sstevel@tonic-gate nint = prod = NULL; 19940Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 19950Sstevel@tonic-gate apowers[i] = NULL; 19960Sstevel@tonic-gate } 19970Sstevel@tonic-gate 19980Sstevel@tonic-gate if ((dn = big_malloc(nlen * sizeof (double))) == NULL) { 19990Sstevel@tonic-gate err = BIG_NO_MEM; 20000Sstevel@tonic-gate goto ret; 20010Sstevel@tonic-gate } 20020Sstevel@tonic-gate if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) { 20030Sstevel@tonic-gate err = BIG_NO_MEM; 20040Sstevel@tonic-gate goto ret; 20050Sstevel@tonic-gate } 20060Sstevel@tonic-gate if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) { 20070Sstevel@tonic-gate err = BIG_NO_MEM; 20080Sstevel@tonic-gate goto ret; 20090Sstevel@tonic-gate } 20100Sstevel@tonic-gate if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) { 20110Sstevel@tonic-gate err = BIG_NO_MEM; 20120Sstevel@tonic-gate goto ret; 20130Sstevel@tonic-gate } 20140Sstevel@tonic-gate if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) { 20150Sstevel@tonic-gate err = BIG_NO_MEM; 20160Sstevel@tonic-gate goto ret; 20170Sstevel@tonic-gate } 20180Sstevel@tonic-gate if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) { 20190Sstevel@tonic-gate err = BIG_NO_MEM; 20200Sstevel@tonic-gate goto ret; 20210Sstevel@tonic-gate } 20220Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 20230Sstevel@tonic-gate if ((apowers[i] = big_malloc((2 * nlen + 1) * 20240Sstevel@tonic-gate sizeof (double))) == NULL) { 20250Sstevel@tonic-gate err = BIG_NO_MEM; 20260Sstevel@tonic-gate goto ret; 20270Sstevel@tonic-gate } 20280Sstevel@tonic-gate } 20290Sstevel@tonic-gate 20306557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 20316557Sfr41279 for (i = 0; i < ma->len; i++) { 20326557Sfr41279 nint[i] = ma->value[i]; 20336557Sfr41279 } 20346557Sfr41279 for (; i < nlen; i++) { 20356557Sfr41279 nint[i] = 0; 20366557Sfr41279 } 20376557Sfr41279 #else 20386557Sfr41279 for (i = 0; i < ma->len; i++) { 20396557Sfr41279 nint[2 * i] = (uint32_t)(ma->value[i] & 0xffffffffULL); 20406557Sfr41279 nint[2 * i + 1] = (uint32_t)(ma->value[i] >> 32); 20416557Sfr41279 } 20426557Sfr41279 for (i = ma->len * 2; i < nlen; i++) { 20436557Sfr41279 nint[i] = 0; 20446557Sfr41279 } 20456557Sfr41279 #endif 20460Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen); 20470Sstevel@tonic-gate 20486557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 20496557Sfr41279 for (i = 0; i < n->len; i++) { 20506557Sfr41279 nint[i] = n->value[i]; 20516557Sfr41279 } 20526557Sfr41279 for (; i < nlen; i++) { 20536557Sfr41279 nint[i] = 0; 20546557Sfr41279 } 20556557Sfr41279 #else 20566557Sfr41279 for (i = 0; i < n->len; i++) { 20576557Sfr41279 nint[2 * i] = (uint32_t)(n->value[i] & 0xffffffffULL); 20586557Sfr41279 nint[2 * i + 1] = (uint32_t)(n->value[i] >> 32); 20596557Sfr41279 } 20606557Sfr41279 for (i = n->len * 2; i < nlen; i++) { 20616557Sfr41279 nint[i] = 0; 20626557Sfr41279 } 20636557Sfr41279 #endif 20640Sstevel@tonic-gate conv_i32_to_d32(dn, nint, nlen); 20650Sstevel@tonic-gate 20660Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0); 20670Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 20680Sstevel@tonic-gate for (i = 1; i < apowerssize; i++) { 20690Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[i - 1], 20700Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 20710Sstevel@tonic-gate conv_i32_to_d16(apowers[i], prod, nlen); 20720Sstevel@tonic-gate } 20730Sstevel@tonic-gate 20746557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 20756557Sfr41279 for (i = 0; i < tmp->len; i++) { 20766557Sfr41279 prod[i] = tmp->value[i]; 20776557Sfr41279 } 20786557Sfr41279 for (; i < nlen + 1; i++) { 20796557Sfr41279 prod[i] = 0; 20806557Sfr41279 } 20816557Sfr41279 #else 20826557Sfr41279 for (i = 0; i < tmp->len; i++) { 20836557Sfr41279 prod[2 * i] = (uint32_t)(tmp->value[i] & 0xffffffffULL); 20846557Sfr41279 prod[2 * i + 1] = (uint32_t)(tmp->value[i] >> 32); 20856557Sfr41279 } 20866557Sfr41279 for (i = tmp->len * 2; i < nlen + 1; i++) { 20876557Sfr41279 prod[i] = 0; 20886557Sfr41279 } 20896557Sfr41279 #endif 20906557Sfr41279 20916557Sfr41279 bitind = nbits % BIG_CHUNK_SIZE; 20920Sstevel@tonic-gate k = 0; 20930Sstevel@tonic-gate l = 0; 20940Sstevel@tonic-gate p = 0; 20950Sstevel@tonic-gate bitcount = 0; 20966557Sfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 20970Sstevel@tonic-gate for (j = bitind - 1; j >= 0; j--) { 20980Sstevel@tonic-gate bit = (e->value[i] >> j) & 1; 20990Sstevel@tonic-gate if ((bitcount == 0) && (bit == 0)) { 21000Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, 21010Sstevel@tonic-gate prod, nlen); 21020Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, 21030Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21040Sstevel@tonic-gate } else { 21050Sstevel@tonic-gate bitcount++; 21060Sstevel@tonic-gate p = p * 2 + bit; 21070Sstevel@tonic-gate if (bit == 1) { 21080Sstevel@tonic-gate k = k + l + 1; 21090Sstevel@tonic-gate l = 0; 21100Sstevel@tonic-gate } else { 21110Sstevel@tonic-gate l++; 21120Sstevel@tonic-gate } 21130Sstevel@tonic-gate if (bitcount == groupbits) { 21140Sstevel@tonic-gate for (m = 0; m < k; m++) { 21156557Sfr41279 conv_i32_to_d32_and_d16(d32r, 21166557Sfr41279 d16r, prod, nlen); 21170Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 21180Sstevel@tonic-gate d16r, dt, dn, nint, 21190Sstevel@tonic-gate nlen, dn0); 21200Sstevel@tonic-gate } 21210Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 21220Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 2123*8933Sopensolaris@drydog.com apowers[p >> (l + 1)], 21240Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21250Sstevel@tonic-gate for (m = 0; m < l; m++) { 21266557Sfr41279 conv_i32_to_d32_and_d16(d32r, 21276557Sfr41279 d16r, prod, nlen); 21280Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 21290Sstevel@tonic-gate d16r, dt, dn, nint, 21300Sstevel@tonic-gate nlen, dn0); 21310Sstevel@tonic-gate } 21320Sstevel@tonic-gate k = 0; 21330Sstevel@tonic-gate l = 0; 21340Sstevel@tonic-gate p = 0; 21350Sstevel@tonic-gate bitcount = 0; 21360Sstevel@tonic-gate } 21370Sstevel@tonic-gate } 21380Sstevel@tonic-gate } 21396557Sfr41279 bitind = BIG_CHUNK_SIZE; 21400Sstevel@tonic-gate } 21410Sstevel@tonic-gate 21420Sstevel@tonic-gate for (m = 0; m < k; m++) { 21430Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 21440Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 21450Sstevel@tonic-gate } 21460Sstevel@tonic-gate if (p != 0) { 21470Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 21480Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)], 21490Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21500Sstevel@tonic-gate } 21510Sstevel@tonic-gate for (m = 0; m < l; m++) { 21520Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 21530Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 21540Sstevel@tonic-gate } 21550Sstevel@tonic-gate 21566557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 21576557Sfr41279 for (i = 0; i < nlen; i++) { 21586557Sfr41279 result->value[i] = prod[i]; 21596557Sfr41279 } 21606557Sfr41279 for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--) 21616557Sfr41279 ; 21626557Sfr41279 #else 21636557Sfr41279 for (i = 0; i < nlen / 2; i++) { 21646557Sfr41279 result->value[i] = (uint64_t)(prod[2 * i]) + 21656557Sfr41279 (((uint64_t)(prod[2 * i + 1])) << 32); 21666557Sfr41279 } 21676557Sfr41279 for (i = nlen / 2 - 1; (i > 0) && (result->value[i] == 0); i--) 21686557Sfr41279 ; 21696557Sfr41279 #endif 21706557Sfr41279 result->len = i + 1; 21716557Sfr41279 21720Sstevel@tonic-gate ret: 21730Sstevel@tonic-gate for (i = apowerssize - 1; i >= 0; i--) { 21740Sstevel@tonic-gate if (apowers[i] != NULL) 21750Sstevel@tonic-gate big_free(apowers[i], (2 * nlen + 1) * sizeof (double)); 21760Sstevel@tonic-gate } 21776557Sfr41279 if (d32r != NULL) { 21780Sstevel@tonic-gate big_free(d32r, nlen * sizeof (double)); 21796557Sfr41279 } 21806557Sfr41279 if (d16r != NULL) { 21810Sstevel@tonic-gate big_free(d16r, (2 * nlen + 1) * sizeof (double)); 21826557Sfr41279 } 21836557Sfr41279 if (prod != NULL) { 21840Sstevel@tonic-gate big_free(prod, (nlen + 1) * sizeof (uint32_t)); 21856557Sfr41279 } 21866557Sfr41279 if (nint != NULL) { 21870Sstevel@tonic-gate big_free(nint, nlen * sizeof (uint32_t)); 21886557Sfr41279 } 21896557Sfr41279 if (dt != NULL) { 21900Sstevel@tonic-gate big_free(dt, (4 * nlen + 2) * sizeof (double)); 21916557Sfr41279 } 21926557Sfr41279 if (dn != NULL) { 21930Sstevel@tonic-gate big_free(dn, nlen * sizeof (double)); 21946557Sfr41279 } 21950Sstevel@tonic-gate 21960Sstevel@tonic-gate #ifdef _KERNEL 21976557Sfr41279 big_restorefp(fpu); 21980Sstevel@tonic-gate #endif 21990Sstevel@tonic-gate 22000Sstevel@tonic-gate return (err); 22010Sstevel@tonic-gate } 22020Sstevel@tonic-gate 22030Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */ 22040Sstevel@tonic-gate 22050Sstevel@tonic-gate 22060Sstevel@tonic-gate BIG_ERR_CODE 22076557Sfr41279 big_modexp_ext(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr, 22086557Sfr41279 big_modexp_ncp_info_t *info) 22090Sstevel@tonic-gate { 22106557Sfr41279 BIGNUM ma, tmp, rr; 22116557Sfr41279 BIG_CHUNK_TYPE mavalue[BIGTMPSIZE]; 22126557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 22136557Sfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 22146557Sfr41279 BIG_ERR_CODE err; 22156557Sfr41279 BIG_CHUNK_TYPE n0; 22166557Sfr41279 22176557Sfr41279 if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue))) != 22186557Sfr41279 BIG_OK) { 22190Sstevel@tonic-gate return (err); 22206557Sfr41279 } 22216557Sfr41279 ma.len = 1; 22226557Sfr41279 ma.value[0] = 0; 22236557Sfr41279 22246557Sfr41279 if ((err = big_init1(&tmp, 2 * n->len + 1, 22256557Sfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 22260Sstevel@tonic-gate goto ret1; 22276557Sfr41279 } 22286557Sfr41279 2229*8933Sopensolaris@drydog.com /* clear the malloced bit to help cleanup */ 22306557Sfr41279 rr.malloced = 0; 2231*8933Sopensolaris@drydog.com 22326557Sfr41279 if (n_rr == NULL) { 22336557Sfr41279 if ((err = big_init1(&rr, 2 * n->len + 1, 22346557Sfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 22356557Sfr41279 goto ret2; 22366557Sfr41279 } 22376557Sfr41279 if (big_mont_rr(&rr, n) != BIG_OK) { 22386557Sfr41279 goto ret; 22396557Sfr41279 } 22406557Sfr41279 n_rr = &rr; 22416557Sfr41279 } 22426557Sfr41279 22436557Sfr41279 n0 = big_n0(n->value[0]); 22446557Sfr41279 22456557Sfr41279 if (big_cmp_abs(a, n) > 0) { 22466557Sfr41279 if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK) { 22476557Sfr41279 goto ret; 22486557Sfr41279 } 22496557Sfr41279 err = big_mont_conv(&ma, &ma, n, n0, n_rr); 22506557Sfr41279 } else { 22516557Sfr41279 err = big_mont_conv(&ma, a, n, n0, n_rr); 22526557Sfr41279 } 22536557Sfr41279 if (err != BIG_OK) { 22546557Sfr41279 goto ret; 22556557Sfr41279 } 22566557Sfr41279 22576557Sfr41279 tmp.len = 1; 22586557Sfr41279 tmp.value[0] = 1; 22596557Sfr41279 if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK) { 22606557Sfr41279 goto ret; 22616557Sfr41279 } 22626557Sfr41279 22636557Sfr41279 if ((info != NULL) && (info->func != NULL)) { 22646557Sfr41279 err = (*(info->func))(&tmp, &ma, e, n, &tmp, n0, 22656557Sfr41279 info->ncp, info->reqp); 22666557Sfr41279 } else { 22676557Sfr41279 err = big_modexp_ncp_sw(&tmp, &ma, e, n, &tmp, n0); 22686557Sfr41279 } 22696557Sfr41279 if (err != BIG_OK) { 22706557Sfr41279 goto ret; 22716557Sfr41279 } 22726557Sfr41279 22736557Sfr41279 ma.value[0] = 1; 22746557Sfr41279 ma.len = 1; 22756557Sfr41279 if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK) { 22766557Sfr41279 goto ret; 22776557Sfr41279 } 22786557Sfr41279 err = big_copy(result, &tmp); 22796557Sfr41279 22806557Sfr41279 ret: 22816557Sfr41279 if (rr.malloced) { 22826557Sfr41279 big_finish(&rr); 22836557Sfr41279 } 22846557Sfr41279 ret2: 22856557Sfr41279 big_finish(&tmp); 22866557Sfr41279 ret1: 22876557Sfr41279 big_finish(&ma); 22886557Sfr41279 22896557Sfr41279 return (err); 22906557Sfr41279 } 22916557Sfr41279 22926557Sfr41279 BIG_ERR_CODE 22936557Sfr41279 big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr) 22946557Sfr41279 { 22956557Sfr41279 return (big_modexp_ext(result, a, e, n, n_rr, NULL)); 22966557Sfr41279 } 22976557Sfr41279 22986557Sfr41279 22996557Sfr41279 BIG_ERR_CODE 23006557Sfr41279 big_modexp_crt_ext(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 23016557Sfr41279 BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 23026557Sfr41279 BIGNUM *p_rr, BIGNUM *q_rr, big_modexp_ncp_info_t *info) 23036557Sfr41279 { 23046557Sfr41279 BIGNUM ap, aq, tmp; 23056557Sfr41279 int alen, biglen, sign; 23066557Sfr41279 BIG_ERR_CODE err; 23076557Sfr41279 23086557Sfr41279 if (p->len > q->len) { 23096557Sfr41279 biglen = p->len; 23106557Sfr41279 } else { 23116557Sfr41279 biglen = q->len; 23126557Sfr41279 } 23136557Sfr41279 23146557Sfr41279 if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK) { 23156557Sfr41279 return (err); 23166557Sfr41279 } 23176557Sfr41279 if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK) { 23186557Sfr41279 goto ret1; 23196557Sfr41279 } 23206557Sfr41279 if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK) { 23210Sstevel@tonic-gate goto ret2; 23226557Sfr41279 } 23230Sstevel@tonic-gate 23240Sstevel@tonic-gate /* 23250Sstevel@tonic-gate * check whether a is too short - to avoid timing attacks 23260Sstevel@tonic-gate */ 23270Sstevel@tonic-gate alen = a->len; 23280Sstevel@tonic-gate while ((alen > p->len) && (a->value[alen - 1] == 0)) { 23290Sstevel@tonic-gate alen--; 23300Sstevel@tonic-gate } 23310Sstevel@tonic-gate if (alen < p->len + q->len) { 23320Sstevel@tonic-gate /* 23330Sstevel@tonic-gate * a is too short, add p*q to it before 23340Sstevel@tonic-gate * taking it modulo p and q 23350Sstevel@tonic-gate * this will also affect timing, but this difference 23360Sstevel@tonic-gate * does not depend on p or q, only on a 23370Sstevel@tonic-gate * (in "normal" operation, this path will never be 23380Sstevel@tonic-gate * taken, so it is not a performance penalty 23390Sstevel@tonic-gate */ 23406557Sfr41279 if ((err = big_mul(&tmp, p, q)) != BIG_OK) { 23410Sstevel@tonic-gate goto ret; 23426557Sfr41279 } 23436557Sfr41279 if ((err = big_add(&tmp, &tmp, a)) != BIG_OK) { 23446557Sfr41279 goto ret; 23456557Sfr41279 } 23466557Sfr41279 if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK) { 23470Sstevel@tonic-gate goto ret; 23486557Sfr41279 } 23496557Sfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 23500Sstevel@tonic-gate goto ret; 23516557Sfr41279 } 23526557Sfr41279 } else { 23536557Sfr41279 if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK) { 23540Sstevel@tonic-gate goto ret; 23556557Sfr41279 } 23566557Sfr41279 if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK) { 23570Sstevel@tonic-gate goto ret; 23586557Sfr41279 } 23590Sstevel@tonic-gate } 23600Sstevel@tonic-gate 23616557Sfr41279 if ((err = big_modexp_ext(&ap, &ap, dmodpminus1, p, p_rr, info)) != 23626557Sfr41279 BIG_OK) { 23630Sstevel@tonic-gate goto ret; 23646557Sfr41279 } 23656557Sfr41279 if ((err = big_modexp_ext(&aq, &aq, dmodqminus1, q, q_rr, info)) != 23666557Sfr41279 BIG_OK) { 23670Sstevel@tonic-gate goto ret; 23686557Sfr41279 } 23696557Sfr41279 if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK) { 23700Sstevel@tonic-gate goto ret; 23716557Sfr41279 } 23726557Sfr41279 if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK) { 23730Sstevel@tonic-gate goto ret; 23746557Sfr41279 } 23750Sstevel@tonic-gate sign = tmp.sign; 23760Sstevel@tonic-gate tmp.sign = 1; 23776557Sfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 23780Sstevel@tonic-gate goto ret; 23796557Sfr41279 } 23800Sstevel@tonic-gate if ((sign == -1) && (!big_is_zero(&aq))) { 23810Sstevel@tonic-gate (void) big_sub_pos(&aq, q, &aq); 23820Sstevel@tonic-gate } 23836557Sfr41279 if ((err = big_mul(&tmp, &aq, p)) != BIG_OK) { 23840Sstevel@tonic-gate goto ret; 23856557Sfr41279 } 23860Sstevel@tonic-gate err = big_add_abs(result, &ap, &tmp); 23870Sstevel@tonic-gate 23880Sstevel@tonic-gate ret: 23890Sstevel@tonic-gate big_finish(&tmp); 23900Sstevel@tonic-gate ret2: 23910Sstevel@tonic-gate big_finish(&aq); 23920Sstevel@tonic-gate ret1: 23930Sstevel@tonic-gate big_finish(&ap); 23940Sstevel@tonic-gate 23950Sstevel@tonic-gate return (err); 23960Sstevel@tonic-gate } 23970Sstevel@tonic-gate 23980Sstevel@tonic-gate 23996557Sfr41279 BIG_ERR_CODE 24006557Sfr41279 big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 24016557Sfr41279 BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 24026557Sfr41279 BIGNUM *p_rr, BIGNUM *q_rr) 24036557Sfr41279 { 24046557Sfr41279 return (big_modexp_crt_ext(result, a, dmodpminus1, dmodqminus1, 24056557Sfr41279 p, q, pinvmodq, p_rr, q_rr, NULL)); 24066557Sfr41279 } 24076557Sfr41279 24086557Sfr41279 24096557Sfr41279 static BIG_CHUNK_TYPE onearr[1] = {(BIG_CHUNK_TYPE)1}; 24106557Sfr41279 BIGNUM big_One = {1, 1, 1, 0, onearr}; 24116557Sfr41279 24126557Sfr41279 static BIG_CHUNK_TYPE twoarr[1] = {(BIG_CHUNK_TYPE)2}; 24136557Sfr41279 BIGNUM big_Two = {1, 1, 1, 0, twoarr}; 24146557Sfr41279 24156557Sfr41279 static BIG_CHUNK_TYPE fourarr[1] = {(BIG_CHUNK_TYPE)4}; 24166557Sfr41279 static BIGNUM big_Four = {1, 1, 1, 0, fourarr}; 24176557Sfr41279 24180Sstevel@tonic-gate 24190Sstevel@tonic-gate BIG_ERR_CODE 24200Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n) 24210Sstevel@tonic-gate { 24226557Sfr41279 BIGNUM *high, *low, *mid, *t; 24236557Sfr41279 BIGNUM t1, t2, t3, prod; 24246557Sfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 24256557Sfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 24266557Sfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 24276557Sfr41279 BIG_CHUNK_TYPE prodvalue[BIGTMPSIZE]; 2428*8933Sopensolaris@drydog.com int i, diff; 2429*8933Sopensolaris@drydog.com uint32_t nbits, nrootbits, highbits; 24306557Sfr41279 BIG_ERR_CODE err; 24310Sstevel@tonic-gate 24320Sstevel@tonic-gate nbits = big_numbits(n); 24330Sstevel@tonic-gate 24340Sstevel@tonic-gate if ((err = big_init1(&t1, n->len + 1, 24350Sstevel@tonic-gate t1value, arraysize(t1value))) != BIG_OK) 24360Sstevel@tonic-gate return (err); 24370Sstevel@tonic-gate if ((err = big_init1(&t2, n->len + 1, 24380Sstevel@tonic-gate t2value, arraysize(t2value))) != BIG_OK) 24390Sstevel@tonic-gate goto ret1; 24400Sstevel@tonic-gate if ((err = big_init1(&t3, n->len + 1, 24410Sstevel@tonic-gate t3value, arraysize(t3value))) != BIG_OK) 24420Sstevel@tonic-gate goto ret2; 24430Sstevel@tonic-gate if ((err = big_init1(&prod, n->len + 1, 24440Sstevel@tonic-gate prodvalue, arraysize(prodvalue))) != BIG_OK) 24450Sstevel@tonic-gate goto ret3; 24460Sstevel@tonic-gate 24470Sstevel@tonic-gate nrootbits = (nbits + 1) / 2; 24486557Sfr41279 t1.len = t2.len = t3.len = (nrootbits - 1) / BIG_CHUNK_SIZE + 1; 24490Sstevel@tonic-gate for (i = 0; i < t1.len; i++) { 24500Sstevel@tonic-gate t1.value[i] = 0; 24516557Sfr41279 t2.value[i] = BIG_CHUNK_ALLBITS; 24520Sstevel@tonic-gate } 24536557Sfr41279 highbits = nrootbits - BIG_CHUNK_SIZE * (t1.len - 1); 24546557Sfr41279 if (highbits == BIG_CHUNK_SIZE) { 24556557Sfr41279 t1.value[t1.len - 1] = BIG_CHUNK_HIGHBIT; 24566557Sfr41279 t2.value[t2.len - 1] = BIG_CHUNK_ALLBITS; 24570Sstevel@tonic-gate } else { 24586557Sfr41279 t1.value[t1.len - 1] = (BIG_CHUNK_TYPE)1 << (highbits - 1); 24590Sstevel@tonic-gate t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1; 24600Sstevel@tonic-gate } 24616557Sfr41279 24620Sstevel@tonic-gate high = &t2; 24630Sstevel@tonic-gate low = &t1; 24640Sstevel@tonic-gate mid = &t3; 24650Sstevel@tonic-gate 24666557Sfr41279 if ((err = big_mul(&prod, high, high)) != BIG_OK) { 24670Sstevel@tonic-gate goto ret; 24686557Sfr41279 } 24690Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 24700Sstevel@tonic-gate if (diff <= 0) { 24710Sstevel@tonic-gate err = big_copy(result, high); 24720Sstevel@tonic-gate goto ret; 24730Sstevel@tonic-gate } 24740Sstevel@tonic-gate 24750Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 24766557Sfr41279 while (big_cmp_abs(&big_One, mid) != 0) { 24770Sstevel@tonic-gate (void) big_add_abs(mid, high, low); 24780Sstevel@tonic-gate (void) big_half_pos(mid, mid); 24790Sstevel@tonic-gate if ((err = big_mul(&prod, mid, mid)) != BIG_OK) 24800Sstevel@tonic-gate goto ret; 24810Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 24820Sstevel@tonic-gate if (diff > 0) { 24830Sstevel@tonic-gate t = high; 24840Sstevel@tonic-gate high = mid; 24850Sstevel@tonic-gate mid = t; 24860Sstevel@tonic-gate } else if (diff < 0) { 24870Sstevel@tonic-gate t = low; 24880Sstevel@tonic-gate low = mid; 24890Sstevel@tonic-gate mid = t; 24900Sstevel@tonic-gate } else { 24910Sstevel@tonic-gate err = big_copy(result, low); 24920Sstevel@tonic-gate goto ret; 24930Sstevel@tonic-gate } 24940Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 24950Sstevel@tonic-gate } 24960Sstevel@tonic-gate 24970Sstevel@tonic-gate err = big_copy(result, low); 24980Sstevel@tonic-gate ret: 24990Sstevel@tonic-gate if (prod.malloced) big_finish(&prod); 25000Sstevel@tonic-gate ret3: 25010Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 25020Sstevel@tonic-gate ret2: 25030Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 25040Sstevel@tonic-gate ret1: 25050Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 25060Sstevel@tonic-gate 25070Sstevel@tonic-gate return (err); 25080Sstevel@tonic-gate } 25090Sstevel@tonic-gate 25100Sstevel@tonic-gate 25110Sstevel@tonic-gate BIG_ERR_CODE 25120Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm) 25130Sstevel@tonic-gate { 25146557Sfr41279 BIGNUM *t, *tmp2, *m, *n; 25156557Sfr41279 BIGNUM t1, t2, t3; 25166557Sfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 25176557Sfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 25186557Sfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 25196557Sfr41279 int len, err; 25200Sstevel@tonic-gate 25210Sstevel@tonic-gate if (big_is_zero(nn) || 25220Sstevel@tonic-gate (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) { 25230Sstevel@tonic-gate *jac = 0; 25240Sstevel@tonic-gate return (BIG_OK); 25250Sstevel@tonic-gate } 25260Sstevel@tonic-gate 25276557Sfr41279 if (nn->len > mm->len) { 25286557Sfr41279 len = nn->len; 25296557Sfr41279 } else { 25306557Sfr41279 len = mm->len; 25316557Sfr41279 } 25320Sstevel@tonic-gate 25330Sstevel@tonic-gate if ((err = big_init1(&t1, len, 25346557Sfr41279 t1value, arraysize(t1value))) != BIG_OK) { 25350Sstevel@tonic-gate return (err); 25366557Sfr41279 } 25370Sstevel@tonic-gate if ((err = big_init1(&t2, len, 25386557Sfr41279 t2value, arraysize(t2value))) != BIG_OK) { 25390Sstevel@tonic-gate goto ret1; 25406557Sfr41279 } 25410Sstevel@tonic-gate if ((err = big_init1(&t3, len, 25426557Sfr41279 t3value, arraysize(t3value))) != BIG_OK) { 25430Sstevel@tonic-gate goto ret2; 25446557Sfr41279 } 25450Sstevel@tonic-gate 25460Sstevel@tonic-gate n = &t1; 25470Sstevel@tonic-gate m = &t2; 25480Sstevel@tonic-gate tmp2 = &t3; 25490Sstevel@tonic-gate 25500Sstevel@tonic-gate (void) big_copy(n, nn); 25510Sstevel@tonic-gate (void) big_copy(m, mm); 25520Sstevel@tonic-gate 25530Sstevel@tonic-gate *jac = 1; 25546557Sfr41279 while (big_cmp_abs(&big_One, m) != 0) { 25550Sstevel@tonic-gate if (big_is_zero(n)) { 25560Sstevel@tonic-gate *jac = 0; 25570Sstevel@tonic-gate goto ret; 25580Sstevel@tonic-gate } 25590Sstevel@tonic-gate if ((m->value[0] & 1) == 0) { 25600Sstevel@tonic-gate if (((n->value[0] & 7) == 3) || 25616557Sfr41279 ((n->value[0] & 7) == 5)) 25626557Sfr41279 *jac = -*jac; 25630Sstevel@tonic-gate (void) big_half_pos(m, m); 25640Sstevel@tonic-gate } else if ((n->value[0] & 1) == 0) { 25650Sstevel@tonic-gate if (((m->value[0] & 7) == 3) || 25666557Sfr41279 ((m->value[0] & 7) == 5)) 25676557Sfr41279 *jac = -*jac; 25680Sstevel@tonic-gate (void) big_half_pos(n, n); 25690Sstevel@tonic-gate } else { 25700Sstevel@tonic-gate if (((m->value[0] & 3) == 3) && 25710Sstevel@tonic-gate ((n->value[0] & 3) == 3)) { 25720Sstevel@tonic-gate *jac = -*jac; 25730Sstevel@tonic-gate } 25746557Sfr41279 if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK) { 25750Sstevel@tonic-gate goto ret; 25766557Sfr41279 } 25770Sstevel@tonic-gate t = tmp2; 25780Sstevel@tonic-gate tmp2 = m; 25790Sstevel@tonic-gate m = n; 25800Sstevel@tonic-gate n = t; 25810Sstevel@tonic-gate } 25820Sstevel@tonic-gate } 25830Sstevel@tonic-gate err = BIG_OK; 25840Sstevel@tonic-gate 25850Sstevel@tonic-gate ret: 25860Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 25870Sstevel@tonic-gate ret2: 25880Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 25890Sstevel@tonic-gate ret1: 25900Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 25910Sstevel@tonic-gate 25920Sstevel@tonic-gate return (err); 25930Sstevel@tonic-gate } 25940Sstevel@tonic-gate 25950Sstevel@tonic-gate 25960Sstevel@tonic-gate BIG_ERR_CODE 25970Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n) 25980Sstevel@tonic-gate { 2599*8933Sopensolaris@drydog.com int i; 2600*8933Sopensolaris@drydog.com uint32_t m, w; 26016557Sfr41279 BIG_CHUNK_TYPE bit; 26026557Sfr41279 BIGNUM ki, tmp, tmp2; 26036557Sfr41279 BIG_CHUNK_TYPE kivalue[BIGTMPSIZE]; 26046557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 26056557Sfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 26066557Sfr41279 BIG_ERR_CODE err; 26076557Sfr41279 26086557Sfr41279 if (big_cmp_abs(k, &big_One) == 0) { 26090Sstevel@tonic-gate (void) big_copy(Lk, p); 26106557Sfr41279 (void) big_copy(Lkminus1, &big_Two); 26110Sstevel@tonic-gate return (BIG_OK); 26120Sstevel@tonic-gate } 26130Sstevel@tonic-gate 26140Sstevel@tonic-gate if ((err = big_init1(&ki, k->len + 1, 26150Sstevel@tonic-gate kivalue, arraysize(kivalue))) != BIG_OK) 26160Sstevel@tonic-gate return (err); 26170Sstevel@tonic-gate 2618*8933Sopensolaris@drydog.com if ((err = big_init1(&tmp, 2 * n->len + 1, 26190Sstevel@tonic-gate tmpvalue, arraysize(tmpvalue))) != BIG_OK) 26200Sstevel@tonic-gate goto ret1; 26210Sstevel@tonic-gate 26220Sstevel@tonic-gate if ((err = big_init1(&tmp2, n->len, 26230Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 26240Sstevel@tonic-gate goto ret2; 26250Sstevel@tonic-gate 26260Sstevel@tonic-gate m = big_numbits(k); 26276557Sfr41279 ki.len = (m - 1) / BIG_CHUNK_SIZE + 1; 26286557Sfr41279 w = (m - 1) / BIG_CHUNK_SIZE; 26296557Sfr41279 bit = (BIG_CHUNK_TYPE)1 << ((m - 1) % BIG_CHUNK_SIZE); 26306557Sfr41279 for (i = 0; i < ki.len; i++) { 26316557Sfr41279 ki.value[i] = 0; 26326557Sfr41279 } 26330Sstevel@tonic-gate ki.value[ki.len - 1] = bit; 26346557Sfr41279 if (big_cmp_abs(k, &ki) != 0) { 26350Sstevel@tonic-gate (void) big_double(&ki, &ki); 26366557Sfr41279 } 26370Sstevel@tonic-gate (void) big_sub_pos(&ki, &ki, k); 26380Sstevel@tonic-gate 26390Sstevel@tonic-gate (void) big_copy(Lk, p); 26406557Sfr41279 (void) big_copy(Lkminus1, &big_Two); 26410Sstevel@tonic-gate 26420Sstevel@tonic-gate for (i = 0; i < m; i++) { 26436557Sfr41279 if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK) { 26440Sstevel@tonic-gate goto ret; 26456557Sfr41279 } 26460Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 26470Sstevel@tonic-gate (void) big_sub_pos(&tmp, &tmp, p); 26486557Sfr41279 if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK) { 26490Sstevel@tonic-gate goto ret; 26506557Sfr41279 } 26510Sstevel@tonic-gate if ((ki.value[w] & bit) != 0) { 26520Sstevel@tonic-gate if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) != 26536557Sfr41279 BIG_OK) { 26540Sstevel@tonic-gate goto ret; 26556557Sfr41279 } 26560Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 26576557Sfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Two); 26580Sstevel@tonic-gate if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) != 26596557Sfr41279 BIG_OK) { 26600Sstevel@tonic-gate goto ret; 26616557Sfr41279 } 26620Sstevel@tonic-gate (void) big_copy(Lk, &tmp2); 26630Sstevel@tonic-gate } else { 26646557Sfr41279 if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK) { 26650Sstevel@tonic-gate goto ret; 26666557Sfr41279 } 26670Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 26686557Sfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Two); 26696557Sfr41279 if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK) { 26700Sstevel@tonic-gate goto ret; 26716557Sfr41279 } 26720Sstevel@tonic-gate (void) big_copy(Lkminus1, &tmp2); 26730Sstevel@tonic-gate } 26740Sstevel@tonic-gate bit = bit >> 1; 26750Sstevel@tonic-gate if (bit == 0) { 26766557Sfr41279 bit = BIG_CHUNK_HIGHBIT; 26770Sstevel@tonic-gate w--; 26780Sstevel@tonic-gate } 26790Sstevel@tonic-gate } 26800Sstevel@tonic-gate 26810Sstevel@tonic-gate err = BIG_OK; 26820Sstevel@tonic-gate 26830Sstevel@tonic-gate ret: 26840Sstevel@tonic-gate if (tmp2.malloced) big_finish(&tmp2); 26850Sstevel@tonic-gate ret2: 26860Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 26870Sstevel@tonic-gate ret1: 26880Sstevel@tonic-gate if (ki.malloced) big_finish(&ki); 26890Sstevel@tonic-gate 26900Sstevel@tonic-gate return (err); 26910Sstevel@tonic-gate } 26920Sstevel@tonic-gate 26930Sstevel@tonic-gate 26940Sstevel@tonic-gate BIG_ERR_CODE 26956557Sfr41279 big_isprime_pos_ext(BIGNUM *n, big_modexp_ncp_info_t *info) 26960Sstevel@tonic-gate { 26976557Sfr41279 BIGNUM o, nminus1, tmp, Lkminus1, Lk; 26986557Sfr41279 BIG_CHUNK_TYPE ovalue[BIGTMPSIZE]; 26996557Sfr41279 BIG_CHUNK_TYPE nminus1value[BIGTMPSIZE]; 27006557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 27016557Sfr41279 BIG_CHUNK_TYPE Lkminus1value[BIGTMPSIZE]; 27026557Sfr41279 BIG_CHUNK_TYPE Lkvalue[BIGTMPSIZE]; 27036557Sfr41279 BIG_ERR_CODE err; 27046557Sfr41279 int e, i, jac; 27056557Sfr41279 27066557Sfr41279 if (big_cmp_abs(n, &big_One) == 0) { 27070Sstevel@tonic-gate return (BIG_FALSE); 27086557Sfr41279 } 27096557Sfr41279 if (big_cmp_abs(n, &big_Two) == 0) { 27100Sstevel@tonic-gate return (BIG_TRUE); 27116557Sfr41279 } 27126557Sfr41279 if ((n->value[0] & 1) == 0) { 27130Sstevel@tonic-gate return (BIG_FALSE); 27146557Sfr41279 } 27156557Sfr41279 27166557Sfr41279 if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) != 27176557Sfr41279 BIG_OK) { 27180Sstevel@tonic-gate return (err); 27196557Sfr41279 } 27200Sstevel@tonic-gate 27210Sstevel@tonic-gate if ((err = big_init1(&nminus1, n->len, 27226557Sfr41279 nminus1value, arraysize(nminus1value))) != BIG_OK) { 27230Sstevel@tonic-gate goto ret1; 27246557Sfr41279 } 27250Sstevel@tonic-gate 27260Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * n->len, 27276557Sfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 27280Sstevel@tonic-gate goto ret2; 27296557Sfr41279 } 27300Sstevel@tonic-gate 27310Sstevel@tonic-gate if ((err = big_init1(&Lkminus1, n->len, 27326557Sfr41279 Lkminus1value, arraysize(Lkminus1value))) != BIG_OK) { 27330Sstevel@tonic-gate goto ret3; 27346557Sfr41279 } 27350Sstevel@tonic-gate 27360Sstevel@tonic-gate if ((err = big_init1(&Lk, n->len, 27376557Sfr41279 Lkvalue, arraysize(Lkvalue))) != BIG_OK) { 27380Sstevel@tonic-gate goto ret4; 27396557Sfr41279 } 27406557Sfr41279 2741*8933Sopensolaris@drydog.com (void) big_sub_pos(&o, n, &big_One); /* cannot fail */ 27420Sstevel@tonic-gate (void) big_copy(&nminus1, &o); /* cannot fail */ 27430Sstevel@tonic-gate e = 0; 27440Sstevel@tonic-gate while ((o.value[0] & 1) == 0) { 27450Sstevel@tonic-gate e++; 27460Sstevel@tonic-gate (void) big_half_pos(&o, &o); /* cannot fail */ 27470Sstevel@tonic-gate } 27486557Sfr41279 if ((err = big_modexp_ext(&tmp, &big_Two, &o, n, NULL, info)) != 27496557Sfr41279 BIG_OK) { 27500Sstevel@tonic-gate goto ret; 27516557Sfr41279 } 27526557Sfr41279 27530Sstevel@tonic-gate i = 0; 27540Sstevel@tonic-gate while ((i < e) && 27556557Sfr41279 (big_cmp_abs(&tmp, &big_One) != 0) && 27560Sstevel@tonic-gate (big_cmp_abs(&tmp, &nminus1) != 0)) { 27576557Sfr41279 if ((err = 27586557Sfr41279 big_modexp_ext(&tmp, &tmp, &big_Two, n, NULL, info)) != 27596557Sfr41279 BIG_OK) 27600Sstevel@tonic-gate goto ret; 27610Sstevel@tonic-gate i++; 27620Sstevel@tonic-gate } 27636557Sfr41279 27640Sstevel@tonic-gate if (!((big_cmp_abs(&tmp, &nminus1) == 0) || 27656557Sfr41279 ((i == 0) && (big_cmp_abs(&tmp, &big_One) == 0)))) { 27660Sstevel@tonic-gate err = BIG_FALSE; 27670Sstevel@tonic-gate goto ret; 27680Sstevel@tonic-gate } 27690Sstevel@tonic-gate 27706557Sfr41279 if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK) { 27710Sstevel@tonic-gate goto ret; 27726557Sfr41279 } 27736557Sfr41279 27746557Sfr41279 if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK) { 27750Sstevel@tonic-gate goto ret; 27766557Sfr41279 } 27770Sstevel@tonic-gate if (big_cmp_abs(&tmp, n) == 0) { 27780Sstevel@tonic-gate err = BIG_FALSE; 27790Sstevel@tonic-gate goto ret; 27800Sstevel@tonic-gate } 27810Sstevel@tonic-gate 27826557Sfr41279 (void) big_copy(&o, &big_Two); 27830Sstevel@tonic-gate do { 27846557Sfr41279 (void) big_add_abs(&o, &o, &big_One); 27856557Sfr41279 if ((err = big_mul(&tmp, &o, &o)) != BIG_OK) { 27860Sstevel@tonic-gate goto ret; 27876557Sfr41279 } 27886557Sfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Four); 27896557Sfr41279 if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK) { 27900Sstevel@tonic-gate goto ret; 27916557Sfr41279 } 27920Sstevel@tonic-gate } while (jac != -1); 27930Sstevel@tonic-gate 27946557Sfr41279 (void) big_add_abs(&tmp, n, &big_One); 27956557Sfr41279 if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK) { 27960Sstevel@tonic-gate goto ret; 27976557Sfr41279 } 27986557Sfr41279 27996557Sfr41279 if ((big_cmp_abs(&Lkminus1, &o) == 0) && 28006557Sfr41279 (big_cmp_abs(&Lk, &big_Two) == 0)) { 28010Sstevel@tonic-gate err = BIG_TRUE; 28026557Sfr41279 } else { 28036557Sfr41279 err = BIG_FALSE; 28046557Sfr41279 } 28050Sstevel@tonic-gate 28060Sstevel@tonic-gate ret: 28070Sstevel@tonic-gate if (Lk.malloced) big_finish(&Lk); 28080Sstevel@tonic-gate ret4: 28090Sstevel@tonic-gate if (Lkminus1.malloced) big_finish(&Lkminus1); 28100Sstevel@tonic-gate ret3: 28110Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 28120Sstevel@tonic-gate ret2: 28130Sstevel@tonic-gate if (nminus1.malloced) big_finish(&nminus1); 28140Sstevel@tonic-gate ret1: 28150Sstevel@tonic-gate if (o.malloced) big_finish(&o); 28160Sstevel@tonic-gate 28170Sstevel@tonic-gate return (err); 28180Sstevel@tonic-gate } 28190Sstevel@tonic-gate 28200Sstevel@tonic-gate 28216557Sfr41279 BIG_ERR_CODE 28226557Sfr41279 big_isprime_pos(BIGNUM *n) 28236557Sfr41279 { 28246557Sfr41279 return (big_isprime_pos_ext(n, NULL)); 28256557Sfr41279 } 28266557Sfr41279 28276557Sfr41279 28280Sstevel@tonic-gate #define SIEVESIZE 1000 28290Sstevel@tonic-gate 28300Sstevel@tonic-gate 28310Sstevel@tonic-gate BIG_ERR_CODE 28326557Sfr41279 big_nextprime_pos_ext(BIGNUM *result, BIGNUM *n, big_modexp_ncp_info_t *info) 28330Sstevel@tonic-gate { 2834*8933Sopensolaris@drydog.com static const uint32_t smallprimes[] = { 2835*8933Sopensolaris@drydog.com 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 2836*8933Sopensolaris@drydog.com 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97 }; 28376557Sfr41279 BIG_ERR_CODE err; 28386557Sfr41279 int sieve[SIEVESIZE]; 28396557Sfr41279 int i; 28406557Sfr41279 uint32_t off, p; 28416557Sfr41279 28426557Sfr41279 if ((err = big_copy(result, n)) != BIG_OK) { 28430Sstevel@tonic-gate return (err); 28446557Sfr41279 } 28450Sstevel@tonic-gate result->value[0] |= 1; 28461027Srobinson /* CONSTCOND */ 28470Sstevel@tonic-gate while (1) { 28480Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0; 28490Sstevel@tonic-gate for (i = 0; 28506557Sfr41279 i < sizeof (smallprimes) / sizeof (smallprimes[0]); i++) { 28510Sstevel@tonic-gate p = smallprimes[i]; 28526557Sfr41279 off = big_modhalf_pos(result, p); 28530Sstevel@tonic-gate off = p - off; 28546557Sfr41279 if ((off % 2) == 1) { 28556557Sfr41279 off = off + p; 28566557Sfr41279 } 28576557Sfr41279 off = off / 2; 28580Sstevel@tonic-gate while (off < SIEVESIZE) { 28590Sstevel@tonic-gate sieve[off] = 1; 28600Sstevel@tonic-gate off = off + p; 28610Sstevel@tonic-gate } 28620Sstevel@tonic-gate } 28630Sstevel@tonic-gate 28640Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) { 28650Sstevel@tonic-gate if (sieve[i] == 0) { 28666557Sfr41279 err = big_isprime_pos_ext(result, info); 28670Sstevel@tonic-gate if (err != BIG_FALSE) { 28686557Sfr41279 if (err != BIG_TRUE) { 28690Sstevel@tonic-gate return (err); 28706557Sfr41279 } else { 28716557Sfr41279 goto out; 28726557Sfr41279 } 28730Sstevel@tonic-gate } 28740Sstevel@tonic-gate 28750Sstevel@tonic-gate } 28766557Sfr41279 if ((err = big_add_abs(result, result, &big_Two)) != 28776557Sfr41279 BIG_OK) { 28780Sstevel@tonic-gate return (err); 28796557Sfr41279 } 28800Sstevel@tonic-gate } 28810Sstevel@tonic-gate } 28826557Sfr41279 28836557Sfr41279 out: 28846557Sfr41279 return (BIG_OK); 28856557Sfr41279 } 28866557Sfr41279 28876557Sfr41279 28886557Sfr41279 BIG_ERR_CODE 28896557Sfr41279 big_nextprime_pos(BIGNUM *result, BIGNUM *n) 28906557Sfr41279 { 28916557Sfr41279 return (big_nextprime_pos_ext(result, n, NULL)); 28920Sstevel@tonic-gate } 28930Sstevel@tonic-gate 28940Sstevel@tonic-gate 28950Sstevel@tonic-gate BIG_ERR_CODE 28960Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n) 28970Sstevel@tonic-gate { 28980Sstevel@tonic-gate BIG_ERR_CODE err; 28990Sstevel@tonic-gate 29000Sstevel@tonic-gate 29010Sstevel@tonic-gate if ((err = big_copy(result, n)) != BIG_OK) 29020Sstevel@tonic-gate return (err); 29030Sstevel@tonic-gate result->value[0] |= 1; 29046557Sfr41279 while ((err = big_isprime_pos_ext(result, NULL)) != BIG_TRUE) { 29050Sstevel@tonic-gate if (err != BIG_FALSE) 29060Sstevel@tonic-gate return (err); 29076557Sfr41279 if ((err = big_add_abs(result, result, &big_Two)) != BIG_OK) 29080Sstevel@tonic-gate return (err); 29090Sstevel@tonic-gate } 29100Sstevel@tonic-gate return (BIG_OK); 29110Sstevel@tonic-gate } 29120Sstevel@tonic-gate 29130Sstevel@tonic-gate 29140Sstevel@tonic-gate /* 29150Sstevel@tonic-gate * given m and e, computes the rest in the equation 29160Sstevel@tonic-gate * gcd(m, e) = cm * m + ce * e 29170Sstevel@tonic-gate */ 29180Sstevel@tonic-gate BIG_ERR_CODE 29190Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e) 29200Sstevel@tonic-gate { 29216557Sfr41279 BIGNUM *xi, *ri, *riminus1, *riminus2, *t; 29226557Sfr41279 BIGNUM *vmi, *vei, *vmiminus1, *veiminus1; 29236557Sfr41279 BIGNUM t1, t2, t3, t4, t5, t6, t7, t8, tmp; 29246557Sfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 29256557Sfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 29266557Sfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 29276557Sfr41279 BIG_CHUNK_TYPE t4value[BIGTMPSIZE]; 29286557Sfr41279 BIG_CHUNK_TYPE t5value[BIGTMPSIZE]; 29296557Sfr41279 BIG_CHUNK_TYPE t6value[BIGTMPSIZE]; 29306557Sfr41279 BIG_CHUNK_TYPE t7value[BIGTMPSIZE]; 29316557Sfr41279 BIG_CHUNK_TYPE t8value[BIGTMPSIZE]; 29326557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 29336557Sfr41279 BIG_ERR_CODE err; 29346557Sfr41279 int len; 29356557Sfr41279 29366557Sfr41279 if (big_cmp_abs(m, e) >= 0) { 29376557Sfr41279 len = m->len; 29386557Sfr41279 } else { 29396557Sfr41279 len = e->len; 29406557Sfr41279 } 29410Sstevel@tonic-gate 29420Sstevel@tonic-gate if ((err = big_init1(&t1, len, 29436557Sfr41279 t1value, arraysize(t1value))) != BIG_OK) { 29440Sstevel@tonic-gate return (err); 29456557Sfr41279 } 29460Sstevel@tonic-gate if ((err = big_init1(&t2, len, 29476557Sfr41279 t2value, arraysize(t2value))) != BIG_OK) { 29486557Sfr41279 goto ret1; 29496557Sfr41279 } 29500Sstevel@tonic-gate if ((err = big_init1(&t3, len, 29516557Sfr41279 t3value, arraysize(t3value))) != BIG_OK) { 29526557Sfr41279 goto ret2; 29536557Sfr41279 } 29540Sstevel@tonic-gate if ((err = big_init1(&t4, len, 29556557Sfr41279 t4value, arraysize(t3value))) != BIG_OK) { 29566557Sfr41279 goto ret3; 29576557Sfr41279 } 29580Sstevel@tonic-gate if ((err = big_init1(&t5, len, 29596557Sfr41279 t5value, arraysize(t5value))) != BIG_OK) { 29606557Sfr41279 goto ret4; 29616557Sfr41279 } 29620Sstevel@tonic-gate if ((err = big_init1(&t6, len, 29636557Sfr41279 t6value, arraysize(t6value))) != BIG_OK) { 29646557Sfr41279 goto ret5; 29656557Sfr41279 } 29660Sstevel@tonic-gate if ((err = big_init1(&t7, len, 29676557Sfr41279 t7value, arraysize(t7value))) != BIG_OK) { 29686557Sfr41279 goto ret6; 29696557Sfr41279 } 29700Sstevel@tonic-gate if ((err = big_init1(&t8, len, 29716557Sfr41279 t8value, arraysize(t8value))) != BIG_OK) { 29726557Sfr41279 goto ret7; 29736557Sfr41279 } 29740Sstevel@tonic-gate 29750Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * len, 29766557Sfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 29770Sstevel@tonic-gate goto ret8; 29786557Sfr41279 } 29790Sstevel@tonic-gate 29800Sstevel@tonic-gate ri = &t1; 29810Sstevel@tonic-gate ri->value[0] = 1; 29820Sstevel@tonic-gate ri->len = 1; 29830Sstevel@tonic-gate xi = &t2; 29840Sstevel@tonic-gate riminus1 = &t3; 29850Sstevel@tonic-gate riminus2 = &t4; 29860Sstevel@tonic-gate vmi = &t5; 29870Sstevel@tonic-gate vei = &t6; 29880Sstevel@tonic-gate vmiminus1 = &t7; 29890Sstevel@tonic-gate veiminus1 = &t8; 29900Sstevel@tonic-gate 29916557Sfr41279 (void) big_copy(vmiminus1, &big_One); 29926557Sfr41279 (void) big_copy(vmi, &big_One); 29936557Sfr41279 (void) big_copy(veiminus1, &big_One); 29946557Sfr41279 (void) big_copy(xi, &big_One); 29950Sstevel@tonic-gate vei->len = 1; 29960Sstevel@tonic-gate vei->value[0] = 0; 29970Sstevel@tonic-gate 29980Sstevel@tonic-gate (void) big_copy(riminus1, m); 29990Sstevel@tonic-gate (void) big_copy(ri, e); 30000Sstevel@tonic-gate 30010Sstevel@tonic-gate while (!big_is_zero(ri)) { 30020Sstevel@tonic-gate t = riminus2; 30030Sstevel@tonic-gate riminus2 = riminus1; 30040Sstevel@tonic-gate riminus1 = ri; 30050Sstevel@tonic-gate ri = t; 30066557Sfr41279 if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK) { 30070Sstevel@tonic-gate goto ret; 30086557Sfr41279 } 30096557Sfr41279 if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK) { 30100Sstevel@tonic-gate goto ret; 30116557Sfr41279 } 30120Sstevel@tonic-gate t = vmiminus1; 30130Sstevel@tonic-gate vmiminus1 = vmi; 30140Sstevel@tonic-gate vmi = t; 30156557Sfr41279 if ((err = big_mul(&tmp, vei, xi)) != BIG_OK) { 30160Sstevel@tonic-gate goto ret; 30176557Sfr41279 } 30186557Sfr41279 if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK) { 30190Sstevel@tonic-gate goto ret; 30206557Sfr41279 } 30210Sstevel@tonic-gate t = veiminus1; 30220Sstevel@tonic-gate veiminus1 = vei; 30230Sstevel@tonic-gate vei = t; 30246557Sfr41279 if ((err = big_div_pos(xi, ri, riminus2, riminus1)) != 30256557Sfr41279 BIG_OK) { 30260Sstevel@tonic-gate goto ret; 30276557Sfr41279 } 30280Sstevel@tonic-gate } 30296557Sfr41279 if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK)) { 30300Sstevel@tonic-gate goto ret; 30316557Sfr41279 } 30326557Sfr41279 if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK)) { 30330Sstevel@tonic-gate goto ret; 30346557Sfr41279 } 30356557Sfr41279 if (ce != NULL) { 30360Sstevel@tonic-gate err = big_copy(ce, vei); 30376557Sfr41279 } 30380Sstevel@tonic-gate ret: 30390Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 30400Sstevel@tonic-gate ret8: 30410Sstevel@tonic-gate if (t8.malloced) big_finish(&t8); 30420Sstevel@tonic-gate ret7: 30430Sstevel@tonic-gate if (t7.malloced) big_finish(&t7); 30440Sstevel@tonic-gate ret6: 30450Sstevel@tonic-gate if (t6.malloced) big_finish(&t6); 30460Sstevel@tonic-gate ret5: 30470Sstevel@tonic-gate if (t5.malloced) big_finish(&t5); 30480Sstevel@tonic-gate ret4: 30490Sstevel@tonic-gate if (t4.malloced) big_finish(&t4); 30500Sstevel@tonic-gate ret3: 30510Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 30520Sstevel@tonic-gate ret2: 30530Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 30540Sstevel@tonic-gate ret1: 30550Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 30560Sstevel@tonic-gate 30570Sstevel@tonic-gate return (err); 30580Sstevel@tonic-gate } 3059