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 849302Sopensolaris@drydog.com #ifdef __amd64 859302Sopensolaris@drydog.com #ifdef _KERNEL 869302Sopensolaris@drydog.com #include <sys/x86_archext.h> /* cpuid_getvendor() */ 879302Sopensolaris@drydog.com #include <sys/cpuvar.h> 889302Sopensolaris@drydog.com #else 899302Sopensolaris@drydog.com #include <sys/auxv.h> /* getisax() */ 909302Sopensolaris@drydog.com #endif /* _KERNEL */ 919302Sopensolaris@drydog.com #endif /* __amd64 */ 929302Sopensolaris@drydog.com 939302Sopensolaris@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 1059302Sopensolaris@drydog.com /* 1069302Sopensolaris@drydog.com * big_realloc() 1079302Sopensolaris@drydog.com * Allocate memory of newsize bytes and copy oldsize bytes 1089302Sopensolaris@drydog.com * to the newly-allocated memory, then free the 1099302Sopensolaris@drydog.com * previously-allocated memory. 1109302Sopensolaris@drydog.com * Note: newsize must be > oldsize 1119302Sopensolaris@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 1839302Sopensolaris@drydog.com #ifdef __amd64 1849302Sopensolaris@drydog.com /* 1859302Sopensolaris@drydog.com * Return 1 if executing on Intel, otherwise 0 (e.g., AMD64). 186*11141Sopensolaris@drydog.com * Cache the result, as the CPU can't change. 187*11141Sopensolaris@drydog.com * 188*11141Sopensolaris@drydog.com * Note: the userland version uses getisax() and checks for an AMD-64-only 189*11141Sopensolaris@drydog.com * feature. The kernel version uses cpuid_getvendor(). 1909302Sopensolaris@drydog.com */ 1919302Sopensolaris@drydog.com static int 1929302Sopensolaris@drydog.com bignum_on_intel(void) 1939302Sopensolaris@drydog.com { 194*11141Sopensolaris@drydog.com static int cached_result = -1; 195*11141Sopensolaris@drydog.com 196*11141Sopensolaris@drydog.com if (cached_result == -1) { /* first time */ 1979302Sopensolaris@drydog.com #ifdef _KERNEL 198*11141Sopensolaris@drydog.com cached_result = (cpuid_getvendor(CPU) == X86_VENDOR_Intel); 1999302Sopensolaris@drydog.com #else 200*11141Sopensolaris@drydog.com uint_t ui; 201*11141Sopensolaris@drydog.com 202*11141Sopensolaris@drydog.com (void) getisax(&ui, 1); 203*11141Sopensolaris@drydog.com cached_result = ((ui & AV_386_AMD_MMX) == 0); 2049302Sopensolaris@drydog.com #endif /* _KERNEL */ 205*11141Sopensolaris@drydog.com } 206*11141Sopensolaris@drydog.com 207*11141Sopensolaris@drydog.com return (cached_result); 2089302Sopensolaris@drydog.com } 2099302Sopensolaris@drydog.com #endif /* __amd64 */ 2109302Sopensolaris@drydog.com 2119302Sopensolaris@drydog.com 2128933Sopensolaris@drydog.com /* 2138933Sopensolaris@drydog.com * big_init() 2148933Sopensolaris@drydog.com * Initialize and allocate memory for a BIGNUM type. 2158933Sopensolaris@drydog.com * 2168933Sopensolaris@drydog.com * big_init(number, size) is equivalent to big_init1(number, size, NULL, 0) 2178933Sopensolaris@drydog.com * 2188933Sopensolaris@drydog.com * Note: call big_finish() to free memory allocated by big_init(). 2198933Sopensolaris@drydog.com * 2208933Sopensolaris@drydog.com * Input: 2218933Sopensolaris@drydog.com * number Uninitialized memory for BIGNUM 2228933Sopensolaris@drydog.com * size Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM 2238933Sopensolaris@drydog.com * 2248933Sopensolaris@drydog.com * Output: 2258933Sopensolaris@drydog.com * number Initialized BIGNUM 2268933Sopensolaris@drydog.com * 2278933Sopensolaris@drydog.com * Return BIG_OK on success or BIG_NO_MEM for an allocation error. 2288933Sopensolaris@drydog.com */ 2290Sstevel@tonic-gate BIG_ERR_CODE 2300Sstevel@tonic-gate big_init(BIGNUM *number, int size) 2310Sstevel@tonic-gate { 2328933Sopensolaris@drydog.com number->value = big_malloc(BIGNUM_WORDSIZE * size); 2330Sstevel@tonic-gate if (number->value == NULL) { 2340Sstevel@tonic-gate return (BIG_NO_MEM); 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate number->size = size; 2370Sstevel@tonic-gate number->len = 0; 2380Sstevel@tonic-gate number->sign = 1; 2390Sstevel@tonic-gate number->malloced = 1; 2400Sstevel@tonic-gate return (BIG_OK); 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate 2438933Sopensolaris@drydog.com 2448933Sopensolaris@drydog.com /* 2458933Sopensolaris@drydog.com * big_init1() 2468933Sopensolaris@drydog.com * Initialize and, if needed, allocate memory for a BIGNUM type. 2478933Sopensolaris@drydog.com * Use the buffer passed, buf, if any, instad of allocating memory 2488933Sopensolaris@drydog.com * if it's at least "size" bytes. 2498933Sopensolaris@drydog.com * 2508933Sopensolaris@drydog.com * Note: call big_finish() to free memory allocated by big_init(). 2518933Sopensolaris@drydog.com * 2528933Sopensolaris@drydog.com * Input: 2538933Sopensolaris@drydog.com * number Uninitialized memory for BIGNUM 2548933Sopensolaris@drydog.com * size Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM 2558933Sopensolaris@drydog.com * buf Buffer for storing a BIGNUM. 2568933Sopensolaris@drydog.com * If NULL, big_init1() will allocate a buffer 2578933Sopensolaris@drydog.com * bufsize Size, in BIG_CHUNK_SIZE_bit words, of buf 2588933Sopensolaris@drydog.com * 2598933Sopensolaris@drydog.com * Output: 2608933Sopensolaris@drydog.com * number Initialized BIGNUM 2618933Sopensolaris@drydog.com * 2628933Sopensolaris@drydog.com * Return BIG_OK on success or BIG_NO_MEM for an allocation error. 2638933Sopensolaris@drydog.com */ 2640Sstevel@tonic-gate BIG_ERR_CODE 2656557Sfr41279 big_init1(BIGNUM *number, int size, BIG_CHUNK_TYPE *buf, int bufsize) 2660Sstevel@tonic-gate { 2670Sstevel@tonic-gate if ((buf == NULL) || (size > bufsize)) { 2688933Sopensolaris@drydog.com number->value = big_malloc(BIGNUM_WORDSIZE * size); 2690Sstevel@tonic-gate if (number->value == NULL) { 2700Sstevel@tonic-gate return (BIG_NO_MEM); 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate number->size = size; 2730Sstevel@tonic-gate number->malloced = 1; 2740Sstevel@tonic-gate } else { 2750Sstevel@tonic-gate number->value = buf; 2760Sstevel@tonic-gate number->size = bufsize; 2770Sstevel@tonic-gate number->malloced = 0; 2780Sstevel@tonic-gate } 2798933Sopensolaris@drydog.com number->len = 0; 2808933Sopensolaris@drydog.com number->sign = 1; 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate return (BIG_OK); 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate 2858933Sopensolaris@drydog.com 2868933Sopensolaris@drydog.com /* 2878933Sopensolaris@drydog.com * big_finish() 2888933Sopensolaris@drydog.com * Free memory, if any, allocated by big_init() or big_init1(). 2898933Sopensolaris@drydog.com */ 2900Sstevel@tonic-gate void 2910Sstevel@tonic-gate big_finish(BIGNUM *number) 2920Sstevel@tonic-gate { 2930Sstevel@tonic-gate if (number->malloced == 1) { 2948933Sopensolaris@drydog.com big_free(number->value, BIGNUM_WORDSIZE * number->size); 2950Sstevel@tonic-gate number->malloced = 0; 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate 2996557Sfr41279 3000Sstevel@tonic-gate /* 3018933Sopensolaris@drydog.com * bn->size should be at least 3028933Sopensolaris@drydog.com * (len + BIGNUM_WORDSIZE - 1) / BIGNUM_WORDSIZE bytes 3030Sstevel@tonic-gate * converts from byte-big-endian format to bignum format (words in 3040Sstevel@tonic-gate * little endian order, but bytes within the words big endian) 3050Sstevel@tonic-gate */ 3060Sstevel@tonic-gate void 3070Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len) 3080Sstevel@tonic-gate { 3098933Sopensolaris@drydog.com int i, j; 3108933Sopensolaris@drydog.com uint32_t offs; 3118933Sopensolaris@drydog.com const uint32_t slen = UI32(len); 3126557Sfr41279 BIG_CHUNK_TYPE word; 3130Sstevel@tonic-gate uchar_t *knwordp; 3140Sstevel@tonic-gate 3158933Sopensolaris@drydog.com if (slen == 0) { 3168933Sopensolaris@drydog.com bn->len = 1; 3178933Sopensolaris@drydog.com bn->value[0] = 0; 3188933Sopensolaris@drydog.com return; 3198933Sopensolaris@drydog.com } 3208933Sopensolaris@drydog.com 3218933Sopensolaris@drydog.com offs = slen % BIGNUM_WORDSIZE; 3228933Sopensolaris@drydog.com bn->len = slen / BIGNUM_WORDSIZE; 3238933Sopensolaris@drydog.com 3248933Sopensolaris@drydog.com for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) { 3258933Sopensolaris@drydog.com knwordp = &(kn[slen - BIGNUM_WORDSIZE * (i + 1)]); 3260Sstevel@tonic-gate word = knwordp[0]; 3278933Sopensolaris@drydog.com for (j = 1; j < BIGNUM_WORDSIZE; j++) { 3288933Sopensolaris@drydog.com word = (word << BITSINBYTE) + knwordp[j]; 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate bn->value[i] = word; 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate if (offs > 0) { 3330Sstevel@tonic-gate word = kn[0]; 3348933Sopensolaris@drydog.com for (i = 1; i < offs; i++) word = (word << BITSINBYTE) + kn[i]; 3350Sstevel@tonic-gate bn->value[bn->len++] = word; 3360Sstevel@tonic-gate } 3378933Sopensolaris@drydog.com while ((bn->len > 1) && (bn->value[bn->len - 1] == 0)) { 3380Sstevel@tonic-gate bn->len --; 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate 3428933Sopensolaris@drydog.com 3430Sstevel@tonic-gate /* 3440Sstevel@tonic-gate * copies the least significant len bytes if 3458933Sopensolaris@drydog.com * len < bn->len * BIGNUM_WORDSIZE 3460Sstevel@tonic-gate * converts from bignum format to byte-big-endian format. 3476557Sfr41279 * bignum format is words of type BIG_CHUNK_TYPE in little endian order. 3480Sstevel@tonic-gate */ 3490Sstevel@tonic-gate void 3500Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len) 3510Sstevel@tonic-gate { 3528933Sopensolaris@drydog.com int i, j; 3538933Sopensolaris@drydog.com uint32_t offs; 3548933Sopensolaris@drydog.com const uint32_t slen = UI32(len); 3556557Sfr41279 BIG_CHUNK_TYPE word; 3566557Sfr41279 3578933Sopensolaris@drydog.com if (len < BIGNUM_WORDSIZE * bn->len) { 3588933Sopensolaris@drydog.com for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) { 3590Sstevel@tonic-gate word = bn->value[i]; 3608933Sopensolaris@drydog.com for (j = 0; j < BIGNUM_WORDSIZE; j++) { 3618933Sopensolaris@drydog.com kn[slen - BIGNUM_WORDSIZE * i - j - 1] = 3620Sstevel@tonic-gate word & 0xff; 3638933Sopensolaris@drydog.com word = word >> BITSINBYTE; 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate } 3668933Sopensolaris@drydog.com offs = slen % BIGNUM_WORDSIZE; 3670Sstevel@tonic-gate if (offs > 0) { 3688933Sopensolaris@drydog.com word = bn->value[slen / BIGNUM_WORDSIZE]; 3698933Sopensolaris@drydog.com for (i = slen % BIGNUM_WORDSIZE; i > 0; i --) { 3706557Sfr41279 kn[i - 1] = word & 0xff; 3718933Sopensolaris@drydog.com word = word >> BITSINBYTE; 3726557Sfr41279 } 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate } else { 3750Sstevel@tonic-gate for (i = 0; i < bn->len; i++) { 3760Sstevel@tonic-gate word = bn->value[i]; 3778933Sopensolaris@drydog.com for (j = 0; j < BIGNUM_WORDSIZE; j++) { 3788933Sopensolaris@drydog.com kn[slen - BIGNUM_WORDSIZE * i - j - 1] = 3790Sstevel@tonic-gate word & 0xff; 3808933Sopensolaris@drydog.com word = word >> BITSINBYTE; 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate } 3838933Sopensolaris@drydog.com for (i = 0; i < slen - BIGNUM_WORDSIZE * bn->len; i++) { 3840Sstevel@tonic-gate kn[i] = 0; 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate } 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate int 3910Sstevel@tonic-gate big_bitlength(BIGNUM *a) 3920Sstevel@tonic-gate { 3936557Sfr41279 int l = 0, b = 0; 3946557Sfr41279 BIG_CHUNK_TYPE c; 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate l = a->len - 1; 3970Sstevel@tonic-gate while ((l > 0) && (a->value[l] == 0)) { 3980Sstevel@tonic-gate l--; 3990Sstevel@tonic-gate } 4008933Sopensolaris@drydog.com b = BIG_CHUNK_SIZE; 4010Sstevel@tonic-gate c = a->value[l]; 4026557Sfr41279 while ((b > 1) && ((c & BIG_CHUNK_HIGHBIT) == 0)) { 4030Sstevel@tonic-gate c = c << 1; 4040Sstevel@tonic-gate b--; 4050Sstevel@tonic-gate } 4066557Sfr41279 4078933Sopensolaris@drydog.com return (l * BIG_CHUNK_SIZE + b); 4080Sstevel@tonic-gate } 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate 4119302Sopensolaris@drydog.com /* 4129302Sopensolaris@drydog.com * big_copy() 4139302Sopensolaris@drydog.com * Copy BIGNUM src to dest, allocating memory if needed. 4149302Sopensolaris@drydog.com */ 4150Sstevel@tonic-gate BIG_ERR_CODE 4160Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src) 4170Sstevel@tonic-gate { 4186557Sfr41279 BIG_CHUNK_TYPE *newptr; 4196557Sfr41279 int i, len; 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate len = src->len; 4226557Sfr41279 while ((len > 1) && (src->value[len - 1] == 0)) { 4230Sstevel@tonic-gate len--; 4246557Sfr41279 } 4250Sstevel@tonic-gate src->len = len; 4260Sstevel@tonic-gate if (dest->size < len) { 4270Sstevel@tonic-gate if (dest->malloced == 1) { 4286557Sfr41279 newptr = (BIG_CHUNK_TYPE *)big_realloc(dest->value, 4298933Sopensolaris@drydog.com BIGNUM_WORDSIZE * dest->size, 4308933Sopensolaris@drydog.com BIGNUM_WORDSIZE * len); 4310Sstevel@tonic-gate } else { 4326557Sfr41279 newptr = (BIG_CHUNK_TYPE *) 4338933Sopensolaris@drydog.com big_malloc(BIGNUM_WORDSIZE * len); 4346557Sfr41279 if (newptr != NULL) { 4356557Sfr41279 dest->malloced = 1; 4366557Sfr41279 } 4370Sstevel@tonic-gate } 4386557Sfr41279 if (newptr == NULL) { 4390Sstevel@tonic-gate return (BIG_NO_MEM); 4406557Sfr41279 } 4410Sstevel@tonic-gate dest->value = newptr; 4420Sstevel@tonic-gate dest->size = len; 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate dest->len = len; 4450Sstevel@tonic-gate dest->sign = src->sign; 4466557Sfr41279 for (i = 0; i < len; i++) { 4476557Sfr41279 dest->value[i] = src->value[i]; 4486557Sfr41279 } 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate return (BIG_OK); 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate 4549302Sopensolaris@drydog.com /* 4559302Sopensolaris@drydog.com * big_extend() 4569302Sopensolaris@drydog.com * Allocate memory to extend BIGNUM number to size bignum chunks, 4579302Sopensolaris@drydog.com * if not at least that size already. 4589302Sopensolaris@drydog.com */ 4590Sstevel@tonic-gate BIG_ERR_CODE 4600Sstevel@tonic-gate big_extend(BIGNUM *number, int size) 4610Sstevel@tonic-gate { 4626557Sfr41279 BIG_CHUNK_TYPE *newptr; 4630Sstevel@tonic-gate int i; 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate if (number->size >= size) 4660Sstevel@tonic-gate return (BIG_OK); 4670Sstevel@tonic-gate if (number->malloced) { 4686557Sfr41279 number->value = big_realloc(number->value, 4698933Sopensolaris@drydog.com BIGNUM_WORDSIZE * number->size, 4708933Sopensolaris@drydog.com BIGNUM_WORDSIZE * size); 4710Sstevel@tonic-gate } else { 4728933Sopensolaris@drydog.com newptr = big_malloc(BIGNUM_WORDSIZE * size); 4730Sstevel@tonic-gate if (newptr != NULL) { 4740Sstevel@tonic-gate for (i = 0; i < number->size; i++) { 4750Sstevel@tonic-gate newptr[i] = number->value[i]; 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate number->value = newptr; 4790Sstevel@tonic-gate } 4800Sstevel@tonic-gate 4816557Sfr41279 if (number->value == NULL) { 4820Sstevel@tonic-gate return (BIG_NO_MEM); 4836557Sfr41279 } 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate number->size = size; 4860Sstevel@tonic-gate number->malloced = 1; 4870Sstevel@tonic-gate return (BIG_OK); 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate 4916557Sfr41279 /* returns 1 if n == 0 */ 4920Sstevel@tonic-gate int 4930Sstevel@tonic-gate big_is_zero(BIGNUM *n) 4940Sstevel@tonic-gate { 4956557Sfr41279 int i, result; 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate result = 1; 4986557Sfr41279 for (i = 0; i < n->len; i++) { 4996557Sfr41279 if (n->value[i] != 0) { 5006557Sfr41279 result = 0; 5016557Sfr41279 } 5026557Sfr41279 } 5030Sstevel@tonic-gate return (result); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate BIG_ERR_CODE 5080Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 5090Sstevel@tonic-gate { 5106557Sfr41279 int i, shorter, longer; 5116557Sfr41279 BIG_CHUNK_TYPE cy, ai; 5126557Sfr41279 BIG_CHUNK_TYPE *r, *a, *b, *c; 5136557Sfr41279 BIG_ERR_CODE err; 5146557Sfr41279 BIGNUM *longerarg; 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate if (aa->len > bb->len) { 5170Sstevel@tonic-gate shorter = bb->len; 5180Sstevel@tonic-gate longer = aa->len; 5196557Sfr41279 longerarg = aa; 5200Sstevel@tonic-gate } else { 5210Sstevel@tonic-gate shorter = aa->len; 5220Sstevel@tonic-gate longer = bb->len; 5236557Sfr41279 longerarg = bb; 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate if (result->size < longer + 1) { 5260Sstevel@tonic-gate err = big_extend(result, longer + 1); 5276557Sfr41279 if (err != BIG_OK) { 5280Sstevel@tonic-gate return (err); 5296557Sfr41279 } 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate r = result->value; 5330Sstevel@tonic-gate a = aa->value; 5340Sstevel@tonic-gate b = bb->value; 5356557Sfr41279 c = longerarg->value; 5360Sstevel@tonic-gate cy = 0; 5370Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 5380Sstevel@tonic-gate ai = a[i]; 5390Sstevel@tonic-gate r[i] = ai + b[i] + cy; 5406557Sfr41279 if (r[i] > ai) { 5416557Sfr41279 cy = 0; 5426557Sfr41279 } else if (r[i] < ai) { 5436557Sfr41279 cy = 1; 5446557Sfr41279 } 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate for (; i < longer; i++) { 5470Sstevel@tonic-gate ai = c[i]; 5480Sstevel@tonic-gate r[i] = ai + cy; 5496557Sfr41279 if (r[i] >= ai) { 5506557Sfr41279 cy = 0; 5516557Sfr41279 } 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate if (cy == 1) { 5540Sstevel@tonic-gate r[i] = cy; 5550Sstevel@tonic-gate result->len = longer + 1; 5560Sstevel@tonic-gate } else { 5570Sstevel@tonic-gate result->len = longer; 5580Sstevel@tonic-gate } 5590Sstevel@tonic-gate result->sign = 1; 5600Sstevel@tonic-gate return (BIG_OK); 5610Sstevel@tonic-gate } 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */ 5650Sstevel@tonic-gate void 5666557Sfr41279 big_sub_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, BIG_CHUNK_TYPE *b, int len) 5670Sstevel@tonic-gate { 5686557Sfr41279 int i; 5696557Sfr41279 BIG_CHUNK_TYPE cy, ai; 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate cy = 1; 5720Sstevel@tonic-gate for (i = 0; i < len; i++) { 5730Sstevel@tonic-gate ai = a[i]; 5740Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 5756557Sfr41279 if (r[i] > ai) { 5766557Sfr41279 cy = 0; 5776557Sfr41279 } else if (r[i] < ai) { 5786557Sfr41279 cy = 1; 5796557Sfr41279 } 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate /* result=aa-bb it is assumed that aa>=bb */ 5850Sstevel@tonic-gate BIG_ERR_CODE 5860Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 5870Sstevel@tonic-gate { 5886557Sfr41279 int i, shorter; 5896557Sfr41279 BIG_CHUNK_TYPE cy = 1, ai; 5906557Sfr41279 BIG_CHUNK_TYPE *r, *a, *b; 5916557Sfr41279 BIG_ERR_CODE err = BIG_OK; 5926557Sfr41279 5936557Sfr41279 if (aa->len > bb->len) { 5946557Sfr41279 shorter = bb->len; 5956557Sfr41279 } else { 5966557Sfr41279 shorter = aa->len; 5976557Sfr41279 } 5980Sstevel@tonic-gate if (result->size < aa->len) { 5990Sstevel@tonic-gate err = big_extend(result, aa->len); 6006557Sfr41279 if (err != BIG_OK) { 6010Sstevel@tonic-gate return (err); 6026557Sfr41279 } 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate r = result->value; 6060Sstevel@tonic-gate a = aa->value; 6070Sstevel@tonic-gate b = bb->value; 6080Sstevel@tonic-gate result->len = aa->len; 6090Sstevel@tonic-gate cy = 1; 6100Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 6110Sstevel@tonic-gate ai = a[i]; 6120Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 6136557Sfr41279 if (r[i] > ai) { 6146557Sfr41279 cy = 0; 6156557Sfr41279 } else if (r[i] < ai) { 6166557Sfr41279 cy = 1; 6176557Sfr41279 } 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate for (; i < aa->len; i++) { 6200Sstevel@tonic-gate ai = a[i]; 6210Sstevel@tonic-gate r[i] = ai + (~0) + cy; 6226557Sfr41279 if (r[i] < ai) { 6236557Sfr41279 cy = 1; 6246557Sfr41279 } 6250Sstevel@tonic-gate } 6260Sstevel@tonic-gate result->sign = 1; 6276557Sfr41279 6286557Sfr41279 if (cy == 0) { 6290Sstevel@tonic-gate return (BIG_INVALID_ARGS); 6306557Sfr41279 } else { 6310Sstevel@tonic-gate return (BIG_OK); 6326557Sfr41279 } 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */ 6370Sstevel@tonic-gate int 6380Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb) 6390Sstevel@tonic-gate { 6406557Sfr41279 int i; 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate if (aa->len > bb->len) { 6430Sstevel@tonic-gate for (i = aa->len - 1; i > bb->len - 1; i--) { 6446557Sfr41279 if (aa->value[i] > 0) { 6450Sstevel@tonic-gate return (1); 6466557Sfr41279 } 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate } else if (aa->len < bb->len) { 6490Sstevel@tonic-gate for (i = bb->len - 1; i > aa->len - 1; i--) { 6506557Sfr41279 if (bb->value[i] > 0) { 6510Sstevel@tonic-gate return (-1); 6526557Sfr41279 } 6530Sstevel@tonic-gate } 6546557Sfr41279 } else { 6558933Sopensolaris@drydog.com i = aa->len - 1; 6566557Sfr41279 } 6570Sstevel@tonic-gate for (; i >= 0; i--) { 6586557Sfr41279 if (aa->value[i] > bb->value[i]) { 6590Sstevel@tonic-gate return (1); 6606557Sfr41279 } else if (aa->value[i] < bb->value[i]) { 6610Sstevel@tonic-gate return (-1); 6626557Sfr41279 } 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate return (0); 6660Sstevel@tonic-gate } 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate BIG_ERR_CODE 6700Sstevel@tonic-gate big_sub(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 6710Sstevel@tonic-gate { 6726557Sfr41279 BIG_ERR_CODE err; 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate if ((bb->sign == -1) && (aa->sign == 1)) { 6756557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6760Sstevel@tonic-gate return (err); 6776557Sfr41279 } 6780Sstevel@tonic-gate result->sign = 1; 6790Sstevel@tonic-gate } else if ((aa->sign == -1) && (bb->sign == 1)) { 6806557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6810Sstevel@tonic-gate return (err); 6826557Sfr41279 } 6830Sstevel@tonic-gate result->sign = -1; 6840Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == 1)) { 6850Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 6866557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6870Sstevel@tonic-gate return (err); 6886557Sfr41279 } 6890Sstevel@tonic-gate result->sign = 1; 6900Sstevel@tonic-gate } else { 6916557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6920Sstevel@tonic-gate return (err); 6936557Sfr41279 } 6940Sstevel@tonic-gate result->sign = -1; 6950Sstevel@tonic-gate } 6960Sstevel@tonic-gate } else { 6970Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 6986557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6990Sstevel@tonic-gate return (err); 7006557Sfr41279 } 7010Sstevel@tonic-gate result->sign = -1; 7020Sstevel@tonic-gate } else { 7036557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 7040Sstevel@tonic-gate return (err); 7056557Sfr41279 } 7060Sstevel@tonic-gate result->sign = 1; 7070Sstevel@tonic-gate } 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate return (BIG_OK); 7100Sstevel@tonic-gate } 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate BIG_ERR_CODE 7140Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 7150Sstevel@tonic-gate { 7166557Sfr41279 BIG_ERR_CODE err; 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate if ((bb->sign == -1) && (aa->sign == -1)) { 7196557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 7200Sstevel@tonic-gate return (err); 7216557Sfr41279 } 7220Sstevel@tonic-gate result->sign = -1; 7230Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == 1)) { 7246557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 7250Sstevel@tonic-gate return (err); 7266557Sfr41279 } 7270Sstevel@tonic-gate result->sign = 1; 7280Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == -1)) { 7290Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 7306557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 7310Sstevel@tonic-gate return (err); 7326557Sfr41279 } 7330Sstevel@tonic-gate result->sign = 1; 7340Sstevel@tonic-gate } else { 7356557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 7360Sstevel@tonic-gate return (err); 7376557Sfr41279 } 7380Sstevel@tonic-gate result->sign = -1; 7390Sstevel@tonic-gate } 7400Sstevel@tonic-gate } else { 7410Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 7426557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 7430Sstevel@tonic-gate return (err); 7446557Sfr41279 } 7450Sstevel@tonic-gate result->sign = -1; 7460Sstevel@tonic-gate } else { 7476557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 7480Sstevel@tonic-gate return (err); 7496557Sfr41279 } 7500Sstevel@tonic-gate result->sign = 1; 7510Sstevel@tonic-gate } 7520Sstevel@tonic-gate } 7530Sstevel@tonic-gate return (BIG_OK); 7540Sstevel@tonic-gate } 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate 7576557Sfr41279 /* result = aa/2 */ 7580Sstevel@tonic-gate BIG_ERR_CODE 7590Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa) 7600Sstevel@tonic-gate { 7616557Sfr41279 BIG_ERR_CODE err; 7626557Sfr41279 int i; 7636557Sfr41279 BIG_CHUNK_TYPE cy, cy1; 7646557Sfr41279 BIG_CHUNK_TYPE *a, *r; 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate if (result->size < aa->len) { 7670Sstevel@tonic-gate err = big_extend(result, aa->len); 7686557Sfr41279 if (err != BIG_OK) { 7690Sstevel@tonic-gate return (err); 7706557Sfr41279 } 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate result->len = aa->len; 7740Sstevel@tonic-gate a = aa->value; 7750Sstevel@tonic-gate r = result->value; 7760Sstevel@tonic-gate cy = 0; 7776557Sfr41279 for (i = aa->len - 1; i >= 0; i--) { 7786557Sfr41279 cy1 = a[i] << (BIG_CHUNK_SIZE - 1); 7796557Sfr41279 r[i] = (cy | (a[i] >> 1)); 7800Sstevel@tonic-gate cy = cy1; 7810Sstevel@tonic-gate } 7826557Sfr41279 if (r[result->len - 1] == 0) { 7836557Sfr41279 result->len--; 7846557Sfr41279 } 7856557Sfr41279 7860Sstevel@tonic-gate return (BIG_OK); 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7896557Sfr41279 /* result = aa*2 */ 7900Sstevel@tonic-gate BIG_ERR_CODE 7910Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa) 7920Sstevel@tonic-gate { 7936557Sfr41279 BIG_ERR_CODE err; 7946557Sfr41279 int i, rsize; 7956557Sfr41279 BIG_CHUNK_TYPE cy, cy1; 7966557Sfr41279 BIG_CHUNK_TYPE *a, *r; 7976557Sfr41279 7986557Sfr41279 if ((aa->len > 0) && 7996557Sfr41279 ((aa->value[aa->len - 1] & BIG_CHUNK_HIGHBIT) != 0)) { 8000Sstevel@tonic-gate rsize = aa->len + 1; 8016557Sfr41279 } else { 8026557Sfr41279 rsize = aa->len; 8036557Sfr41279 } 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate if (result->size < rsize) { 8060Sstevel@tonic-gate err = big_extend(result, rsize); 8070Sstevel@tonic-gate if (err != BIG_OK) 8080Sstevel@tonic-gate return (err); 8090Sstevel@tonic-gate } 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate a = aa->value; 8120Sstevel@tonic-gate r = result->value; 8136557Sfr41279 if (rsize == aa->len + 1) { 8146557Sfr41279 r[rsize - 1] = 1; 8156557Sfr41279 } 8160Sstevel@tonic-gate cy = 0; 8170Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 8186557Sfr41279 cy1 = a[i] >> (BIG_CHUNK_SIZE - 1); 8190Sstevel@tonic-gate r[i] = (cy | (a[i] << 1)); 8200Sstevel@tonic-gate cy = cy1; 8210Sstevel@tonic-gate } 8220Sstevel@tonic-gate result->len = rsize; 8230Sstevel@tonic-gate return (BIG_OK); 8240Sstevel@tonic-gate } 8250Sstevel@tonic-gate 8266557Sfr41279 8276557Sfr41279 /* 8286557Sfr41279 * returns aa mod b, aa must be nonneg, b must be a max 8296557Sfr41279 * (BIG_CHUNK_SIZE / 2)-bit integer 8306557Sfr41279 */ 8316557Sfr41279 static uint32_t 8326557Sfr41279 big_modhalf_pos(BIGNUM *aa, uint32_t b) 8330Sstevel@tonic-gate { 8346557Sfr41279 int i; 8356557Sfr41279 BIG_CHUNK_TYPE rem; 8366557Sfr41279 8376557Sfr41279 if (aa->len == 0) { 8380Sstevel@tonic-gate return (0); 8396557Sfr41279 } 8400Sstevel@tonic-gate rem = aa->value[aa->len - 1] % b; 8410Sstevel@tonic-gate for (i = aa->len - 2; i >= 0; i--) { 8426557Sfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 8436557Sfr41279 (aa->value[i] >> (BIG_CHUNK_SIZE / 2))) % b; 8446557Sfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 8456557Sfr41279 (aa->value[i] & BIG_CHUNK_LOWHALFBITS)) % b; 8460Sstevel@tonic-gate } 8476557Sfr41279 8486557Sfr41279 return ((uint32_t)rem); 8490Sstevel@tonic-gate } 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate /* 8536557Sfr41279 * result = aa - (2^BIG_CHUNK_SIZE)^lendiff * bb 8540Sstevel@tonic-gate * result->size should be at least aa->len at entry 8550Sstevel@tonic-gate * aa, bb, and result should be positive 8560Sstevel@tonic-gate */ 8570Sstevel@tonic-gate void 8580Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 8590Sstevel@tonic-gate { 8600Sstevel@tonic-gate int i, lendiff; 8610Sstevel@tonic-gate BIGNUM res1, aa1; 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate lendiff = aa->len - bb->len; 8640Sstevel@tonic-gate res1.size = result->size - lendiff; 8650Sstevel@tonic-gate res1.malloced = 0; 8660Sstevel@tonic-gate res1.value = result->value + lendiff; 8670Sstevel@tonic-gate aa1.size = aa->size - lendiff; 8680Sstevel@tonic-gate aa1.value = aa->value + lendiff; 8690Sstevel@tonic-gate aa1.len = bb->len; 8700Sstevel@tonic-gate aa1.sign = 1; 8710Sstevel@tonic-gate (void) big_sub_pos(&res1, &aa1, bb); 8720Sstevel@tonic-gate if (result->value != aa->value) { 8730Sstevel@tonic-gate for (i = 0; i < lendiff; i++) { 8740Sstevel@tonic-gate result->value[i] = aa->value[i]; 8750Sstevel@tonic-gate } 8760Sstevel@tonic-gate } 8770Sstevel@tonic-gate result->len = aa->len; 8780Sstevel@tonic-gate } 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate /* 8820Sstevel@tonic-gate * returns 1, 0, or -1 depending on whether |aa| > , ==, or < 8836557Sfr41279 * (2^BIG_CHUNK_SIZE)^lendiff * |bb| 8840Sstevel@tonic-gate * aa->len should be >= bb->len 8850Sstevel@tonic-gate */ 8860Sstevel@tonic-gate int 8870Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb) 8880Sstevel@tonic-gate { 8898933Sopensolaris@drydog.com int lendiff; 8908933Sopensolaris@drydog.com BIGNUM aa1; 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate lendiff = aa->len - bb->len; 8930Sstevel@tonic-gate aa1.len = bb->len; 8940Sstevel@tonic-gate aa1.size = aa->size - lendiff; 8950Sstevel@tonic-gate aa1.malloced = 0; 8960Sstevel@tonic-gate aa1.value = aa->value + lendiff; 8970Sstevel@tonic-gate return (big_cmp_abs(&aa1, bb)); 8980Sstevel@tonic-gate } 8990Sstevel@tonic-gate 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate /* 9026557Sfr41279 * result = aa * b where b is a max. (BIG_CHUNK_SIZE / 2)-bit positive integer. 9030Sstevel@tonic-gate * result should have enough space allocated. 9040Sstevel@tonic-gate */ 9056557Sfr41279 static void 9066557Sfr41279 big_mulhalf_low(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 9070Sstevel@tonic-gate { 9086557Sfr41279 int i; 9096557Sfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy; 9106557Sfr41279 BIG_CHUNK_TYPE *a, *r; 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate a = aa->value; 9130Sstevel@tonic-gate r = result->value; 9140Sstevel@tonic-gate cy = 0; 9150Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 9160Sstevel@tonic-gate ai = a[i]; 9176557Sfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 9186557Sfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 9196557Sfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 9206557Sfr41279 r[i] = (t1 & BIG_CHUNK_LOWHALFBITS) | 9216557Sfr41279 (t2 << (BIG_CHUNK_SIZE / 2)); 9226557Sfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 9230Sstevel@tonic-gate } 9240Sstevel@tonic-gate r[i] = cy; 9250Sstevel@tonic-gate result->len = aa->len + 1; 9260Sstevel@tonic-gate result->sign = aa->sign; 9270Sstevel@tonic-gate } 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate /* 9316557Sfr41279 * result = aa * b * 2^(BIG_CHUNK_SIZE / 2) where b is a max. 9326557Sfr41279 * (BIG_CHUNK_SIZE / 2)-bit positive integer. 9330Sstevel@tonic-gate * result should have enough space allocated. 9340Sstevel@tonic-gate */ 9356557Sfr41279 static void 9366557Sfr41279 big_mulhalf_high(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 9370Sstevel@tonic-gate { 9386557Sfr41279 int i; 9396557Sfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy, ri; 9406557Sfr41279 BIG_CHUNK_TYPE *a, *r; 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate a = aa->value; 9430Sstevel@tonic-gate r = result->value; 9440Sstevel@tonic-gate cy = 0; 9450Sstevel@tonic-gate ri = 0; 9460Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 9470Sstevel@tonic-gate ai = a[i]; 9486557Sfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 9496557Sfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 9506557Sfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 9516557Sfr41279 r[i] = (t1 << (BIG_CHUNK_SIZE / 2)) + ri; 9526557Sfr41279 ri = t2 & BIG_CHUNK_LOWHALFBITS; 9536557Sfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 9540Sstevel@tonic-gate } 9556557Sfr41279 r[i] = (cy << (BIG_CHUNK_SIZE / 2)) + ri; 9560Sstevel@tonic-gate result->len = aa->len + 1; 9570Sstevel@tonic-gate result->sign = aa->sign; 9580Sstevel@tonic-gate } 9590Sstevel@tonic-gate 9606557Sfr41279 9610Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 9620Sstevel@tonic-gate void 9630Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs) 9640Sstevel@tonic-gate { 9656557Sfr41279 int i; 9666557Sfr41279 BIG_CHUNK_TYPE cy, ai; 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate if (offs == 0) { 9690Sstevel@tonic-gate if (result != aa) { 9700Sstevel@tonic-gate (void) big_copy(result, aa); 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate return; 9730Sstevel@tonic-gate } 9740Sstevel@tonic-gate cy = 0; 9750Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 9760Sstevel@tonic-gate ai = aa->value[i]; 9770Sstevel@tonic-gate result->value[i] = (ai << offs) | cy; 9786557Sfr41279 cy = ai >> (BIG_CHUNK_SIZE - offs); 9790Sstevel@tonic-gate } 9800Sstevel@tonic-gate if (cy != 0) { 9810Sstevel@tonic-gate result->len = aa->len + 1; 9820Sstevel@tonic-gate result->value[result->len - 1] = cy; 9830Sstevel@tonic-gate } else { 9840Sstevel@tonic-gate result->len = aa->len; 9850Sstevel@tonic-gate } 9860Sstevel@tonic-gate result->sign = aa->sign; 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate 9896557Sfr41279 9900Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 9910Sstevel@tonic-gate void 9920Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs) 9930Sstevel@tonic-gate { 9946557Sfr41279 int i; 9956557Sfr41279 BIG_CHUNK_TYPE cy, ai; 9960Sstevel@tonic-gate 9970Sstevel@tonic-gate if (offs == 0) { 9980Sstevel@tonic-gate if (result != aa) { 9990Sstevel@tonic-gate (void) big_copy(result, aa); 10000Sstevel@tonic-gate } 10010Sstevel@tonic-gate return; 10020Sstevel@tonic-gate } 10030Sstevel@tonic-gate cy = aa->value[0] >> offs; 10040Sstevel@tonic-gate for (i = 1; i < aa->len; i++) { 10050Sstevel@tonic-gate ai = aa->value[i]; 10068933Sopensolaris@drydog.com result->value[i - 1] = (ai << (BIG_CHUNK_SIZE - offs)) | cy; 10070Sstevel@tonic-gate cy = ai >> offs; 10080Sstevel@tonic-gate } 10090Sstevel@tonic-gate result->len = aa->len; 10100Sstevel@tonic-gate result->value[result->len - 1] = cy; 10110Sstevel@tonic-gate result->sign = aa->sign; 10120Sstevel@tonic-gate } 10130Sstevel@tonic-gate 10140Sstevel@tonic-gate 10150Sstevel@tonic-gate /* 10160Sstevel@tonic-gate * result = aa/bb remainder = aa mod bb 10170Sstevel@tonic-gate * it is assumed that aa and bb are positive 10180Sstevel@tonic-gate */ 10190Sstevel@tonic-gate BIG_ERR_CODE 10208933Sopensolaris@drydog.com big_div_pos(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb) 10210Sstevel@tonic-gate { 10226557Sfr41279 BIG_ERR_CODE err = BIG_OK; 10236557Sfr41279 int i, alen, blen, tlen, rlen, offs; 10246557Sfr41279 BIG_CHUNK_TYPE higha, highb, coeff; 10256557Sfr41279 BIG_CHUNK_TYPE *a, *b; 10266557Sfr41279 BIGNUM bbhigh, bblow, tresult, tmp1, tmp2; 10276557Sfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 10286557Sfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 10296557Sfr41279 BIG_CHUNK_TYPE tresultvalue[BIGTMPSIZE]; 10306557Sfr41279 BIG_CHUNK_TYPE bblowvalue[BIGTMPSIZE]; 10316557Sfr41279 BIG_CHUNK_TYPE bbhighvalue[BIGTMPSIZE]; 10320Sstevel@tonic-gate 10330Sstevel@tonic-gate a = aa->value; 10340Sstevel@tonic-gate b = bb->value; 10350Sstevel@tonic-gate alen = aa->len; 10360Sstevel@tonic-gate blen = bb->len; 10376557Sfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 10386557Sfr41279 alen = alen - 1; 10396557Sfr41279 } 10400Sstevel@tonic-gate aa->len = alen; 10416557Sfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 10426557Sfr41279 blen = blen - 1; 10436557Sfr41279 } 10440Sstevel@tonic-gate bb->len = blen; 10456557Sfr41279 if ((blen == 1) && (b[0] == 0)) { 10460Sstevel@tonic-gate return (BIG_DIV_BY_0); 10476557Sfr41279 } 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate if (big_cmp_abs(aa, bb) < 0) { 10500Sstevel@tonic-gate if ((remainder != NULL) && 10516557Sfr41279 ((err = big_copy(remainder, aa)) != BIG_OK)) { 10520Sstevel@tonic-gate return (err); 10536557Sfr41279 } 10540Sstevel@tonic-gate if (result != NULL) { 10550Sstevel@tonic-gate result->len = 1; 10560Sstevel@tonic-gate result->sign = 1; 10570Sstevel@tonic-gate result->value[0] = 0; 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate return (BIG_OK); 10600Sstevel@tonic-gate } 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate if ((err = big_init1(&bblow, blen + 1, 10630Sstevel@tonic-gate bblowvalue, arraysize(bblowvalue))) != BIG_OK) 10640Sstevel@tonic-gate return (err); 10650Sstevel@tonic-gate 10660Sstevel@tonic-gate if ((err = big_init1(&bbhigh, blen + 1, 10670Sstevel@tonic-gate bbhighvalue, arraysize(bbhighvalue))) != BIG_OK) 10680Sstevel@tonic-gate goto ret1; 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate if ((err = big_init1(&tmp1, alen + 2, 10710Sstevel@tonic-gate tmp1value, arraysize(tmp1value))) != BIG_OK) 10720Sstevel@tonic-gate goto ret2; 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate if ((err = big_init1(&tmp2, blen + 2, 10750Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 10760Sstevel@tonic-gate goto ret3; 10770Sstevel@tonic-gate 10780Sstevel@tonic-gate if ((err = big_init1(&tresult, alen - blen + 2, 10790Sstevel@tonic-gate tresultvalue, arraysize(tresultvalue))) != BIG_OK) 10800Sstevel@tonic-gate goto ret4; 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate offs = 0; 10836557Sfr41279 highb = b[blen - 1]; 10846557Sfr41279 if (highb >= (BIG_CHUNK_HALF_HIGHBIT << 1)) { 10856557Sfr41279 highb = highb >> (BIG_CHUNK_SIZE / 2); 10866557Sfr41279 offs = (BIG_CHUNK_SIZE / 2); 10870Sstevel@tonic-gate } 10886557Sfr41279 while ((highb & BIG_CHUNK_HALF_HIGHBIT) == 0) { 10896557Sfr41279 highb = highb << 1; 10900Sstevel@tonic-gate offs++; 10910Sstevel@tonic-gate } 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate big_shiftleft(&bblow, bb, offs); 10946557Sfr41279 10956557Sfr41279 if (offs <= (BIG_CHUNK_SIZE / 2 - 1)) { 10966557Sfr41279 big_shiftleft(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10970Sstevel@tonic-gate } else { 10986557Sfr41279 big_shiftright(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10990Sstevel@tonic-gate } 11000Sstevel@tonic-gate if (bbhigh.value[bbhigh.len - 1] == 0) { 11010Sstevel@tonic-gate bbhigh.len--; 11020Sstevel@tonic-gate } else { 11030Sstevel@tonic-gate bbhigh.value[bbhigh.len] = 0; 11040Sstevel@tonic-gate } 11050Sstevel@tonic-gate 11066557Sfr41279 highb = bblow.value[bblow.len - 1]; 11076557Sfr41279 11080Sstevel@tonic-gate big_shiftleft(&tmp1, aa, offs); 11090Sstevel@tonic-gate rlen = tmp1.len - bblow.len + 1; 11100Sstevel@tonic-gate tresult.len = rlen; 11110Sstevel@tonic-gate 11120Sstevel@tonic-gate tmp1.len++; 11130Sstevel@tonic-gate tlen = tmp1.len; 11140Sstevel@tonic-gate tmp1.value[tmp1.len - 1] = 0; 11150Sstevel@tonic-gate for (i = 0; i < rlen; i++) { 11166557Sfr41279 higha = (tmp1.value[tlen - 1] << (BIG_CHUNK_SIZE / 2)) + 11176557Sfr41279 (tmp1.value[tlen - 2] >> (BIG_CHUNK_SIZE / 2)); 11180Sstevel@tonic-gate coeff = higha / (highb + 1); 11196557Sfr41279 big_mulhalf_high(&tmp2, &bblow, coeff); 11200Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 11210Sstevel@tonic-gate bbhigh.len++; 11220Sstevel@tonic-gate while (tmp1.value[tlen - 1] > 0) { 11230Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 11240Sstevel@tonic-gate coeff++; 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate bbhigh.len--; 11270Sstevel@tonic-gate tlen--; 11280Sstevel@tonic-gate tmp1.len--; 11290Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) { 11300Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 11310Sstevel@tonic-gate coeff++; 11320Sstevel@tonic-gate } 11336557Sfr41279 tresult.value[rlen - i - 1] = coeff << (BIG_CHUNK_SIZE / 2); 11340Sstevel@tonic-gate higha = tmp1.value[tlen - 1]; 11350Sstevel@tonic-gate coeff = higha / (highb + 1); 11366557Sfr41279 big_mulhalf_low(&tmp2, &bblow, coeff); 11370Sstevel@tonic-gate tmp2.len--; 11380Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 11390Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bblow) >= 0) { 11400Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bblow); 11410Sstevel@tonic-gate coeff++; 11420Sstevel@tonic-gate } 11430Sstevel@tonic-gate tresult.value[rlen - i - 1] = 11440Sstevel@tonic-gate tresult.value[rlen - i - 1] + coeff; 11450Sstevel@tonic-gate } 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate big_shiftright(&tmp1, &tmp1, offs); 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate err = BIG_OK; 11500Sstevel@tonic-gate 11510Sstevel@tonic-gate if ((remainder != NULL) && 11520Sstevel@tonic-gate ((err = big_copy(remainder, &tmp1)) != BIG_OK)) 11530Sstevel@tonic-gate goto ret; 11540Sstevel@tonic-gate 11550Sstevel@tonic-gate if (result != NULL) 11560Sstevel@tonic-gate err = big_copy(result, &tresult); 11570Sstevel@tonic-gate 11580Sstevel@tonic-gate ret: 11590Sstevel@tonic-gate big_finish(&tresult); 11600Sstevel@tonic-gate ret4: 11610Sstevel@tonic-gate big_finish(&tmp1); 11620Sstevel@tonic-gate ret3: 11630Sstevel@tonic-gate big_finish(&tmp2); 11640Sstevel@tonic-gate ret2: 11650Sstevel@tonic-gate big_finish(&bbhigh); 11660Sstevel@tonic-gate ret1: 11670Sstevel@tonic-gate big_finish(&bblow); 11680Sstevel@tonic-gate return (err); 11690Sstevel@tonic-gate } 11700Sstevel@tonic-gate 11718933Sopensolaris@drydog.com 11720Sstevel@tonic-gate /* 11730Sstevel@tonic-gate * If there is no processor-specific integer implementation of 11740Sstevel@tonic-gate * the lower level multiply functions, then this code is provided 11750Sstevel@tonic-gate * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and 11760Sstevel@tonic-gate * big_sqr_vec(). 11770Sstevel@tonic-gate * 11780Sstevel@tonic-gate * There are two generic implementations. One that assumes that 11790Sstevel@tonic-gate * there is hardware and C compiler support for a 32 x 32 --> 64 11800Sstevel@tonic-gate * bit unsigned multiply, but otherwise is not specific to any 11810Sstevel@tonic-gate * processor, platform, or ISA. 11820Sstevel@tonic-gate * 11830Sstevel@tonic-gate * The other makes very few assumptions about hardware capabilities. 11840Sstevel@tonic-gate * It does not even assume that there is any implementation of a 11850Sstevel@tonic-gate * 32 x 32 --> 64 bit multiply that is accessible to C code and 11860Sstevel@tonic-gate * appropriate to use. It falls constructs 32 x 32 --> 64 bit 11870Sstevel@tonic-gate * multiplies from 16 x 16 --> 32 bit multiplies. 11880Sstevel@tonic-gate * 11890Sstevel@tonic-gate */ 11900Sstevel@tonic-gate 11910Sstevel@tonic-gate #if !defined(PSR_MUL) 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate #ifdef UMUL64 11940Sstevel@tonic-gate 11956557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 11966557Sfr41279 11970Sstevel@tonic-gate #define UNROLL8 11980Sstevel@tonic-gate 11990Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_PREFETCH(R) \ 12000Sstevel@tonic-gate p = pf * d; \ 12018933Sopensolaris@drydog.com pf = (uint64_t)a[R + 1]; \ 12020Sstevel@tonic-gate t = p + cy; \ 12030Sstevel@tonic-gate r[R] = (uint32_t)t; \ 12040Sstevel@tonic-gate cy = t >> 32 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_NOPREFETCH(R) \ 12070Sstevel@tonic-gate p = pf * d; \ 12080Sstevel@tonic-gate t = p + cy; \ 12090Sstevel@tonic-gate r[R] = (uint32_t)t; \ 12100Sstevel@tonic-gate cy = t >> 32 12110Sstevel@tonic-gate 12120Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_PREFETCH(R) \ 12130Sstevel@tonic-gate t = (uint64_t)r[R]; \ 12140Sstevel@tonic-gate p = pf * d; \ 12158933Sopensolaris@drydog.com pf = (uint64_t)a[R + 1]; \ 12160Sstevel@tonic-gate t = p + t + cy; \ 12170Sstevel@tonic-gate r[R] = (uint32_t)t; \ 12180Sstevel@tonic-gate cy = t >> 32 12190Sstevel@tonic-gate 12200Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_NOPREFETCH(R) \ 12210Sstevel@tonic-gate t = (uint64_t)r[R]; \ 12220Sstevel@tonic-gate p = pf * d; \ 12230Sstevel@tonic-gate t = p + t + cy; \ 12240Sstevel@tonic-gate r[R] = (uint32_t)t; \ 12250Sstevel@tonic-gate cy = t >> 32 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate #ifdef UNROLL8 12280Sstevel@tonic-gate 12290Sstevel@tonic-gate #define UNROLL 8 12300Sstevel@tonic-gate 12310Sstevel@tonic-gate /* 12320Sstevel@tonic-gate * r = a * b 12330Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 12340Sstevel@tonic-gate */ 12350Sstevel@tonic-gate 12360Sstevel@tonic-gate uint32_t 12370Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 12380Sstevel@tonic-gate { 12390Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 12400Sstevel@tonic-gate 12410Sstevel@tonic-gate if (len == 0) 12420Sstevel@tonic-gate return (0); 12430Sstevel@tonic-gate cy = 0; 12440Sstevel@tonic-gate d = (uint64_t)b; 12450Sstevel@tonic-gate pf = (uint64_t)a[0]; 12460Sstevel@tonic-gate while (len > UNROLL) { 12470Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 12480Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 12490Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 12500Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 12510Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 12520Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 12530Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 12540Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(7); 12550Sstevel@tonic-gate r += UNROLL; 12560Sstevel@tonic-gate a += UNROLL; 12570Sstevel@tonic-gate len -= UNROLL; 12580Sstevel@tonic-gate } 12590Sstevel@tonic-gate if (len == UNROLL) { 12600Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 12610Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 12620Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 12630Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 12640Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 12650Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 12660Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 12670Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(7); 12680Sstevel@tonic-gate return ((uint32_t)cy); 12690Sstevel@tonic-gate } 12700Sstevel@tonic-gate while (len > 1) { 12710Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 12720Sstevel@tonic-gate ++r; 12730Sstevel@tonic-gate ++a; 12740Sstevel@tonic-gate --len; 12750Sstevel@tonic-gate } 12760Sstevel@tonic-gate if (len > 0) { 12770Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(0); 12780Sstevel@tonic-gate } 12790Sstevel@tonic-gate return ((uint32_t)cy); 12800Sstevel@tonic-gate } 12810Sstevel@tonic-gate 12820Sstevel@tonic-gate /* 12830Sstevel@tonic-gate * r += a * b 12840Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 12850Sstevel@tonic-gate */ 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate uint32_t 12880Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 12890Sstevel@tonic-gate { 12900Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 12910Sstevel@tonic-gate 12920Sstevel@tonic-gate if (len == 0) 12930Sstevel@tonic-gate return (0); 12940Sstevel@tonic-gate cy = 0; 12950Sstevel@tonic-gate d = (uint64_t)b; 12960Sstevel@tonic-gate pf = (uint64_t)a[0]; 12970Sstevel@tonic-gate while (len > 8) { 12980Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12990Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 13000Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 13010Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 13020Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 13030Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 13040Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 13050Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(7); 13060Sstevel@tonic-gate r += 8; 13070Sstevel@tonic-gate a += 8; 13080Sstevel@tonic-gate len -= 8; 13090Sstevel@tonic-gate } 13100Sstevel@tonic-gate if (len == 8) { 13110Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 13120Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 13130Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 13140Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 13150Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 13160Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 13170Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 13180Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(7); 13190Sstevel@tonic-gate return ((uint32_t)cy); 13200Sstevel@tonic-gate } 13210Sstevel@tonic-gate while (len > 1) { 13220Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 13230Sstevel@tonic-gate ++r; 13240Sstevel@tonic-gate ++a; 13250Sstevel@tonic-gate --len; 13260Sstevel@tonic-gate } 13270Sstevel@tonic-gate if (len > 0) { 13280Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(0); 13290Sstevel@tonic-gate } 13300Sstevel@tonic-gate return ((uint32_t)cy); 13310Sstevel@tonic-gate } 13320Sstevel@tonic-gate #endif /* UNROLL8 */ 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate void 13350Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 13360Sstevel@tonic-gate { 13378933Sopensolaris@drydog.com uint32_t *tr, *ta; 13388933Sopensolaris@drydog.com int tlen, row, col; 13398933Sopensolaris@drydog.com uint64_t p, s, t, t2, cy; 13408933Sopensolaris@drydog.com uint32_t d; 13410Sstevel@tonic-gate 13420Sstevel@tonic-gate tr = r + 1; 13430Sstevel@tonic-gate ta = a; 13440Sstevel@tonic-gate tlen = len - 1; 13450Sstevel@tonic-gate tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]); 13460Sstevel@tonic-gate while (--tlen > 0) { 13470Sstevel@tonic-gate tr += 2; 13480Sstevel@tonic-gate ++ta; 13490Sstevel@tonic-gate tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]); 13500Sstevel@tonic-gate } 13510Sstevel@tonic-gate s = (uint64_t)a[0]; 13520Sstevel@tonic-gate s = s * s; 13530Sstevel@tonic-gate r[0] = (uint32_t)s; 13540Sstevel@tonic-gate cy = s >> 32; 13550Sstevel@tonic-gate p = ((uint64_t)r[1] << 1) + cy; 13560Sstevel@tonic-gate r[1] = (uint32_t)p; 13570Sstevel@tonic-gate cy = p >> 32; 13580Sstevel@tonic-gate row = 1; 13590Sstevel@tonic-gate col = 2; 13600Sstevel@tonic-gate while (row < len) { 13610Sstevel@tonic-gate s = (uint64_t)a[row]; 13620Sstevel@tonic-gate s = s * s; 13630Sstevel@tonic-gate p = (uint64_t)r[col] << 1; 13640Sstevel@tonic-gate t = p + s; 13650Sstevel@tonic-gate d = (uint32_t)t; 13660Sstevel@tonic-gate t2 = (uint64_t)d + cy; 13670Sstevel@tonic-gate r[col] = (uint32_t)t2; 13680Sstevel@tonic-gate cy = (t >> 32) + (t2 >> 32); 13690Sstevel@tonic-gate if (row == len - 1) 13700Sstevel@tonic-gate break; 13718933Sopensolaris@drydog.com p = ((uint64_t)r[col + 1] << 1) + cy; 13728933Sopensolaris@drydog.com r[col + 1] = (uint32_t)p; 13730Sstevel@tonic-gate cy = p >> 32; 13740Sstevel@tonic-gate ++row; 13750Sstevel@tonic-gate col += 2; 13760Sstevel@tonic-gate } 13778933Sopensolaris@drydog.com r[col + 1] = (uint32_t)cy; 13780Sstevel@tonic-gate } 13790Sstevel@tonic-gate 13806557Sfr41279 #else /* BIG_CHUNK_SIZE == 64 */ 13816557Sfr41279 13826557Sfr41279 /* 13836557Sfr41279 * r = r + a * digit, r and a are vectors of length len 13846557Sfr41279 * returns the carry digit 13856557Sfr41279 */ 13866557Sfr41279 BIG_CHUNK_TYPE 13876557Sfr41279 big_mul_add_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 13886557Sfr41279 BIG_CHUNK_TYPE digit) 13896557Sfr41279 { 13906557Sfr41279 BIG_CHUNK_TYPE cy, cy1, retcy, dlow, dhigh; 13916557Sfr41279 int i; 13926557Sfr41279 13936557Sfr41279 cy1 = 0; 13946557Sfr41279 dlow = digit & BIG_CHUNK_LOWHALFBITS; 13956557Sfr41279 dhigh = digit >> (BIG_CHUNK_SIZE / 2); 13966557Sfr41279 for (i = 0; i < len; i++) { 13976557Sfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 13986557Sfr41279 dlow * (a[i] & BIG_CHUNK_LOWHALFBITS) + 13996557Sfr41279 (r[i] & BIG_CHUNK_LOWHALFBITS); 14006557Sfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 14016557Sfr41279 dlow * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 14026557Sfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 14036557Sfr41279 r[i] = (cy & BIG_CHUNK_LOWHALFBITS) | 14046557Sfr41279 (cy1 << (BIG_CHUNK_SIZE / 2)); 14056557Sfr41279 } 14066557Sfr41279 retcy = cy1 >> (BIG_CHUNK_SIZE / 2); 14076557Sfr41279 14086557Sfr41279 cy1 = r[0] & BIG_CHUNK_LOWHALFBITS; 14096557Sfr41279 for (i = 0; i < len - 1; i++) { 14106557Sfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 14116557Sfr41279 dhigh * (a[i] & BIG_CHUNK_LOWHALFBITS) + 14126557Sfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 14136557Sfr41279 r[i] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 14146557Sfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 14156557Sfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 14166557Sfr41279 dhigh * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 14176557Sfr41279 (r[i + 1] & BIG_CHUNK_LOWHALFBITS); 14186557Sfr41279 } 14196557Sfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 14206557Sfr41279 dhigh * (a[len - 1] & BIG_CHUNK_LOWHALFBITS) + 14216557Sfr41279 (r[len - 1] >> (BIG_CHUNK_SIZE / 2)); 14226557Sfr41279 r[len - 1] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 14236557Sfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 14246557Sfr41279 retcy = (cy >> (BIG_CHUNK_SIZE / 2)) + 14256557Sfr41279 dhigh * (a[len - 1] >> (BIG_CHUNK_SIZE / 2)) + retcy; 14266557Sfr41279 14276557Sfr41279 return (retcy); 14286557Sfr41279 } 14296557Sfr41279 14306557Sfr41279 14316557Sfr41279 /* 14326557Sfr41279 * r = a * digit, r and a are vectors of length len 14336557Sfr41279 * returns the carry digit 14346557Sfr41279 */ 14356557Sfr41279 BIG_CHUNK_TYPE 14366557Sfr41279 big_mul_set_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 14376557Sfr41279 BIG_CHUNK_TYPE digit) 14386557Sfr41279 { 14396557Sfr41279 int i; 14406557Sfr41279 14416557Sfr41279 ASSERT(r != a); 14426557Sfr41279 for (i = 0; i < len; i++) { 14436557Sfr41279 r[i] = 0; 14446557Sfr41279 } 14456557Sfr41279 return (big_mul_add_vec(r, a, len, digit)); 14466557Sfr41279 } 14476557Sfr41279 14486557Sfr41279 void 14496557Sfr41279 big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len) 14506557Sfr41279 { 14516557Sfr41279 int i; 14526557Sfr41279 14536557Sfr41279 ASSERT(r != a); 14546557Sfr41279 r[len] = big_mul_set_vec(r, a, len, a[0]); 14556557Sfr41279 for (i = 1; i < len; ++i) 14568933Sopensolaris@drydog.com r[len + i] = big_mul_add_vec(r + i, a, len, a[i]); 14576557Sfr41279 } 14586557Sfr41279 14596557Sfr41279 #endif /* BIG_CHUNK_SIZE == 32/64 */ 14606557Sfr41279 14618933Sopensolaris@drydog.com 14620Sstevel@tonic-gate #else /* ! UMUL64 */ 14630Sstevel@tonic-gate 14646557Sfr41279 #if (BIG_CHUNK_SIZE != 32) 14656557Sfr41279 #error Don't use 64-bit chunks without defining UMUL64 14666557Sfr41279 #endif 14676557Sfr41279 14686557Sfr41279 14690Sstevel@tonic-gate /* 14700Sstevel@tonic-gate * r = r + a * digit, r and a are vectors of length len 14710Sstevel@tonic-gate * returns the carry digit 14720Sstevel@tonic-gate */ 14730Sstevel@tonic-gate uint32_t 14740Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 14750Sstevel@tonic-gate { 14760Sstevel@tonic-gate uint32_t cy, cy1, retcy, dlow, dhigh; 14770Sstevel@tonic-gate int i; 14780Sstevel@tonic-gate 14790Sstevel@tonic-gate cy1 = 0; 14800Sstevel@tonic-gate dlow = digit & 0xffff; 14810Sstevel@tonic-gate dhigh = digit >> 16; 14820Sstevel@tonic-gate for (i = 0; i < len; i++) { 14830Sstevel@tonic-gate cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff); 14840Sstevel@tonic-gate cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16); 14850Sstevel@tonic-gate r[i] = (cy & 0xffff) | (cy1 << 16); 14860Sstevel@tonic-gate } 14870Sstevel@tonic-gate retcy = cy1 >> 16; 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate cy1 = r[0] & 0xffff; 14900Sstevel@tonic-gate for (i = 0; i < len - 1; i++) { 14910Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16); 14920Sstevel@tonic-gate r[i] = (cy1 & 0xffff) | (cy << 16); 14930Sstevel@tonic-gate cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff); 14940Sstevel@tonic-gate } 14950Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16); 14960Sstevel@tonic-gate r[len - 1] = (cy1 & 0xffff) | (cy << 16); 14970Sstevel@tonic-gate retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy; 14980Sstevel@tonic-gate 14990Sstevel@tonic-gate return (retcy); 15000Sstevel@tonic-gate } 15010Sstevel@tonic-gate 15026557Sfr41279 15030Sstevel@tonic-gate /* 15040Sstevel@tonic-gate * r = a * digit, r and a are vectors of length len 15050Sstevel@tonic-gate * returns the carry digit 15060Sstevel@tonic-gate */ 15070Sstevel@tonic-gate uint32_t 15080Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 15090Sstevel@tonic-gate { 15106557Sfr41279 int i; 15116557Sfr41279 15126557Sfr41279 ASSERT(r != a); 15136557Sfr41279 for (i = 0; i < len; i++) { 15146557Sfr41279 r[i] = 0; 15156557Sfr41279 } 15166557Sfr41279 15170Sstevel@tonic-gate return (big_mul_add_vec(r, a, len, digit)); 15180Sstevel@tonic-gate } 15190Sstevel@tonic-gate 15200Sstevel@tonic-gate void 15210Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 15220Sstevel@tonic-gate { 15230Sstevel@tonic-gate int i; 15240Sstevel@tonic-gate 15256557Sfr41279 ASSERT(r != a); 15260Sstevel@tonic-gate r[len] = big_mul_set_vec(r, a, len, a[0]); 15270Sstevel@tonic-gate for (i = 1; i < len; ++i) 15288933Sopensolaris@drydog.com r[len + i] = big_mul_add_vec(r + i, a, len, a[i]); 15290Sstevel@tonic-gate } 15300Sstevel@tonic-gate 15310Sstevel@tonic-gate #endif /* UMUL64 */ 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate void 15346557Sfr41279 big_mul_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int alen, 15356557Sfr41279 BIG_CHUNK_TYPE *b, int blen) 15360Sstevel@tonic-gate { 15370Sstevel@tonic-gate int i; 15380Sstevel@tonic-gate 15390Sstevel@tonic-gate r[alen] = big_mul_set_vec(r, a, alen, b[0]); 15400Sstevel@tonic-gate for (i = 1; i < blen; ++i) 15418933Sopensolaris@drydog.com r[alen + i] = big_mul_add_vec(r + i, a, alen, b[i]); 15420Sstevel@tonic-gate } 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate 15450Sstevel@tonic-gate #endif /* ! PSR_MUL */ 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate 15480Sstevel@tonic-gate /* 15490Sstevel@tonic-gate * result = aa * bb result->value should be big enough to hold the result 15500Sstevel@tonic-gate * 15510Sstevel@tonic-gate * Implementation: Standard grammar school algorithm 15520Sstevel@tonic-gate * 15530Sstevel@tonic-gate */ 15540Sstevel@tonic-gate BIG_ERR_CODE 15550Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 15560Sstevel@tonic-gate { 15576557Sfr41279 BIGNUM tmp1; 15586557Sfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 15596557Sfr41279 BIG_CHUNK_TYPE *r, *t, *a, *b; 15606557Sfr41279 BIG_ERR_CODE err; 15616557Sfr41279 int i, alen, blen, rsize, sign, diff; 15620Sstevel@tonic-gate 15630Sstevel@tonic-gate if (aa == bb) { 15640Sstevel@tonic-gate diff = 0; 15650Sstevel@tonic-gate } else { 15660Sstevel@tonic-gate diff = big_cmp_abs(aa, bb); 15670Sstevel@tonic-gate if (diff < 0) { 15680Sstevel@tonic-gate BIGNUM *tt; 15690Sstevel@tonic-gate tt = aa; 15700Sstevel@tonic-gate aa = bb; 15710Sstevel@tonic-gate bb = tt; 15720Sstevel@tonic-gate } 15730Sstevel@tonic-gate } 15740Sstevel@tonic-gate a = aa->value; 15750Sstevel@tonic-gate b = bb->value; 15760Sstevel@tonic-gate alen = aa->len; 15770Sstevel@tonic-gate blen = bb->len; 15786557Sfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 15796557Sfr41279 alen--; 15806557Sfr41279 } 15810Sstevel@tonic-gate aa->len = alen; 15826557Sfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 15836557Sfr41279 blen--; 15846557Sfr41279 } 15850Sstevel@tonic-gate bb->len = blen; 15860Sstevel@tonic-gate 15870Sstevel@tonic-gate rsize = alen + blen; 15888933Sopensolaris@drydog.com ASSERT(rsize > 0); 15890Sstevel@tonic-gate if (result->size < rsize) { 15900Sstevel@tonic-gate err = big_extend(result, rsize); 15916557Sfr41279 if (err != BIG_OK) { 15920Sstevel@tonic-gate return (err); 15936557Sfr41279 } 15940Sstevel@tonic-gate /* aa or bb might be an alias to result */ 15950Sstevel@tonic-gate a = aa->value; 15960Sstevel@tonic-gate b = bb->value; 15970Sstevel@tonic-gate } 15980Sstevel@tonic-gate r = result->value; 15990Sstevel@tonic-gate 16000Sstevel@tonic-gate if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) { 16010Sstevel@tonic-gate result->len = 1; 16020Sstevel@tonic-gate result->sign = 1; 16030Sstevel@tonic-gate r[0] = 0; 16040Sstevel@tonic-gate return (BIG_OK); 16050Sstevel@tonic-gate } 16060Sstevel@tonic-gate sign = aa->sign * bb->sign; 16070Sstevel@tonic-gate if ((alen == 1) && (a[0] == 1)) { 16086557Sfr41279 for (i = 0; i < blen; i++) { 16096557Sfr41279 r[i] = b[i]; 16106557Sfr41279 } 16110Sstevel@tonic-gate result->len = blen; 16120Sstevel@tonic-gate result->sign = sign; 16130Sstevel@tonic-gate return (BIG_OK); 16140Sstevel@tonic-gate } 16150Sstevel@tonic-gate if ((blen == 1) && (b[0] == 1)) { 16166557Sfr41279 for (i = 0; i < alen; i++) { 16176557Sfr41279 r[i] = a[i]; 16186557Sfr41279 } 16190Sstevel@tonic-gate result->len = alen; 16200Sstevel@tonic-gate result->sign = sign; 16210Sstevel@tonic-gate return (BIG_OK); 16220Sstevel@tonic-gate } 16230Sstevel@tonic-gate 16246557Sfr41279 if ((err = big_init1(&tmp1, rsize, 16256557Sfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 16260Sstevel@tonic-gate return (err); 16276557Sfr41279 } 16280Sstevel@tonic-gate t = tmp1.value; 16296557Sfr41279 16306557Sfr41279 for (i = 0; i < rsize; i++) { 16316557Sfr41279 t[i] = 0; 16326557Sfr41279 } 16336557Sfr41279 16346557Sfr41279 if (diff == 0 && alen > 2) { 16350Sstevel@tonic-gate BIG_SQR_VEC(t, a, alen); 16366557Sfr41279 } else if (blen > 0) { 16370Sstevel@tonic-gate BIG_MUL_VEC(t, a, alen, b, blen); 16386557Sfr41279 } 16396557Sfr41279 16406557Sfr41279 if (t[rsize - 1] == 0) { 16416557Sfr41279 tmp1.len = rsize - 1; 16426557Sfr41279 } else { 16436557Sfr41279 tmp1.len = rsize; 16446557Sfr41279 } 16458933Sopensolaris@drydog.com 16468933Sopensolaris@drydog.com err = big_copy(result, &tmp1); 16478933Sopensolaris@drydog.com 16480Sstevel@tonic-gate result->sign = sign; 16490Sstevel@tonic-gate 16506557Sfr41279 big_finish(&tmp1); 16510Sstevel@tonic-gate 16528933Sopensolaris@drydog.com return (err); 16530Sstevel@tonic-gate } 16540Sstevel@tonic-gate 16550Sstevel@tonic-gate 16560Sstevel@tonic-gate /* 16579302Sopensolaris@drydog.com * big_mont_mul() 16589302Sopensolaris@drydog.com * Montgomery multiplication. 16599302Sopensolaris@drydog.com * 16609302Sopensolaris@drydog.com * Caller must ensure that a < n, b < n, ret->size >= 2 * n->len + 1, 16619302Sopensolaris@drydog.com * and that ret is not n. 16620Sstevel@tonic-gate */ 16630Sstevel@tonic-gate BIG_ERR_CODE 16646557Sfr41279 big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, BIG_CHUNK_TYPE n0) 16650Sstevel@tonic-gate { 16669302Sopensolaris@drydog.com int i, j, nlen, needsubtract; 16679302Sopensolaris@drydog.com BIG_CHUNK_TYPE *nn, *rr, *rrplusi; 16686557Sfr41279 BIG_CHUNK_TYPE digit, c; 16696557Sfr41279 BIG_ERR_CODE err; 16709302Sopensolaris@drydog.com #ifdef __amd64 16719302Sopensolaris@drydog.com #define BIG_CPU_UNKNOWN 0 16729302Sopensolaris@drydog.com #define BIG_CPU_AMD 1 16739302Sopensolaris@drydog.com #define BIG_CPU_INTEL 2 16749302Sopensolaris@drydog.com static int big_cpu = BIG_CPU_UNKNOWN; 16759302Sopensolaris@drydog.com BIG_CHUNK_TYPE carry[BIGTMPSIZE]; 16769302Sopensolaris@drydog.com 16779302Sopensolaris@drydog.com if (big_cpu == BIG_CPU_UNKNOWN) { 16789302Sopensolaris@drydog.com big_cpu = 1 + bignum_on_intel(); 16799302Sopensolaris@drydog.com } 16809302Sopensolaris@drydog.com #endif /* __amd64 */ 16810Sstevel@tonic-gate 16820Sstevel@tonic-gate nlen = n->len; 16830Sstevel@tonic-gate nn = n->value; 16840Sstevel@tonic-gate 16850Sstevel@tonic-gate rr = ret->value; 16860Sstevel@tonic-gate 16876557Sfr41279 if ((err = big_mul(ret, a, b)) != BIG_OK) { 16880Sstevel@tonic-gate return (err); 16896557Sfr41279 } 16900Sstevel@tonic-gate 16910Sstevel@tonic-gate rr = ret->value; 16926557Sfr41279 for (i = ret->len; i < 2 * nlen + 1; i++) { 16936557Sfr41279 rr[i] = 0; 16946557Sfr41279 } 16959302Sopensolaris@drydog.com 16969302Sopensolaris@drydog.com #ifdef __amd64 /* pipelining optimization for Intel 64, but not AMD64 */ 16979302Sopensolaris@drydog.com if ((big_cpu == BIG_CPU_INTEL) && (nlen <= BIGTMPSIZE)) { 16989302Sopensolaris@drydog.com /* 16999302Sopensolaris@drydog.com * Perform the following in two for loops to reduce the 17009302Sopensolaris@drydog.com * dependency between computing the carryover bits with 17019302Sopensolaris@drydog.com * BIG_MUL_ADD_VEC() and adding them, thus improving pipelining. 17029302Sopensolaris@drydog.com */ 17039302Sopensolaris@drydog.com for (i = 0; i < nlen; i++) { 17049302Sopensolaris@drydog.com rrplusi = rr + i; 17059302Sopensolaris@drydog.com digit = *rrplusi * n0; 17069302Sopensolaris@drydog.com carry[i] = BIG_MUL_ADD_VEC(rrplusi, nn, nlen, digit); 17079302Sopensolaris@drydog.com } 17089302Sopensolaris@drydog.com for (i = 0; i < nlen; i++) { 17099302Sopensolaris@drydog.com j = i + nlen; 17109302Sopensolaris@drydog.com rr[j] += carry[i]; 17119302Sopensolaris@drydog.com while (rr[j] < carry[i]) { 17129302Sopensolaris@drydog.com rr[++j] += 1; 17139302Sopensolaris@drydog.com carry[i] = 1; 17149302Sopensolaris@drydog.com } 17159302Sopensolaris@drydog.com } 17169302Sopensolaris@drydog.com } else 17179302Sopensolaris@drydog.com #endif /* __amd64 */ 17189302Sopensolaris@drydog.com { /* no pipelining optimization */ 17199302Sopensolaris@drydog.com for (i = 0; i < nlen; i++) { 17209302Sopensolaris@drydog.com rrplusi = rr + i; 17219302Sopensolaris@drydog.com digit = *rrplusi * n0; 17229302Sopensolaris@drydog.com c = BIG_MUL_ADD_VEC(rrplusi, nn, nlen, digit); 17239302Sopensolaris@drydog.com j = i + nlen; 17249302Sopensolaris@drydog.com rr[j] += c; 17259302Sopensolaris@drydog.com while (rr[j] < c) { 17269302Sopensolaris@drydog.com rr[++j] += 1; 17279302Sopensolaris@drydog.com c = 1; 17289302Sopensolaris@drydog.com } 17290Sstevel@tonic-gate } 17300Sstevel@tonic-gate } 17310Sstevel@tonic-gate 17320Sstevel@tonic-gate needsubtract = 0; 17330Sstevel@tonic-gate if ((rr[2 * nlen] != 0)) 17340Sstevel@tonic-gate needsubtract = 1; 17350Sstevel@tonic-gate else { 17360Sstevel@tonic-gate for (i = 2 * nlen - 1; i >= nlen; i--) { 17370Sstevel@tonic-gate if (rr[i] > nn[i - nlen]) { 17380Sstevel@tonic-gate needsubtract = 1; 17390Sstevel@tonic-gate break; 17406557Sfr41279 } else if (rr[i] < nn[i - nlen]) { 17416557Sfr41279 break; 17426557Sfr41279 } 17430Sstevel@tonic-gate } 17440Sstevel@tonic-gate } 17450Sstevel@tonic-gate if (needsubtract) 17460Sstevel@tonic-gate big_sub_vec(rr, rr + nlen, nn, nlen); 17470Sstevel@tonic-gate else { 17486557Sfr41279 for (i = 0; i < nlen; i++) { 17490Sstevel@tonic-gate rr[i] = rr[i + nlen]; 17506557Sfr41279 } 17510Sstevel@tonic-gate } 17528933Sopensolaris@drydog.com 17538933Sopensolaris@drydog.com /* Remove leading zeros, but keep at least 1 digit: */ 17548933Sopensolaris@drydog.com for (i = nlen - 1; (i > 0) && (rr[i] == 0); i--) 17556557Sfr41279 ; 17568933Sopensolaris@drydog.com ret->len = i + 1; 17570Sstevel@tonic-gate 17580Sstevel@tonic-gate return (BIG_OK); 17590Sstevel@tonic-gate } 17600Sstevel@tonic-gate 17616557Sfr41279 17626557Sfr41279 BIG_CHUNK_TYPE 17636557Sfr41279 big_n0(BIG_CHUNK_TYPE n) 17640Sstevel@tonic-gate { 17656557Sfr41279 int i; 17666557Sfr41279 BIG_CHUNK_TYPE result, tmp; 17670Sstevel@tonic-gate 17680Sstevel@tonic-gate result = 0; 17696557Sfr41279 tmp = BIG_CHUNK_ALLBITS; 17706557Sfr41279 for (i = 0; i < BIG_CHUNK_SIZE; i++) { 17710Sstevel@tonic-gate if ((tmp & 1) == 1) { 17726557Sfr41279 result = (result >> 1) | BIG_CHUNK_HIGHBIT; 17730Sstevel@tonic-gate tmp = tmp - n; 17746557Sfr41279 } else { 17756557Sfr41279 result = (result >> 1); 17766557Sfr41279 } 17770Sstevel@tonic-gate tmp = tmp >> 1; 17780Sstevel@tonic-gate } 17790Sstevel@tonic-gate 17800Sstevel@tonic-gate return (result); 17810Sstevel@tonic-gate } 17820Sstevel@tonic-gate 17830Sstevel@tonic-gate 17840Sstevel@tonic-gate int 17850Sstevel@tonic-gate big_numbits(BIGNUM *n) 17860Sstevel@tonic-gate { 17876557Sfr41279 int i, j; 17886557Sfr41279 BIG_CHUNK_TYPE t; 17896557Sfr41279 17906557Sfr41279 for (i = n->len - 1; i > 0; i--) { 17916557Sfr41279 if (n->value[i] != 0) { 17926557Sfr41279 break; 17936557Sfr41279 } 17946557Sfr41279 } 17950Sstevel@tonic-gate t = n->value[i]; 17966557Sfr41279 for (j = BIG_CHUNK_SIZE; j > 0; j--) { 17976557Sfr41279 if ((t & BIG_CHUNK_HIGHBIT) == 0) { 17980Sstevel@tonic-gate t = t << 1; 17996557Sfr41279 } else { 18006557Sfr41279 return (BIG_CHUNK_SIZE * i + j); 18016557Sfr41279 } 18020Sstevel@tonic-gate } 18030Sstevel@tonic-gate return (0); 18040Sstevel@tonic-gate } 18050Sstevel@tonic-gate 18066557Sfr41279 18070Sstevel@tonic-gate /* caller must make sure that a < n */ 18080Sstevel@tonic-gate BIG_ERR_CODE 18090Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n) 18100Sstevel@tonic-gate { 18116557Sfr41279 BIGNUM rr; 18126557Sfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 18136557Sfr41279 int len, i; 18146557Sfr41279 BIG_ERR_CODE err; 18150Sstevel@tonic-gate 18160Sstevel@tonic-gate rr.malloced = 0; 18170Sstevel@tonic-gate len = n->len; 18180Sstevel@tonic-gate 18190Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, 18206557Sfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 18210Sstevel@tonic-gate return (err); 18226557Sfr41279 } 18236557Sfr41279 18246557Sfr41279 for (i = 0; i < 2 * len; i++) { 18256557Sfr41279 rr.value[i] = 0; 18266557Sfr41279 } 18270Sstevel@tonic-gate rr.value[2 * len] = 1; 18280Sstevel@tonic-gate rr.len = 2 * len + 1; 18296557Sfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 18300Sstevel@tonic-gate goto ret; 18316557Sfr41279 } 18320Sstevel@tonic-gate err = big_copy(result, &rr); 18330Sstevel@tonic-gate ret: 18346557Sfr41279 big_finish(&rr); 18350Sstevel@tonic-gate return (err); 18360Sstevel@tonic-gate } 18370Sstevel@tonic-gate 18386557Sfr41279 18390Sstevel@tonic-gate /* caller must make sure that a < n */ 18400Sstevel@tonic-gate BIG_ERR_CODE 18416557Sfr41279 big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, BIG_CHUNK_TYPE n0, 18426557Sfr41279 BIGNUM *n_rr) 18430Sstevel@tonic-gate { 18446557Sfr41279 BIGNUM rr; 18456557Sfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 18466557Sfr41279 int len, i; 18476557Sfr41279 BIG_ERR_CODE err; 18480Sstevel@tonic-gate 18490Sstevel@tonic-gate rr.malloced = 0; 18500Sstevel@tonic-gate len = n->len; 18510Sstevel@tonic-gate 18520Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue))) 18536557Sfr41279 != BIG_OK) { 18546557Sfr41279 return (err); 18556557Sfr41279 } 18560Sstevel@tonic-gate 18570Sstevel@tonic-gate if (n_rr == NULL) { 18586557Sfr41279 for (i = 0; i < 2 * len; i++) { 18596557Sfr41279 rr.value[i] = 0; 18606557Sfr41279 } 18610Sstevel@tonic-gate rr.value[2 * len] = 1; 18620Sstevel@tonic-gate rr.len = 2 * len + 1; 18636557Sfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 18640Sstevel@tonic-gate goto ret; 18656557Sfr41279 } 18660Sstevel@tonic-gate n_rr = &rr; 18670Sstevel@tonic-gate } 18680Sstevel@tonic-gate 18696557Sfr41279 if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK) { 18700Sstevel@tonic-gate goto ret; 18716557Sfr41279 } 18720Sstevel@tonic-gate err = big_copy(result, &rr); 18736557Sfr41279 18740Sstevel@tonic-gate ret: 18756557Sfr41279 big_finish(&rr); 18760Sstevel@tonic-gate return (err); 18770Sstevel@tonic-gate } 18780Sstevel@tonic-gate 18790Sstevel@tonic-gate 18806557Sfr41279 #ifdef USE_FLOATING_POINT 18816557Sfr41279 #define big_modexp_ncp_float big_modexp_ncp_sw 18826557Sfr41279 #else 18836557Sfr41279 #define big_modexp_ncp_int big_modexp_ncp_sw 18846557Sfr41279 #endif 18856557Sfr41279 18860Sstevel@tonic-gate #define MAX_EXP_BIT_GROUP_SIZE 6 18870Sstevel@tonic-gate #define APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1)) 18880Sstevel@tonic-gate 18896557Sfr41279 /* ARGSUSED */ 18900Sstevel@tonic-gate static BIG_ERR_CODE 18916557Sfr41279 big_modexp_ncp_int(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 18926557Sfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 18936557Sfr41279 18940Sstevel@tonic-gate { 18956557Sfr41279 BIGNUM apowers[APOWERS_MAX_SIZE]; 18966557Sfr41279 BIGNUM tmp1; 18976557Sfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 18986557Sfr41279 int i, j, k, l, m, p; 18998933Sopensolaris@drydog.com uint32_t bit, bitind, bitcount, groupbits, apowerssize; 19008933Sopensolaris@drydog.com uint32_t nbits; 19016557Sfr41279 BIG_ERR_CODE err; 19020Sstevel@tonic-gate 19030Sstevel@tonic-gate nbits = big_numbits(e); 19040Sstevel@tonic-gate if (nbits < 50) { 19050Sstevel@tonic-gate groupbits = 1; 19060Sstevel@tonic-gate apowerssize = 1; 19070Sstevel@tonic-gate } else { 19080Sstevel@tonic-gate groupbits = MAX_EXP_BIT_GROUP_SIZE; 19090Sstevel@tonic-gate apowerssize = 1 << (groupbits - 1); 19100Sstevel@tonic-gate } 19110Sstevel@tonic-gate 19126557Sfr41279 19136557Sfr41279 if ((err = big_init1(&tmp1, 2 * n->len + 1, 19146557Sfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 19150Sstevel@tonic-gate return (err); 19166557Sfr41279 } 19176557Sfr41279 19188933Sopensolaris@drydog.com /* clear the malloced bit to help cleanup */ 19196557Sfr41279 for (i = 0; i < apowerssize; i++) { 19206557Sfr41279 apowers[i].malloced = 0; 19216557Sfr41279 } 19228933Sopensolaris@drydog.com 19236557Sfr41279 for (i = 0; i < apowerssize; i++) { 19246557Sfr41279 if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) != 19256557Sfr41279 BIG_OK) { 19266557Sfr41279 goto ret; 19276557Sfr41279 } 19286557Sfr41279 } 19296557Sfr41279 19306557Sfr41279 (void) big_copy(&(apowers[0]), ma); 19316557Sfr41279 19326557Sfr41279 if ((err = big_mont_mul(&tmp1, ma, ma, n, n0)) != BIG_OK) { 19336557Sfr41279 goto ret; 19346557Sfr41279 } 19356557Sfr41279 (void) big_copy(ma, &tmp1); 19366557Sfr41279 19376557Sfr41279 for (i = 1; i < apowerssize; i++) { 19386557Sfr41279 if ((err = big_mont_mul(&tmp1, ma, 19398933Sopensolaris@drydog.com &(apowers[i - 1]), n, n0)) != BIG_OK) { 19406557Sfr41279 goto ret; 19416557Sfr41279 } 19426557Sfr41279 (void) big_copy(&apowers[i], &tmp1); 19436557Sfr41279 } 19446557Sfr41279 19456557Sfr41279 bitind = nbits % BIG_CHUNK_SIZE; 19466557Sfr41279 k = 0; 19476557Sfr41279 l = 0; 19486557Sfr41279 p = 0; 19496557Sfr41279 bitcount = 0; 19506557Sfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 19516557Sfr41279 for (j = bitind - 1; j >= 0; j--) { 19526557Sfr41279 bit = (e->value[i] >> j) & 1; 19536557Sfr41279 if ((bitcount == 0) && (bit == 0)) { 19546557Sfr41279 if ((err = big_mont_mul(tmp, 19556557Sfr41279 tmp, tmp, n, n0)) != BIG_OK) { 19566557Sfr41279 goto ret; 19576557Sfr41279 } 19586557Sfr41279 } else { 19596557Sfr41279 bitcount++; 19606557Sfr41279 p = p * 2 + bit; 19616557Sfr41279 if (bit == 1) { 19626557Sfr41279 k = k + l + 1; 19636557Sfr41279 l = 0; 19646557Sfr41279 } else { 19656557Sfr41279 l++; 19666557Sfr41279 } 19676557Sfr41279 if (bitcount == groupbits) { 19686557Sfr41279 for (m = 0; m < k; m++) { 19696557Sfr41279 if ((err = big_mont_mul(tmp, 19706557Sfr41279 tmp, tmp, n, n0)) != 19716557Sfr41279 BIG_OK) { 19726557Sfr41279 goto ret; 19736557Sfr41279 } 19746557Sfr41279 } 19756557Sfr41279 if ((err = big_mont_mul(tmp, tmp, 19766557Sfr41279 &(apowers[p >> (l + 1)]), 19776557Sfr41279 n, n0)) != BIG_OK) { 19786557Sfr41279 goto ret; 19796557Sfr41279 } 19806557Sfr41279 for (m = 0; m < l; m++) { 19816557Sfr41279 if ((err = big_mont_mul(tmp, 19826557Sfr41279 tmp, tmp, n, n0)) != 19836557Sfr41279 BIG_OK) { 19846557Sfr41279 goto ret; 19856557Sfr41279 } 19866557Sfr41279 } 19876557Sfr41279 k = 0; 19886557Sfr41279 l = 0; 19896557Sfr41279 p = 0; 19906557Sfr41279 bitcount = 0; 19916557Sfr41279 } 19926557Sfr41279 } 19936557Sfr41279 } 19946557Sfr41279 bitind = BIG_CHUNK_SIZE; 19950Sstevel@tonic-gate } 19960Sstevel@tonic-gate 19976557Sfr41279 for (m = 0; m < k; m++) { 19986557Sfr41279 if ((err = big_mont_mul(tmp, tmp, tmp, n, n0)) != BIG_OK) { 19996557Sfr41279 goto ret; 20006557Sfr41279 } 20016557Sfr41279 } 20026557Sfr41279 if (p != 0) { 20036557Sfr41279 if ((err = big_mont_mul(tmp, tmp, 20046557Sfr41279 &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK) { 20056557Sfr41279 goto ret; 20066557Sfr41279 } 20076557Sfr41279 } 20086557Sfr41279 for (m = 0; m < l; m++) { 20096557Sfr41279 if ((err = big_mont_mul(result, tmp, tmp, n, n0)) != BIG_OK) { 20106557Sfr41279 goto ret; 20116557Sfr41279 } 20126557Sfr41279 } 20136557Sfr41279 20146557Sfr41279 ret: 20156557Sfr41279 for (i = apowerssize - 1; i >= 0; i--) { 20166557Sfr41279 big_finish(&(apowers[i])); 20170Sstevel@tonic-gate } 20186557Sfr41279 big_finish(&tmp1); 20196557Sfr41279 20206557Sfr41279 return (err); 20216557Sfr41279 } 20226557Sfr41279 20236557Sfr41279 20246557Sfr41279 #ifdef USE_FLOATING_POINT 20256557Sfr41279 20266557Sfr41279 #ifdef _KERNEL 20276557Sfr41279 20286557Sfr41279 #include <sys/sysmacros.h> 20296557Sfr41279 #include <sys/regset.h> 20306557Sfr41279 #include <sys/fpu/fpusystm.h> 20316557Sfr41279 20326557Sfr41279 /* the alignment for block stores to save fp registers */ 20336557Sfr41279 #define FPR_ALIGN (64) 20346557Sfr41279 20356557Sfr41279 extern void big_savefp(kfpu_t *); 20366557Sfr41279 extern void big_restorefp(kfpu_t *); 20376557Sfr41279 20386557Sfr41279 #endif /* _KERNEL */ 20396557Sfr41279 20406557Sfr41279 /* 20416557Sfr41279 * This version makes use of floating point for performance 20426557Sfr41279 */ 20436557Sfr41279 static BIG_ERR_CODE 20446557Sfr41279 big_modexp_ncp_float(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 20456557Sfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 20466557Sfr41279 { 20476557Sfr41279 20488933Sopensolaris@drydog.com int i, j, k, l, m, p; 20498933Sopensolaris@drydog.com uint32_t bit, bitind, bitcount, nlen; 20506557Sfr41279 double dn0; 20516557Sfr41279 double *dn, *dt, *d16r, *d32r; 20526557Sfr41279 uint32_t *nint, *prod; 20536557Sfr41279 double *apowers[APOWERS_MAX_SIZE]; 20548933Sopensolaris@drydog.com uint32_t nbits, groupbits, apowerssize; 20556557Sfr41279 BIG_ERR_CODE err = BIG_OK; 20566557Sfr41279 20576557Sfr41279 #ifdef _KERNEL 20586557Sfr41279 uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN]; 20596557Sfr41279 kfpu_t *fpu; 20606557Sfr41279 20616557Sfr41279 #ifdef DEBUG 20626557Sfr41279 if (!fpu_exists) 20636557Sfr41279 return (BIG_GENERAL_ERR); 20646557Sfr41279 #endif 20656557Sfr41279 20666557Sfr41279 fpu = (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN); 20676557Sfr41279 big_savefp(fpu); 20686557Sfr41279 20696557Sfr41279 #endif /* _KERNEL */ 20706557Sfr41279 20716557Sfr41279 nbits = big_numbits(e); 20726557Sfr41279 if (nbits < 50) { 20736557Sfr41279 groupbits = 1; 20746557Sfr41279 apowerssize = 1; 20756557Sfr41279 } else { 20766557Sfr41279 groupbits = MAX_EXP_BIT_GROUP_SIZE; 20776557Sfr41279 apowerssize = 1 << (groupbits - 1); 20786557Sfr41279 } 20796557Sfr41279 20806557Sfr41279 nlen = (BIG_CHUNK_SIZE / 32) * n->len; 20810Sstevel@tonic-gate dn0 = (double)(n0 & 0xffff); 20820Sstevel@tonic-gate 20830Sstevel@tonic-gate dn = dt = d16r = d32r = NULL; 20840Sstevel@tonic-gate nint = prod = NULL; 20850Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 20860Sstevel@tonic-gate apowers[i] = NULL; 20870Sstevel@tonic-gate } 20880Sstevel@tonic-gate 20890Sstevel@tonic-gate if ((dn = big_malloc(nlen * sizeof (double))) == NULL) { 20900Sstevel@tonic-gate err = BIG_NO_MEM; 20910Sstevel@tonic-gate goto ret; 20920Sstevel@tonic-gate } 20930Sstevel@tonic-gate if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) { 20940Sstevel@tonic-gate err = BIG_NO_MEM; 20950Sstevel@tonic-gate goto ret; 20960Sstevel@tonic-gate } 20970Sstevel@tonic-gate if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) { 20980Sstevel@tonic-gate err = BIG_NO_MEM; 20990Sstevel@tonic-gate goto ret; 21000Sstevel@tonic-gate } 21010Sstevel@tonic-gate if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) { 21020Sstevel@tonic-gate err = BIG_NO_MEM; 21030Sstevel@tonic-gate goto ret; 21040Sstevel@tonic-gate } 21050Sstevel@tonic-gate if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) { 21060Sstevel@tonic-gate err = BIG_NO_MEM; 21070Sstevel@tonic-gate goto ret; 21080Sstevel@tonic-gate } 21090Sstevel@tonic-gate if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) { 21100Sstevel@tonic-gate err = BIG_NO_MEM; 21110Sstevel@tonic-gate goto ret; 21120Sstevel@tonic-gate } 21130Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 21140Sstevel@tonic-gate if ((apowers[i] = big_malloc((2 * nlen + 1) * 21150Sstevel@tonic-gate sizeof (double))) == NULL) { 21160Sstevel@tonic-gate err = BIG_NO_MEM; 21170Sstevel@tonic-gate goto ret; 21180Sstevel@tonic-gate } 21190Sstevel@tonic-gate } 21200Sstevel@tonic-gate 21216557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 21226557Sfr41279 for (i = 0; i < ma->len; i++) { 21236557Sfr41279 nint[i] = ma->value[i]; 21246557Sfr41279 } 21256557Sfr41279 for (; i < nlen; i++) { 21266557Sfr41279 nint[i] = 0; 21276557Sfr41279 } 21286557Sfr41279 #else 21296557Sfr41279 for (i = 0; i < ma->len; i++) { 21306557Sfr41279 nint[2 * i] = (uint32_t)(ma->value[i] & 0xffffffffULL); 21316557Sfr41279 nint[2 * i + 1] = (uint32_t)(ma->value[i] >> 32); 21326557Sfr41279 } 21336557Sfr41279 for (i = ma->len * 2; i < nlen; i++) { 21346557Sfr41279 nint[i] = 0; 21356557Sfr41279 } 21366557Sfr41279 #endif 21370Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen); 21380Sstevel@tonic-gate 21396557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 21406557Sfr41279 for (i = 0; i < n->len; i++) { 21416557Sfr41279 nint[i] = n->value[i]; 21426557Sfr41279 } 21436557Sfr41279 for (; i < nlen; i++) { 21446557Sfr41279 nint[i] = 0; 21456557Sfr41279 } 21466557Sfr41279 #else 21476557Sfr41279 for (i = 0; i < n->len; i++) { 21486557Sfr41279 nint[2 * i] = (uint32_t)(n->value[i] & 0xffffffffULL); 21496557Sfr41279 nint[2 * i + 1] = (uint32_t)(n->value[i] >> 32); 21506557Sfr41279 } 21516557Sfr41279 for (i = n->len * 2; i < nlen; i++) { 21526557Sfr41279 nint[i] = 0; 21536557Sfr41279 } 21546557Sfr41279 #endif 21550Sstevel@tonic-gate conv_i32_to_d32(dn, nint, nlen); 21560Sstevel@tonic-gate 21570Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0); 21580Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 21590Sstevel@tonic-gate for (i = 1; i < apowerssize; i++) { 21600Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[i - 1], 21610Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21620Sstevel@tonic-gate conv_i32_to_d16(apowers[i], prod, nlen); 21630Sstevel@tonic-gate } 21640Sstevel@tonic-gate 21656557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 21666557Sfr41279 for (i = 0; i < tmp->len; i++) { 21676557Sfr41279 prod[i] = tmp->value[i]; 21686557Sfr41279 } 21696557Sfr41279 for (; i < nlen + 1; i++) { 21706557Sfr41279 prod[i] = 0; 21716557Sfr41279 } 21726557Sfr41279 #else 21736557Sfr41279 for (i = 0; i < tmp->len; i++) { 21746557Sfr41279 prod[2 * i] = (uint32_t)(tmp->value[i] & 0xffffffffULL); 21756557Sfr41279 prod[2 * i + 1] = (uint32_t)(tmp->value[i] >> 32); 21766557Sfr41279 } 21776557Sfr41279 for (i = tmp->len * 2; i < nlen + 1; i++) { 21786557Sfr41279 prod[i] = 0; 21796557Sfr41279 } 21806557Sfr41279 #endif 21816557Sfr41279 21826557Sfr41279 bitind = nbits % BIG_CHUNK_SIZE; 21830Sstevel@tonic-gate k = 0; 21840Sstevel@tonic-gate l = 0; 21850Sstevel@tonic-gate p = 0; 21860Sstevel@tonic-gate bitcount = 0; 21876557Sfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 21880Sstevel@tonic-gate for (j = bitind - 1; j >= 0; j--) { 21890Sstevel@tonic-gate bit = (e->value[i] >> j) & 1; 21900Sstevel@tonic-gate if ((bitcount == 0) && (bit == 0)) { 21910Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, 21920Sstevel@tonic-gate prod, nlen); 21930Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, 21940Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21950Sstevel@tonic-gate } else { 21960Sstevel@tonic-gate bitcount++; 21970Sstevel@tonic-gate p = p * 2 + bit; 21980Sstevel@tonic-gate if (bit == 1) { 21990Sstevel@tonic-gate k = k + l + 1; 22000Sstevel@tonic-gate l = 0; 22010Sstevel@tonic-gate } else { 22020Sstevel@tonic-gate l++; 22030Sstevel@tonic-gate } 22040Sstevel@tonic-gate if (bitcount == groupbits) { 22050Sstevel@tonic-gate for (m = 0; m < k; 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 conv_i32_to_d32(d32r, prod, nlen); 22130Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 22148933Sopensolaris@drydog.com apowers[p >> (l + 1)], 22150Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 22160Sstevel@tonic-gate for (m = 0; m < l; m++) { 22176557Sfr41279 conv_i32_to_d32_and_d16(d32r, 22186557Sfr41279 d16r, prod, nlen); 22190Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 22200Sstevel@tonic-gate d16r, dt, dn, nint, 22210Sstevel@tonic-gate nlen, dn0); 22220Sstevel@tonic-gate } 22230Sstevel@tonic-gate k = 0; 22240Sstevel@tonic-gate l = 0; 22250Sstevel@tonic-gate p = 0; 22260Sstevel@tonic-gate bitcount = 0; 22270Sstevel@tonic-gate } 22280Sstevel@tonic-gate } 22290Sstevel@tonic-gate } 22306557Sfr41279 bitind = BIG_CHUNK_SIZE; 22310Sstevel@tonic-gate } 22320Sstevel@tonic-gate 22330Sstevel@tonic-gate for (m = 0; m < k; m++) { 22340Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 22350Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 22360Sstevel@tonic-gate } 22370Sstevel@tonic-gate if (p != 0) { 22380Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 22390Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)], 22400Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 22410Sstevel@tonic-gate } 22420Sstevel@tonic-gate for (m = 0; m < l; m++) { 22430Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 22440Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 22450Sstevel@tonic-gate } 22460Sstevel@tonic-gate 22476557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 22486557Sfr41279 for (i = 0; i < nlen; i++) { 22496557Sfr41279 result->value[i] = prod[i]; 22506557Sfr41279 } 22516557Sfr41279 for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--) 22526557Sfr41279 ; 22536557Sfr41279 #else 22546557Sfr41279 for (i = 0; i < nlen / 2; i++) { 22556557Sfr41279 result->value[i] = (uint64_t)(prod[2 * i]) + 22566557Sfr41279 (((uint64_t)(prod[2 * i + 1])) << 32); 22576557Sfr41279 } 22586557Sfr41279 for (i = nlen / 2 - 1; (i > 0) && (result->value[i] == 0); i--) 22596557Sfr41279 ; 22606557Sfr41279 #endif 22616557Sfr41279 result->len = i + 1; 22626557Sfr41279 22630Sstevel@tonic-gate ret: 22640Sstevel@tonic-gate for (i = apowerssize - 1; i >= 0; i--) { 22650Sstevel@tonic-gate if (apowers[i] != NULL) 22660Sstevel@tonic-gate big_free(apowers[i], (2 * nlen + 1) * sizeof (double)); 22670Sstevel@tonic-gate } 22686557Sfr41279 if (d32r != NULL) { 22690Sstevel@tonic-gate big_free(d32r, nlen * sizeof (double)); 22706557Sfr41279 } 22716557Sfr41279 if (d16r != NULL) { 22720Sstevel@tonic-gate big_free(d16r, (2 * nlen + 1) * sizeof (double)); 22736557Sfr41279 } 22746557Sfr41279 if (prod != NULL) { 22750Sstevel@tonic-gate big_free(prod, (nlen + 1) * sizeof (uint32_t)); 22766557Sfr41279 } 22776557Sfr41279 if (nint != NULL) { 22780Sstevel@tonic-gate big_free(nint, nlen * sizeof (uint32_t)); 22796557Sfr41279 } 22806557Sfr41279 if (dt != NULL) { 22810Sstevel@tonic-gate big_free(dt, (4 * nlen + 2) * sizeof (double)); 22826557Sfr41279 } 22836557Sfr41279 if (dn != NULL) { 22840Sstevel@tonic-gate big_free(dn, nlen * sizeof (double)); 22856557Sfr41279 } 22860Sstevel@tonic-gate 22870Sstevel@tonic-gate #ifdef _KERNEL 22886557Sfr41279 big_restorefp(fpu); 22890Sstevel@tonic-gate #endif 22900Sstevel@tonic-gate 22910Sstevel@tonic-gate return (err); 22920Sstevel@tonic-gate } 22930Sstevel@tonic-gate 22940Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */ 22950Sstevel@tonic-gate 22960Sstevel@tonic-gate 22970Sstevel@tonic-gate BIG_ERR_CODE 22986557Sfr41279 big_modexp_ext(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr, 22996557Sfr41279 big_modexp_ncp_info_t *info) 23000Sstevel@tonic-gate { 23016557Sfr41279 BIGNUM ma, tmp, rr; 23026557Sfr41279 BIG_CHUNK_TYPE mavalue[BIGTMPSIZE]; 23036557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 23046557Sfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 23056557Sfr41279 BIG_ERR_CODE err; 23066557Sfr41279 BIG_CHUNK_TYPE n0; 23076557Sfr41279 23086557Sfr41279 if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue))) != 23096557Sfr41279 BIG_OK) { 23100Sstevel@tonic-gate return (err); 23116557Sfr41279 } 23126557Sfr41279 ma.len = 1; 23136557Sfr41279 ma.value[0] = 0; 23146557Sfr41279 23156557Sfr41279 if ((err = big_init1(&tmp, 2 * n->len + 1, 23166557Sfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 23170Sstevel@tonic-gate goto ret1; 23186557Sfr41279 } 23196557Sfr41279 23208933Sopensolaris@drydog.com /* clear the malloced bit to help cleanup */ 23216557Sfr41279 rr.malloced = 0; 23228933Sopensolaris@drydog.com 23236557Sfr41279 if (n_rr == NULL) { 23246557Sfr41279 if ((err = big_init1(&rr, 2 * n->len + 1, 23256557Sfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 23266557Sfr41279 goto ret2; 23276557Sfr41279 } 23286557Sfr41279 if (big_mont_rr(&rr, n) != BIG_OK) { 23296557Sfr41279 goto ret; 23306557Sfr41279 } 23316557Sfr41279 n_rr = &rr; 23326557Sfr41279 } 23336557Sfr41279 23346557Sfr41279 n0 = big_n0(n->value[0]); 23356557Sfr41279 23366557Sfr41279 if (big_cmp_abs(a, n) > 0) { 23376557Sfr41279 if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK) { 23386557Sfr41279 goto ret; 23396557Sfr41279 } 23406557Sfr41279 err = big_mont_conv(&ma, &ma, n, n0, n_rr); 23416557Sfr41279 } else { 23426557Sfr41279 err = big_mont_conv(&ma, a, n, n0, n_rr); 23436557Sfr41279 } 23446557Sfr41279 if (err != BIG_OK) { 23456557Sfr41279 goto ret; 23466557Sfr41279 } 23476557Sfr41279 23486557Sfr41279 tmp.len = 1; 23496557Sfr41279 tmp.value[0] = 1; 23506557Sfr41279 if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK) { 23516557Sfr41279 goto ret; 23526557Sfr41279 } 23536557Sfr41279 23546557Sfr41279 if ((info != NULL) && (info->func != NULL)) { 23556557Sfr41279 err = (*(info->func))(&tmp, &ma, e, n, &tmp, n0, 23566557Sfr41279 info->ncp, info->reqp); 23576557Sfr41279 } else { 23586557Sfr41279 err = big_modexp_ncp_sw(&tmp, &ma, e, n, &tmp, n0); 23596557Sfr41279 } 23606557Sfr41279 if (err != BIG_OK) { 23616557Sfr41279 goto ret; 23626557Sfr41279 } 23636557Sfr41279 23646557Sfr41279 ma.value[0] = 1; 23656557Sfr41279 ma.len = 1; 23666557Sfr41279 if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK) { 23676557Sfr41279 goto ret; 23686557Sfr41279 } 23696557Sfr41279 err = big_copy(result, &tmp); 23706557Sfr41279 23716557Sfr41279 ret: 23726557Sfr41279 if (rr.malloced) { 23736557Sfr41279 big_finish(&rr); 23746557Sfr41279 } 23756557Sfr41279 ret2: 23766557Sfr41279 big_finish(&tmp); 23776557Sfr41279 ret1: 23786557Sfr41279 big_finish(&ma); 23796557Sfr41279 23806557Sfr41279 return (err); 23816557Sfr41279 } 23826557Sfr41279 23836557Sfr41279 BIG_ERR_CODE 23846557Sfr41279 big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr) 23856557Sfr41279 { 23866557Sfr41279 return (big_modexp_ext(result, a, e, n, n_rr, NULL)); 23876557Sfr41279 } 23886557Sfr41279 23896557Sfr41279 23906557Sfr41279 BIG_ERR_CODE 23916557Sfr41279 big_modexp_crt_ext(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 23926557Sfr41279 BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 23936557Sfr41279 BIGNUM *p_rr, BIGNUM *q_rr, big_modexp_ncp_info_t *info) 23946557Sfr41279 { 23956557Sfr41279 BIGNUM ap, aq, tmp; 23966557Sfr41279 int alen, biglen, sign; 23976557Sfr41279 BIG_ERR_CODE err; 23986557Sfr41279 23996557Sfr41279 if (p->len > q->len) { 24006557Sfr41279 biglen = p->len; 24016557Sfr41279 } else { 24026557Sfr41279 biglen = q->len; 24036557Sfr41279 } 24046557Sfr41279 24056557Sfr41279 if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK) { 24066557Sfr41279 return (err); 24076557Sfr41279 } 24086557Sfr41279 if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK) { 24096557Sfr41279 goto ret1; 24106557Sfr41279 } 24116557Sfr41279 if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK) { 24120Sstevel@tonic-gate goto ret2; 24136557Sfr41279 } 24140Sstevel@tonic-gate 24150Sstevel@tonic-gate /* 24160Sstevel@tonic-gate * check whether a is too short - to avoid timing attacks 24170Sstevel@tonic-gate */ 24180Sstevel@tonic-gate alen = a->len; 24190Sstevel@tonic-gate while ((alen > p->len) && (a->value[alen - 1] == 0)) { 24200Sstevel@tonic-gate alen--; 24210Sstevel@tonic-gate } 24220Sstevel@tonic-gate if (alen < p->len + q->len) { 24230Sstevel@tonic-gate /* 24240Sstevel@tonic-gate * a is too short, add p*q to it before 24250Sstevel@tonic-gate * taking it modulo p and q 24260Sstevel@tonic-gate * this will also affect timing, but this difference 24270Sstevel@tonic-gate * does not depend on p or q, only on a 24280Sstevel@tonic-gate * (in "normal" operation, this path will never be 24290Sstevel@tonic-gate * taken, so it is not a performance penalty 24300Sstevel@tonic-gate */ 24316557Sfr41279 if ((err = big_mul(&tmp, p, q)) != BIG_OK) { 24320Sstevel@tonic-gate goto ret; 24336557Sfr41279 } 24346557Sfr41279 if ((err = big_add(&tmp, &tmp, a)) != BIG_OK) { 24356557Sfr41279 goto ret; 24366557Sfr41279 } 24376557Sfr41279 if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK) { 24380Sstevel@tonic-gate goto ret; 24396557Sfr41279 } 24406557Sfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 24410Sstevel@tonic-gate goto ret; 24426557Sfr41279 } 24436557Sfr41279 } else { 24446557Sfr41279 if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK) { 24450Sstevel@tonic-gate goto ret; 24466557Sfr41279 } 24476557Sfr41279 if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK) { 24480Sstevel@tonic-gate goto ret; 24496557Sfr41279 } 24500Sstevel@tonic-gate } 24510Sstevel@tonic-gate 24526557Sfr41279 if ((err = big_modexp_ext(&ap, &ap, dmodpminus1, p, p_rr, info)) != 24536557Sfr41279 BIG_OK) { 24540Sstevel@tonic-gate goto ret; 24556557Sfr41279 } 24566557Sfr41279 if ((err = big_modexp_ext(&aq, &aq, dmodqminus1, q, q_rr, info)) != 24576557Sfr41279 BIG_OK) { 24580Sstevel@tonic-gate goto ret; 24596557Sfr41279 } 24606557Sfr41279 if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK) { 24610Sstevel@tonic-gate goto ret; 24626557Sfr41279 } 24636557Sfr41279 if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK) { 24640Sstevel@tonic-gate goto ret; 24656557Sfr41279 } 24660Sstevel@tonic-gate sign = tmp.sign; 24670Sstevel@tonic-gate tmp.sign = 1; 24686557Sfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 24690Sstevel@tonic-gate goto ret; 24706557Sfr41279 } 24710Sstevel@tonic-gate if ((sign == -1) && (!big_is_zero(&aq))) { 24720Sstevel@tonic-gate (void) big_sub_pos(&aq, q, &aq); 24730Sstevel@tonic-gate } 24746557Sfr41279 if ((err = big_mul(&tmp, &aq, p)) != BIG_OK) { 24750Sstevel@tonic-gate goto ret; 24766557Sfr41279 } 24770Sstevel@tonic-gate err = big_add_abs(result, &ap, &tmp); 24780Sstevel@tonic-gate 24790Sstevel@tonic-gate ret: 24800Sstevel@tonic-gate big_finish(&tmp); 24810Sstevel@tonic-gate ret2: 24820Sstevel@tonic-gate big_finish(&aq); 24830Sstevel@tonic-gate ret1: 24840Sstevel@tonic-gate big_finish(&ap); 24850Sstevel@tonic-gate 24860Sstevel@tonic-gate return (err); 24870Sstevel@tonic-gate } 24880Sstevel@tonic-gate 24890Sstevel@tonic-gate 24906557Sfr41279 BIG_ERR_CODE 24916557Sfr41279 big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 24926557Sfr41279 BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 24936557Sfr41279 BIGNUM *p_rr, BIGNUM *q_rr) 24946557Sfr41279 { 24956557Sfr41279 return (big_modexp_crt_ext(result, a, dmodpminus1, dmodqminus1, 24966557Sfr41279 p, q, pinvmodq, p_rr, q_rr, NULL)); 24976557Sfr41279 } 24986557Sfr41279 24996557Sfr41279 25006557Sfr41279 static BIG_CHUNK_TYPE onearr[1] = {(BIG_CHUNK_TYPE)1}; 25016557Sfr41279 BIGNUM big_One = {1, 1, 1, 0, onearr}; 25026557Sfr41279 25036557Sfr41279 static BIG_CHUNK_TYPE twoarr[1] = {(BIG_CHUNK_TYPE)2}; 25046557Sfr41279 BIGNUM big_Two = {1, 1, 1, 0, twoarr}; 25056557Sfr41279 25066557Sfr41279 static BIG_CHUNK_TYPE fourarr[1] = {(BIG_CHUNK_TYPE)4}; 25076557Sfr41279 static BIGNUM big_Four = {1, 1, 1, 0, fourarr}; 25086557Sfr41279 25090Sstevel@tonic-gate 25100Sstevel@tonic-gate BIG_ERR_CODE 25110Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n) 25120Sstevel@tonic-gate { 25136557Sfr41279 BIGNUM *high, *low, *mid, *t; 25146557Sfr41279 BIGNUM t1, t2, t3, prod; 25156557Sfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 25166557Sfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 25176557Sfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 25186557Sfr41279 BIG_CHUNK_TYPE prodvalue[BIGTMPSIZE]; 25198933Sopensolaris@drydog.com int i, diff; 25208933Sopensolaris@drydog.com uint32_t nbits, nrootbits, highbits; 25216557Sfr41279 BIG_ERR_CODE err; 25220Sstevel@tonic-gate 25230Sstevel@tonic-gate nbits = big_numbits(n); 25240Sstevel@tonic-gate 25250Sstevel@tonic-gate if ((err = big_init1(&t1, n->len + 1, 25260Sstevel@tonic-gate t1value, arraysize(t1value))) != BIG_OK) 25270Sstevel@tonic-gate return (err); 25280Sstevel@tonic-gate if ((err = big_init1(&t2, n->len + 1, 25290Sstevel@tonic-gate t2value, arraysize(t2value))) != BIG_OK) 25300Sstevel@tonic-gate goto ret1; 25310Sstevel@tonic-gate if ((err = big_init1(&t3, n->len + 1, 25320Sstevel@tonic-gate t3value, arraysize(t3value))) != BIG_OK) 25330Sstevel@tonic-gate goto ret2; 25340Sstevel@tonic-gate if ((err = big_init1(&prod, n->len + 1, 25350Sstevel@tonic-gate prodvalue, arraysize(prodvalue))) != BIG_OK) 25360Sstevel@tonic-gate goto ret3; 25370Sstevel@tonic-gate 25380Sstevel@tonic-gate nrootbits = (nbits + 1) / 2; 25396557Sfr41279 t1.len = t2.len = t3.len = (nrootbits - 1) / BIG_CHUNK_SIZE + 1; 25400Sstevel@tonic-gate for (i = 0; i < t1.len; i++) { 25410Sstevel@tonic-gate t1.value[i] = 0; 25426557Sfr41279 t2.value[i] = BIG_CHUNK_ALLBITS; 25430Sstevel@tonic-gate } 25446557Sfr41279 highbits = nrootbits - BIG_CHUNK_SIZE * (t1.len - 1); 25456557Sfr41279 if (highbits == BIG_CHUNK_SIZE) { 25466557Sfr41279 t1.value[t1.len - 1] = BIG_CHUNK_HIGHBIT; 25476557Sfr41279 t2.value[t2.len - 1] = BIG_CHUNK_ALLBITS; 25480Sstevel@tonic-gate } else { 25496557Sfr41279 t1.value[t1.len - 1] = (BIG_CHUNK_TYPE)1 << (highbits - 1); 25500Sstevel@tonic-gate t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1; 25510Sstevel@tonic-gate } 25526557Sfr41279 25530Sstevel@tonic-gate high = &t2; 25540Sstevel@tonic-gate low = &t1; 25550Sstevel@tonic-gate mid = &t3; 25560Sstevel@tonic-gate 25576557Sfr41279 if ((err = big_mul(&prod, high, high)) != BIG_OK) { 25580Sstevel@tonic-gate goto ret; 25596557Sfr41279 } 25600Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 25610Sstevel@tonic-gate if (diff <= 0) { 25620Sstevel@tonic-gate err = big_copy(result, high); 25630Sstevel@tonic-gate goto ret; 25640Sstevel@tonic-gate } 25650Sstevel@tonic-gate 25660Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 25676557Sfr41279 while (big_cmp_abs(&big_One, mid) != 0) { 25680Sstevel@tonic-gate (void) big_add_abs(mid, high, low); 25690Sstevel@tonic-gate (void) big_half_pos(mid, mid); 25700Sstevel@tonic-gate if ((err = big_mul(&prod, mid, mid)) != BIG_OK) 25710Sstevel@tonic-gate goto ret; 25720Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 25730Sstevel@tonic-gate if (diff > 0) { 25740Sstevel@tonic-gate t = high; 25750Sstevel@tonic-gate high = mid; 25760Sstevel@tonic-gate mid = t; 25770Sstevel@tonic-gate } else if (diff < 0) { 25780Sstevel@tonic-gate t = low; 25790Sstevel@tonic-gate low = mid; 25800Sstevel@tonic-gate mid = t; 25810Sstevel@tonic-gate } else { 25820Sstevel@tonic-gate err = big_copy(result, low); 25830Sstevel@tonic-gate goto ret; 25840Sstevel@tonic-gate } 25850Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 25860Sstevel@tonic-gate } 25870Sstevel@tonic-gate 25880Sstevel@tonic-gate err = big_copy(result, low); 25890Sstevel@tonic-gate ret: 25900Sstevel@tonic-gate if (prod.malloced) big_finish(&prod); 25910Sstevel@tonic-gate ret3: 25920Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 25930Sstevel@tonic-gate ret2: 25940Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 25950Sstevel@tonic-gate ret1: 25960Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 25970Sstevel@tonic-gate 25980Sstevel@tonic-gate return (err); 25990Sstevel@tonic-gate } 26000Sstevel@tonic-gate 26010Sstevel@tonic-gate 26020Sstevel@tonic-gate BIG_ERR_CODE 26030Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm) 26040Sstevel@tonic-gate { 26056557Sfr41279 BIGNUM *t, *tmp2, *m, *n; 26066557Sfr41279 BIGNUM t1, t2, t3; 26076557Sfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 26086557Sfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 26096557Sfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 26106557Sfr41279 int len, err; 26110Sstevel@tonic-gate 26120Sstevel@tonic-gate if (big_is_zero(nn) || 26130Sstevel@tonic-gate (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) { 26140Sstevel@tonic-gate *jac = 0; 26150Sstevel@tonic-gate return (BIG_OK); 26160Sstevel@tonic-gate } 26170Sstevel@tonic-gate 26186557Sfr41279 if (nn->len > mm->len) { 26196557Sfr41279 len = nn->len; 26206557Sfr41279 } else { 26216557Sfr41279 len = mm->len; 26226557Sfr41279 } 26230Sstevel@tonic-gate 26240Sstevel@tonic-gate if ((err = big_init1(&t1, len, 26256557Sfr41279 t1value, arraysize(t1value))) != BIG_OK) { 26260Sstevel@tonic-gate return (err); 26276557Sfr41279 } 26280Sstevel@tonic-gate if ((err = big_init1(&t2, len, 26296557Sfr41279 t2value, arraysize(t2value))) != BIG_OK) { 26300Sstevel@tonic-gate goto ret1; 26316557Sfr41279 } 26320Sstevel@tonic-gate if ((err = big_init1(&t3, len, 26336557Sfr41279 t3value, arraysize(t3value))) != BIG_OK) { 26340Sstevel@tonic-gate goto ret2; 26356557Sfr41279 } 26360Sstevel@tonic-gate 26370Sstevel@tonic-gate n = &t1; 26380Sstevel@tonic-gate m = &t2; 26390Sstevel@tonic-gate tmp2 = &t3; 26400Sstevel@tonic-gate 26410Sstevel@tonic-gate (void) big_copy(n, nn); 26420Sstevel@tonic-gate (void) big_copy(m, mm); 26430Sstevel@tonic-gate 26440Sstevel@tonic-gate *jac = 1; 26456557Sfr41279 while (big_cmp_abs(&big_One, m) != 0) { 26460Sstevel@tonic-gate if (big_is_zero(n)) { 26470Sstevel@tonic-gate *jac = 0; 26480Sstevel@tonic-gate goto ret; 26490Sstevel@tonic-gate } 26500Sstevel@tonic-gate if ((m->value[0] & 1) == 0) { 26510Sstevel@tonic-gate if (((n->value[0] & 7) == 3) || 26526557Sfr41279 ((n->value[0] & 7) == 5)) 26536557Sfr41279 *jac = -*jac; 26540Sstevel@tonic-gate (void) big_half_pos(m, m); 26550Sstevel@tonic-gate } else if ((n->value[0] & 1) == 0) { 26560Sstevel@tonic-gate if (((m->value[0] & 7) == 3) || 26576557Sfr41279 ((m->value[0] & 7) == 5)) 26586557Sfr41279 *jac = -*jac; 26590Sstevel@tonic-gate (void) big_half_pos(n, n); 26600Sstevel@tonic-gate } else { 26610Sstevel@tonic-gate if (((m->value[0] & 3) == 3) && 26620Sstevel@tonic-gate ((n->value[0] & 3) == 3)) { 26630Sstevel@tonic-gate *jac = -*jac; 26640Sstevel@tonic-gate } 26656557Sfr41279 if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK) { 26660Sstevel@tonic-gate goto ret; 26676557Sfr41279 } 26680Sstevel@tonic-gate t = tmp2; 26690Sstevel@tonic-gate tmp2 = m; 26700Sstevel@tonic-gate m = n; 26710Sstevel@tonic-gate n = t; 26720Sstevel@tonic-gate } 26730Sstevel@tonic-gate } 26740Sstevel@tonic-gate err = BIG_OK; 26750Sstevel@tonic-gate 26760Sstevel@tonic-gate ret: 26770Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 26780Sstevel@tonic-gate ret2: 26790Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 26800Sstevel@tonic-gate ret1: 26810Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 26820Sstevel@tonic-gate 26830Sstevel@tonic-gate return (err); 26840Sstevel@tonic-gate } 26850Sstevel@tonic-gate 26860Sstevel@tonic-gate 26870Sstevel@tonic-gate BIG_ERR_CODE 26880Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n) 26890Sstevel@tonic-gate { 26908933Sopensolaris@drydog.com int i; 26918933Sopensolaris@drydog.com uint32_t m, w; 26926557Sfr41279 BIG_CHUNK_TYPE bit; 26936557Sfr41279 BIGNUM ki, tmp, tmp2; 26946557Sfr41279 BIG_CHUNK_TYPE kivalue[BIGTMPSIZE]; 26956557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 26966557Sfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 26976557Sfr41279 BIG_ERR_CODE err; 26986557Sfr41279 26996557Sfr41279 if (big_cmp_abs(k, &big_One) == 0) { 27000Sstevel@tonic-gate (void) big_copy(Lk, p); 27016557Sfr41279 (void) big_copy(Lkminus1, &big_Two); 27020Sstevel@tonic-gate return (BIG_OK); 27030Sstevel@tonic-gate } 27040Sstevel@tonic-gate 27050Sstevel@tonic-gate if ((err = big_init1(&ki, k->len + 1, 27060Sstevel@tonic-gate kivalue, arraysize(kivalue))) != BIG_OK) 27070Sstevel@tonic-gate return (err); 27080Sstevel@tonic-gate 27098933Sopensolaris@drydog.com if ((err = big_init1(&tmp, 2 * n->len + 1, 27100Sstevel@tonic-gate tmpvalue, arraysize(tmpvalue))) != BIG_OK) 27110Sstevel@tonic-gate goto ret1; 27120Sstevel@tonic-gate 27130Sstevel@tonic-gate if ((err = big_init1(&tmp2, n->len, 27140Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 27150Sstevel@tonic-gate goto ret2; 27160Sstevel@tonic-gate 27170Sstevel@tonic-gate m = big_numbits(k); 27186557Sfr41279 ki.len = (m - 1) / BIG_CHUNK_SIZE + 1; 27196557Sfr41279 w = (m - 1) / BIG_CHUNK_SIZE; 27206557Sfr41279 bit = (BIG_CHUNK_TYPE)1 << ((m - 1) % BIG_CHUNK_SIZE); 27216557Sfr41279 for (i = 0; i < ki.len; i++) { 27226557Sfr41279 ki.value[i] = 0; 27236557Sfr41279 } 27240Sstevel@tonic-gate ki.value[ki.len - 1] = bit; 27256557Sfr41279 if (big_cmp_abs(k, &ki) != 0) { 27260Sstevel@tonic-gate (void) big_double(&ki, &ki); 27276557Sfr41279 } 27280Sstevel@tonic-gate (void) big_sub_pos(&ki, &ki, k); 27290Sstevel@tonic-gate 27300Sstevel@tonic-gate (void) big_copy(Lk, p); 27316557Sfr41279 (void) big_copy(Lkminus1, &big_Two); 27320Sstevel@tonic-gate 27330Sstevel@tonic-gate for (i = 0; i < m; i++) { 27346557Sfr41279 if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK) { 27350Sstevel@tonic-gate goto ret; 27366557Sfr41279 } 27370Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 27380Sstevel@tonic-gate (void) big_sub_pos(&tmp, &tmp, p); 27396557Sfr41279 if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK) { 27400Sstevel@tonic-gate goto ret; 27416557Sfr41279 } 27420Sstevel@tonic-gate if ((ki.value[w] & bit) != 0) { 27430Sstevel@tonic-gate if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) != 27446557Sfr41279 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); 27490Sstevel@tonic-gate if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) != 27506557Sfr41279 BIG_OK) { 27510Sstevel@tonic-gate goto ret; 27526557Sfr41279 } 27530Sstevel@tonic-gate (void) big_copy(Lk, &tmp2); 27540Sstevel@tonic-gate } else { 27556557Sfr41279 if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK) { 27560Sstevel@tonic-gate goto ret; 27576557Sfr41279 } 27580Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 27596557Sfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Two); 27606557Sfr41279 if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK) { 27610Sstevel@tonic-gate goto ret; 27626557Sfr41279 } 27630Sstevel@tonic-gate (void) big_copy(Lkminus1, &tmp2); 27640Sstevel@tonic-gate } 27650Sstevel@tonic-gate bit = bit >> 1; 27660Sstevel@tonic-gate if (bit == 0) { 27676557Sfr41279 bit = BIG_CHUNK_HIGHBIT; 27680Sstevel@tonic-gate w--; 27690Sstevel@tonic-gate } 27700Sstevel@tonic-gate } 27710Sstevel@tonic-gate 27720Sstevel@tonic-gate err = BIG_OK; 27730Sstevel@tonic-gate 27740Sstevel@tonic-gate ret: 27750Sstevel@tonic-gate if (tmp2.malloced) big_finish(&tmp2); 27760Sstevel@tonic-gate ret2: 27770Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 27780Sstevel@tonic-gate ret1: 27790Sstevel@tonic-gate if (ki.malloced) big_finish(&ki); 27800Sstevel@tonic-gate 27810Sstevel@tonic-gate return (err); 27820Sstevel@tonic-gate } 27830Sstevel@tonic-gate 27840Sstevel@tonic-gate 27850Sstevel@tonic-gate BIG_ERR_CODE 27866557Sfr41279 big_isprime_pos_ext(BIGNUM *n, big_modexp_ncp_info_t *info) 27870Sstevel@tonic-gate { 27886557Sfr41279 BIGNUM o, nminus1, tmp, Lkminus1, Lk; 27896557Sfr41279 BIG_CHUNK_TYPE ovalue[BIGTMPSIZE]; 27906557Sfr41279 BIG_CHUNK_TYPE nminus1value[BIGTMPSIZE]; 27916557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 27926557Sfr41279 BIG_CHUNK_TYPE Lkminus1value[BIGTMPSIZE]; 27936557Sfr41279 BIG_CHUNK_TYPE Lkvalue[BIGTMPSIZE]; 27946557Sfr41279 BIG_ERR_CODE err; 27956557Sfr41279 int e, i, jac; 27966557Sfr41279 27976557Sfr41279 if (big_cmp_abs(n, &big_One) == 0) { 27980Sstevel@tonic-gate return (BIG_FALSE); 27996557Sfr41279 } 28006557Sfr41279 if (big_cmp_abs(n, &big_Two) == 0) { 28010Sstevel@tonic-gate return (BIG_TRUE); 28026557Sfr41279 } 28036557Sfr41279 if ((n->value[0] & 1) == 0) { 28040Sstevel@tonic-gate return (BIG_FALSE); 28056557Sfr41279 } 28066557Sfr41279 28076557Sfr41279 if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) != 28086557Sfr41279 BIG_OK) { 28090Sstevel@tonic-gate return (err); 28106557Sfr41279 } 28110Sstevel@tonic-gate 28120Sstevel@tonic-gate if ((err = big_init1(&nminus1, n->len, 28136557Sfr41279 nminus1value, arraysize(nminus1value))) != BIG_OK) { 28140Sstevel@tonic-gate goto ret1; 28156557Sfr41279 } 28160Sstevel@tonic-gate 28170Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * n->len, 28186557Sfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 28190Sstevel@tonic-gate goto ret2; 28206557Sfr41279 } 28210Sstevel@tonic-gate 28220Sstevel@tonic-gate if ((err = big_init1(&Lkminus1, n->len, 28236557Sfr41279 Lkminus1value, arraysize(Lkminus1value))) != BIG_OK) { 28240Sstevel@tonic-gate goto ret3; 28256557Sfr41279 } 28260Sstevel@tonic-gate 28270Sstevel@tonic-gate if ((err = big_init1(&Lk, n->len, 28286557Sfr41279 Lkvalue, arraysize(Lkvalue))) != BIG_OK) { 28290Sstevel@tonic-gate goto ret4; 28306557Sfr41279 } 28316557Sfr41279 28328933Sopensolaris@drydog.com (void) big_sub_pos(&o, n, &big_One); /* cannot fail */ 28330Sstevel@tonic-gate (void) big_copy(&nminus1, &o); /* cannot fail */ 28340Sstevel@tonic-gate e = 0; 28350Sstevel@tonic-gate while ((o.value[0] & 1) == 0) { 28360Sstevel@tonic-gate e++; 28370Sstevel@tonic-gate (void) big_half_pos(&o, &o); /* cannot fail */ 28380Sstevel@tonic-gate } 28396557Sfr41279 if ((err = big_modexp_ext(&tmp, &big_Two, &o, n, NULL, info)) != 28406557Sfr41279 BIG_OK) { 28410Sstevel@tonic-gate goto ret; 28426557Sfr41279 } 28436557Sfr41279 28440Sstevel@tonic-gate i = 0; 28450Sstevel@tonic-gate while ((i < e) && 28466557Sfr41279 (big_cmp_abs(&tmp, &big_One) != 0) && 28470Sstevel@tonic-gate (big_cmp_abs(&tmp, &nminus1) != 0)) { 28486557Sfr41279 if ((err = 28496557Sfr41279 big_modexp_ext(&tmp, &tmp, &big_Two, n, NULL, info)) != 28506557Sfr41279 BIG_OK) 28510Sstevel@tonic-gate goto ret; 28520Sstevel@tonic-gate i++; 28530Sstevel@tonic-gate } 28546557Sfr41279 28550Sstevel@tonic-gate if (!((big_cmp_abs(&tmp, &nminus1) == 0) || 28566557Sfr41279 ((i == 0) && (big_cmp_abs(&tmp, &big_One) == 0)))) { 28570Sstevel@tonic-gate err = BIG_FALSE; 28580Sstevel@tonic-gate goto ret; 28590Sstevel@tonic-gate } 28600Sstevel@tonic-gate 28616557Sfr41279 if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK) { 28620Sstevel@tonic-gate goto ret; 28636557Sfr41279 } 28646557Sfr41279 28656557Sfr41279 if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK) { 28660Sstevel@tonic-gate goto ret; 28676557Sfr41279 } 28680Sstevel@tonic-gate if (big_cmp_abs(&tmp, n) == 0) { 28690Sstevel@tonic-gate err = BIG_FALSE; 28700Sstevel@tonic-gate goto ret; 28710Sstevel@tonic-gate } 28720Sstevel@tonic-gate 28736557Sfr41279 (void) big_copy(&o, &big_Two); 28740Sstevel@tonic-gate do { 28756557Sfr41279 (void) big_add_abs(&o, &o, &big_One); 28766557Sfr41279 if ((err = big_mul(&tmp, &o, &o)) != BIG_OK) { 28770Sstevel@tonic-gate goto ret; 28786557Sfr41279 } 28796557Sfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Four); 28806557Sfr41279 if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK) { 28810Sstevel@tonic-gate goto ret; 28826557Sfr41279 } 28830Sstevel@tonic-gate } while (jac != -1); 28840Sstevel@tonic-gate 28856557Sfr41279 (void) big_add_abs(&tmp, n, &big_One); 28866557Sfr41279 if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK) { 28870Sstevel@tonic-gate goto ret; 28886557Sfr41279 } 28896557Sfr41279 28906557Sfr41279 if ((big_cmp_abs(&Lkminus1, &o) == 0) && 28916557Sfr41279 (big_cmp_abs(&Lk, &big_Two) == 0)) { 28920Sstevel@tonic-gate err = BIG_TRUE; 28936557Sfr41279 } else { 28946557Sfr41279 err = BIG_FALSE; 28956557Sfr41279 } 28960Sstevel@tonic-gate 28970Sstevel@tonic-gate ret: 28980Sstevel@tonic-gate if (Lk.malloced) big_finish(&Lk); 28990Sstevel@tonic-gate ret4: 29000Sstevel@tonic-gate if (Lkminus1.malloced) big_finish(&Lkminus1); 29010Sstevel@tonic-gate ret3: 29020Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 29030Sstevel@tonic-gate ret2: 29040Sstevel@tonic-gate if (nminus1.malloced) big_finish(&nminus1); 29050Sstevel@tonic-gate ret1: 29060Sstevel@tonic-gate if (o.malloced) big_finish(&o); 29070Sstevel@tonic-gate 29080Sstevel@tonic-gate return (err); 29090Sstevel@tonic-gate } 29100Sstevel@tonic-gate 29110Sstevel@tonic-gate 29126557Sfr41279 BIG_ERR_CODE 29136557Sfr41279 big_isprime_pos(BIGNUM *n) 29146557Sfr41279 { 29156557Sfr41279 return (big_isprime_pos_ext(n, NULL)); 29166557Sfr41279 } 29176557Sfr41279 29186557Sfr41279 29190Sstevel@tonic-gate #define SIEVESIZE 1000 29200Sstevel@tonic-gate 29210Sstevel@tonic-gate 29220Sstevel@tonic-gate BIG_ERR_CODE 29236557Sfr41279 big_nextprime_pos_ext(BIGNUM *result, BIGNUM *n, big_modexp_ncp_info_t *info) 29240Sstevel@tonic-gate { 29258933Sopensolaris@drydog.com static const uint32_t smallprimes[] = { 29268933Sopensolaris@drydog.com 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 29278933Sopensolaris@drydog.com 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97 }; 29286557Sfr41279 BIG_ERR_CODE err; 29296557Sfr41279 int sieve[SIEVESIZE]; 29306557Sfr41279 int i; 29316557Sfr41279 uint32_t off, p; 29326557Sfr41279 29336557Sfr41279 if ((err = big_copy(result, n)) != BIG_OK) { 29340Sstevel@tonic-gate return (err); 29356557Sfr41279 } 29360Sstevel@tonic-gate result->value[0] |= 1; 29371027Srobinson /* CONSTCOND */ 29380Sstevel@tonic-gate while (1) { 29390Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0; 29400Sstevel@tonic-gate for (i = 0; 29416557Sfr41279 i < sizeof (smallprimes) / sizeof (smallprimes[0]); i++) { 29420Sstevel@tonic-gate p = smallprimes[i]; 29436557Sfr41279 off = big_modhalf_pos(result, p); 29440Sstevel@tonic-gate off = p - off; 29456557Sfr41279 if ((off % 2) == 1) { 29466557Sfr41279 off = off + p; 29476557Sfr41279 } 29486557Sfr41279 off = off / 2; 29490Sstevel@tonic-gate while (off < SIEVESIZE) { 29500Sstevel@tonic-gate sieve[off] = 1; 29510Sstevel@tonic-gate off = off + p; 29520Sstevel@tonic-gate } 29530Sstevel@tonic-gate } 29540Sstevel@tonic-gate 29550Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) { 29560Sstevel@tonic-gate if (sieve[i] == 0) { 29576557Sfr41279 err = big_isprime_pos_ext(result, info); 29580Sstevel@tonic-gate if (err != BIG_FALSE) { 29596557Sfr41279 if (err != BIG_TRUE) { 29600Sstevel@tonic-gate return (err); 29616557Sfr41279 } else { 29626557Sfr41279 goto out; 29636557Sfr41279 } 29640Sstevel@tonic-gate } 29650Sstevel@tonic-gate 29660Sstevel@tonic-gate } 29676557Sfr41279 if ((err = big_add_abs(result, result, &big_Two)) != 29686557Sfr41279 BIG_OK) { 29690Sstevel@tonic-gate return (err); 29706557Sfr41279 } 29710Sstevel@tonic-gate } 29720Sstevel@tonic-gate } 29736557Sfr41279 29746557Sfr41279 out: 29756557Sfr41279 return (BIG_OK); 29766557Sfr41279 } 29776557Sfr41279 29786557Sfr41279 29796557Sfr41279 BIG_ERR_CODE 29806557Sfr41279 big_nextprime_pos(BIGNUM *result, BIGNUM *n) 29816557Sfr41279 { 29826557Sfr41279 return (big_nextprime_pos_ext(result, n, NULL)); 29830Sstevel@tonic-gate } 29840Sstevel@tonic-gate 29850Sstevel@tonic-gate 29860Sstevel@tonic-gate BIG_ERR_CODE 29870Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n) 29880Sstevel@tonic-gate { 29890Sstevel@tonic-gate BIG_ERR_CODE err; 29900Sstevel@tonic-gate 29910Sstevel@tonic-gate 29920Sstevel@tonic-gate if ((err = big_copy(result, n)) != BIG_OK) 29930Sstevel@tonic-gate return (err); 29940Sstevel@tonic-gate result->value[0] |= 1; 29956557Sfr41279 while ((err = big_isprime_pos_ext(result, NULL)) != BIG_TRUE) { 29960Sstevel@tonic-gate if (err != BIG_FALSE) 29970Sstevel@tonic-gate return (err); 29986557Sfr41279 if ((err = big_add_abs(result, result, &big_Two)) != BIG_OK) 29990Sstevel@tonic-gate return (err); 30000Sstevel@tonic-gate } 30010Sstevel@tonic-gate return (BIG_OK); 30020Sstevel@tonic-gate } 30030Sstevel@tonic-gate 30040Sstevel@tonic-gate 30050Sstevel@tonic-gate /* 30060Sstevel@tonic-gate * given m and e, computes the rest in the equation 30070Sstevel@tonic-gate * gcd(m, e) = cm * m + ce * e 30080Sstevel@tonic-gate */ 30090Sstevel@tonic-gate BIG_ERR_CODE 30100Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e) 30110Sstevel@tonic-gate { 30126557Sfr41279 BIGNUM *xi, *ri, *riminus1, *riminus2, *t; 30136557Sfr41279 BIGNUM *vmi, *vei, *vmiminus1, *veiminus1; 30146557Sfr41279 BIGNUM t1, t2, t3, t4, t5, t6, t7, t8, tmp; 30156557Sfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 30166557Sfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 30176557Sfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 30186557Sfr41279 BIG_CHUNK_TYPE t4value[BIGTMPSIZE]; 30196557Sfr41279 BIG_CHUNK_TYPE t5value[BIGTMPSIZE]; 30206557Sfr41279 BIG_CHUNK_TYPE t6value[BIGTMPSIZE]; 30216557Sfr41279 BIG_CHUNK_TYPE t7value[BIGTMPSIZE]; 30226557Sfr41279 BIG_CHUNK_TYPE t8value[BIGTMPSIZE]; 30236557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 30246557Sfr41279 BIG_ERR_CODE err; 30256557Sfr41279 int len; 30266557Sfr41279 30276557Sfr41279 if (big_cmp_abs(m, e) >= 0) { 30286557Sfr41279 len = m->len; 30296557Sfr41279 } else { 30306557Sfr41279 len = e->len; 30316557Sfr41279 } 30320Sstevel@tonic-gate 30330Sstevel@tonic-gate if ((err = big_init1(&t1, len, 30346557Sfr41279 t1value, arraysize(t1value))) != BIG_OK) { 30350Sstevel@tonic-gate return (err); 30366557Sfr41279 } 30370Sstevel@tonic-gate if ((err = big_init1(&t2, len, 30386557Sfr41279 t2value, arraysize(t2value))) != BIG_OK) { 30396557Sfr41279 goto ret1; 30406557Sfr41279 } 30410Sstevel@tonic-gate if ((err = big_init1(&t3, len, 30426557Sfr41279 t3value, arraysize(t3value))) != BIG_OK) { 30436557Sfr41279 goto ret2; 30446557Sfr41279 } 30450Sstevel@tonic-gate if ((err = big_init1(&t4, len, 30466557Sfr41279 t4value, arraysize(t3value))) != BIG_OK) { 30476557Sfr41279 goto ret3; 30486557Sfr41279 } 30490Sstevel@tonic-gate if ((err = big_init1(&t5, len, 30506557Sfr41279 t5value, arraysize(t5value))) != BIG_OK) { 30516557Sfr41279 goto ret4; 30526557Sfr41279 } 30530Sstevel@tonic-gate if ((err = big_init1(&t6, len, 30546557Sfr41279 t6value, arraysize(t6value))) != BIG_OK) { 30556557Sfr41279 goto ret5; 30566557Sfr41279 } 30570Sstevel@tonic-gate if ((err = big_init1(&t7, len, 30586557Sfr41279 t7value, arraysize(t7value))) != BIG_OK) { 30596557Sfr41279 goto ret6; 30606557Sfr41279 } 30610Sstevel@tonic-gate if ((err = big_init1(&t8, len, 30626557Sfr41279 t8value, arraysize(t8value))) != BIG_OK) { 30636557Sfr41279 goto ret7; 30646557Sfr41279 } 30650Sstevel@tonic-gate 30660Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * len, 30676557Sfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 30680Sstevel@tonic-gate goto ret8; 30696557Sfr41279 } 30700Sstevel@tonic-gate 30710Sstevel@tonic-gate ri = &t1; 30720Sstevel@tonic-gate ri->value[0] = 1; 30730Sstevel@tonic-gate ri->len = 1; 30740Sstevel@tonic-gate xi = &t2; 30750Sstevel@tonic-gate riminus1 = &t3; 30760Sstevel@tonic-gate riminus2 = &t4; 30770Sstevel@tonic-gate vmi = &t5; 30780Sstevel@tonic-gate vei = &t6; 30790Sstevel@tonic-gate vmiminus1 = &t7; 30800Sstevel@tonic-gate veiminus1 = &t8; 30810Sstevel@tonic-gate 30826557Sfr41279 (void) big_copy(vmiminus1, &big_One); 30836557Sfr41279 (void) big_copy(vmi, &big_One); 30846557Sfr41279 (void) big_copy(veiminus1, &big_One); 30856557Sfr41279 (void) big_copy(xi, &big_One); 30860Sstevel@tonic-gate vei->len = 1; 30870Sstevel@tonic-gate vei->value[0] = 0; 30880Sstevel@tonic-gate 30890Sstevel@tonic-gate (void) big_copy(riminus1, m); 30900Sstevel@tonic-gate (void) big_copy(ri, e); 30910Sstevel@tonic-gate 30920Sstevel@tonic-gate while (!big_is_zero(ri)) { 30930Sstevel@tonic-gate t = riminus2; 30940Sstevel@tonic-gate riminus2 = riminus1; 30950Sstevel@tonic-gate riminus1 = ri; 30960Sstevel@tonic-gate ri = t; 30976557Sfr41279 if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK) { 30980Sstevel@tonic-gate goto ret; 30996557Sfr41279 } 31006557Sfr41279 if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK) { 31010Sstevel@tonic-gate goto ret; 31026557Sfr41279 } 31030Sstevel@tonic-gate t = vmiminus1; 31040Sstevel@tonic-gate vmiminus1 = vmi; 31050Sstevel@tonic-gate vmi = t; 31066557Sfr41279 if ((err = big_mul(&tmp, vei, xi)) != BIG_OK) { 31070Sstevel@tonic-gate goto ret; 31086557Sfr41279 } 31096557Sfr41279 if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK) { 31100Sstevel@tonic-gate goto ret; 31116557Sfr41279 } 31120Sstevel@tonic-gate t = veiminus1; 31130Sstevel@tonic-gate veiminus1 = vei; 31140Sstevel@tonic-gate vei = t; 31156557Sfr41279 if ((err = big_div_pos(xi, ri, riminus2, riminus1)) != 31166557Sfr41279 BIG_OK) { 31170Sstevel@tonic-gate goto ret; 31186557Sfr41279 } 31190Sstevel@tonic-gate } 31206557Sfr41279 if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK)) { 31210Sstevel@tonic-gate goto ret; 31226557Sfr41279 } 31236557Sfr41279 if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK)) { 31240Sstevel@tonic-gate goto ret; 31256557Sfr41279 } 31266557Sfr41279 if (ce != NULL) { 31270Sstevel@tonic-gate err = big_copy(ce, vei); 31286557Sfr41279 } 31290Sstevel@tonic-gate ret: 31300Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 31310Sstevel@tonic-gate ret8: 31320Sstevel@tonic-gate if (t8.malloced) big_finish(&t8); 31330Sstevel@tonic-gate ret7: 31340Sstevel@tonic-gate if (t7.malloced) big_finish(&t7); 31350Sstevel@tonic-gate ret6: 31360Sstevel@tonic-gate if (t6.malloced) big_finish(&t6); 31370Sstevel@tonic-gate ret5: 31380Sstevel@tonic-gate if (t5.malloced) big_finish(&t5); 31390Sstevel@tonic-gate ret4: 31400Sstevel@tonic-gate if (t4.malloced) big_finish(&t4); 31410Sstevel@tonic-gate ret3: 31420Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 31430Sstevel@tonic-gate ret2: 31440Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 31450Sstevel@tonic-gate ret1: 31460Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 31470Sstevel@tonic-gate 31480Sstevel@tonic-gate return (err); 31490Sstevel@tonic-gate } 3150