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 /* 228933Sopensolaris@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. 478933Sopensolaris@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 658933Sopensolaris@drydog.com #include <sys/types.h> 668933Sopensolaris@drydog.com #include "bignum.h" 678933Sopensolaris@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 778933Sopensolaris@drydog.com #else 788933Sopensolaris@drydog.com #include <stdlib.h> 798933Sopensolaris@drydog.com #include <stdio.h> 808933Sopensolaris@drydog.com #include <assert.h> 818933Sopensolaris@drydog.com #define ASSERT assert 828933Sopensolaris@drydog.com #endif /* _KERNEL */ 838933Sopensolaris@drydog.com 84*9302Sopensolaris@drydog.com #ifdef __amd64 85*9302Sopensolaris@drydog.com #ifdef _KERNEL 86*9302Sopensolaris@drydog.com #include <sys/x86_archext.h> /* cpuid_getvendor() */ 87*9302Sopensolaris@drydog.com #include <sys/cpuvar.h> 88*9302Sopensolaris@drydog.com #else 89*9302Sopensolaris@drydog.com #include <sys/auxv.h> /* getisax() */ 90*9302Sopensolaris@drydog.com #endif /* _KERNEL */ 91*9302Sopensolaris@drydog.com #endif /* __amd64 */ 92*9302Sopensolaris@drydog.com 93*9302Sopensolaris@drydog.com 948933Sopensolaris@drydog.com #ifdef _LP64 /* truncate 64-bit size_t to 32-bits */ 958933Sopensolaris@drydog.com #define UI32(ui) ((uint32_t)ui) 968933Sopensolaris@drydog.com #else /* size_t already 32-bits */ 978933Sopensolaris@drydog.com #define UI32(ui) (ui) 988933Sopensolaris@drydog.com #endif 998933Sopensolaris@drydog.com 1008933Sopensolaris@drydog.com 1018933Sopensolaris@drydog.com #ifdef _KERNEL 1020Sstevel@tonic-gate #define big_malloc(size) kmem_alloc(size, KM_NOSLEEP) 1030Sstevel@tonic-gate #define big_free(ptr, size) kmem_free(ptr, size) 1040Sstevel@tonic-gate 105*9302Sopensolaris@drydog.com /* 106*9302Sopensolaris@drydog.com * big_realloc() 107*9302Sopensolaris@drydog.com * Allocate memory of newsize bytes and copy oldsize bytes 108*9302Sopensolaris@drydog.com * to the newly-allocated memory, then free the 109*9302Sopensolaris@drydog.com * previously-allocated memory. 110*9302Sopensolaris@drydog.com * Note: newsize must be > oldsize 111*9302Sopensolaris@drydog.com */ 1120Sstevel@tonic-gate void * 1130Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize) 1140Sstevel@tonic-gate { 1150Sstevel@tonic-gate void *rv; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate rv = kmem_alloc(newsize, KM_NOSLEEP); 1180Sstevel@tonic-gate if (rv != NULL) 1190Sstevel@tonic-gate bcopy(from, rv, oldsize); 1200Sstevel@tonic-gate kmem_free(from, oldsize); 1210Sstevel@tonic-gate return (rv); 1220Sstevel@tonic-gate } 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate #else /* _KERNEL */ 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate #ifndef MALLOC_DEBUG 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate #define big_malloc(size) malloc(size) 1290Sstevel@tonic-gate #define big_free(ptr, size) free(ptr) 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate #else 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate void 1340Sstevel@tonic-gate big_free(void *ptr, size_t size) 1350Sstevel@tonic-gate { 1360Sstevel@tonic-gate printf("freed %d bytes at %p\n", size, ptr); 1370Sstevel@tonic-gate free(ptr); 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate void * 1410Sstevel@tonic-gate big_malloc(size_t size) 1420Sstevel@tonic-gate { 1430Sstevel@tonic-gate void *rv; 1440Sstevel@tonic-gate rv = malloc(size); 1450Sstevel@tonic-gate printf("malloced %d bytes, addr:%p\n", size, rv); 1460Sstevel@tonic-gate return (rv); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate #endif /* MALLOC_DEBUG */ 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate #define big_realloc(x, y, z) realloc((x), (z)) 1510Sstevel@tonic-gate 1528933Sopensolaris@drydog.com 1538933Sopensolaris@drydog.com /* 1548933Sopensolaris@drydog.com * printbignum() 1558933Sopensolaris@drydog.com * Print a BIGNUM type to stdout. 1568933Sopensolaris@drydog.com */ 1570Sstevel@tonic-gate void 1580Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a) 1590Sstevel@tonic-gate { 1600Sstevel@tonic-gate int i; 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate (void) printf("\n%s\n%d\n", aname, a->sign*a->len); 1630Sstevel@tonic-gate for (i = a->len - 1; i >= 0; i--) { 1646557Sfr41279 #ifdef BIGNUM_CHUNK_32 1650Sstevel@tonic-gate (void) printf("%08x ", a->value[i]); 1668933Sopensolaris@drydog.com if (((i & (BITSINBYTE - 1)) == 0) && (i != 0)) { 1676557Sfr41279 (void) printf("\n"); 1686557Sfr41279 } 1696557Sfr41279 #else 1706557Sfr41279 (void) printf("%08x %08x ", (uint32_t)((a->value[i]) >> 32), 1716557Sfr41279 (uint32_t)((a->value[i]) & 0xffffffff)); 1728933Sopensolaris@drydog.com if (((i & 3) == 0) && (i != 0)) { /* end of this chunk */ 1736557Sfr41279 (void) printf("\n"); 1746557Sfr41279 } 1756557Sfr41279 #endif 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate (void) printf("\n"); 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate #endif /* _KERNEL */ 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate 183*9302Sopensolaris@drydog.com #ifdef __amd64 184*9302Sopensolaris@drydog.com /* 185*9302Sopensolaris@drydog.com * Return 1 if executing on Intel, otherwise 0 (e.g., AMD64). 186*9302Sopensolaris@drydog.com */ 187*9302Sopensolaris@drydog.com static int 188*9302Sopensolaris@drydog.com bignum_on_intel(void) 189*9302Sopensolaris@drydog.com { 190*9302Sopensolaris@drydog.com #ifdef _KERNEL 191*9302Sopensolaris@drydog.com return (cpuid_getvendor(CPU) == X86_VENDOR_Intel); 192*9302Sopensolaris@drydog.com #else 193*9302Sopensolaris@drydog.com uint_t ui; 194*9302Sopensolaris@drydog.com (void) getisax(&ui, 1); 195*9302Sopensolaris@drydog.com return ((ui & AV_386_AMD_MMX) == 0); 196*9302Sopensolaris@drydog.com #endif /* _KERNEL */ 197*9302Sopensolaris@drydog.com } 198*9302Sopensolaris@drydog.com #endif /* __amd64 */ 199*9302Sopensolaris@drydog.com 200*9302Sopensolaris@drydog.com 2018933Sopensolaris@drydog.com /* 2028933Sopensolaris@drydog.com * big_init() 2038933Sopensolaris@drydog.com * Initialize and allocate memory for a BIGNUM type. 2048933Sopensolaris@drydog.com * 2058933Sopensolaris@drydog.com * big_init(number, size) is equivalent to big_init1(number, size, NULL, 0) 2068933Sopensolaris@drydog.com * 2078933Sopensolaris@drydog.com * Note: call big_finish() to free memory allocated by big_init(). 2088933Sopensolaris@drydog.com * 2098933Sopensolaris@drydog.com * Input: 2108933Sopensolaris@drydog.com * number Uninitialized memory for BIGNUM 2118933Sopensolaris@drydog.com * size Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM 2128933Sopensolaris@drydog.com * 2138933Sopensolaris@drydog.com * Output: 2148933Sopensolaris@drydog.com * number Initialized BIGNUM 2158933Sopensolaris@drydog.com * 2168933Sopensolaris@drydog.com * Return BIG_OK on success or BIG_NO_MEM for an allocation error. 2178933Sopensolaris@drydog.com */ 2180Sstevel@tonic-gate BIG_ERR_CODE 2190Sstevel@tonic-gate big_init(BIGNUM *number, int size) 2200Sstevel@tonic-gate { 2218933Sopensolaris@drydog.com number->value = big_malloc(BIGNUM_WORDSIZE * size); 2220Sstevel@tonic-gate if (number->value == NULL) { 2230Sstevel@tonic-gate return (BIG_NO_MEM); 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate number->size = size; 2260Sstevel@tonic-gate number->len = 0; 2270Sstevel@tonic-gate number->sign = 1; 2280Sstevel@tonic-gate number->malloced = 1; 2290Sstevel@tonic-gate return (BIG_OK); 2300Sstevel@tonic-gate } 2310Sstevel@tonic-gate 2328933Sopensolaris@drydog.com 2338933Sopensolaris@drydog.com /* 2348933Sopensolaris@drydog.com * big_init1() 2358933Sopensolaris@drydog.com * Initialize and, if needed, allocate memory for a BIGNUM type. 2368933Sopensolaris@drydog.com * Use the buffer passed, buf, if any, instad of allocating memory 2378933Sopensolaris@drydog.com * if it's at least "size" bytes. 2388933Sopensolaris@drydog.com * 2398933Sopensolaris@drydog.com * Note: call big_finish() to free memory allocated by big_init(). 2408933Sopensolaris@drydog.com * 2418933Sopensolaris@drydog.com * Input: 2428933Sopensolaris@drydog.com * number Uninitialized memory for BIGNUM 2438933Sopensolaris@drydog.com * size Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM 2448933Sopensolaris@drydog.com * buf Buffer for storing a BIGNUM. 2458933Sopensolaris@drydog.com * If NULL, big_init1() will allocate a buffer 2468933Sopensolaris@drydog.com * bufsize Size, in BIG_CHUNK_SIZE_bit words, of buf 2478933Sopensolaris@drydog.com * 2488933Sopensolaris@drydog.com * Output: 2498933Sopensolaris@drydog.com * number Initialized BIGNUM 2508933Sopensolaris@drydog.com * 2518933Sopensolaris@drydog.com * Return BIG_OK on success or BIG_NO_MEM for an allocation error. 2528933Sopensolaris@drydog.com */ 2530Sstevel@tonic-gate BIG_ERR_CODE 2546557Sfr41279 big_init1(BIGNUM *number, int size, BIG_CHUNK_TYPE *buf, int bufsize) 2550Sstevel@tonic-gate { 2560Sstevel@tonic-gate if ((buf == NULL) || (size > bufsize)) { 2578933Sopensolaris@drydog.com number->value = big_malloc(BIGNUM_WORDSIZE * size); 2580Sstevel@tonic-gate if (number->value == NULL) { 2590Sstevel@tonic-gate return (BIG_NO_MEM); 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate number->size = size; 2620Sstevel@tonic-gate number->malloced = 1; 2630Sstevel@tonic-gate } else { 2640Sstevel@tonic-gate number->value = buf; 2650Sstevel@tonic-gate number->size = bufsize; 2660Sstevel@tonic-gate number->malloced = 0; 2670Sstevel@tonic-gate } 2688933Sopensolaris@drydog.com number->len = 0; 2698933Sopensolaris@drydog.com number->sign = 1; 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate return (BIG_OK); 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate 2748933Sopensolaris@drydog.com 2758933Sopensolaris@drydog.com /* 2768933Sopensolaris@drydog.com * big_finish() 2778933Sopensolaris@drydog.com * Free memory, if any, allocated by big_init() or big_init1(). 2788933Sopensolaris@drydog.com */ 2790Sstevel@tonic-gate void 2800Sstevel@tonic-gate big_finish(BIGNUM *number) 2810Sstevel@tonic-gate { 2820Sstevel@tonic-gate if (number->malloced == 1) { 2838933Sopensolaris@drydog.com big_free(number->value, BIGNUM_WORDSIZE * number->size); 2840Sstevel@tonic-gate number->malloced = 0; 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate 2886557Sfr41279 2890Sstevel@tonic-gate /* 2908933Sopensolaris@drydog.com * bn->size should be at least 2918933Sopensolaris@drydog.com * (len + BIGNUM_WORDSIZE - 1) / BIGNUM_WORDSIZE bytes 2920Sstevel@tonic-gate * converts from byte-big-endian format to bignum format (words in 2930Sstevel@tonic-gate * little endian order, but bytes within the words big endian) 2940Sstevel@tonic-gate */ 2950Sstevel@tonic-gate void 2960Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len) 2970Sstevel@tonic-gate { 2988933Sopensolaris@drydog.com int i, j; 2998933Sopensolaris@drydog.com uint32_t offs; 3008933Sopensolaris@drydog.com const uint32_t slen = UI32(len); 3016557Sfr41279 BIG_CHUNK_TYPE word; 3020Sstevel@tonic-gate uchar_t *knwordp; 3030Sstevel@tonic-gate 3048933Sopensolaris@drydog.com if (slen == 0) { 3058933Sopensolaris@drydog.com bn->len = 1; 3068933Sopensolaris@drydog.com bn->value[0] = 0; 3078933Sopensolaris@drydog.com return; 3088933Sopensolaris@drydog.com } 3098933Sopensolaris@drydog.com 3108933Sopensolaris@drydog.com offs = slen % BIGNUM_WORDSIZE; 3118933Sopensolaris@drydog.com bn->len = slen / BIGNUM_WORDSIZE; 3128933Sopensolaris@drydog.com 3138933Sopensolaris@drydog.com for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) { 3148933Sopensolaris@drydog.com knwordp = &(kn[slen - BIGNUM_WORDSIZE * (i + 1)]); 3150Sstevel@tonic-gate word = knwordp[0]; 3168933Sopensolaris@drydog.com for (j = 1; j < BIGNUM_WORDSIZE; j++) { 3178933Sopensolaris@drydog.com word = (word << BITSINBYTE) + knwordp[j]; 3180Sstevel@tonic-gate } 3190Sstevel@tonic-gate bn->value[i] = word; 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate if (offs > 0) { 3220Sstevel@tonic-gate word = kn[0]; 3238933Sopensolaris@drydog.com for (i = 1; i < offs; i++) word = (word << BITSINBYTE) + kn[i]; 3240Sstevel@tonic-gate bn->value[bn->len++] = word; 3250Sstevel@tonic-gate } 3268933Sopensolaris@drydog.com while ((bn->len > 1) && (bn->value[bn->len - 1] == 0)) { 3270Sstevel@tonic-gate bn->len --; 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate 3318933Sopensolaris@drydog.com 3320Sstevel@tonic-gate /* 3330Sstevel@tonic-gate * copies the least significant len bytes if 3348933Sopensolaris@drydog.com * len < bn->len * BIGNUM_WORDSIZE 3350Sstevel@tonic-gate * converts from bignum format to byte-big-endian format. 3366557Sfr41279 * bignum format is words of type BIG_CHUNK_TYPE in little endian order. 3370Sstevel@tonic-gate */ 3380Sstevel@tonic-gate void 3390Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len) 3400Sstevel@tonic-gate { 3418933Sopensolaris@drydog.com int i, j; 3428933Sopensolaris@drydog.com uint32_t offs; 3438933Sopensolaris@drydog.com const uint32_t slen = UI32(len); 3446557Sfr41279 BIG_CHUNK_TYPE word; 3456557Sfr41279 3468933Sopensolaris@drydog.com if (len < BIGNUM_WORDSIZE * bn->len) { 3478933Sopensolaris@drydog.com for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) { 3480Sstevel@tonic-gate word = bn->value[i]; 3498933Sopensolaris@drydog.com for (j = 0; j < BIGNUM_WORDSIZE; j++) { 3508933Sopensolaris@drydog.com kn[slen - BIGNUM_WORDSIZE * i - j - 1] = 3510Sstevel@tonic-gate word & 0xff; 3528933Sopensolaris@drydog.com word = word >> BITSINBYTE; 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate } 3558933Sopensolaris@drydog.com offs = slen % BIGNUM_WORDSIZE; 3560Sstevel@tonic-gate if (offs > 0) { 3578933Sopensolaris@drydog.com word = bn->value[slen / BIGNUM_WORDSIZE]; 3588933Sopensolaris@drydog.com for (i = slen % BIGNUM_WORDSIZE; i > 0; i --) { 3596557Sfr41279 kn[i - 1] = word & 0xff; 3608933Sopensolaris@drydog.com word = word >> BITSINBYTE; 3616557Sfr41279 } 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate } else { 3640Sstevel@tonic-gate for (i = 0; i < bn->len; i++) { 3650Sstevel@tonic-gate word = bn->value[i]; 3668933Sopensolaris@drydog.com for (j = 0; j < BIGNUM_WORDSIZE; j++) { 3678933Sopensolaris@drydog.com kn[slen - BIGNUM_WORDSIZE * i - j - 1] = 3680Sstevel@tonic-gate word & 0xff; 3698933Sopensolaris@drydog.com word = word >> BITSINBYTE; 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate } 3728933Sopensolaris@drydog.com for (i = 0; i < slen - BIGNUM_WORDSIZE * bn->len; i++) { 3730Sstevel@tonic-gate kn[i] = 0; 3740Sstevel@tonic-gate } 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate int 3800Sstevel@tonic-gate big_bitlength(BIGNUM *a) 3810Sstevel@tonic-gate { 3826557Sfr41279 int l = 0, b = 0; 3836557Sfr41279 BIG_CHUNK_TYPE c; 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate l = a->len - 1; 3860Sstevel@tonic-gate while ((l > 0) && (a->value[l] == 0)) { 3870Sstevel@tonic-gate l--; 3880Sstevel@tonic-gate } 3898933Sopensolaris@drydog.com b = BIG_CHUNK_SIZE; 3900Sstevel@tonic-gate c = a->value[l]; 3916557Sfr41279 while ((b > 1) && ((c & BIG_CHUNK_HIGHBIT) == 0)) { 3920Sstevel@tonic-gate c = c << 1; 3930Sstevel@tonic-gate b--; 3940Sstevel@tonic-gate } 3956557Sfr41279 3968933Sopensolaris@drydog.com return (l * BIG_CHUNK_SIZE + b); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate 400*9302Sopensolaris@drydog.com /* 401*9302Sopensolaris@drydog.com * big_copy() 402*9302Sopensolaris@drydog.com * Copy BIGNUM src to dest, allocating memory if needed. 403*9302Sopensolaris@drydog.com */ 4040Sstevel@tonic-gate BIG_ERR_CODE 4050Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src) 4060Sstevel@tonic-gate { 4076557Sfr41279 BIG_CHUNK_TYPE *newptr; 4086557Sfr41279 int i, len; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate len = src->len; 4116557Sfr41279 while ((len > 1) && (src->value[len - 1] == 0)) { 4120Sstevel@tonic-gate len--; 4136557Sfr41279 } 4140Sstevel@tonic-gate src->len = len; 4150Sstevel@tonic-gate if (dest->size < len) { 4160Sstevel@tonic-gate if (dest->malloced == 1) { 4176557Sfr41279 newptr = (BIG_CHUNK_TYPE *)big_realloc(dest->value, 4188933Sopensolaris@drydog.com BIGNUM_WORDSIZE * dest->size, 4198933Sopensolaris@drydog.com BIGNUM_WORDSIZE * len); 4200Sstevel@tonic-gate } else { 4216557Sfr41279 newptr = (BIG_CHUNK_TYPE *) 4228933Sopensolaris@drydog.com big_malloc(BIGNUM_WORDSIZE * len); 4236557Sfr41279 if (newptr != NULL) { 4246557Sfr41279 dest->malloced = 1; 4256557Sfr41279 } 4260Sstevel@tonic-gate } 4276557Sfr41279 if (newptr == NULL) { 4280Sstevel@tonic-gate return (BIG_NO_MEM); 4296557Sfr41279 } 4300Sstevel@tonic-gate dest->value = newptr; 4310Sstevel@tonic-gate dest->size = len; 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate dest->len = len; 4340Sstevel@tonic-gate dest->sign = src->sign; 4356557Sfr41279 for (i = 0; i < len; i++) { 4366557Sfr41279 dest->value[i] = src->value[i]; 4376557Sfr41279 } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate return (BIG_OK); 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate 443*9302Sopensolaris@drydog.com /* 444*9302Sopensolaris@drydog.com * big_extend() 445*9302Sopensolaris@drydog.com * Allocate memory to extend BIGNUM number to size bignum chunks, 446*9302Sopensolaris@drydog.com * if not at least that size already. 447*9302Sopensolaris@drydog.com */ 4480Sstevel@tonic-gate BIG_ERR_CODE 4490Sstevel@tonic-gate big_extend(BIGNUM *number, int size) 4500Sstevel@tonic-gate { 4516557Sfr41279 BIG_CHUNK_TYPE *newptr; 4520Sstevel@tonic-gate int i; 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate if (number->size >= size) 4550Sstevel@tonic-gate return (BIG_OK); 4560Sstevel@tonic-gate if (number->malloced) { 4576557Sfr41279 number->value = big_realloc(number->value, 4588933Sopensolaris@drydog.com BIGNUM_WORDSIZE * number->size, 4598933Sopensolaris@drydog.com BIGNUM_WORDSIZE * size); 4600Sstevel@tonic-gate } else { 4618933Sopensolaris@drydog.com newptr = big_malloc(BIGNUM_WORDSIZE * size); 4620Sstevel@tonic-gate if (newptr != NULL) { 4630Sstevel@tonic-gate for (i = 0; i < number->size; i++) { 4640Sstevel@tonic-gate newptr[i] = number->value[i]; 4650Sstevel@tonic-gate } 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate number->value = newptr; 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate 4706557Sfr41279 if (number->value == NULL) { 4710Sstevel@tonic-gate return (BIG_NO_MEM); 4726557Sfr41279 } 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate number->size = size; 4750Sstevel@tonic-gate number->malloced = 1; 4760Sstevel@tonic-gate return (BIG_OK); 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate 4806557Sfr41279 /* returns 1 if n == 0 */ 4810Sstevel@tonic-gate int 4820Sstevel@tonic-gate big_is_zero(BIGNUM *n) 4830Sstevel@tonic-gate { 4846557Sfr41279 int i, result; 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate result = 1; 4876557Sfr41279 for (i = 0; i < n->len; i++) { 4886557Sfr41279 if (n->value[i] != 0) { 4896557Sfr41279 result = 0; 4906557Sfr41279 } 4916557Sfr41279 } 4920Sstevel@tonic-gate return (result); 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate BIG_ERR_CODE 4970Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 4980Sstevel@tonic-gate { 4996557Sfr41279 int i, shorter, longer; 5006557Sfr41279 BIG_CHUNK_TYPE cy, ai; 5016557Sfr41279 BIG_CHUNK_TYPE *r, *a, *b, *c; 5026557Sfr41279 BIG_ERR_CODE err; 5036557Sfr41279 BIGNUM *longerarg; 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate if (aa->len > bb->len) { 5060Sstevel@tonic-gate shorter = bb->len; 5070Sstevel@tonic-gate longer = aa->len; 5086557Sfr41279 longerarg = aa; 5090Sstevel@tonic-gate } else { 5100Sstevel@tonic-gate shorter = aa->len; 5110Sstevel@tonic-gate longer = bb->len; 5126557Sfr41279 longerarg = bb; 5130Sstevel@tonic-gate } 5140Sstevel@tonic-gate if (result->size < longer + 1) { 5150Sstevel@tonic-gate err = big_extend(result, longer + 1); 5166557Sfr41279 if (err != BIG_OK) { 5170Sstevel@tonic-gate return (err); 5186557Sfr41279 } 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate r = result->value; 5220Sstevel@tonic-gate a = aa->value; 5230Sstevel@tonic-gate b = bb->value; 5246557Sfr41279 c = longerarg->value; 5250Sstevel@tonic-gate cy = 0; 5260Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 5270Sstevel@tonic-gate ai = a[i]; 5280Sstevel@tonic-gate r[i] = ai + b[i] + cy; 5296557Sfr41279 if (r[i] > ai) { 5306557Sfr41279 cy = 0; 5316557Sfr41279 } else if (r[i] < ai) { 5326557Sfr41279 cy = 1; 5336557Sfr41279 } 5340Sstevel@tonic-gate } 5350Sstevel@tonic-gate for (; i < longer; i++) { 5360Sstevel@tonic-gate ai = c[i]; 5370Sstevel@tonic-gate r[i] = ai + cy; 5386557Sfr41279 if (r[i] >= ai) { 5396557Sfr41279 cy = 0; 5406557Sfr41279 } 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate if (cy == 1) { 5430Sstevel@tonic-gate r[i] = cy; 5440Sstevel@tonic-gate result->len = longer + 1; 5450Sstevel@tonic-gate } else { 5460Sstevel@tonic-gate result->len = longer; 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate result->sign = 1; 5490Sstevel@tonic-gate return (BIG_OK); 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */ 5540Sstevel@tonic-gate void 5556557Sfr41279 big_sub_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, BIG_CHUNK_TYPE *b, int len) 5560Sstevel@tonic-gate { 5576557Sfr41279 int i; 5586557Sfr41279 BIG_CHUNK_TYPE cy, ai; 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate cy = 1; 5610Sstevel@tonic-gate for (i = 0; i < len; i++) { 5620Sstevel@tonic-gate ai = a[i]; 5630Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 5646557Sfr41279 if (r[i] > ai) { 5656557Sfr41279 cy = 0; 5666557Sfr41279 } else if (r[i] < ai) { 5676557Sfr41279 cy = 1; 5686557Sfr41279 } 5690Sstevel@tonic-gate } 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate /* result=aa-bb it is assumed that aa>=bb */ 5740Sstevel@tonic-gate BIG_ERR_CODE 5750Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 5760Sstevel@tonic-gate { 5776557Sfr41279 int i, shorter; 5786557Sfr41279 BIG_CHUNK_TYPE cy = 1, ai; 5796557Sfr41279 BIG_CHUNK_TYPE *r, *a, *b; 5806557Sfr41279 BIG_ERR_CODE err = BIG_OK; 5816557Sfr41279 5826557Sfr41279 if (aa->len > bb->len) { 5836557Sfr41279 shorter = bb->len; 5846557Sfr41279 } else { 5856557Sfr41279 shorter = aa->len; 5866557Sfr41279 } 5870Sstevel@tonic-gate if (result->size < aa->len) { 5880Sstevel@tonic-gate err = big_extend(result, aa->len); 5896557Sfr41279 if (err != BIG_OK) { 5900Sstevel@tonic-gate return (err); 5916557Sfr41279 } 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate r = result->value; 5950Sstevel@tonic-gate a = aa->value; 5960Sstevel@tonic-gate b = bb->value; 5970Sstevel@tonic-gate result->len = aa->len; 5980Sstevel@tonic-gate cy = 1; 5990Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 6000Sstevel@tonic-gate ai = a[i]; 6010Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 6026557Sfr41279 if (r[i] > ai) { 6036557Sfr41279 cy = 0; 6046557Sfr41279 } else if (r[i] < ai) { 6056557Sfr41279 cy = 1; 6066557Sfr41279 } 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate for (; i < aa->len; i++) { 6090Sstevel@tonic-gate ai = a[i]; 6100Sstevel@tonic-gate r[i] = ai + (~0) + cy; 6116557Sfr41279 if (r[i] < ai) { 6126557Sfr41279 cy = 1; 6136557Sfr41279 } 6140Sstevel@tonic-gate } 6150Sstevel@tonic-gate result->sign = 1; 6166557Sfr41279 6176557Sfr41279 if (cy == 0) { 6180Sstevel@tonic-gate return (BIG_INVALID_ARGS); 6196557Sfr41279 } else { 6200Sstevel@tonic-gate return (BIG_OK); 6216557Sfr41279 } 6220Sstevel@tonic-gate } 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */ 6260Sstevel@tonic-gate int 6270Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb) 6280Sstevel@tonic-gate { 6296557Sfr41279 int i; 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate if (aa->len > bb->len) { 6320Sstevel@tonic-gate for (i = aa->len - 1; i > bb->len - 1; i--) { 6336557Sfr41279 if (aa->value[i] > 0) { 6340Sstevel@tonic-gate return (1); 6356557Sfr41279 } 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate } else if (aa->len < bb->len) { 6380Sstevel@tonic-gate for (i = bb->len - 1; i > aa->len - 1; i--) { 6396557Sfr41279 if (bb->value[i] > 0) { 6400Sstevel@tonic-gate return (-1); 6416557Sfr41279 } 6420Sstevel@tonic-gate } 6436557Sfr41279 } else { 6448933Sopensolaris@drydog.com i = aa->len - 1; 6456557Sfr41279 } 6460Sstevel@tonic-gate for (; i >= 0; i--) { 6476557Sfr41279 if (aa->value[i] > bb->value[i]) { 6480Sstevel@tonic-gate return (1); 6496557Sfr41279 } else if (aa->value[i] < bb->value[i]) { 6500Sstevel@tonic-gate return (-1); 6516557Sfr41279 } 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate return (0); 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate BIG_ERR_CODE 6590Sstevel@tonic-gate big_sub(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 7020Sstevel@tonic-gate BIG_ERR_CODE 7030Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 7040Sstevel@tonic-gate { 7056557Sfr41279 BIG_ERR_CODE err; 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate if ((bb->sign == -1) && (aa->sign == -1)) { 7086557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 7090Sstevel@tonic-gate return (err); 7106557Sfr41279 } 7110Sstevel@tonic-gate result->sign = -1; 7120Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == 1)) { 7136557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 7140Sstevel@tonic-gate return (err); 7156557Sfr41279 } 7160Sstevel@tonic-gate result->sign = 1; 7170Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == -1)) { 7180Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 7196557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 7200Sstevel@tonic-gate return (err); 7216557Sfr41279 } 7220Sstevel@tonic-gate result->sign = 1; 7230Sstevel@tonic-gate } else { 7246557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 7250Sstevel@tonic-gate return (err); 7266557Sfr41279 } 7270Sstevel@tonic-gate result->sign = -1; 7280Sstevel@tonic-gate } 7290Sstevel@tonic-gate } else { 7300Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 7316557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 7320Sstevel@tonic-gate return (err); 7336557Sfr41279 } 7340Sstevel@tonic-gate result->sign = -1; 7350Sstevel@tonic-gate } else { 7366557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 7370Sstevel@tonic-gate return (err); 7386557Sfr41279 } 7390Sstevel@tonic-gate result->sign = 1; 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate return (BIG_OK); 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate 7466557Sfr41279 /* result = aa/2 */ 7470Sstevel@tonic-gate BIG_ERR_CODE 7480Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa) 7490Sstevel@tonic-gate { 7506557Sfr41279 BIG_ERR_CODE err; 7516557Sfr41279 int i; 7526557Sfr41279 BIG_CHUNK_TYPE cy, cy1; 7536557Sfr41279 BIG_CHUNK_TYPE *a, *r; 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate if (result->size < aa->len) { 7560Sstevel@tonic-gate err = big_extend(result, aa->len); 7576557Sfr41279 if (err != BIG_OK) { 7580Sstevel@tonic-gate return (err); 7596557Sfr41279 } 7600Sstevel@tonic-gate } 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate result->len = aa->len; 7630Sstevel@tonic-gate a = aa->value; 7640Sstevel@tonic-gate r = result->value; 7650Sstevel@tonic-gate cy = 0; 7666557Sfr41279 for (i = aa->len - 1; i >= 0; i--) { 7676557Sfr41279 cy1 = a[i] << (BIG_CHUNK_SIZE - 1); 7686557Sfr41279 r[i] = (cy | (a[i] >> 1)); 7690Sstevel@tonic-gate cy = cy1; 7700Sstevel@tonic-gate } 7716557Sfr41279 if (r[result->len - 1] == 0) { 7726557Sfr41279 result->len--; 7736557Sfr41279 } 7746557Sfr41279 7750Sstevel@tonic-gate return (BIG_OK); 7760Sstevel@tonic-gate } 7770Sstevel@tonic-gate 7786557Sfr41279 /* result = aa*2 */ 7790Sstevel@tonic-gate BIG_ERR_CODE 7800Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa) 7810Sstevel@tonic-gate { 7826557Sfr41279 BIG_ERR_CODE err; 7836557Sfr41279 int i, rsize; 7846557Sfr41279 BIG_CHUNK_TYPE cy, cy1; 7856557Sfr41279 BIG_CHUNK_TYPE *a, *r; 7866557Sfr41279 7876557Sfr41279 if ((aa->len > 0) && 7886557Sfr41279 ((aa->value[aa->len - 1] & BIG_CHUNK_HIGHBIT) != 0)) { 7890Sstevel@tonic-gate rsize = aa->len + 1; 7906557Sfr41279 } else { 7916557Sfr41279 rsize = aa->len; 7926557Sfr41279 } 7930Sstevel@tonic-gate 7940Sstevel@tonic-gate if (result->size < rsize) { 7950Sstevel@tonic-gate err = big_extend(result, rsize); 7960Sstevel@tonic-gate if (err != BIG_OK) 7970Sstevel@tonic-gate return (err); 7980Sstevel@tonic-gate } 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate a = aa->value; 8010Sstevel@tonic-gate r = result->value; 8026557Sfr41279 if (rsize == aa->len + 1) { 8036557Sfr41279 r[rsize - 1] = 1; 8046557Sfr41279 } 8050Sstevel@tonic-gate cy = 0; 8060Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 8076557Sfr41279 cy1 = a[i] >> (BIG_CHUNK_SIZE - 1); 8080Sstevel@tonic-gate r[i] = (cy | (a[i] << 1)); 8090Sstevel@tonic-gate cy = cy1; 8100Sstevel@tonic-gate } 8110Sstevel@tonic-gate result->len = rsize; 8120Sstevel@tonic-gate return (BIG_OK); 8130Sstevel@tonic-gate } 8140Sstevel@tonic-gate 8156557Sfr41279 8166557Sfr41279 /* 8176557Sfr41279 * returns aa mod b, aa must be nonneg, b must be a max 8186557Sfr41279 * (BIG_CHUNK_SIZE / 2)-bit integer 8196557Sfr41279 */ 8206557Sfr41279 static uint32_t 8216557Sfr41279 big_modhalf_pos(BIGNUM *aa, uint32_t b) 8220Sstevel@tonic-gate { 8236557Sfr41279 int i; 8246557Sfr41279 BIG_CHUNK_TYPE rem; 8256557Sfr41279 8266557Sfr41279 if (aa->len == 0) { 8270Sstevel@tonic-gate return (0); 8286557Sfr41279 } 8290Sstevel@tonic-gate rem = aa->value[aa->len - 1] % b; 8300Sstevel@tonic-gate for (i = aa->len - 2; i >= 0; i--) { 8316557Sfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 8326557Sfr41279 (aa->value[i] >> (BIG_CHUNK_SIZE / 2))) % b; 8336557Sfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 8346557Sfr41279 (aa->value[i] & BIG_CHUNK_LOWHALFBITS)) % b; 8350Sstevel@tonic-gate } 8366557Sfr41279 8376557Sfr41279 return ((uint32_t)rem); 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate /* 8426557Sfr41279 * result = aa - (2^BIG_CHUNK_SIZE)^lendiff * bb 8430Sstevel@tonic-gate * result->size should be at least aa->len at entry 8440Sstevel@tonic-gate * aa, bb, and result should be positive 8450Sstevel@tonic-gate */ 8460Sstevel@tonic-gate void 8470Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 8480Sstevel@tonic-gate { 8490Sstevel@tonic-gate int i, lendiff; 8500Sstevel@tonic-gate BIGNUM res1, aa1; 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate lendiff = aa->len - bb->len; 8530Sstevel@tonic-gate res1.size = result->size - lendiff; 8540Sstevel@tonic-gate res1.malloced = 0; 8550Sstevel@tonic-gate res1.value = result->value + lendiff; 8560Sstevel@tonic-gate aa1.size = aa->size - lendiff; 8570Sstevel@tonic-gate aa1.value = aa->value + lendiff; 8580Sstevel@tonic-gate aa1.len = bb->len; 8590Sstevel@tonic-gate aa1.sign = 1; 8600Sstevel@tonic-gate (void) big_sub_pos(&res1, &aa1, bb); 8610Sstevel@tonic-gate if (result->value != aa->value) { 8620Sstevel@tonic-gate for (i = 0; i < lendiff; i++) { 8630Sstevel@tonic-gate result->value[i] = aa->value[i]; 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate result->len = aa->len; 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate 8690Sstevel@tonic-gate 8700Sstevel@tonic-gate /* 8710Sstevel@tonic-gate * returns 1, 0, or -1 depending on whether |aa| > , ==, or < 8726557Sfr41279 * (2^BIG_CHUNK_SIZE)^lendiff * |bb| 8730Sstevel@tonic-gate * aa->len should be >= bb->len 8740Sstevel@tonic-gate */ 8750Sstevel@tonic-gate int 8760Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb) 8770Sstevel@tonic-gate { 8788933Sopensolaris@drydog.com int lendiff; 8798933Sopensolaris@drydog.com BIGNUM aa1; 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate lendiff = aa->len - bb->len; 8820Sstevel@tonic-gate aa1.len = bb->len; 8830Sstevel@tonic-gate aa1.size = aa->size - lendiff; 8840Sstevel@tonic-gate aa1.malloced = 0; 8850Sstevel@tonic-gate aa1.value = aa->value + lendiff; 8860Sstevel@tonic-gate return (big_cmp_abs(&aa1, bb)); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate /* 8916557Sfr41279 * result = aa * b where b is a max. (BIG_CHUNK_SIZE / 2)-bit positive integer. 8920Sstevel@tonic-gate * result should have enough space allocated. 8930Sstevel@tonic-gate */ 8946557Sfr41279 static void 8956557Sfr41279 big_mulhalf_low(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 8960Sstevel@tonic-gate { 8976557Sfr41279 int i; 8986557Sfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy; 8996557Sfr41279 BIG_CHUNK_TYPE *a, *r; 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate a = aa->value; 9020Sstevel@tonic-gate r = result->value; 9030Sstevel@tonic-gate cy = 0; 9040Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 9050Sstevel@tonic-gate ai = a[i]; 9066557Sfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 9076557Sfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 9086557Sfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 9096557Sfr41279 r[i] = (t1 & BIG_CHUNK_LOWHALFBITS) | 9106557Sfr41279 (t2 << (BIG_CHUNK_SIZE / 2)); 9116557Sfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 9120Sstevel@tonic-gate } 9130Sstevel@tonic-gate r[i] = cy; 9140Sstevel@tonic-gate result->len = aa->len + 1; 9150Sstevel@tonic-gate result->sign = aa->sign; 9160Sstevel@tonic-gate } 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate 9190Sstevel@tonic-gate /* 9206557Sfr41279 * result = aa * b * 2^(BIG_CHUNK_SIZE / 2) where b is a max. 9216557Sfr41279 * (BIG_CHUNK_SIZE / 2)-bit positive integer. 9220Sstevel@tonic-gate * result should have enough space allocated. 9230Sstevel@tonic-gate */ 9246557Sfr41279 static void 9256557Sfr41279 big_mulhalf_high(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 9260Sstevel@tonic-gate { 9276557Sfr41279 int i; 9286557Sfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy, ri; 9296557Sfr41279 BIG_CHUNK_TYPE *a, *r; 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate a = aa->value; 9320Sstevel@tonic-gate r = result->value; 9330Sstevel@tonic-gate cy = 0; 9340Sstevel@tonic-gate ri = 0; 9350Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 9360Sstevel@tonic-gate ai = a[i]; 9376557Sfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 9386557Sfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 9396557Sfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 9406557Sfr41279 r[i] = (t1 << (BIG_CHUNK_SIZE / 2)) + ri; 9416557Sfr41279 ri = t2 & BIG_CHUNK_LOWHALFBITS; 9426557Sfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 9430Sstevel@tonic-gate } 9446557Sfr41279 r[i] = (cy << (BIG_CHUNK_SIZE / 2)) + ri; 9450Sstevel@tonic-gate result->len = aa->len + 1; 9460Sstevel@tonic-gate result->sign = aa->sign; 9470Sstevel@tonic-gate } 9480Sstevel@tonic-gate 9496557Sfr41279 9500Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 9510Sstevel@tonic-gate void 9520Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs) 9530Sstevel@tonic-gate { 9546557Sfr41279 int i; 9556557Sfr41279 BIG_CHUNK_TYPE cy, ai; 9560Sstevel@tonic-gate 9570Sstevel@tonic-gate if (offs == 0) { 9580Sstevel@tonic-gate if (result != aa) { 9590Sstevel@tonic-gate (void) big_copy(result, aa); 9600Sstevel@tonic-gate } 9610Sstevel@tonic-gate return; 9620Sstevel@tonic-gate } 9630Sstevel@tonic-gate cy = 0; 9640Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 9650Sstevel@tonic-gate ai = aa->value[i]; 9660Sstevel@tonic-gate result->value[i] = (ai << offs) | cy; 9676557Sfr41279 cy = ai >> (BIG_CHUNK_SIZE - offs); 9680Sstevel@tonic-gate } 9690Sstevel@tonic-gate if (cy != 0) { 9700Sstevel@tonic-gate result->len = aa->len + 1; 9710Sstevel@tonic-gate result->value[result->len - 1] = cy; 9720Sstevel@tonic-gate } else { 9730Sstevel@tonic-gate result->len = aa->len; 9740Sstevel@tonic-gate } 9750Sstevel@tonic-gate result->sign = aa->sign; 9760Sstevel@tonic-gate } 9770Sstevel@tonic-gate 9786557Sfr41279 9790Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 9800Sstevel@tonic-gate void 9810Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs) 9820Sstevel@tonic-gate { 9836557Sfr41279 int i; 9846557Sfr41279 BIG_CHUNK_TYPE cy, ai; 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate if (offs == 0) { 9870Sstevel@tonic-gate if (result != aa) { 9880Sstevel@tonic-gate (void) big_copy(result, aa); 9890Sstevel@tonic-gate } 9900Sstevel@tonic-gate return; 9910Sstevel@tonic-gate } 9920Sstevel@tonic-gate cy = aa->value[0] >> offs; 9930Sstevel@tonic-gate for (i = 1; i < aa->len; i++) { 9940Sstevel@tonic-gate ai = aa->value[i]; 9958933Sopensolaris@drydog.com result->value[i - 1] = (ai << (BIG_CHUNK_SIZE - offs)) | cy; 9960Sstevel@tonic-gate cy = ai >> offs; 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate result->len = aa->len; 9990Sstevel@tonic-gate result->value[result->len - 1] = cy; 10000Sstevel@tonic-gate result->sign = aa->sign; 10010Sstevel@tonic-gate } 10020Sstevel@tonic-gate 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate /* 10050Sstevel@tonic-gate * result = aa/bb remainder = aa mod bb 10060Sstevel@tonic-gate * it is assumed that aa and bb are positive 10070Sstevel@tonic-gate */ 10080Sstevel@tonic-gate BIG_ERR_CODE 10098933Sopensolaris@drydog.com big_div_pos(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb) 10100Sstevel@tonic-gate { 10116557Sfr41279 BIG_ERR_CODE err = BIG_OK; 10126557Sfr41279 int i, alen, blen, tlen, rlen, offs; 10136557Sfr41279 BIG_CHUNK_TYPE higha, highb, coeff; 10146557Sfr41279 BIG_CHUNK_TYPE *a, *b; 10156557Sfr41279 BIGNUM bbhigh, bblow, tresult, tmp1, tmp2; 10166557Sfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 10176557Sfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 10186557Sfr41279 BIG_CHUNK_TYPE tresultvalue[BIGTMPSIZE]; 10196557Sfr41279 BIG_CHUNK_TYPE bblowvalue[BIGTMPSIZE]; 10206557Sfr41279 BIG_CHUNK_TYPE bbhighvalue[BIGTMPSIZE]; 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate a = aa->value; 10230Sstevel@tonic-gate b = bb->value; 10240Sstevel@tonic-gate alen = aa->len; 10250Sstevel@tonic-gate blen = bb->len; 10266557Sfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 10276557Sfr41279 alen = alen - 1; 10286557Sfr41279 } 10290Sstevel@tonic-gate aa->len = alen; 10306557Sfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 10316557Sfr41279 blen = blen - 1; 10326557Sfr41279 } 10330Sstevel@tonic-gate bb->len = blen; 10346557Sfr41279 if ((blen == 1) && (b[0] == 0)) { 10350Sstevel@tonic-gate return (BIG_DIV_BY_0); 10366557Sfr41279 } 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate if (big_cmp_abs(aa, bb) < 0) { 10390Sstevel@tonic-gate if ((remainder != NULL) && 10406557Sfr41279 ((err = big_copy(remainder, aa)) != BIG_OK)) { 10410Sstevel@tonic-gate return (err); 10426557Sfr41279 } 10430Sstevel@tonic-gate if (result != NULL) { 10440Sstevel@tonic-gate result->len = 1; 10450Sstevel@tonic-gate result->sign = 1; 10460Sstevel@tonic-gate result->value[0] = 0; 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate return (BIG_OK); 10490Sstevel@tonic-gate } 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate if ((err = big_init1(&bblow, blen + 1, 10520Sstevel@tonic-gate bblowvalue, arraysize(bblowvalue))) != BIG_OK) 10530Sstevel@tonic-gate return (err); 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate if ((err = big_init1(&bbhigh, blen + 1, 10560Sstevel@tonic-gate bbhighvalue, arraysize(bbhighvalue))) != BIG_OK) 10570Sstevel@tonic-gate goto ret1; 10580Sstevel@tonic-gate 10590Sstevel@tonic-gate if ((err = big_init1(&tmp1, alen + 2, 10600Sstevel@tonic-gate tmp1value, arraysize(tmp1value))) != BIG_OK) 10610Sstevel@tonic-gate goto ret2; 10620Sstevel@tonic-gate 10630Sstevel@tonic-gate if ((err = big_init1(&tmp2, blen + 2, 10640Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 10650Sstevel@tonic-gate goto ret3; 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate if ((err = big_init1(&tresult, alen - blen + 2, 10680Sstevel@tonic-gate tresultvalue, arraysize(tresultvalue))) != BIG_OK) 10690Sstevel@tonic-gate goto ret4; 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate offs = 0; 10726557Sfr41279 highb = b[blen - 1]; 10736557Sfr41279 if (highb >= (BIG_CHUNK_HALF_HIGHBIT << 1)) { 10746557Sfr41279 highb = highb >> (BIG_CHUNK_SIZE / 2); 10756557Sfr41279 offs = (BIG_CHUNK_SIZE / 2); 10760Sstevel@tonic-gate } 10776557Sfr41279 while ((highb & BIG_CHUNK_HALF_HIGHBIT) == 0) { 10786557Sfr41279 highb = highb << 1; 10790Sstevel@tonic-gate offs++; 10800Sstevel@tonic-gate } 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate big_shiftleft(&bblow, bb, offs); 10836557Sfr41279 10846557Sfr41279 if (offs <= (BIG_CHUNK_SIZE / 2 - 1)) { 10856557Sfr41279 big_shiftleft(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10860Sstevel@tonic-gate } else { 10876557Sfr41279 big_shiftright(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10880Sstevel@tonic-gate } 10890Sstevel@tonic-gate if (bbhigh.value[bbhigh.len - 1] == 0) { 10900Sstevel@tonic-gate bbhigh.len--; 10910Sstevel@tonic-gate } else { 10920Sstevel@tonic-gate bbhigh.value[bbhigh.len] = 0; 10930Sstevel@tonic-gate } 10940Sstevel@tonic-gate 10956557Sfr41279 highb = bblow.value[bblow.len - 1]; 10966557Sfr41279 10970Sstevel@tonic-gate big_shiftleft(&tmp1, aa, offs); 10980Sstevel@tonic-gate rlen = tmp1.len - bblow.len + 1; 10990Sstevel@tonic-gate tresult.len = rlen; 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate tmp1.len++; 11020Sstevel@tonic-gate tlen = tmp1.len; 11030Sstevel@tonic-gate tmp1.value[tmp1.len - 1] = 0; 11040Sstevel@tonic-gate for (i = 0; i < rlen; i++) { 11056557Sfr41279 higha = (tmp1.value[tlen - 1] << (BIG_CHUNK_SIZE / 2)) + 11066557Sfr41279 (tmp1.value[tlen - 2] >> (BIG_CHUNK_SIZE / 2)); 11070Sstevel@tonic-gate coeff = higha / (highb + 1); 11086557Sfr41279 big_mulhalf_high(&tmp2, &bblow, coeff); 11090Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 11100Sstevel@tonic-gate bbhigh.len++; 11110Sstevel@tonic-gate while (tmp1.value[tlen - 1] > 0) { 11120Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 11130Sstevel@tonic-gate coeff++; 11140Sstevel@tonic-gate } 11150Sstevel@tonic-gate bbhigh.len--; 11160Sstevel@tonic-gate tlen--; 11170Sstevel@tonic-gate tmp1.len--; 11180Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) { 11190Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 11200Sstevel@tonic-gate coeff++; 11210Sstevel@tonic-gate } 11226557Sfr41279 tresult.value[rlen - i - 1] = coeff << (BIG_CHUNK_SIZE / 2); 11230Sstevel@tonic-gate higha = tmp1.value[tlen - 1]; 11240Sstevel@tonic-gate coeff = higha / (highb + 1); 11256557Sfr41279 big_mulhalf_low(&tmp2, &bblow, coeff); 11260Sstevel@tonic-gate tmp2.len--; 11270Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 11280Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bblow) >= 0) { 11290Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bblow); 11300Sstevel@tonic-gate coeff++; 11310Sstevel@tonic-gate } 11320Sstevel@tonic-gate tresult.value[rlen - i - 1] = 11330Sstevel@tonic-gate tresult.value[rlen - i - 1] + coeff; 11340Sstevel@tonic-gate } 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate big_shiftright(&tmp1, &tmp1, offs); 11370Sstevel@tonic-gate 11380Sstevel@tonic-gate err = BIG_OK; 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate if ((remainder != NULL) && 11410Sstevel@tonic-gate ((err = big_copy(remainder, &tmp1)) != BIG_OK)) 11420Sstevel@tonic-gate goto ret; 11430Sstevel@tonic-gate 11440Sstevel@tonic-gate if (result != NULL) 11450Sstevel@tonic-gate err = big_copy(result, &tresult); 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate ret: 11480Sstevel@tonic-gate big_finish(&tresult); 11490Sstevel@tonic-gate ret4: 11500Sstevel@tonic-gate big_finish(&tmp1); 11510Sstevel@tonic-gate ret3: 11520Sstevel@tonic-gate big_finish(&tmp2); 11530Sstevel@tonic-gate ret2: 11540Sstevel@tonic-gate big_finish(&bbhigh); 11550Sstevel@tonic-gate ret1: 11560Sstevel@tonic-gate big_finish(&bblow); 11570Sstevel@tonic-gate return (err); 11580Sstevel@tonic-gate } 11590Sstevel@tonic-gate 11608933Sopensolaris@drydog.com 11610Sstevel@tonic-gate /* 11620Sstevel@tonic-gate * If there is no processor-specific integer implementation of 11630Sstevel@tonic-gate * the lower level multiply functions, then this code is provided 11640Sstevel@tonic-gate * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and 11650Sstevel@tonic-gate * big_sqr_vec(). 11660Sstevel@tonic-gate * 11670Sstevel@tonic-gate * There are two generic implementations. One that assumes that 11680Sstevel@tonic-gate * there is hardware and C compiler support for a 32 x 32 --> 64 11690Sstevel@tonic-gate * bit unsigned multiply, but otherwise is not specific to any 11700Sstevel@tonic-gate * processor, platform, or ISA. 11710Sstevel@tonic-gate * 11720Sstevel@tonic-gate * The other makes very few assumptions about hardware capabilities. 11730Sstevel@tonic-gate * It does not even assume that there is any implementation of a 11740Sstevel@tonic-gate * 32 x 32 --> 64 bit multiply that is accessible to C code and 11750Sstevel@tonic-gate * appropriate to use. It falls constructs 32 x 32 --> 64 bit 11760Sstevel@tonic-gate * multiplies from 16 x 16 --> 32 bit multiplies. 11770Sstevel@tonic-gate * 11780Sstevel@tonic-gate */ 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate #if !defined(PSR_MUL) 11810Sstevel@tonic-gate 11820Sstevel@tonic-gate #ifdef UMUL64 11830Sstevel@tonic-gate 11846557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 11856557Sfr41279 11860Sstevel@tonic-gate #define UNROLL8 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_PREFETCH(R) \ 11890Sstevel@tonic-gate p = pf * d; \ 11908933Sopensolaris@drydog.com pf = (uint64_t)a[R + 1]; \ 11910Sstevel@tonic-gate t = p + cy; \ 11920Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11930Sstevel@tonic-gate cy = t >> 32 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_NOPREFETCH(R) \ 11960Sstevel@tonic-gate p = pf * d; \ 11970Sstevel@tonic-gate t = p + cy; \ 11980Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11990Sstevel@tonic-gate cy = t >> 32 12000Sstevel@tonic-gate 12010Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_PREFETCH(R) \ 12020Sstevel@tonic-gate t = (uint64_t)r[R]; \ 12030Sstevel@tonic-gate p = pf * d; \ 12048933Sopensolaris@drydog.com pf = (uint64_t)a[R + 1]; \ 12050Sstevel@tonic-gate t = p + t + cy; \ 12060Sstevel@tonic-gate r[R] = (uint32_t)t; \ 12070Sstevel@tonic-gate cy = t >> 32 12080Sstevel@tonic-gate 12090Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_NOPREFETCH(R) \ 12100Sstevel@tonic-gate t = (uint64_t)r[R]; \ 12110Sstevel@tonic-gate p = pf * d; \ 12120Sstevel@tonic-gate t = p + t + cy; \ 12130Sstevel@tonic-gate r[R] = (uint32_t)t; \ 12140Sstevel@tonic-gate cy = t >> 32 12150Sstevel@tonic-gate 12160Sstevel@tonic-gate #ifdef UNROLL8 12170Sstevel@tonic-gate 12180Sstevel@tonic-gate #define UNROLL 8 12190Sstevel@tonic-gate 12200Sstevel@tonic-gate /* 12210Sstevel@tonic-gate * r = a * b 12220Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 12230Sstevel@tonic-gate */ 12240Sstevel@tonic-gate 12250Sstevel@tonic-gate uint32_t 12260Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 12270Sstevel@tonic-gate { 12280Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate if (len == 0) 12310Sstevel@tonic-gate return (0); 12320Sstevel@tonic-gate cy = 0; 12330Sstevel@tonic-gate d = (uint64_t)b; 12340Sstevel@tonic-gate pf = (uint64_t)a[0]; 12350Sstevel@tonic-gate while (len > UNROLL) { 12360Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 12370Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 12380Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 12390Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 12400Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 12410Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 12420Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 12430Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(7); 12440Sstevel@tonic-gate r += UNROLL; 12450Sstevel@tonic-gate a += UNROLL; 12460Sstevel@tonic-gate len -= UNROLL; 12470Sstevel@tonic-gate } 12480Sstevel@tonic-gate if (len == UNROLL) { 12490Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 12500Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 12510Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 12520Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 12530Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 12540Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 12550Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 12560Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(7); 12570Sstevel@tonic-gate return ((uint32_t)cy); 12580Sstevel@tonic-gate } 12590Sstevel@tonic-gate while (len > 1) { 12600Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 12610Sstevel@tonic-gate ++r; 12620Sstevel@tonic-gate ++a; 12630Sstevel@tonic-gate --len; 12640Sstevel@tonic-gate } 12650Sstevel@tonic-gate if (len > 0) { 12660Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(0); 12670Sstevel@tonic-gate } 12680Sstevel@tonic-gate return ((uint32_t)cy); 12690Sstevel@tonic-gate } 12700Sstevel@tonic-gate 12710Sstevel@tonic-gate /* 12720Sstevel@tonic-gate * r += a * b 12730Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 12740Sstevel@tonic-gate */ 12750Sstevel@tonic-gate 12760Sstevel@tonic-gate uint32_t 12770Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 12780Sstevel@tonic-gate { 12790Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 12800Sstevel@tonic-gate 12810Sstevel@tonic-gate if (len == 0) 12820Sstevel@tonic-gate return (0); 12830Sstevel@tonic-gate cy = 0; 12840Sstevel@tonic-gate d = (uint64_t)b; 12850Sstevel@tonic-gate pf = (uint64_t)a[0]; 12860Sstevel@tonic-gate while (len > 8) { 12870Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12880Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 12890Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 12900Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 12910Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 12920Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 12930Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 12940Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(7); 12950Sstevel@tonic-gate r += 8; 12960Sstevel@tonic-gate a += 8; 12970Sstevel@tonic-gate len -= 8; 12980Sstevel@tonic-gate } 12990Sstevel@tonic-gate if (len == 8) { 13000Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 13010Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 13020Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 13030Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 13040Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 13050Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 13060Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 13070Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(7); 13080Sstevel@tonic-gate return ((uint32_t)cy); 13090Sstevel@tonic-gate } 13100Sstevel@tonic-gate while (len > 1) { 13110Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 13120Sstevel@tonic-gate ++r; 13130Sstevel@tonic-gate ++a; 13140Sstevel@tonic-gate --len; 13150Sstevel@tonic-gate } 13160Sstevel@tonic-gate if (len > 0) { 13170Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(0); 13180Sstevel@tonic-gate } 13190Sstevel@tonic-gate return ((uint32_t)cy); 13200Sstevel@tonic-gate } 13210Sstevel@tonic-gate #endif /* UNROLL8 */ 13220Sstevel@tonic-gate 13230Sstevel@tonic-gate void 13240Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 13250Sstevel@tonic-gate { 13268933Sopensolaris@drydog.com uint32_t *tr, *ta; 13278933Sopensolaris@drydog.com int tlen, row, col; 13288933Sopensolaris@drydog.com uint64_t p, s, t, t2, cy; 13298933Sopensolaris@drydog.com uint32_t d; 13300Sstevel@tonic-gate 13310Sstevel@tonic-gate tr = r + 1; 13320Sstevel@tonic-gate ta = a; 13330Sstevel@tonic-gate tlen = len - 1; 13340Sstevel@tonic-gate tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]); 13350Sstevel@tonic-gate while (--tlen > 0) { 13360Sstevel@tonic-gate tr += 2; 13370Sstevel@tonic-gate ++ta; 13380Sstevel@tonic-gate tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]); 13390Sstevel@tonic-gate } 13400Sstevel@tonic-gate s = (uint64_t)a[0]; 13410Sstevel@tonic-gate s = s * s; 13420Sstevel@tonic-gate r[0] = (uint32_t)s; 13430Sstevel@tonic-gate cy = s >> 32; 13440Sstevel@tonic-gate p = ((uint64_t)r[1] << 1) + cy; 13450Sstevel@tonic-gate r[1] = (uint32_t)p; 13460Sstevel@tonic-gate cy = p >> 32; 13470Sstevel@tonic-gate row = 1; 13480Sstevel@tonic-gate col = 2; 13490Sstevel@tonic-gate while (row < len) { 13500Sstevel@tonic-gate s = (uint64_t)a[row]; 13510Sstevel@tonic-gate s = s * s; 13520Sstevel@tonic-gate p = (uint64_t)r[col] << 1; 13530Sstevel@tonic-gate t = p + s; 13540Sstevel@tonic-gate d = (uint32_t)t; 13550Sstevel@tonic-gate t2 = (uint64_t)d + cy; 13560Sstevel@tonic-gate r[col] = (uint32_t)t2; 13570Sstevel@tonic-gate cy = (t >> 32) + (t2 >> 32); 13580Sstevel@tonic-gate if (row == len - 1) 13590Sstevel@tonic-gate break; 13608933Sopensolaris@drydog.com p = ((uint64_t)r[col + 1] << 1) + cy; 13618933Sopensolaris@drydog.com r[col + 1] = (uint32_t)p; 13620Sstevel@tonic-gate cy = p >> 32; 13630Sstevel@tonic-gate ++row; 13640Sstevel@tonic-gate col += 2; 13650Sstevel@tonic-gate } 13668933Sopensolaris@drydog.com r[col + 1] = (uint32_t)cy; 13670Sstevel@tonic-gate } 13680Sstevel@tonic-gate 13696557Sfr41279 #else /* BIG_CHUNK_SIZE == 64 */ 13706557Sfr41279 13716557Sfr41279 /* 13726557Sfr41279 * r = r + a * digit, r and a are vectors of length len 13736557Sfr41279 * returns the carry digit 13746557Sfr41279 */ 13756557Sfr41279 BIG_CHUNK_TYPE 13766557Sfr41279 big_mul_add_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 13776557Sfr41279 BIG_CHUNK_TYPE digit) 13786557Sfr41279 { 13796557Sfr41279 BIG_CHUNK_TYPE cy, cy1, retcy, dlow, dhigh; 13806557Sfr41279 int i; 13816557Sfr41279 13826557Sfr41279 cy1 = 0; 13836557Sfr41279 dlow = digit & BIG_CHUNK_LOWHALFBITS; 13846557Sfr41279 dhigh = digit >> (BIG_CHUNK_SIZE / 2); 13856557Sfr41279 for (i = 0; i < len; i++) { 13866557Sfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 13876557Sfr41279 dlow * (a[i] & BIG_CHUNK_LOWHALFBITS) + 13886557Sfr41279 (r[i] & BIG_CHUNK_LOWHALFBITS); 13896557Sfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 13906557Sfr41279 dlow * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 13916557Sfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 13926557Sfr41279 r[i] = (cy & BIG_CHUNK_LOWHALFBITS) | 13936557Sfr41279 (cy1 << (BIG_CHUNK_SIZE / 2)); 13946557Sfr41279 } 13956557Sfr41279 retcy = cy1 >> (BIG_CHUNK_SIZE / 2); 13966557Sfr41279 13976557Sfr41279 cy1 = r[0] & BIG_CHUNK_LOWHALFBITS; 13986557Sfr41279 for (i = 0; i < len - 1; i++) { 13996557Sfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 14006557Sfr41279 dhigh * (a[i] & BIG_CHUNK_LOWHALFBITS) + 14016557Sfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 14026557Sfr41279 r[i] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 14036557Sfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 14046557Sfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 14056557Sfr41279 dhigh * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 14066557Sfr41279 (r[i + 1] & BIG_CHUNK_LOWHALFBITS); 14076557Sfr41279 } 14086557Sfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 14096557Sfr41279 dhigh * (a[len - 1] & BIG_CHUNK_LOWHALFBITS) + 14106557Sfr41279 (r[len - 1] >> (BIG_CHUNK_SIZE / 2)); 14116557Sfr41279 r[len - 1] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 14126557Sfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 14136557Sfr41279 retcy = (cy >> (BIG_CHUNK_SIZE / 2)) + 14146557Sfr41279 dhigh * (a[len - 1] >> (BIG_CHUNK_SIZE / 2)) + retcy; 14156557Sfr41279 14166557Sfr41279 return (retcy); 14176557Sfr41279 } 14186557Sfr41279 14196557Sfr41279 14206557Sfr41279 /* 14216557Sfr41279 * r = a * digit, r and a are vectors of length len 14226557Sfr41279 * returns the carry digit 14236557Sfr41279 */ 14246557Sfr41279 BIG_CHUNK_TYPE 14256557Sfr41279 big_mul_set_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 14266557Sfr41279 BIG_CHUNK_TYPE digit) 14276557Sfr41279 { 14286557Sfr41279 int i; 14296557Sfr41279 14306557Sfr41279 ASSERT(r != a); 14316557Sfr41279 for (i = 0; i < len; i++) { 14326557Sfr41279 r[i] = 0; 14336557Sfr41279 } 14346557Sfr41279 return (big_mul_add_vec(r, a, len, digit)); 14356557Sfr41279 } 14366557Sfr41279 14376557Sfr41279 void 14386557Sfr41279 big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len) 14396557Sfr41279 { 14406557Sfr41279 int i; 14416557Sfr41279 14426557Sfr41279 ASSERT(r != a); 14436557Sfr41279 r[len] = big_mul_set_vec(r, a, len, a[0]); 14446557Sfr41279 for (i = 1; i < len; ++i) 14458933Sopensolaris@drydog.com r[len + i] = big_mul_add_vec(r + i, a, len, a[i]); 14466557Sfr41279 } 14476557Sfr41279 14486557Sfr41279 #endif /* BIG_CHUNK_SIZE == 32/64 */ 14496557Sfr41279 14508933Sopensolaris@drydog.com 14510Sstevel@tonic-gate #else /* ! UMUL64 */ 14520Sstevel@tonic-gate 14536557Sfr41279 #if (BIG_CHUNK_SIZE != 32) 14546557Sfr41279 #error Don't use 64-bit chunks without defining UMUL64 14556557Sfr41279 #endif 14566557Sfr41279 14576557Sfr41279 14580Sstevel@tonic-gate /* 14590Sstevel@tonic-gate * r = r + a * digit, r and a are vectors of length len 14600Sstevel@tonic-gate * returns the carry digit 14610Sstevel@tonic-gate */ 14620Sstevel@tonic-gate uint32_t 14630Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 14640Sstevel@tonic-gate { 14650Sstevel@tonic-gate uint32_t cy, cy1, retcy, dlow, dhigh; 14660Sstevel@tonic-gate int i; 14670Sstevel@tonic-gate 14680Sstevel@tonic-gate cy1 = 0; 14690Sstevel@tonic-gate dlow = digit & 0xffff; 14700Sstevel@tonic-gate dhigh = digit >> 16; 14710Sstevel@tonic-gate for (i = 0; i < len; i++) { 14720Sstevel@tonic-gate cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff); 14730Sstevel@tonic-gate cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16); 14740Sstevel@tonic-gate r[i] = (cy & 0xffff) | (cy1 << 16); 14750Sstevel@tonic-gate } 14760Sstevel@tonic-gate retcy = cy1 >> 16; 14770Sstevel@tonic-gate 14780Sstevel@tonic-gate cy1 = r[0] & 0xffff; 14790Sstevel@tonic-gate for (i = 0; i < len - 1; i++) { 14800Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16); 14810Sstevel@tonic-gate r[i] = (cy1 & 0xffff) | (cy << 16); 14820Sstevel@tonic-gate cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff); 14830Sstevel@tonic-gate } 14840Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16); 14850Sstevel@tonic-gate r[len - 1] = (cy1 & 0xffff) | (cy << 16); 14860Sstevel@tonic-gate retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy; 14870Sstevel@tonic-gate 14880Sstevel@tonic-gate return (retcy); 14890Sstevel@tonic-gate } 14900Sstevel@tonic-gate 14916557Sfr41279 14920Sstevel@tonic-gate /* 14930Sstevel@tonic-gate * r = a * digit, r and a are vectors of length len 14940Sstevel@tonic-gate * returns the carry digit 14950Sstevel@tonic-gate */ 14960Sstevel@tonic-gate uint32_t 14970Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 14980Sstevel@tonic-gate { 14996557Sfr41279 int i; 15006557Sfr41279 15016557Sfr41279 ASSERT(r != a); 15026557Sfr41279 for (i = 0; i < len; i++) { 15036557Sfr41279 r[i] = 0; 15046557Sfr41279 } 15056557Sfr41279 15060Sstevel@tonic-gate return (big_mul_add_vec(r, a, len, digit)); 15070Sstevel@tonic-gate } 15080Sstevel@tonic-gate 15090Sstevel@tonic-gate void 15100Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 15110Sstevel@tonic-gate { 15120Sstevel@tonic-gate int i; 15130Sstevel@tonic-gate 15146557Sfr41279 ASSERT(r != a); 15150Sstevel@tonic-gate r[len] = big_mul_set_vec(r, a, len, a[0]); 15160Sstevel@tonic-gate for (i = 1; i < len; ++i) 15178933Sopensolaris@drydog.com r[len + i] = big_mul_add_vec(r + i, a, len, a[i]); 15180Sstevel@tonic-gate } 15190Sstevel@tonic-gate 15200Sstevel@tonic-gate #endif /* UMUL64 */ 15210Sstevel@tonic-gate 15220Sstevel@tonic-gate void 15236557Sfr41279 big_mul_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int alen, 15246557Sfr41279 BIG_CHUNK_TYPE *b, int blen) 15250Sstevel@tonic-gate { 15260Sstevel@tonic-gate int i; 15270Sstevel@tonic-gate 15280Sstevel@tonic-gate r[alen] = big_mul_set_vec(r, a, alen, b[0]); 15290Sstevel@tonic-gate for (i = 1; i < blen; ++i) 15308933Sopensolaris@drydog.com r[alen + i] = big_mul_add_vec(r + i, a, alen, b[i]); 15310Sstevel@tonic-gate } 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate 15340Sstevel@tonic-gate #endif /* ! PSR_MUL */ 15350Sstevel@tonic-gate 15360Sstevel@tonic-gate 15370Sstevel@tonic-gate /* 15380Sstevel@tonic-gate * result = aa * bb result->value should be big enough to hold the result 15390Sstevel@tonic-gate * 15400Sstevel@tonic-gate * Implementation: Standard grammar school algorithm 15410Sstevel@tonic-gate * 15420Sstevel@tonic-gate */ 15430Sstevel@tonic-gate BIG_ERR_CODE 15440Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 15450Sstevel@tonic-gate { 15466557Sfr41279 BIGNUM tmp1; 15476557Sfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 15486557Sfr41279 BIG_CHUNK_TYPE *r, *t, *a, *b; 15496557Sfr41279 BIG_ERR_CODE err; 15506557Sfr41279 int i, alen, blen, rsize, sign, diff; 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate if (aa == bb) { 15530Sstevel@tonic-gate diff = 0; 15540Sstevel@tonic-gate } else { 15550Sstevel@tonic-gate diff = big_cmp_abs(aa, bb); 15560Sstevel@tonic-gate if (diff < 0) { 15570Sstevel@tonic-gate BIGNUM *tt; 15580Sstevel@tonic-gate tt = aa; 15590Sstevel@tonic-gate aa = bb; 15600Sstevel@tonic-gate bb = tt; 15610Sstevel@tonic-gate } 15620Sstevel@tonic-gate } 15630Sstevel@tonic-gate a = aa->value; 15640Sstevel@tonic-gate b = bb->value; 15650Sstevel@tonic-gate alen = aa->len; 15660Sstevel@tonic-gate blen = bb->len; 15676557Sfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 15686557Sfr41279 alen--; 15696557Sfr41279 } 15700Sstevel@tonic-gate aa->len = alen; 15716557Sfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 15726557Sfr41279 blen--; 15736557Sfr41279 } 15740Sstevel@tonic-gate bb->len = blen; 15750Sstevel@tonic-gate 15760Sstevel@tonic-gate rsize = alen + blen; 15778933Sopensolaris@drydog.com ASSERT(rsize > 0); 15780Sstevel@tonic-gate if (result->size < rsize) { 15790Sstevel@tonic-gate err = big_extend(result, rsize); 15806557Sfr41279 if (err != BIG_OK) { 15810Sstevel@tonic-gate return (err); 15826557Sfr41279 } 15830Sstevel@tonic-gate /* aa or bb might be an alias to result */ 15840Sstevel@tonic-gate a = aa->value; 15850Sstevel@tonic-gate b = bb->value; 15860Sstevel@tonic-gate } 15870Sstevel@tonic-gate r = result->value; 15880Sstevel@tonic-gate 15890Sstevel@tonic-gate if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) { 15900Sstevel@tonic-gate result->len = 1; 15910Sstevel@tonic-gate result->sign = 1; 15920Sstevel@tonic-gate r[0] = 0; 15930Sstevel@tonic-gate return (BIG_OK); 15940Sstevel@tonic-gate } 15950Sstevel@tonic-gate sign = aa->sign * bb->sign; 15960Sstevel@tonic-gate if ((alen == 1) && (a[0] == 1)) { 15976557Sfr41279 for (i = 0; i < blen; i++) { 15986557Sfr41279 r[i] = b[i]; 15996557Sfr41279 } 16000Sstevel@tonic-gate result->len = blen; 16010Sstevel@tonic-gate result->sign = sign; 16020Sstevel@tonic-gate return (BIG_OK); 16030Sstevel@tonic-gate } 16040Sstevel@tonic-gate if ((blen == 1) && (b[0] == 1)) { 16056557Sfr41279 for (i = 0; i < alen; i++) { 16066557Sfr41279 r[i] = a[i]; 16076557Sfr41279 } 16080Sstevel@tonic-gate result->len = alen; 16090Sstevel@tonic-gate result->sign = sign; 16100Sstevel@tonic-gate return (BIG_OK); 16110Sstevel@tonic-gate } 16120Sstevel@tonic-gate 16136557Sfr41279 if ((err = big_init1(&tmp1, rsize, 16146557Sfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 16150Sstevel@tonic-gate return (err); 16166557Sfr41279 } 16170Sstevel@tonic-gate t = tmp1.value; 16186557Sfr41279 16196557Sfr41279 for (i = 0; i < rsize; i++) { 16206557Sfr41279 t[i] = 0; 16216557Sfr41279 } 16226557Sfr41279 16236557Sfr41279 if (diff == 0 && alen > 2) { 16240Sstevel@tonic-gate BIG_SQR_VEC(t, a, alen); 16256557Sfr41279 } else if (blen > 0) { 16260Sstevel@tonic-gate BIG_MUL_VEC(t, a, alen, b, blen); 16276557Sfr41279 } 16286557Sfr41279 16296557Sfr41279 if (t[rsize - 1] == 0) { 16306557Sfr41279 tmp1.len = rsize - 1; 16316557Sfr41279 } else { 16326557Sfr41279 tmp1.len = rsize; 16336557Sfr41279 } 16348933Sopensolaris@drydog.com 16358933Sopensolaris@drydog.com err = big_copy(result, &tmp1); 16368933Sopensolaris@drydog.com 16370Sstevel@tonic-gate result->sign = sign; 16380Sstevel@tonic-gate 16396557Sfr41279 big_finish(&tmp1); 16400Sstevel@tonic-gate 16418933Sopensolaris@drydog.com return (err); 16420Sstevel@tonic-gate } 16430Sstevel@tonic-gate 16440Sstevel@tonic-gate 16450Sstevel@tonic-gate /* 1646*9302Sopensolaris@drydog.com * big_mont_mul() 1647*9302Sopensolaris@drydog.com * Montgomery multiplication. 1648*9302Sopensolaris@drydog.com * 1649*9302Sopensolaris@drydog.com * Caller must ensure that a < n, b < n, ret->size >= 2 * n->len + 1, 1650*9302Sopensolaris@drydog.com * and that ret is not n. 16510Sstevel@tonic-gate */ 16520Sstevel@tonic-gate BIG_ERR_CODE 16536557Sfr41279 big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, BIG_CHUNK_TYPE n0) 16540Sstevel@tonic-gate { 1655*9302Sopensolaris@drydog.com int i, j, nlen, needsubtract; 1656*9302Sopensolaris@drydog.com BIG_CHUNK_TYPE *nn, *rr, *rrplusi; 16576557Sfr41279 BIG_CHUNK_TYPE digit, c; 16586557Sfr41279 BIG_ERR_CODE err; 1659*9302Sopensolaris@drydog.com #ifdef __amd64 1660*9302Sopensolaris@drydog.com #define BIG_CPU_UNKNOWN 0 1661*9302Sopensolaris@drydog.com #define BIG_CPU_AMD 1 1662*9302Sopensolaris@drydog.com #define BIG_CPU_INTEL 2 1663*9302Sopensolaris@drydog.com static int big_cpu = BIG_CPU_UNKNOWN; 1664*9302Sopensolaris@drydog.com BIG_CHUNK_TYPE carry[BIGTMPSIZE]; 1665*9302Sopensolaris@drydog.com 1666*9302Sopensolaris@drydog.com if (big_cpu == BIG_CPU_UNKNOWN) { 1667*9302Sopensolaris@drydog.com big_cpu = 1 + bignum_on_intel(); 1668*9302Sopensolaris@drydog.com } 1669*9302Sopensolaris@drydog.com #endif /* __amd64 */ 16700Sstevel@tonic-gate 16710Sstevel@tonic-gate nlen = n->len; 16720Sstevel@tonic-gate nn = n->value; 16730Sstevel@tonic-gate 16740Sstevel@tonic-gate rr = ret->value; 16750Sstevel@tonic-gate 16766557Sfr41279 if ((err = big_mul(ret, a, b)) != BIG_OK) { 16770Sstevel@tonic-gate return (err); 16786557Sfr41279 } 16790Sstevel@tonic-gate 16800Sstevel@tonic-gate rr = ret->value; 16816557Sfr41279 for (i = ret->len; i < 2 * nlen + 1; i++) { 16826557Sfr41279 rr[i] = 0; 16836557Sfr41279 } 1684*9302Sopensolaris@drydog.com 1685*9302Sopensolaris@drydog.com #ifdef __amd64 /* pipelining optimization for Intel 64, but not AMD64 */ 1686*9302Sopensolaris@drydog.com if ((big_cpu == BIG_CPU_INTEL) && (nlen <= BIGTMPSIZE)) { 1687*9302Sopensolaris@drydog.com /* 1688*9302Sopensolaris@drydog.com * Perform the following in two for loops to reduce the 1689*9302Sopensolaris@drydog.com * dependency between computing the carryover bits with 1690*9302Sopensolaris@drydog.com * BIG_MUL_ADD_VEC() and adding them, thus improving pipelining. 1691*9302Sopensolaris@drydog.com */ 1692*9302Sopensolaris@drydog.com for (i = 0; i < nlen; i++) { 1693*9302Sopensolaris@drydog.com rrplusi = rr + i; 1694*9302Sopensolaris@drydog.com digit = *rrplusi * n0; 1695*9302Sopensolaris@drydog.com carry[i] = BIG_MUL_ADD_VEC(rrplusi, nn, nlen, digit); 1696*9302Sopensolaris@drydog.com } 1697*9302Sopensolaris@drydog.com for (i = 0; i < nlen; i++) { 1698*9302Sopensolaris@drydog.com j = i + nlen; 1699*9302Sopensolaris@drydog.com rr[j] += carry[i]; 1700*9302Sopensolaris@drydog.com while (rr[j] < carry[i]) { 1701*9302Sopensolaris@drydog.com rr[++j] += 1; 1702*9302Sopensolaris@drydog.com carry[i] = 1; 1703*9302Sopensolaris@drydog.com } 1704*9302Sopensolaris@drydog.com } 1705*9302Sopensolaris@drydog.com } else 1706*9302Sopensolaris@drydog.com #endif /* __amd64 */ 1707*9302Sopensolaris@drydog.com { /* no pipelining optimization */ 1708*9302Sopensolaris@drydog.com for (i = 0; i < nlen; i++) { 1709*9302Sopensolaris@drydog.com rrplusi = rr + i; 1710*9302Sopensolaris@drydog.com digit = *rrplusi * n0; 1711*9302Sopensolaris@drydog.com c = BIG_MUL_ADD_VEC(rrplusi, nn, nlen, digit); 1712*9302Sopensolaris@drydog.com j = i + nlen; 1713*9302Sopensolaris@drydog.com rr[j] += c; 1714*9302Sopensolaris@drydog.com while (rr[j] < c) { 1715*9302Sopensolaris@drydog.com rr[++j] += 1; 1716*9302Sopensolaris@drydog.com c = 1; 1717*9302Sopensolaris@drydog.com } 17180Sstevel@tonic-gate } 17190Sstevel@tonic-gate } 17200Sstevel@tonic-gate 17210Sstevel@tonic-gate needsubtract = 0; 17220Sstevel@tonic-gate if ((rr[2 * nlen] != 0)) 17230Sstevel@tonic-gate needsubtract = 1; 17240Sstevel@tonic-gate else { 17250Sstevel@tonic-gate for (i = 2 * nlen - 1; i >= nlen; i--) { 17260Sstevel@tonic-gate if (rr[i] > nn[i - nlen]) { 17270Sstevel@tonic-gate needsubtract = 1; 17280Sstevel@tonic-gate break; 17296557Sfr41279 } else if (rr[i] < nn[i - nlen]) { 17306557Sfr41279 break; 17316557Sfr41279 } 17320Sstevel@tonic-gate } 17330Sstevel@tonic-gate } 17340Sstevel@tonic-gate if (needsubtract) 17350Sstevel@tonic-gate big_sub_vec(rr, rr + nlen, nn, nlen); 17360Sstevel@tonic-gate else { 17376557Sfr41279 for (i = 0; i < nlen; i++) { 17380Sstevel@tonic-gate rr[i] = rr[i + nlen]; 17396557Sfr41279 } 17400Sstevel@tonic-gate } 17418933Sopensolaris@drydog.com 17428933Sopensolaris@drydog.com /* Remove leading zeros, but keep at least 1 digit: */ 17438933Sopensolaris@drydog.com for (i = nlen - 1; (i > 0) && (rr[i] == 0); i--) 17446557Sfr41279 ; 17458933Sopensolaris@drydog.com ret->len = i + 1; 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate return (BIG_OK); 17480Sstevel@tonic-gate } 17490Sstevel@tonic-gate 17506557Sfr41279 17516557Sfr41279 BIG_CHUNK_TYPE 17526557Sfr41279 big_n0(BIG_CHUNK_TYPE n) 17530Sstevel@tonic-gate { 17546557Sfr41279 int i; 17556557Sfr41279 BIG_CHUNK_TYPE result, tmp; 17560Sstevel@tonic-gate 17570Sstevel@tonic-gate result = 0; 17586557Sfr41279 tmp = BIG_CHUNK_ALLBITS; 17596557Sfr41279 for (i = 0; i < BIG_CHUNK_SIZE; i++) { 17600Sstevel@tonic-gate if ((tmp & 1) == 1) { 17616557Sfr41279 result = (result >> 1) | BIG_CHUNK_HIGHBIT; 17620Sstevel@tonic-gate tmp = tmp - n; 17636557Sfr41279 } else { 17646557Sfr41279 result = (result >> 1); 17656557Sfr41279 } 17660Sstevel@tonic-gate tmp = tmp >> 1; 17670Sstevel@tonic-gate } 17680Sstevel@tonic-gate 17690Sstevel@tonic-gate return (result); 17700Sstevel@tonic-gate } 17710Sstevel@tonic-gate 17720Sstevel@tonic-gate 17730Sstevel@tonic-gate int 17740Sstevel@tonic-gate big_numbits(BIGNUM *n) 17750Sstevel@tonic-gate { 17766557Sfr41279 int i, j; 17776557Sfr41279 BIG_CHUNK_TYPE t; 17786557Sfr41279 17796557Sfr41279 for (i = n->len - 1; i > 0; i--) { 17806557Sfr41279 if (n->value[i] != 0) { 17816557Sfr41279 break; 17826557Sfr41279 } 17836557Sfr41279 } 17840Sstevel@tonic-gate t = n->value[i]; 17856557Sfr41279 for (j = BIG_CHUNK_SIZE; j > 0; j--) { 17866557Sfr41279 if ((t & BIG_CHUNK_HIGHBIT) == 0) { 17870Sstevel@tonic-gate t = t << 1; 17886557Sfr41279 } else { 17896557Sfr41279 return (BIG_CHUNK_SIZE * i + j); 17906557Sfr41279 } 17910Sstevel@tonic-gate } 17920Sstevel@tonic-gate return (0); 17930Sstevel@tonic-gate } 17940Sstevel@tonic-gate 17956557Sfr41279 17960Sstevel@tonic-gate /* caller must make sure that a < n */ 17970Sstevel@tonic-gate BIG_ERR_CODE 17980Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n) 17990Sstevel@tonic-gate { 18006557Sfr41279 BIGNUM rr; 18016557Sfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 18026557Sfr41279 int len, i; 18036557Sfr41279 BIG_ERR_CODE err; 18040Sstevel@tonic-gate 18050Sstevel@tonic-gate rr.malloced = 0; 18060Sstevel@tonic-gate len = n->len; 18070Sstevel@tonic-gate 18080Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, 18096557Sfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 18100Sstevel@tonic-gate return (err); 18116557Sfr41279 } 18126557Sfr41279 18136557Sfr41279 for (i = 0; i < 2 * len; i++) { 18146557Sfr41279 rr.value[i] = 0; 18156557Sfr41279 } 18160Sstevel@tonic-gate rr.value[2 * len] = 1; 18170Sstevel@tonic-gate rr.len = 2 * len + 1; 18186557Sfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 18190Sstevel@tonic-gate goto ret; 18206557Sfr41279 } 18210Sstevel@tonic-gate err = big_copy(result, &rr); 18220Sstevel@tonic-gate ret: 18236557Sfr41279 big_finish(&rr); 18240Sstevel@tonic-gate return (err); 18250Sstevel@tonic-gate } 18260Sstevel@tonic-gate 18276557Sfr41279 18280Sstevel@tonic-gate /* caller must make sure that a < n */ 18290Sstevel@tonic-gate BIG_ERR_CODE 18306557Sfr41279 big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, BIG_CHUNK_TYPE n0, 18316557Sfr41279 BIGNUM *n_rr) 18320Sstevel@tonic-gate { 18336557Sfr41279 BIGNUM rr; 18346557Sfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 18356557Sfr41279 int len, i; 18366557Sfr41279 BIG_ERR_CODE err; 18370Sstevel@tonic-gate 18380Sstevel@tonic-gate rr.malloced = 0; 18390Sstevel@tonic-gate len = n->len; 18400Sstevel@tonic-gate 18410Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue))) 18426557Sfr41279 != BIG_OK) { 18436557Sfr41279 return (err); 18446557Sfr41279 } 18450Sstevel@tonic-gate 18460Sstevel@tonic-gate if (n_rr == NULL) { 18476557Sfr41279 for (i = 0; i < 2 * len; i++) { 18486557Sfr41279 rr.value[i] = 0; 18496557Sfr41279 } 18500Sstevel@tonic-gate rr.value[2 * len] = 1; 18510Sstevel@tonic-gate rr.len = 2 * len + 1; 18526557Sfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 18530Sstevel@tonic-gate goto ret; 18546557Sfr41279 } 18550Sstevel@tonic-gate n_rr = &rr; 18560Sstevel@tonic-gate } 18570Sstevel@tonic-gate 18586557Sfr41279 if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK) { 18590Sstevel@tonic-gate goto ret; 18606557Sfr41279 } 18610Sstevel@tonic-gate err = big_copy(result, &rr); 18626557Sfr41279 18630Sstevel@tonic-gate ret: 18646557Sfr41279 big_finish(&rr); 18650Sstevel@tonic-gate return (err); 18660Sstevel@tonic-gate } 18670Sstevel@tonic-gate 18680Sstevel@tonic-gate 18696557Sfr41279 #ifdef USE_FLOATING_POINT 18706557Sfr41279 #define big_modexp_ncp_float big_modexp_ncp_sw 18716557Sfr41279 #else 18726557Sfr41279 #define big_modexp_ncp_int big_modexp_ncp_sw 18736557Sfr41279 #endif 18746557Sfr41279 18750Sstevel@tonic-gate #define MAX_EXP_BIT_GROUP_SIZE 6 18760Sstevel@tonic-gate #define APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1)) 18770Sstevel@tonic-gate 18786557Sfr41279 /* ARGSUSED */ 18790Sstevel@tonic-gate static BIG_ERR_CODE 18806557Sfr41279 big_modexp_ncp_int(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 18816557Sfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 18826557Sfr41279 18830Sstevel@tonic-gate { 18846557Sfr41279 BIGNUM apowers[APOWERS_MAX_SIZE]; 18856557Sfr41279 BIGNUM tmp1; 18866557Sfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 18876557Sfr41279 int i, j, k, l, m, p; 18888933Sopensolaris@drydog.com uint32_t bit, bitind, bitcount, groupbits, apowerssize; 18898933Sopensolaris@drydog.com uint32_t nbits; 18906557Sfr41279 BIG_ERR_CODE err; 18910Sstevel@tonic-gate 18920Sstevel@tonic-gate nbits = big_numbits(e); 18930Sstevel@tonic-gate if (nbits < 50) { 18940Sstevel@tonic-gate groupbits = 1; 18950Sstevel@tonic-gate apowerssize = 1; 18960Sstevel@tonic-gate } else { 18970Sstevel@tonic-gate groupbits = MAX_EXP_BIT_GROUP_SIZE; 18980Sstevel@tonic-gate apowerssize = 1 << (groupbits - 1); 18990Sstevel@tonic-gate } 19000Sstevel@tonic-gate 19016557Sfr41279 19026557Sfr41279 if ((err = big_init1(&tmp1, 2 * n->len + 1, 19036557Sfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 19040Sstevel@tonic-gate return (err); 19056557Sfr41279 } 19066557Sfr41279 19078933Sopensolaris@drydog.com /* clear the malloced bit to help cleanup */ 19086557Sfr41279 for (i = 0; i < apowerssize; i++) { 19096557Sfr41279 apowers[i].malloced = 0; 19106557Sfr41279 } 19118933Sopensolaris@drydog.com 19126557Sfr41279 for (i = 0; i < apowerssize; i++) { 19136557Sfr41279 if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) != 19146557Sfr41279 BIG_OK) { 19156557Sfr41279 goto ret; 19166557Sfr41279 } 19176557Sfr41279 } 19186557Sfr41279 19196557Sfr41279 (void) big_copy(&(apowers[0]), ma); 19206557Sfr41279 19216557Sfr41279 if ((err = big_mont_mul(&tmp1, ma, ma, n, n0)) != BIG_OK) { 19226557Sfr41279 goto ret; 19236557Sfr41279 } 19246557Sfr41279 (void) big_copy(ma, &tmp1); 19256557Sfr41279 19266557Sfr41279 for (i = 1; i < apowerssize; i++) { 19276557Sfr41279 if ((err = big_mont_mul(&tmp1, ma, 19288933Sopensolaris@drydog.com &(apowers[i - 1]), n, n0)) != BIG_OK) { 19296557Sfr41279 goto ret; 19306557Sfr41279 } 19316557Sfr41279 (void) big_copy(&apowers[i], &tmp1); 19326557Sfr41279 } 19336557Sfr41279 19346557Sfr41279 bitind = nbits % BIG_CHUNK_SIZE; 19356557Sfr41279 k = 0; 19366557Sfr41279 l = 0; 19376557Sfr41279 p = 0; 19386557Sfr41279 bitcount = 0; 19396557Sfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 19406557Sfr41279 for (j = bitind - 1; j >= 0; j--) { 19416557Sfr41279 bit = (e->value[i] >> j) & 1; 19426557Sfr41279 if ((bitcount == 0) && (bit == 0)) { 19436557Sfr41279 if ((err = big_mont_mul(tmp, 19446557Sfr41279 tmp, tmp, n, n0)) != BIG_OK) { 19456557Sfr41279 goto ret; 19466557Sfr41279 } 19476557Sfr41279 } else { 19486557Sfr41279 bitcount++; 19496557Sfr41279 p = p * 2 + bit; 19506557Sfr41279 if (bit == 1) { 19516557Sfr41279 k = k + l + 1; 19526557Sfr41279 l = 0; 19536557Sfr41279 } else { 19546557Sfr41279 l++; 19556557Sfr41279 } 19566557Sfr41279 if (bitcount == groupbits) { 19576557Sfr41279 for (m = 0; m < k; m++) { 19586557Sfr41279 if ((err = big_mont_mul(tmp, 19596557Sfr41279 tmp, tmp, n, n0)) != 19606557Sfr41279 BIG_OK) { 19616557Sfr41279 goto ret; 19626557Sfr41279 } 19636557Sfr41279 } 19646557Sfr41279 if ((err = big_mont_mul(tmp, tmp, 19656557Sfr41279 &(apowers[p >> (l + 1)]), 19666557Sfr41279 n, n0)) != BIG_OK) { 19676557Sfr41279 goto ret; 19686557Sfr41279 } 19696557Sfr41279 for (m = 0; m < l; m++) { 19706557Sfr41279 if ((err = big_mont_mul(tmp, 19716557Sfr41279 tmp, tmp, n, n0)) != 19726557Sfr41279 BIG_OK) { 19736557Sfr41279 goto ret; 19746557Sfr41279 } 19756557Sfr41279 } 19766557Sfr41279 k = 0; 19776557Sfr41279 l = 0; 19786557Sfr41279 p = 0; 19796557Sfr41279 bitcount = 0; 19806557Sfr41279 } 19816557Sfr41279 } 19826557Sfr41279 } 19836557Sfr41279 bitind = BIG_CHUNK_SIZE; 19840Sstevel@tonic-gate } 19850Sstevel@tonic-gate 19866557Sfr41279 for (m = 0; m < k; m++) { 19876557Sfr41279 if ((err = big_mont_mul(tmp, tmp, tmp, n, n0)) != BIG_OK) { 19886557Sfr41279 goto ret; 19896557Sfr41279 } 19906557Sfr41279 } 19916557Sfr41279 if (p != 0) { 19926557Sfr41279 if ((err = big_mont_mul(tmp, tmp, 19936557Sfr41279 &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK) { 19946557Sfr41279 goto ret; 19956557Sfr41279 } 19966557Sfr41279 } 19976557Sfr41279 for (m = 0; m < l; m++) { 19986557Sfr41279 if ((err = big_mont_mul(result, tmp, tmp, n, n0)) != BIG_OK) { 19996557Sfr41279 goto ret; 20006557Sfr41279 } 20016557Sfr41279 } 20026557Sfr41279 20036557Sfr41279 ret: 20046557Sfr41279 for (i = apowerssize - 1; i >= 0; i--) { 20056557Sfr41279 big_finish(&(apowers[i])); 20060Sstevel@tonic-gate } 20076557Sfr41279 big_finish(&tmp1); 20086557Sfr41279 20096557Sfr41279 return (err); 20106557Sfr41279 } 20116557Sfr41279 20126557Sfr41279 20136557Sfr41279 #ifdef USE_FLOATING_POINT 20146557Sfr41279 20156557Sfr41279 #ifdef _KERNEL 20166557Sfr41279 20176557Sfr41279 #include <sys/sysmacros.h> 20186557Sfr41279 #include <sys/regset.h> 20196557Sfr41279 #include <sys/fpu/fpusystm.h> 20206557Sfr41279 20216557Sfr41279 /* the alignment for block stores to save fp registers */ 20226557Sfr41279 #define FPR_ALIGN (64) 20236557Sfr41279 20246557Sfr41279 extern void big_savefp(kfpu_t *); 20256557Sfr41279 extern void big_restorefp(kfpu_t *); 20266557Sfr41279 20276557Sfr41279 #endif /* _KERNEL */ 20286557Sfr41279 20296557Sfr41279 /* 20306557Sfr41279 * This version makes use of floating point for performance 20316557Sfr41279 */ 20326557Sfr41279 static BIG_ERR_CODE 20336557Sfr41279 big_modexp_ncp_float(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 20346557Sfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 20356557Sfr41279 { 20366557Sfr41279 20378933Sopensolaris@drydog.com int i, j, k, l, m, p; 20388933Sopensolaris@drydog.com uint32_t bit, bitind, bitcount, nlen; 20396557Sfr41279 double dn0; 20406557Sfr41279 double *dn, *dt, *d16r, *d32r; 20416557Sfr41279 uint32_t *nint, *prod; 20426557Sfr41279 double *apowers[APOWERS_MAX_SIZE]; 20438933Sopensolaris@drydog.com uint32_t nbits, groupbits, apowerssize; 20446557Sfr41279 BIG_ERR_CODE err = BIG_OK; 20456557Sfr41279 20466557Sfr41279 #ifdef _KERNEL 20476557Sfr41279 uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN]; 20486557Sfr41279 kfpu_t *fpu; 20496557Sfr41279 20506557Sfr41279 #ifdef DEBUG 20516557Sfr41279 if (!fpu_exists) 20526557Sfr41279 return (BIG_GENERAL_ERR); 20536557Sfr41279 #endif 20546557Sfr41279 20556557Sfr41279 fpu = (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN); 20566557Sfr41279 big_savefp(fpu); 20576557Sfr41279 20586557Sfr41279 #endif /* _KERNEL */ 20596557Sfr41279 20606557Sfr41279 nbits = big_numbits(e); 20616557Sfr41279 if (nbits < 50) { 20626557Sfr41279 groupbits = 1; 20636557Sfr41279 apowerssize = 1; 20646557Sfr41279 } else { 20656557Sfr41279 groupbits = MAX_EXP_BIT_GROUP_SIZE; 20666557Sfr41279 apowerssize = 1 << (groupbits - 1); 20676557Sfr41279 } 20686557Sfr41279 20696557Sfr41279 nlen = (BIG_CHUNK_SIZE / 32) * n->len; 20700Sstevel@tonic-gate dn0 = (double)(n0 & 0xffff); 20710Sstevel@tonic-gate 20720Sstevel@tonic-gate dn = dt = d16r = d32r = NULL; 20730Sstevel@tonic-gate nint = prod = NULL; 20740Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 20750Sstevel@tonic-gate apowers[i] = NULL; 20760Sstevel@tonic-gate } 20770Sstevel@tonic-gate 20780Sstevel@tonic-gate if ((dn = big_malloc(nlen * sizeof (double))) == NULL) { 20790Sstevel@tonic-gate err = BIG_NO_MEM; 20800Sstevel@tonic-gate goto ret; 20810Sstevel@tonic-gate } 20820Sstevel@tonic-gate if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) { 20830Sstevel@tonic-gate err = BIG_NO_MEM; 20840Sstevel@tonic-gate goto ret; 20850Sstevel@tonic-gate } 20860Sstevel@tonic-gate if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) { 20870Sstevel@tonic-gate err = BIG_NO_MEM; 20880Sstevel@tonic-gate goto ret; 20890Sstevel@tonic-gate } 20900Sstevel@tonic-gate if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) { 20910Sstevel@tonic-gate err = BIG_NO_MEM; 20920Sstevel@tonic-gate goto ret; 20930Sstevel@tonic-gate } 20940Sstevel@tonic-gate if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) { 20950Sstevel@tonic-gate err = BIG_NO_MEM; 20960Sstevel@tonic-gate goto ret; 20970Sstevel@tonic-gate } 20980Sstevel@tonic-gate if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) { 20990Sstevel@tonic-gate err = BIG_NO_MEM; 21000Sstevel@tonic-gate goto ret; 21010Sstevel@tonic-gate } 21020Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 21030Sstevel@tonic-gate if ((apowers[i] = big_malloc((2 * nlen + 1) * 21040Sstevel@tonic-gate sizeof (double))) == NULL) { 21050Sstevel@tonic-gate err = BIG_NO_MEM; 21060Sstevel@tonic-gate goto ret; 21070Sstevel@tonic-gate } 21080Sstevel@tonic-gate } 21090Sstevel@tonic-gate 21106557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 21116557Sfr41279 for (i = 0; i < ma->len; i++) { 21126557Sfr41279 nint[i] = ma->value[i]; 21136557Sfr41279 } 21146557Sfr41279 for (; i < nlen; i++) { 21156557Sfr41279 nint[i] = 0; 21166557Sfr41279 } 21176557Sfr41279 #else 21186557Sfr41279 for (i = 0; i < ma->len; i++) { 21196557Sfr41279 nint[2 * i] = (uint32_t)(ma->value[i] & 0xffffffffULL); 21206557Sfr41279 nint[2 * i + 1] = (uint32_t)(ma->value[i] >> 32); 21216557Sfr41279 } 21226557Sfr41279 for (i = ma->len * 2; i < nlen; i++) { 21236557Sfr41279 nint[i] = 0; 21246557Sfr41279 } 21256557Sfr41279 #endif 21260Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen); 21270Sstevel@tonic-gate 21286557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 21296557Sfr41279 for (i = 0; i < n->len; i++) { 21306557Sfr41279 nint[i] = n->value[i]; 21316557Sfr41279 } 21326557Sfr41279 for (; i < nlen; i++) { 21336557Sfr41279 nint[i] = 0; 21346557Sfr41279 } 21356557Sfr41279 #else 21366557Sfr41279 for (i = 0; i < n->len; i++) { 21376557Sfr41279 nint[2 * i] = (uint32_t)(n->value[i] & 0xffffffffULL); 21386557Sfr41279 nint[2 * i + 1] = (uint32_t)(n->value[i] >> 32); 21396557Sfr41279 } 21406557Sfr41279 for (i = n->len * 2; i < nlen; i++) { 21416557Sfr41279 nint[i] = 0; 21426557Sfr41279 } 21436557Sfr41279 #endif 21440Sstevel@tonic-gate conv_i32_to_d32(dn, nint, nlen); 21450Sstevel@tonic-gate 21460Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0); 21470Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 21480Sstevel@tonic-gate for (i = 1; i < apowerssize; i++) { 21490Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[i - 1], 21500Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21510Sstevel@tonic-gate conv_i32_to_d16(apowers[i], prod, nlen); 21520Sstevel@tonic-gate } 21530Sstevel@tonic-gate 21546557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 21556557Sfr41279 for (i = 0; i < tmp->len; i++) { 21566557Sfr41279 prod[i] = tmp->value[i]; 21576557Sfr41279 } 21586557Sfr41279 for (; i < nlen + 1; i++) { 21596557Sfr41279 prod[i] = 0; 21606557Sfr41279 } 21616557Sfr41279 #else 21626557Sfr41279 for (i = 0; i < tmp->len; i++) { 21636557Sfr41279 prod[2 * i] = (uint32_t)(tmp->value[i] & 0xffffffffULL); 21646557Sfr41279 prod[2 * i + 1] = (uint32_t)(tmp->value[i] >> 32); 21656557Sfr41279 } 21666557Sfr41279 for (i = tmp->len * 2; i < nlen + 1; i++) { 21676557Sfr41279 prod[i] = 0; 21686557Sfr41279 } 21696557Sfr41279 #endif 21706557Sfr41279 21716557Sfr41279 bitind = nbits % BIG_CHUNK_SIZE; 21720Sstevel@tonic-gate k = 0; 21730Sstevel@tonic-gate l = 0; 21740Sstevel@tonic-gate p = 0; 21750Sstevel@tonic-gate bitcount = 0; 21766557Sfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 21770Sstevel@tonic-gate for (j = bitind - 1; j >= 0; j--) { 21780Sstevel@tonic-gate bit = (e->value[i] >> j) & 1; 21790Sstevel@tonic-gate if ((bitcount == 0) && (bit == 0)) { 21800Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, 21810Sstevel@tonic-gate prod, nlen); 21820Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, 21830Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21840Sstevel@tonic-gate } else { 21850Sstevel@tonic-gate bitcount++; 21860Sstevel@tonic-gate p = p * 2 + bit; 21870Sstevel@tonic-gate if (bit == 1) { 21880Sstevel@tonic-gate k = k + l + 1; 21890Sstevel@tonic-gate l = 0; 21900Sstevel@tonic-gate } else { 21910Sstevel@tonic-gate l++; 21920Sstevel@tonic-gate } 21930Sstevel@tonic-gate if (bitcount == groupbits) { 21940Sstevel@tonic-gate for (m = 0; m < k; m++) { 21956557Sfr41279 conv_i32_to_d32_and_d16(d32r, 21966557Sfr41279 d16r, prod, nlen); 21970Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 21980Sstevel@tonic-gate d16r, dt, dn, nint, 21990Sstevel@tonic-gate nlen, dn0); 22000Sstevel@tonic-gate } 22010Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 22020Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 22038933Sopensolaris@drydog.com apowers[p >> (l + 1)], 22040Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 22050Sstevel@tonic-gate for (m = 0; m < l; m++) { 22066557Sfr41279 conv_i32_to_d32_and_d16(d32r, 22076557Sfr41279 d16r, prod, nlen); 22080Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 22090Sstevel@tonic-gate d16r, dt, dn, nint, 22100Sstevel@tonic-gate nlen, dn0); 22110Sstevel@tonic-gate } 22120Sstevel@tonic-gate k = 0; 22130Sstevel@tonic-gate l = 0; 22140Sstevel@tonic-gate p = 0; 22150Sstevel@tonic-gate bitcount = 0; 22160Sstevel@tonic-gate } 22170Sstevel@tonic-gate } 22180Sstevel@tonic-gate } 22196557Sfr41279 bitind = BIG_CHUNK_SIZE; 22200Sstevel@tonic-gate } 22210Sstevel@tonic-gate 22220Sstevel@tonic-gate for (m = 0; m < k; m++) { 22230Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 22240Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 22250Sstevel@tonic-gate } 22260Sstevel@tonic-gate if (p != 0) { 22270Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 22280Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)], 22290Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 22300Sstevel@tonic-gate } 22310Sstevel@tonic-gate for (m = 0; m < l; m++) { 22320Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 22330Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 22340Sstevel@tonic-gate } 22350Sstevel@tonic-gate 22366557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 22376557Sfr41279 for (i = 0; i < nlen; i++) { 22386557Sfr41279 result->value[i] = prod[i]; 22396557Sfr41279 } 22406557Sfr41279 for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--) 22416557Sfr41279 ; 22426557Sfr41279 #else 22436557Sfr41279 for (i = 0; i < nlen / 2; i++) { 22446557Sfr41279 result->value[i] = (uint64_t)(prod[2 * i]) + 22456557Sfr41279 (((uint64_t)(prod[2 * i + 1])) << 32); 22466557Sfr41279 } 22476557Sfr41279 for (i = nlen / 2 - 1; (i > 0) && (result->value[i] == 0); i--) 22486557Sfr41279 ; 22496557Sfr41279 #endif 22506557Sfr41279 result->len = i + 1; 22516557Sfr41279 22520Sstevel@tonic-gate ret: 22530Sstevel@tonic-gate for (i = apowerssize - 1; i >= 0; i--) { 22540Sstevel@tonic-gate if (apowers[i] != NULL) 22550Sstevel@tonic-gate big_free(apowers[i], (2 * nlen + 1) * sizeof (double)); 22560Sstevel@tonic-gate } 22576557Sfr41279 if (d32r != NULL) { 22580Sstevel@tonic-gate big_free(d32r, nlen * sizeof (double)); 22596557Sfr41279 } 22606557Sfr41279 if (d16r != NULL) { 22610Sstevel@tonic-gate big_free(d16r, (2 * nlen + 1) * sizeof (double)); 22626557Sfr41279 } 22636557Sfr41279 if (prod != NULL) { 22640Sstevel@tonic-gate big_free(prod, (nlen + 1) * sizeof (uint32_t)); 22656557Sfr41279 } 22666557Sfr41279 if (nint != NULL) { 22670Sstevel@tonic-gate big_free(nint, nlen * sizeof (uint32_t)); 22686557Sfr41279 } 22696557Sfr41279 if (dt != NULL) { 22700Sstevel@tonic-gate big_free(dt, (4 * nlen + 2) * sizeof (double)); 22716557Sfr41279 } 22726557Sfr41279 if (dn != NULL) { 22730Sstevel@tonic-gate big_free(dn, nlen * sizeof (double)); 22746557Sfr41279 } 22750Sstevel@tonic-gate 22760Sstevel@tonic-gate #ifdef _KERNEL 22776557Sfr41279 big_restorefp(fpu); 22780Sstevel@tonic-gate #endif 22790Sstevel@tonic-gate 22800Sstevel@tonic-gate return (err); 22810Sstevel@tonic-gate } 22820Sstevel@tonic-gate 22830Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */ 22840Sstevel@tonic-gate 22850Sstevel@tonic-gate 22860Sstevel@tonic-gate BIG_ERR_CODE 22876557Sfr41279 big_modexp_ext(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr, 22886557Sfr41279 big_modexp_ncp_info_t *info) 22890Sstevel@tonic-gate { 22906557Sfr41279 BIGNUM ma, tmp, rr; 22916557Sfr41279 BIG_CHUNK_TYPE mavalue[BIGTMPSIZE]; 22926557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 22936557Sfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 22946557Sfr41279 BIG_ERR_CODE err; 22956557Sfr41279 BIG_CHUNK_TYPE n0; 22966557Sfr41279 22976557Sfr41279 if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue))) != 22986557Sfr41279 BIG_OK) { 22990Sstevel@tonic-gate return (err); 23006557Sfr41279 } 23016557Sfr41279 ma.len = 1; 23026557Sfr41279 ma.value[0] = 0; 23036557Sfr41279 23046557Sfr41279 if ((err = big_init1(&tmp, 2 * n->len + 1, 23056557Sfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 23060Sstevel@tonic-gate goto ret1; 23076557Sfr41279 } 23086557Sfr41279 23098933Sopensolaris@drydog.com /* clear the malloced bit to help cleanup */ 23106557Sfr41279 rr.malloced = 0; 23118933Sopensolaris@drydog.com 23126557Sfr41279 if (n_rr == NULL) { 23136557Sfr41279 if ((err = big_init1(&rr, 2 * n->len + 1, 23146557Sfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 23156557Sfr41279 goto ret2; 23166557Sfr41279 } 23176557Sfr41279 if (big_mont_rr(&rr, n) != BIG_OK) { 23186557Sfr41279 goto ret; 23196557Sfr41279 } 23206557Sfr41279 n_rr = &rr; 23216557Sfr41279 } 23226557Sfr41279 23236557Sfr41279 n0 = big_n0(n->value[0]); 23246557Sfr41279 23256557Sfr41279 if (big_cmp_abs(a, n) > 0) { 23266557Sfr41279 if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK) { 23276557Sfr41279 goto ret; 23286557Sfr41279 } 23296557Sfr41279 err = big_mont_conv(&ma, &ma, n, n0, n_rr); 23306557Sfr41279 } else { 23316557Sfr41279 err = big_mont_conv(&ma, a, n, n0, n_rr); 23326557Sfr41279 } 23336557Sfr41279 if (err != BIG_OK) { 23346557Sfr41279 goto ret; 23356557Sfr41279 } 23366557Sfr41279 23376557Sfr41279 tmp.len = 1; 23386557Sfr41279 tmp.value[0] = 1; 23396557Sfr41279 if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK) { 23406557Sfr41279 goto ret; 23416557Sfr41279 } 23426557Sfr41279 23436557Sfr41279 if ((info != NULL) && (info->func != NULL)) { 23446557Sfr41279 err = (*(info->func))(&tmp, &ma, e, n, &tmp, n0, 23456557Sfr41279 info->ncp, info->reqp); 23466557Sfr41279 } else { 23476557Sfr41279 err = big_modexp_ncp_sw(&tmp, &ma, e, n, &tmp, n0); 23486557Sfr41279 } 23496557Sfr41279 if (err != BIG_OK) { 23506557Sfr41279 goto ret; 23516557Sfr41279 } 23526557Sfr41279 23536557Sfr41279 ma.value[0] = 1; 23546557Sfr41279 ma.len = 1; 23556557Sfr41279 if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK) { 23566557Sfr41279 goto ret; 23576557Sfr41279 } 23586557Sfr41279 err = big_copy(result, &tmp); 23596557Sfr41279 23606557Sfr41279 ret: 23616557Sfr41279 if (rr.malloced) { 23626557Sfr41279 big_finish(&rr); 23636557Sfr41279 } 23646557Sfr41279 ret2: 23656557Sfr41279 big_finish(&tmp); 23666557Sfr41279 ret1: 23676557Sfr41279 big_finish(&ma); 23686557Sfr41279 23696557Sfr41279 return (err); 23706557Sfr41279 } 23716557Sfr41279 23726557Sfr41279 BIG_ERR_CODE 23736557Sfr41279 big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr) 23746557Sfr41279 { 23756557Sfr41279 return (big_modexp_ext(result, a, e, n, n_rr, NULL)); 23766557Sfr41279 } 23776557Sfr41279 23786557Sfr41279 23796557Sfr41279 BIG_ERR_CODE 23806557Sfr41279 big_modexp_crt_ext(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 23816557Sfr41279 BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 23826557Sfr41279 BIGNUM *p_rr, BIGNUM *q_rr, big_modexp_ncp_info_t *info) 23836557Sfr41279 { 23846557Sfr41279 BIGNUM ap, aq, tmp; 23856557Sfr41279 int alen, biglen, sign; 23866557Sfr41279 BIG_ERR_CODE err; 23876557Sfr41279 23886557Sfr41279 if (p->len > q->len) { 23896557Sfr41279 biglen = p->len; 23906557Sfr41279 } else { 23916557Sfr41279 biglen = q->len; 23926557Sfr41279 } 23936557Sfr41279 23946557Sfr41279 if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK) { 23956557Sfr41279 return (err); 23966557Sfr41279 } 23976557Sfr41279 if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK) { 23986557Sfr41279 goto ret1; 23996557Sfr41279 } 24006557Sfr41279 if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK) { 24010Sstevel@tonic-gate goto ret2; 24026557Sfr41279 } 24030Sstevel@tonic-gate 24040Sstevel@tonic-gate /* 24050Sstevel@tonic-gate * check whether a is too short - to avoid timing attacks 24060Sstevel@tonic-gate */ 24070Sstevel@tonic-gate alen = a->len; 24080Sstevel@tonic-gate while ((alen > p->len) && (a->value[alen - 1] == 0)) { 24090Sstevel@tonic-gate alen--; 24100Sstevel@tonic-gate } 24110Sstevel@tonic-gate if (alen < p->len + q->len) { 24120Sstevel@tonic-gate /* 24130Sstevel@tonic-gate * a is too short, add p*q to it before 24140Sstevel@tonic-gate * taking it modulo p and q 24150Sstevel@tonic-gate * this will also affect timing, but this difference 24160Sstevel@tonic-gate * does not depend on p or q, only on a 24170Sstevel@tonic-gate * (in "normal" operation, this path will never be 24180Sstevel@tonic-gate * taken, so it is not a performance penalty 24190Sstevel@tonic-gate */ 24206557Sfr41279 if ((err = big_mul(&tmp, p, q)) != BIG_OK) { 24210Sstevel@tonic-gate goto ret; 24226557Sfr41279 } 24236557Sfr41279 if ((err = big_add(&tmp, &tmp, a)) != BIG_OK) { 24246557Sfr41279 goto ret; 24256557Sfr41279 } 24266557Sfr41279 if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK) { 24270Sstevel@tonic-gate goto ret; 24286557Sfr41279 } 24296557Sfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 24300Sstevel@tonic-gate goto ret; 24316557Sfr41279 } 24326557Sfr41279 } else { 24336557Sfr41279 if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK) { 24340Sstevel@tonic-gate goto ret; 24356557Sfr41279 } 24366557Sfr41279 if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK) { 24370Sstevel@tonic-gate goto ret; 24386557Sfr41279 } 24390Sstevel@tonic-gate } 24400Sstevel@tonic-gate 24416557Sfr41279 if ((err = big_modexp_ext(&ap, &ap, dmodpminus1, p, p_rr, info)) != 24426557Sfr41279 BIG_OK) { 24430Sstevel@tonic-gate goto ret; 24446557Sfr41279 } 24456557Sfr41279 if ((err = big_modexp_ext(&aq, &aq, dmodqminus1, q, q_rr, info)) != 24466557Sfr41279 BIG_OK) { 24470Sstevel@tonic-gate goto ret; 24486557Sfr41279 } 24496557Sfr41279 if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK) { 24500Sstevel@tonic-gate goto ret; 24516557Sfr41279 } 24526557Sfr41279 if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK) { 24530Sstevel@tonic-gate goto ret; 24546557Sfr41279 } 24550Sstevel@tonic-gate sign = tmp.sign; 24560Sstevel@tonic-gate tmp.sign = 1; 24576557Sfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 24580Sstevel@tonic-gate goto ret; 24596557Sfr41279 } 24600Sstevel@tonic-gate if ((sign == -1) && (!big_is_zero(&aq))) { 24610Sstevel@tonic-gate (void) big_sub_pos(&aq, q, &aq); 24620Sstevel@tonic-gate } 24636557Sfr41279 if ((err = big_mul(&tmp, &aq, p)) != BIG_OK) { 24640Sstevel@tonic-gate goto ret; 24656557Sfr41279 } 24660Sstevel@tonic-gate err = big_add_abs(result, &ap, &tmp); 24670Sstevel@tonic-gate 24680Sstevel@tonic-gate ret: 24690Sstevel@tonic-gate big_finish(&tmp); 24700Sstevel@tonic-gate ret2: 24710Sstevel@tonic-gate big_finish(&aq); 24720Sstevel@tonic-gate ret1: 24730Sstevel@tonic-gate big_finish(&ap); 24740Sstevel@tonic-gate 24750Sstevel@tonic-gate return (err); 24760Sstevel@tonic-gate } 24770Sstevel@tonic-gate 24780Sstevel@tonic-gate 24796557Sfr41279 BIG_ERR_CODE 24806557Sfr41279 big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 24816557Sfr41279 BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 24826557Sfr41279 BIGNUM *p_rr, BIGNUM *q_rr) 24836557Sfr41279 { 24846557Sfr41279 return (big_modexp_crt_ext(result, a, dmodpminus1, dmodqminus1, 24856557Sfr41279 p, q, pinvmodq, p_rr, q_rr, NULL)); 24866557Sfr41279 } 24876557Sfr41279 24886557Sfr41279 24896557Sfr41279 static BIG_CHUNK_TYPE onearr[1] = {(BIG_CHUNK_TYPE)1}; 24906557Sfr41279 BIGNUM big_One = {1, 1, 1, 0, onearr}; 24916557Sfr41279 24926557Sfr41279 static BIG_CHUNK_TYPE twoarr[1] = {(BIG_CHUNK_TYPE)2}; 24936557Sfr41279 BIGNUM big_Two = {1, 1, 1, 0, twoarr}; 24946557Sfr41279 24956557Sfr41279 static BIG_CHUNK_TYPE fourarr[1] = {(BIG_CHUNK_TYPE)4}; 24966557Sfr41279 static BIGNUM big_Four = {1, 1, 1, 0, fourarr}; 24976557Sfr41279 24980Sstevel@tonic-gate 24990Sstevel@tonic-gate BIG_ERR_CODE 25000Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n) 25010Sstevel@tonic-gate { 25026557Sfr41279 BIGNUM *high, *low, *mid, *t; 25036557Sfr41279 BIGNUM t1, t2, t3, prod; 25046557Sfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 25056557Sfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 25066557Sfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 25076557Sfr41279 BIG_CHUNK_TYPE prodvalue[BIGTMPSIZE]; 25088933Sopensolaris@drydog.com int i, diff; 25098933Sopensolaris@drydog.com uint32_t nbits, nrootbits, highbits; 25106557Sfr41279 BIG_ERR_CODE err; 25110Sstevel@tonic-gate 25120Sstevel@tonic-gate nbits = big_numbits(n); 25130Sstevel@tonic-gate 25140Sstevel@tonic-gate if ((err = big_init1(&t1, n->len + 1, 25150Sstevel@tonic-gate t1value, arraysize(t1value))) != BIG_OK) 25160Sstevel@tonic-gate return (err); 25170Sstevel@tonic-gate if ((err = big_init1(&t2, n->len + 1, 25180Sstevel@tonic-gate t2value, arraysize(t2value))) != BIG_OK) 25190Sstevel@tonic-gate goto ret1; 25200Sstevel@tonic-gate if ((err = big_init1(&t3, n->len + 1, 25210Sstevel@tonic-gate t3value, arraysize(t3value))) != BIG_OK) 25220Sstevel@tonic-gate goto ret2; 25230Sstevel@tonic-gate if ((err = big_init1(&prod, n->len + 1, 25240Sstevel@tonic-gate prodvalue, arraysize(prodvalue))) != BIG_OK) 25250Sstevel@tonic-gate goto ret3; 25260Sstevel@tonic-gate 25270Sstevel@tonic-gate nrootbits = (nbits + 1) / 2; 25286557Sfr41279 t1.len = t2.len = t3.len = (nrootbits - 1) / BIG_CHUNK_SIZE + 1; 25290Sstevel@tonic-gate for (i = 0; i < t1.len; i++) { 25300Sstevel@tonic-gate t1.value[i] = 0; 25316557Sfr41279 t2.value[i] = BIG_CHUNK_ALLBITS; 25320Sstevel@tonic-gate } 25336557Sfr41279 highbits = nrootbits - BIG_CHUNK_SIZE * (t1.len - 1); 25346557Sfr41279 if (highbits == BIG_CHUNK_SIZE) { 25356557Sfr41279 t1.value[t1.len - 1] = BIG_CHUNK_HIGHBIT; 25366557Sfr41279 t2.value[t2.len - 1] = BIG_CHUNK_ALLBITS; 25370Sstevel@tonic-gate } else { 25386557Sfr41279 t1.value[t1.len - 1] = (BIG_CHUNK_TYPE)1 << (highbits - 1); 25390Sstevel@tonic-gate t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1; 25400Sstevel@tonic-gate } 25416557Sfr41279 25420Sstevel@tonic-gate high = &t2; 25430Sstevel@tonic-gate low = &t1; 25440Sstevel@tonic-gate mid = &t3; 25450Sstevel@tonic-gate 25466557Sfr41279 if ((err = big_mul(&prod, high, high)) != BIG_OK) { 25470Sstevel@tonic-gate goto ret; 25486557Sfr41279 } 25490Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 25500Sstevel@tonic-gate if (diff <= 0) { 25510Sstevel@tonic-gate err = big_copy(result, high); 25520Sstevel@tonic-gate goto ret; 25530Sstevel@tonic-gate } 25540Sstevel@tonic-gate 25550Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 25566557Sfr41279 while (big_cmp_abs(&big_One, mid) != 0) { 25570Sstevel@tonic-gate (void) big_add_abs(mid, high, low); 25580Sstevel@tonic-gate (void) big_half_pos(mid, mid); 25590Sstevel@tonic-gate if ((err = big_mul(&prod, mid, mid)) != BIG_OK) 25600Sstevel@tonic-gate goto ret; 25610Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 25620Sstevel@tonic-gate if (diff > 0) { 25630Sstevel@tonic-gate t = high; 25640Sstevel@tonic-gate high = mid; 25650Sstevel@tonic-gate mid = t; 25660Sstevel@tonic-gate } else if (diff < 0) { 25670Sstevel@tonic-gate t = low; 25680Sstevel@tonic-gate low = mid; 25690Sstevel@tonic-gate mid = t; 25700Sstevel@tonic-gate } else { 25710Sstevel@tonic-gate err = big_copy(result, low); 25720Sstevel@tonic-gate goto ret; 25730Sstevel@tonic-gate } 25740Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 25750Sstevel@tonic-gate } 25760Sstevel@tonic-gate 25770Sstevel@tonic-gate err = big_copy(result, low); 25780Sstevel@tonic-gate ret: 25790Sstevel@tonic-gate if (prod.malloced) big_finish(&prod); 25800Sstevel@tonic-gate ret3: 25810Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 25820Sstevel@tonic-gate ret2: 25830Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 25840Sstevel@tonic-gate ret1: 25850Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 25860Sstevel@tonic-gate 25870Sstevel@tonic-gate return (err); 25880Sstevel@tonic-gate } 25890Sstevel@tonic-gate 25900Sstevel@tonic-gate 25910Sstevel@tonic-gate BIG_ERR_CODE 25920Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm) 25930Sstevel@tonic-gate { 25946557Sfr41279 BIGNUM *t, *tmp2, *m, *n; 25956557Sfr41279 BIGNUM t1, t2, t3; 25966557Sfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 25976557Sfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 25986557Sfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 25996557Sfr41279 int len, err; 26000Sstevel@tonic-gate 26010Sstevel@tonic-gate if (big_is_zero(nn) || 26020Sstevel@tonic-gate (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) { 26030Sstevel@tonic-gate *jac = 0; 26040Sstevel@tonic-gate return (BIG_OK); 26050Sstevel@tonic-gate } 26060Sstevel@tonic-gate 26076557Sfr41279 if (nn->len > mm->len) { 26086557Sfr41279 len = nn->len; 26096557Sfr41279 } else { 26106557Sfr41279 len = mm->len; 26116557Sfr41279 } 26120Sstevel@tonic-gate 26130Sstevel@tonic-gate if ((err = big_init1(&t1, len, 26146557Sfr41279 t1value, arraysize(t1value))) != BIG_OK) { 26150Sstevel@tonic-gate return (err); 26166557Sfr41279 } 26170Sstevel@tonic-gate if ((err = big_init1(&t2, len, 26186557Sfr41279 t2value, arraysize(t2value))) != BIG_OK) { 26190Sstevel@tonic-gate goto ret1; 26206557Sfr41279 } 26210Sstevel@tonic-gate if ((err = big_init1(&t3, len, 26226557Sfr41279 t3value, arraysize(t3value))) != BIG_OK) { 26230Sstevel@tonic-gate goto ret2; 26246557Sfr41279 } 26250Sstevel@tonic-gate 26260Sstevel@tonic-gate n = &t1; 26270Sstevel@tonic-gate m = &t2; 26280Sstevel@tonic-gate tmp2 = &t3; 26290Sstevel@tonic-gate 26300Sstevel@tonic-gate (void) big_copy(n, nn); 26310Sstevel@tonic-gate (void) big_copy(m, mm); 26320Sstevel@tonic-gate 26330Sstevel@tonic-gate *jac = 1; 26346557Sfr41279 while (big_cmp_abs(&big_One, m) != 0) { 26350Sstevel@tonic-gate if (big_is_zero(n)) { 26360Sstevel@tonic-gate *jac = 0; 26370Sstevel@tonic-gate goto ret; 26380Sstevel@tonic-gate } 26390Sstevel@tonic-gate if ((m->value[0] & 1) == 0) { 26400Sstevel@tonic-gate if (((n->value[0] & 7) == 3) || 26416557Sfr41279 ((n->value[0] & 7) == 5)) 26426557Sfr41279 *jac = -*jac; 26430Sstevel@tonic-gate (void) big_half_pos(m, m); 26440Sstevel@tonic-gate } else if ((n->value[0] & 1) == 0) { 26450Sstevel@tonic-gate if (((m->value[0] & 7) == 3) || 26466557Sfr41279 ((m->value[0] & 7) == 5)) 26476557Sfr41279 *jac = -*jac; 26480Sstevel@tonic-gate (void) big_half_pos(n, n); 26490Sstevel@tonic-gate } else { 26500Sstevel@tonic-gate if (((m->value[0] & 3) == 3) && 26510Sstevel@tonic-gate ((n->value[0] & 3) == 3)) { 26520Sstevel@tonic-gate *jac = -*jac; 26530Sstevel@tonic-gate } 26546557Sfr41279 if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK) { 26550Sstevel@tonic-gate goto ret; 26566557Sfr41279 } 26570Sstevel@tonic-gate t = tmp2; 26580Sstevel@tonic-gate tmp2 = m; 26590Sstevel@tonic-gate m = n; 26600Sstevel@tonic-gate n = t; 26610Sstevel@tonic-gate } 26620Sstevel@tonic-gate } 26630Sstevel@tonic-gate err = BIG_OK; 26640Sstevel@tonic-gate 26650Sstevel@tonic-gate ret: 26660Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 26670Sstevel@tonic-gate ret2: 26680Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 26690Sstevel@tonic-gate ret1: 26700Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 26710Sstevel@tonic-gate 26720Sstevel@tonic-gate return (err); 26730Sstevel@tonic-gate } 26740Sstevel@tonic-gate 26750Sstevel@tonic-gate 26760Sstevel@tonic-gate BIG_ERR_CODE 26770Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n) 26780Sstevel@tonic-gate { 26798933Sopensolaris@drydog.com int i; 26808933Sopensolaris@drydog.com uint32_t m, w; 26816557Sfr41279 BIG_CHUNK_TYPE bit; 26826557Sfr41279 BIGNUM ki, tmp, tmp2; 26836557Sfr41279 BIG_CHUNK_TYPE kivalue[BIGTMPSIZE]; 26846557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 26856557Sfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 26866557Sfr41279 BIG_ERR_CODE err; 26876557Sfr41279 26886557Sfr41279 if (big_cmp_abs(k, &big_One) == 0) { 26890Sstevel@tonic-gate (void) big_copy(Lk, p); 26906557Sfr41279 (void) big_copy(Lkminus1, &big_Two); 26910Sstevel@tonic-gate return (BIG_OK); 26920Sstevel@tonic-gate } 26930Sstevel@tonic-gate 26940Sstevel@tonic-gate if ((err = big_init1(&ki, k->len + 1, 26950Sstevel@tonic-gate kivalue, arraysize(kivalue))) != BIG_OK) 26960Sstevel@tonic-gate return (err); 26970Sstevel@tonic-gate 26988933Sopensolaris@drydog.com if ((err = big_init1(&tmp, 2 * n->len + 1, 26990Sstevel@tonic-gate tmpvalue, arraysize(tmpvalue))) != BIG_OK) 27000Sstevel@tonic-gate goto ret1; 27010Sstevel@tonic-gate 27020Sstevel@tonic-gate if ((err = big_init1(&tmp2, n->len, 27030Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 27040Sstevel@tonic-gate goto ret2; 27050Sstevel@tonic-gate 27060Sstevel@tonic-gate m = big_numbits(k); 27076557Sfr41279 ki.len = (m - 1) / BIG_CHUNK_SIZE + 1; 27086557Sfr41279 w = (m - 1) / BIG_CHUNK_SIZE; 27096557Sfr41279 bit = (BIG_CHUNK_TYPE)1 << ((m - 1) % BIG_CHUNK_SIZE); 27106557Sfr41279 for (i = 0; i < ki.len; i++) { 27116557Sfr41279 ki.value[i] = 0; 27126557Sfr41279 } 27130Sstevel@tonic-gate ki.value[ki.len - 1] = bit; 27146557Sfr41279 if (big_cmp_abs(k, &ki) != 0) { 27150Sstevel@tonic-gate (void) big_double(&ki, &ki); 27166557Sfr41279 } 27170Sstevel@tonic-gate (void) big_sub_pos(&ki, &ki, k); 27180Sstevel@tonic-gate 27190Sstevel@tonic-gate (void) big_copy(Lk, p); 27206557Sfr41279 (void) big_copy(Lkminus1, &big_Two); 27210Sstevel@tonic-gate 27220Sstevel@tonic-gate for (i = 0; i < m; i++) { 27236557Sfr41279 if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK) { 27240Sstevel@tonic-gate goto ret; 27256557Sfr41279 } 27260Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 27270Sstevel@tonic-gate (void) big_sub_pos(&tmp, &tmp, p); 27286557Sfr41279 if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK) { 27290Sstevel@tonic-gate goto ret; 27306557Sfr41279 } 27310Sstevel@tonic-gate if ((ki.value[w] & bit) != 0) { 27320Sstevel@tonic-gate if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) != 27336557Sfr41279 BIG_OK) { 27340Sstevel@tonic-gate goto ret; 27356557Sfr41279 } 27360Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 27376557Sfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Two); 27380Sstevel@tonic-gate if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) != 27396557Sfr41279 BIG_OK) { 27400Sstevel@tonic-gate goto ret; 27416557Sfr41279 } 27420Sstevel@tonic-gate (void) big_copy(Lk, &tmp2); 27430Sstevel@tonic-gate } else { 27446557Sfr41279 if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK) { 27450Sstevel@tonic-gate goto ret; 27466557Sfr41279 } 27470Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 27486557Sfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Two); 27496557Sfr41279 if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK) { 27500Sstevel@tonic-gate goto ret; 27516557Sfr41279 } 27520Sstevel@tonic-gate (void) big_copy(Lkminus1, &tmp2); 27530Sstevel@tonic-gate } 27540Sstevel@tonic-gate bit = bit >> 1; 27550Sstevel@tonic-gate if (bit == 0) { 27566557Sfr41279 bit = BIG_CHUNK_HIGHBIT; 27570Sstevel@tonic-gate w--; 27580Sstevel@tonic-gate } 27590Sstevel@tonic-gate } 27600Sstevel@tonic-gate 27610Sstevel@tonic-gate err = BIG_OK; 27620Sstevel@tonic-gate 27630Sstevel@tonic-gate ret: 27640Sstevel@tonic-gate if (tmp2.malloced) big_finish(&tmp2); 27650Sstevel@tonic-gate ret2: 27660Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 27670Sstevel@tonic-gate ret1: 27680Sstevel@tonic-gate if (ki.malloced) big_finish(&ki); 27690Sstevel@tonic-gate 27700Sstevel@tonic-gate return (err); 27710Sstevel@tonic-gate } 27720Sstevel@tonic-gate 27730Sstevel@tonic-gate 27740Sstevel@tonic-gate BIG_ERR_CODE 27756557Sfr41279 big_isprime_pos_ext(BIGNUM *n, big_modexp_ncp_info_t *info) 27760Sstevel@tonic-gate { 27776557Sfr41279 BIGNUM o, nminus1, tmp, Lkminus1, Lk; 27786557Sfr41279 BIG_CHUNK_TYPE ovalue[BIGTMPSIZE]; 27796557Sfr41279 BIG_CHUNK_TYPE nminus1value[BIGTMPSIZE]; 27806557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 27816557Sfr41279 BIG_CHUNK_TYPE Lkminus1value[BIGTMPSIZE]; 27826557Sfr41279 BIG_CHUNK_TYPE Lkvalue[BIGTMPSIZE]; 27836557Sfr41279 BIG_ERR_CODE err; 27846557Sfr41279 int e, i, jac; 27856557Sfr41279 27866557Sfr41279 if (big_cmp_abs(n, &big_One) == 0) { 27870Sstevel@tonic-gate return (BIG_FALSE); 27886557Sfr41279 } 27896557Sfr41279 if (big_cmp_abs(n, &big_Two) == 0) { 27900Sstevel@tonic-gate return (BIG_TRUE); 27916557Sfr41279 } 27926557Sfr41279 if ((n->value[0] & 1) == 0) { 27930Sstevel@tonic-gate return (BIG_FALSE); 27946557Sfr41279 } 27956557Sfr41279 27966557Sfr41279 if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) != 27976557Sfr41279 BIG_OK) { 27980Sstevel@tonic-gate return (err); 27996557Sfr41279 } 28000Sstevel@tonic-gate 28010Sstevel@tonic-gate if ((err = big_init1(&nminus1, n->len, 28026557Sfr41279 nminus1value, arraysize(nminus1value))) != BIG_OK) { 28030Sstevel@tonic-gate goto ret1; 28046557Sfr41279 } 28050Sstevel@tonic-gate 28060Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * n->len, 28076557Sfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 28080Sstevel@tonic-gate goto ret2; 28096557Sfr41279 } 28100Sstevel@tonic-gate 28110Sstevel@tonic-gate if ((err = big_init1(&Lkminus1, n->len, 28126557Sfr41279 Lkminus1value, arraysize(Lkminus1value))) != BIG_OK) { 28130Sstevel@tonic-gate goto ret3; 28146557Sfr41279 } 28150Sstevel@tonic-gate 28160Sstevel@tonic-gate if ((err = big_init1(&Lk, n->len, 28176557Sfr41279 Lkvalue, arraysize(Lkvalue))) != BIG_OK) { 28180Sstevel@tonic-gate goto ret4; 28196557Sfr41279 } 28206557Sfr41279 28218933Sopensolaris@drydog.com (void) big_sub_pos(&o, n, &big_One); /* cannot fail */ 28220Sstevel@tonic-gate (void) big_copy(&nminus1, &o); /* cannot fail */ 28230Sstevel@tonic-gate e = 0; 28240Sstevel@tonic-gate while ((o.value[0] & 1) == 0) { 28250Sstevel@tonic-gate e++; 28260Sstevel@tonic-gate (void) big_half_pos(&o, &o); /* cannot fail */ 28270Sstevel@tonic-gate } 28286557Sfr41279 if ((err = big_modexp_ext(&tmp, &big_Two, &o, n, NULL, info)) != 28296557Sfr41279 BIG_OK) { 28300Sstevel@tonic-gate goto ret; 28316557Sfr41279 } 28326557Sfr41279 28330Sstevel@tonic-gate i = 0; 28340Sstevel@tonic-gate while ((i < e) && 28356557Sfr41279 (big_cmp_abs(&tmp, &big_One) != 0) && 28360Sstevel@tonic-gate (big_cmp_abs(&tmp, &nminus1) != 0)) { 28376557Sfr41279 if ((err = 28386557Sfr41279 big_modexp_ext(&tmp, &tmp, &big_Two, n, NULL, info)) != 28396557Sfr41279 BIG_OK) 28400Sstevel@tonic-gate goto ret; 28410Sstevel@tonic-gate i++; 28420Sstevel@tonic-gate } 28436557Sfr41279 28440Sstevel@tonic-gate if (!((big_cmp_abs(&tmp, &nminus1) == 0) || 28456557Sfr41279 ((i == 0) && (big_cmp_abs(&tmp, &big_One) == 0)))) { 28460Sstevel@tonic-gate err = BIG_FALSE; 28470Sstevel@tonic-gate goto ret; 28480Sstevel@tonic-gate } 28490Sstevel@tonic-gate 28506557Sfr41279 if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK) { 28510Sstevel@tonic-gate goto ret; 28526557Sfr41279 } 28536557Sfr41279 28546557Sfr41279 if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK) { 28550Sstevel@tonic-gate goto ret; 28566557Sfr41279 } 28570Sstevel@tonic-gate if (big_cmp_abs(&tmp, n) == 0) { 28580Sstevel@tonic-gate err = BIG_FALSE; 28590Sstevel@tonic-gate goto ret; 28600Sstevel@tonic-gate } 28610Sstevel@tonic-gate 28626557Sfr41279 (void) big_copy(&o, &big_Two); 28630Sstevel@tonic-gate do { 28646557Sfr41279 (void) big_add_abs(&o, &o, &big_One); 28656557Sfr41279 if ((err = big_mul(&tmp, &o, &o)) != BIG_OK) { 28660Sstevel@tonic-gate goto ret; 28676557Sfr41279 } 28686557Sfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Four); 28696557Sfr41279 if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK) { 28700Sstevel@tonic-gate goto ret; 28716557Sfr41279 } 28720Sstevel@tonic-gate } while (jac != -1); 28730Sstevel@tonic-gate 28746557Sfr41279 (void) big_add_abs(&tmp, n, &big_One); 28756557Sfr41279 if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK) { 28760Sstevel@tonic-gate goto ret; 28776557Sfr41279 } 28786557Sfr41279 28796557Sfr41279 if ((big_cmp_abs(&Lkminus1, &o) == 0) && 28806557Sfr41279 (big_cmp_abs(&Lk, &big_Two) == 0)) { 28810Sstevel@tonic-gate err = BIG_TRUE; 28826557Sfr41279 } else { 28836557Sfr41279 err = BIG_FALSE; 28846557Sfr41279 } 28850Sstevel@tonic-gate 28860Sstevel@tonic-gate ret: 28870Sstevel@tonic-gate if (Lk.malloced) big_finish(&Lk); 28880Sstevel@tonic-gate ret4: 28890Sstevel@tonic-gate if (Lkminus1.malloced) big_finish(&Lkminus1); 28900Sstevel@tonic-gate ret3: 28910Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 28920Sstevel@tonic-gate ret2: 28930Sstevel@tonic-gate if (nminus1.malloced) big_finish(&nminus1); 28940Sstevel@tonic-gate ret1: 28950Sstevel@tonic-gate if (o.malloced) big_finish(&o); 28960Sstevel@tonic-gate 28970Sstevel@tonic-gate return (err); 28980Sstevel@tonic-gate } 28990Sstevel@tonic-gate 29000Sstevel@tonic-gate 29016557Sfr41279 BIG_ERR_CODE 29026557Sfr41279 big_isprime_pos(BIGNUM *n) 29036557Sfr41279 { 29046557Sfr41279 return (big_isprime_pos_ext(n, NULL)); 29056557Sfr41279 } 29066557Sfr41279 29076557Sfr41279 29080Sstevel@tonic-gate #define SIEVESIZE 1000 29090Sstevel@tonic-gate 29100Sstevel@tonic-gate 29110Sstevel@tonic-gate BIG_ERR_CODE 29126557Sfr41279 big_nextprime_pos_ext(BIGNUM *result, BIGNUM *n, big_modexp_ncp_info_t *info) 29130Sstevel@tonic-gate { 29148933Sopensolaris@drydog.com static const uint32_t smallprimes[] = { 29158933Sopensolaris@drydog.com 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 29168933Sopensolaris@drydog.com 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97 }; 29176557Sfr41279 BIG_ERR_CODE err; 29186557Sfr41279 int sieve[SIEVESIZE]; 29196557Sfr41279 int i; 29206557Sfr41279 uint32_t off, p; 29216557Sfr41279 29226557Sfr41279 if ((err = big_copy(result, n)) != BIG_OK) { 29230Sstevel@tonic-gate return (err); 29246557Sfr41279 } 29250Sstevel@tonic-gate result->value[0] |= 1; 29261027Srobinson /* CONSTCOND */ 29270Sstevel@tonic-gate while (1) { 29280Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0; 29290Sstevel@tonic-gate for (i = 0; 29306557Sfr41279 i < sizeof (smallprimes) / sizeof (smallprimes[0]); i++) { 29310Sstevel@tonic-gate p = smallprimes[i]; 29326557Sfr41279 off = big_modhalf_pos(result, p); 29330Sstevel@tonic-gate off = p - off; 29346557Sfr41279 if ((off % 2) == 1) { 29356557Sfr41279 off = off + p; 29366557Sfr41279 } 29376557Sfr41279 off = off / 2; 29380Sstevel@tonic-gate while (off < SIEVESIZE) { 29390Sstevel@tonic-gate sieve[off] = 1; 29400Sstevel@tonic-gate off = off + p; 29410Sstevel@tonic-gate } 29420Sstevel@tonic-gate } 29430Sstevel@tonic-gate 29440Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) { 29450Sstevel@tonic-gate if (sieve[i] == 0) { 29466557Sfr41279 err = big_isprime_pos_ext(result, info); 29470Sstevel@tonic-gate if (err != BIG_FALSE) { 29486557Sfr41279 if (err != BIG_TRUE) { 29490Sstevel@tonic-gate return (err); 29506557Sfr41279 } else { 29516557Sfr41279 goto out; 29526557Sfr41279 } 29530Sstevel@tonic-gate } 29540Sstevel@tonic-gate 29550Sstevel@tonic-gate } 29566557Sfr41279 if ((err = big_add_abs(result, result, &big_Two)) != 29576557Sfr41279 BIG_OK) { 29580Sstevel@tonic-gate return (err); 29596557Sfr41279 } 29600Sstevel@tonic-gate } 29610Sstevel@tonic-gate } 29626557Sfr41279 29636557Sfr41279 out: 29646557Sfr41279 return (BIG_OK); 29656557Sfr41279 } 29666557Sfr41279 29676557Sfr41279 29686557Sfr41279 BIG_ERR_CODE 29696557Sfr41279 big_nextprime_pos(BIGNUM *result, BIGNUM *n) 29706557Sfr41279 { 29716557Sfr41279 return (big_nextprime_pos_ext(result, n, NULL)); 29720Sstevel@tonic-gate } 29730Sstevel@tonic-gate 29740Sstevel@tonic-gate 29750Sstevel@tonic-gate BIG_ERR_CODE 29760Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n) 29770Sstevel@tonic-gate { 29780Sstevel@tonic-gate BIG_ERR_CODE err; 29790Sstevel@tonic-gate 29800Sstevel@tonic-gate 29810Sstevel@tonic-gate if ((err = big_copy(result, n)) != BIG_OK) 29820Sstevel@tonic-gate return (err); 29830Sstevel@tonic-gate result->value[0] |= 1; 29846557Sfr41279 while ((err = big_isprime_pos_ext(result, NULL)) != BIG_TRUE) { 29850Sstevel@tonic-gate if (err != BIG_FALSE) 29860Sstevel@tonic-gate return (err); 29876557Sfr41279 if ((err = big_add_abs(result, result, &big_Two)) != BIG_OK) 29880Sstevel@tonic-gate return (err); 29890Sstevel@tonic-gate } 29900Sstevel@tonic-gate return (BIG_OK); 29910Sstevel@tonic-gate } 29920Sstevel@tonic-gate 29930Sstevel@tonic-gate 29940Sstevel@tonic-gate /* 29950Sstevel@tonic-gate * given m and e, computes the rest in the equation 29960Sstevel@tonic-gate * gcd(m, e) = cm * m + ce * e 29970Sstevel@tonic-gate */ 29980Sstevel@tonic-gate BIG_ERR_CODE 29990Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e) 30000Sstevel@tonic-gate { 30016557Sfr41279 BIGNUM *xi, *ri, *riminus1, *riminus2, *t; 30026557Sfr41279 BIGNUM *vmi, *vei, *vmiminus1, *veiminus1; 30036557Sfr41279 BIGNUM t1, t2, t3, t4, t5, t6, t7, t8, tmp; 30046557Sfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 30056557Sfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 30066557Sfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 30076557Sfr41279 BIG_CHUNK_TYPE t4value[BIGTMPSIZE]; 30086557Sfr41279 BIG_CHUNK_TYPE t5value[BIGTMPSIZE]; 30096557Sfr41279 BIG_CHUNK_TYPE t6value[BIGTMPSIZE]; 30106557Sfr41279 BIG_CHUNK_TYPE t7value[BIGTMPSIZE]; 30116557Sfr41279 BIG_CHUNK_TYPE t8value[BIGTMPSIZE]; 30126557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 30136557Sfr41279 BIG_ERR_CODE err; 30146557Sfr41279 int len; 30156557Sfr41279 30166557Sfr41279 if (big_cmp_abs(m, e) >= 0) { 30176557Sfr41279 len = m->len; 30186557Sfr41279 } else { 30196557Sfr41279 len = e->len; 30206557Sfr41279 } 30210Sstevel@tonic-gate 30220Sstevel@tonic-gate if ((err = big_init1(&t1, len, 30236557Sfr41279 t1value, arraysize(t1value))) != BIG_OK) { 30240Sstevel@tonic-gate return (err); 30256557Sfr41279 } 30260Sstevel@tonic-gate if ((err = big_init1(&t2, len, 30276557Sfr41279 t2value, arraysize(t2value))) != BIG_OK) { 30286557Sfr41279 goto ret1; 30296557Sfr41279 } 30300Sstevel@tonic-gate if ((err = big_init1(&t3, len, 30316557Sfr41279 t3value, arraysize(t3value))) != BIG_OK) { 30326557Sfr41279 goto ret2; 30336557Sfr41279 } 30340Sstevel@tonic-gate if ((err = big_init1(&t4, len, 30356557Sfr41279 t4value, arraysize(t3value))) != BIG_OK) { 30366557Sfr41279 goto ret3; 30376557Sfr41279 } 30380Sstevel@tonic-gate if ((err = big_init1(&t5, len, 30396557Sfr41279 t5value, arraysize(t5value))) != BIG_OK) { 30406557Sfr41279 goto ret4; 30416557Sfr41279 } 30420Sstevel@tonic-gate if ((err = big_init1(&t6, len, 30436557Sfr41279 t6value, arraysize(t6value))) != BIG_OK) { 30446557Sfr41279 goto ret5; 30456557Sfr41279 } 30460Sstevel@tonic-gate if ((err = big_init1(&t7, len, 30476557Sfr41279 t7value, arraysize(t7value))) != BIG_OK) { 30486557Sfr41279 goto ret6; 30496557Sfr41279 } 30500Sstevel@tonic-gate if ((err = big_init1(&t8, len, 30516557Sfr41279 t8value, arraysize(t8value))) != BIG_OK) { 30526557Sfr41279 goto ret7; 30536557Sfr41279 } 30540Sstevel@tonic-gate 30550Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * len, 30566557Sfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 30570Sstevel@tonic-gate goto ret8; 30586557Sfr41279 } 30590Sstevel@tonic-gate 30600Sstevel@tonic-gate ri = &t1; 30610Sstevel@tonic-gate ri->value[0] = 1; 30620Sstevel@tonic-gate ri->len = 1; 30630Sstevel@tonic-gate xi = &t2; 30640Sstevel@tonic-gate riminus1 = &t3; 30650Sstevel@tonic-gate riminus2 = &t4; 30660Sstevel@tonic-gate vmi = &t5; 30670Sstevel@tonic-gate vei = &t6; 30680Sstevel@tonic-gate vmiminus1 = &t7; 30690Sstevel@tonic-gate veiminus1 = &t8; 30700Sstevel@tonic-gate 30716557Sfr41279 (void) big_copy(vmiminus1, &big_One); 30726557Sfr41279 (void) big_copy(vmi, &big_One); 30736557Sfr41279 (void) big_copy(veiminus1, &big_One); 30746557Sfr41279 (void) big_copy(xi, &big_One); 30750Sstevel@tonic-gate vei->len = 1; 30760Sstevel@tonic-gate vei->value[0] = 0; 30770Sstevel@tonic-gate 30780Sstevel@tonic-gate (void) big_copy(riminus1, m); 30790Sstevel@tonic-gate (void) big_copy(ri, e); 30800Sstevel@tonic-gate 30810Sstevel@tonic-gate while (!big_is_zero(ri)) { 30820Sstevel@tonic-gate t = riminus2; 30830Sstevel@tonic-gate riminus2 = riminus1; 30840Sstevel@tonic-gate riminus1 = ri; 30850Sstevel@tonic-gate ri = t; 30866557Sfr41279 if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK) { 30870Sstevel@tonic-gate goto ret; 30886557Sfr41279 } 30896557Sfr41279 if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK) { 30900Sstevel@tonic-gate goto ret; 30916557Sfr41279 } 30920Sstevel@tonic-gate t = vmiminus1; 30930Sstevel@tonic-gate vmiminus1 = vmi; 30940Sstevel@tonic-gate vmi = t; 30956557Sfr41279 if ((err = big_mul(&tmp, vei, xi)) != BIG_OK) { 30960Sstevel@tonic-gate goto ret; 30976557Sfr41279 } 30986557Sfr41279 if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK) { 30990Sstevel@tonic-gate goto ret; 31006557Sfr41279 } 31010Sstevel@tonic-gate t = veiminus1; 31020Sstevel@tonic-gate veiminus1 = vei; 31030Sstevel@tonic-gate vei = t; 31046557Sfr41279 if ((err = big_div_pos(xi, ri, riminus2, riminus1)) != 31056557Sfr41279 BIG_OK) { 31060Sstevel@tonic-gate goto ret; 31076557Sfr41279 } 31080Sstevel@tonic-gate } 31096557Sfr41279 if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK)) { 31100Sstevel@tonic-gate goto ret; 31116557Sfr41279 } 31126557Sfr41279 if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK)) { 31130Sstevel@tonic-gate goto ret; 31146557Sfr41279 } 31156557Sfr41279 if (ce != NULL) { 31160Sstevel@tonic-gate err = big_copy(ce, vei); 31176557Sfr41279 } 31180Sstevel@tonic-gate ret: 31190Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 31200Sstevel@tonic-gate ret8: 31210Sstevel@tonic-gate if (t8.malloced) big_finish(&t8); 31220Sstevel@tonic-gate ret7: 31230Sstevel@tonic-gate if (t7.malloced) big_finish(&t7); 31240Sstevel@tonic-gate ret6: 31250Sstevel@tonic-gate if (t6.malloced) big_finish(&t6); 31260Sstevel@tonic-gate ret5: 31270Sstevel@tonic-gate if (t5.malloced) big_finish(&t5); 31280Sstevel@tonic-gate ret4: 31290Sstevel@tonic-gate if (t4.malloced) big_finish(&t4); 31300Sstevel@tonic-gate ret3: 31310Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 31320Sstevel@tonic-gate ret2: 31330Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 31340Sstevel@tonic-gate ret1: 31350Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 31360Sstevel@tonic-gate 31370Sstevel@tonic-gate return (err); 31380Sstevel@tonic-gate } 3139