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 5*6557Sfr41279 * Common Development and Distribution License (the "License"). 6*6557Sfr41279 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*6557Sfr41279 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #define big_div_pos_fast big_div_pos 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include "bignum.h" 310Sstevel@tonic-gate 320Sstevel@tonic-gate /* 330Sstevel@tonic-gate * Configuration guide 340Sstevel@tonic-gate * ------------------- 350Sstevel@tonic-gate * 360Sstevel@tonic-gate * There are 4 preprocessor symbols used to configure the bignum 370Sstevel@tonic-gate * implementation. This file contains no logic to configure based on 380Sstevel@tonic-gate * processor; we leave that to the Makefiles to specify. 390Sstevel@tonic-gate * 400Sstevel@tonic-gate * USE_FLOATING_POINT 410Sstevel@tonic-gate * Meaning: There is support for a fast floating-point implementation of 420Sstevel@tonic-gate * Montgomery multiply. 430Sstevel@tonic-gate * 440Sstevel@tonic-gate * PSR_MUL 450Sstevel@tonic-gate * Meaning: There are processor-specific versions of the low level 460Sstevel@tonic-gate * functions to implement big_mul. Those functions are: big_mul_set_vec, 470Sstevel@tonic-gate * big_mul_add_vec, big_mul_vec, and big_sqr_vec. PSR_MUL implies support 480Sstevel@tonic-gate * for all 4 functions. You cannot pick and choose which subset of these 490Sstevel@tonic-gate * functions to support; that would lead to a rat's nest of #ifdefs. 500Sstevel@tonic-gate * 510Sstevel@tonic-gate * HWCAP 520Sstevel@tonic-gate * Meaning: Call multiply support functions through a function pointer. 530Sstevel@tonic-gate * On x86, there are multiple implementations for differnt hardware 540Sstevel@tonic-gate * capabilities, such as MMX, SSE2, etc. Tests are made at run-time, when 550Sstevel@tonic-gate * a function is first used. So, the support functions are called through 560Sstevel@tonic-gate * a function pointer. There is no need for that on Sparc, because there 570Sstevel@tonic-gate * is only one implementation; support functions are called directly. 580Sstevel@tonic-gate * Later, if there were some new VIS instruction, or something, and a 590Sstevel@tonic-gate * run-time test were needed, rather than variant kernel modules and 600Sstevel@tonic-gate * libraries, then HWCAP would be defined for Sparc, as well. 610Sstevel@tonic-gate * 620Sstevel@tonic-gate * UMUL64 630Sstevel@tonic-gate * Meaning: It is safe to use generic C code that assumes the existence 640Sstevel@tonic-gate * of a 32 x 32 --> 64 bit unsigned multiply. If this is not defined, 650Sstevel@tonic-gate * then the generic code for big_mul_add_vec() must necessarily be very slow, 660Sstevel@tonic-gate * because it must fall back to using 16 x 16 --> 32 bit multiplication. 670Sstevel@tonic-gate * 680Sstevel@tonic-gate */ 690Sstevel@tonic-gate 700Sstevel@tonic-gate 710Sstevel@tonic-gate #ifdef _KERNEL 72*6557Sfr41279 #include <sys/ddi.h> 73*6557Sfr41279 #include <sys/mdesc.h> 74*6557Sfr41279 #include <sys/crypto/common.h> 750Sstevel@tonic-gate 760Sstevel@tonic-gate #include <sys/types.h> 770Sstevel@tonic-gate #include <sys/kmem.h> 780Sstevel@tonic-gate #include <sys/param.h> 790Sstevel@tonic-gate #include <sys/sunddi.h> 800Sstevel@tonic-gate 810Sstevel@tonic-gate #define big_malloc(size) kmem_alloc(size, KM_NOSLEEP) 820Sstevel@tonic-gate #define big_free(ptr, size) kmem_free(ptr, size) 830Sstevel@tonic-gate 840Sstevel@tonic-gate void * 850Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize) 860Sstevel@tonic-gate { 870Sstevel@tonic-gate void *rv; 880Sstevel@tonic-gate 890Sstevel@tonic-gate rv = kmem_alloc(newsize, KM_NOSLEEP); 900Sstevel@tonic-gate if (rv != NULL) 910Sstevel@tonic-gate bcopy(from, rv, oldsize); 920Sstevel@tonic-gate kmem_free(from, oldsize); 930Sstevel@tonic-gate return (rv); 940Sstevel@tonic-gate } 950Sstevel@tonic-gate 960Sstevel@tonic-gate #else /* _KERNEL */ 970Sstevel@tonic-gate 980Sstevel@tonic-gate #include <stdlib.h> 990Sstevel@tonic-gate #include <stdio.h> 100*6557Sfr41279 #include <assert.h> 101*6557Sfr41279 #define ASSERT assert 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate #ifndef MALLOC_DEBUG 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate #define big_malloc(size) malloc(size) 1060Sstevel@tonic-gate #define big_free(ptr, size) free(ptr) 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate #else 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate void 1110Sstevel@tonic-gate big_free(void *ptr, size_t size) 1120Sstevel@tonic-gate { 1130Sstevel@tonic-gate printf("freed %d bytes at %p\n", size, ptr); 1140Sstevel@tonic-gate free(ptr); 1150Sstevel@tonic-gate } 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate void * 1180Sstevel@tonic-gate big_malloc(size_t size) 1190Sstevel@tonic-gate { 1200Sstevel@tonic-gate void *rv; 1210Sstevel@tonic-gate rv = malloc(size); 1220Sstevel@tonic-gate printf("malloced %d bytes, addr:%p\n", size, rv); 1230Sstevel@tonic-gate return (rv); 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate #endif /* MALLOC_DEBUG */ 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate #define big_realloc(x, y, z) realloc((x), (z)) 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate void 1300Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a) 1310Sstevel@tonic-gate { 1320Sstevel@tonic-gate int i; 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate (void) printf("\n%s\n%d\n", aname, a->sign*a->len); 1350Sstevel@tonic-gate for (i = a->len - 1; i >= 0; i--) { 136*6557Sfr41279 #ifdef BIGNUM_CHUNK_32 1370Sstevel@tonic-gate (void) printf("%08x ", a->value[i]); 138*6557Sfr41279 if ((i % 8 == 0) && (i != 0)) { 139*6557Sfr41279 (void) printf("\n"); 140*6557Sfr41279 } 141*6557Sfr41279 #else 142*6557Sfr41279 (void) printf("%08x %08x ", (uint32_t)((a->value[i]) >> 32), 143*6557Sfr41279 (uint32_t)((a->value[i]) & 0xffffffff)); 144*6557Sfr41279 if ((i % 4 == 0) && (i != 0)) { 145*6557Sfr41279 (void) printf("\n"); 146*6557Sfr41279 } 147*6557Sfr41279 #endif 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate (void) printf("\n"); 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate #endif /* _KERNEL */ 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate 155*6557Sfr41279 /* size in BIG_CHUNK_SIZE-bit words */ 1560Sstevel@tonic-gate BIG_ERR_CODE 1570Sstevel@tonic-gate big_init(BIGNUM *number, int size) 1580Sstevel@tonic-gate { 159*6557Sfr41279 number->value = big_malloc(sizeof (BIG_CHUNK_TYPE) * size); 1600Sstevel@tonic-gate if (number->value == NULL) { 1610Sstevel@tonic-gate return (BIG_NO_MEM); 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate number->size = size; 1640Sstevel@tonic-gate number->len = 0; 1650Sstevel@tonic-gate number->sign = 1; 1660Sstevel@tonic-gate number->malloced = 1; 1670Sstevel@tonic-gate return (BIG_OK); 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate 170*6557Sfr41279 /* size in BIG_CHUNK_SIZE-bit words */ 1710Sstevel@tonic-gate BIG_ERR_CODE 172*6557Sfr41279 big_init1(BIGNUM *number, int size, BIG_CHUNK_TYPE *buf, int bufsize) 1730Sstevel@tonic-gate { 1740Sstevel@tonic-gate if ((buf == NULL) || (size > bufsize)) { 175*6557Sfr41279 number->value = big_malloc(sizeof (BIG_CHUNK_TYPE) * size); 1760Sstevel@tonic-gate if (number->value == NULL) { 1770Sstevel@tonic-gate return (BIG_NO_MEM); 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate number->size = size; 1800Sstevel@tonic-gate number->malloced = 1; 1810Sstevel@tonic-gate } else { 1820Sstevel@tonic-gate number->value = buf; 1830Sstevel@tonic-gate number->size = bufsize; 1840Sstevel@tonic-gate number->malloced = 0; 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate number->len = 0; 1870Sstevel@tonic-gate number->sign = 1; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate return (BIG_OK); 1900Sstevel@tonic-gate } 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate void 1930Sstevel@tonic-gate big_finish(BIGNUM *number) 1940Sstevel@tonic-gate { 1950Sstevel@tonic-gate if (number->malloced == 1) { 196*6557Sfr41279 big_free(number->value, 197*6557Sfr41279 sizeof (BIG_CHUNK_TYPE) * number->size); 1980Sstevel@tonic-gate number->malloced = 0; 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate 202*6557Sfr41279 2030Sstevel@tonic-gate /* 204*6557Sfr41279 * bn->size should be at least 205*6557Sfr41279 * (len + sizeof (BIG_CHUNK_TYPE) - 1) / sizeof (BIG_CHUNK_TYPE) bytes 2060Sstevel@tonic-gate * converts from byte-big-endian format to bignum format (words in 2070Sstevel@tonic-gate * little endian order, but bytes within the words big endian) 2080Sstevel@tonic-gate */ 2090Sstevel@tonic-gate void 2100Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len) 2110Sstevel@tonic-gate { 2120Sstevel@tonic-gate int i, j, offs; 213*6557Sfr41279 BIG_CHUNK_TYPE word; 2140Sstevel@tonic-gate uchar_t *knwordp; 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate #ifdef _LP64 217*6557Sfr41279 offs = (uint32_t)len % sizeof (BIG_CHUNK_TYPE); 218*6557Sfr41279 bn->len = (uint32_t)len / sizeof (BIG_CHUNK_TYPE); 219*6557Sfr41279 220*6557Sfr41279 for (i = 0; i < (uint32_t)len / sizeof (BIG_CHUNK_TYPE); i++) { 2210Sstevel@tonic-gate #else /* !_LP64 */ 222*6557Sfr41279 offs = len % sizeof (BIG_CHUNK_TYPE); 223*6557Sfr41279 bn->len = len / sizeof (BIG_CHUNK_TYPE); 224*6557Sfr41279 for (i = 0; i < len / sizeof (BIG_CHUNK_TYPE); i++) { 2250Sstevel@tonic-gate #endif /* _LP64 */ 226*6557Sfr41279 knwordp = &(kn[len - sizeof (BIG_CHUNK_TYPE) * (i + 1)]); 2270Sstevel@tonic-gate word = knwordp[0]; 228*6557Sfr41279 for (j = 1; j < sizeof (BIG_CHUNK_TYPE); j++) { 2290Sstevel@tonic-gate word = (word << 8)+ knwordp[j]; 2300Sstevel@tonic-gate } 2310Sstevel@tonic-gate bn->value[i] = word; 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate if (offs > 0) { 2340Sstevel@tonic-gate word = kn[0]; 2350Sstevel@tonic-gate for (i = 1; i < offs; i++) word = (word << 8) + kn[i]; 2360Sstevel@tonic-gate bn->value[bn->len++] = word; 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate while ((bn->len > 1) && (bn->value[bn->len-1] == 0)) { 2390Sstevel@tonic-gate bn->len --; 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate /* 2440Sstevel@tonic-gate * copies the least significant len bytes if 245*6557Sfr41279 * len < bn->len * sizeof (BIG_CHUNK_TYPE) 2460Sstevel@tonic-gate * converts from bignum format to byte-big-endian format. 247*6557Sfr41279 * bignum format is words of type BIG_CHUNK_TYPE in little endian order. 2480Sstevel@tonic-gate */ 2490Sstevel@tonic-gate void 2500Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len) 2510Sstevel@tonic-gate { 2520Sstevel@tonic-gate int i, j, offs; 253*6557Sfr41279 BIG_CHUNK_TYPE word; 254*6557Sfr41279 255*6557Sfr41279 if (len < sizeof (BIG_CHUNK_TYPE) * bn->len) { 2560Sstevel@tonic-gate #ifdef _LP64 257*6557Sfr41279 for (i = 0; i < (uint32_t)len / sizeof (BIG_CHUNK_TYPE); i++) { 2580Sstevel@tonic-gate #else /* !_LP64 */ 259*6557Sfr41279 for (i = 0; i < len / sizeof (BIG_CHUNK_TYPE); i++) { 2600Sstevel@tonic-gate #endif /* _LP64 */ 2610Sstevel@tonic-gate word = bn->value[i]; 262*6557Sfr41279 for (j = 0; j < sizeof (BIG_CHUNK_TYPE); j++) { 263*6557Sfr41279 kn[len - sizeof (BIG_CHUNK_TYPE) * i - j - 1] = 2640Sstevel@tonic-gate word & 0xff; 2650Sstevel@tonic-gate word = word >> 8; 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate #ifdef _LP64 269*6557Sfr41279 offs = (uint32_t)len % sizeof (BIG_CHUNK_TYPE); 2700Sstevel@tonic-gate #else /* !_LP64 */ 271*6557Sfr41279 offs = len % sizeof (BIG_CHUNK_TYPE); 2720Sstevel@tonic-gate #endif /* _LP64 */ 2730Sstevel@tonic-gate if (offs > 0) { 274*6557Sfr41279 word = bn->value[len / sizeof (BIG_CHUNK_TYPE)]; 2750Sstevel@tonic-gate #ifdef _LP64 276*6557Sfr41279 for (i = (uint32_t)len % sizeof (BIG_CHUNK_TYPE); 277*6557Sfr41279 i > 0; i --) { 2780Sstevel@tonic-gate #else /* !_LP64 */ 279*6557Sfr41279 for (i = len % sizeof (BIG_CHUNK_TYPE); 280*6557Sfr41279 i > 0; i --) { 2810Sstevel@tonic-gate #endif /* _LP64 */ 282*6557Sfr41279 kn[i - 1] = word & 0xff; 283*6557Sfr41279 word = word >> 8; 284*6557Sfr41279 } 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate } else { 2870Sstevel@tonic-gate for (i = 0; i < bn->len; i++) { 2880Sstevel@tonic-gate word = bn->value[i]; 289*6557Sfr41279 for (j = 0; j < sizeof (BIG_CHUNK_TYPE); j++) { 290*6557Sfr41279 kn[len - sizeof (BIG_CHUNK_TYPE) * i - j - 1] = 2910Sstevel@tonic-gate word & 0xff; 2920Sstevel@tonic-gate word = word >> 8; 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate #ifdef _LP64 296*6557Sfr41279 for (i = 0; 297*6557Sfr41279 i < (uint32_t)len - sizeof (BIG_CHUNK_TYPE) * bn->len; 2980Sstevel@tonic-gate i++) { 2990Sstevel@tonic-gate #else /* !_LP64 */ 300*6557Sfr41279 for (i = 0; i < len - sizeof (BIG_CHUNK_TYPE) * bn->len; i++) { 3010Sstevel@tonic-gate #endif /* _LP64 */ 3020Sstevel@tonic-gate kn[i] = 0; 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate int 3090Sstevel@tonic-gate big_bitlength(BIGNUM *a) 3100Sstevel@tonic-gate { 311*6557Sfr41279 int l = 0, b = 0; 312*6557Sfr41279 BIG_CHUNK_TYPE c; 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate l = a->len - 1; 3150Sstevel@tonic-gate while ((l > 0) && (a->value[l] == 0)) { 3160Sstevel@tonic-gate l--; 3170Sstevel@tonic-gate } 318*6557Sfr41279 b = sizeof (BIG_CHUNK_TYPE) * BITSINBYTE; 3190Sstevel@tonic-gate c = a->value[l]; 320*6557Sfr41279 while ((b > 1) && ((c & BIG_CHUNK_HIGHBIT) == 0)) { 3210Sstevel@tonic-gate c = c << 1; 3220Sstevel@tonic-gate b--; 3230Sstevel@tonic-gate } 324*6557Sfr41279 325*6557Sfr41279 return (l * sizeof (BIG_CHUNK_TYPE) * BITSINBYTE + b); 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate BIG_ERR_CODE 3300Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src) 3310Sstevel@tonic-gate { 332*6557Sfr41279 BIG_CHUNK_TYPE *newptr; 333*6557Sfr41279 int i, len; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate len = src->len; 336*6557Sfr41279 while ((len > 1) && (src->value[len - 1] == 0)) { 3370Sstevel@tonic-gate len--; 338*6557Sfr41279 } 3390Sstevel@tonic-gate src->len = len; 3400Sstevel@tonic-gate if (dest->size < len) { 3410Sstevel@tonic-gate if (dest->malloced == 1) { 342*6557Sfr41279 newptr = (BIG_CHUNK_TYPE *)big_realloc(dest->value, 343*6557Sfr41279 sizeof (BIG_CHUNK_TYPE) * dest->size, 344*6557Sfr41279 sizeof (BIG_CHUNK_TYPE) * len); 3450Sstevel@tonic-gate } else { 346*6557Sfr41279 newptr = (BIG_CHUNK_TYPE *) 347*6557Sfr41279 big_malloc(sizeof (BIG_CHUNK_TYPE) * len); 348*6557Sfr41279 if (newptr != NULL) { 349*6557Sfr41279 dest->malloced = 1; 350*6557Sfr41279 } 3510Sstevel@tonic-gate } 352*6557Sfr41279 if (newptr == NULL) { 3530Sstevel@tonic-gate return (BIG_NO_MEM); 354*6557Sfr41279 } 3550Sstevel@tonic-gate dest->value = newptr; 3560Sstevel@tonic-gate dest->size = len; 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate dest->len = len; 3590Sstevel@tonic-gate dest->sign = src->sign; 360*6557Sfr41279 for (i = 0; i < len; i++) { 361*6557Sfr41279 dest->value[i] = src->value[i]; 362*6557Sfr41279 } 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate return (BIG_OK); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate BIG_ERR_CODE 3690Sstevel@tonic-gate big_extend(BIGNUM *number, int size) 3700Sstevel@tonic-gate { 371*6557Sfr41279 BIG_CHUNK_TYPE *newptr; 3720Sstevel@tonic-gate int i; 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate if (number->size >= size) 3750Sstevel@tonic-gate return (BIG_OK); 3760Sstevel@tonic-gate if (number->malloced) { 377*6557Sfr41279 number->value = big_realloc(number->value, 378*6557Sfr41279 sizeof (BIG_CHUNK_TYPE) * number->size, 379*6557Sfr41279 sizeof (BIG_CHUNK_TYPE) * size); 3800Sstevel@tonic-gate } else { 381*6557Sfr41279 newptr = big_malloc(sizeof (BIG_CHUNK_TYPE) * size); 3820Sstevel@tonic-gate if (newptr != NULL) { 3830Sstevel@tonic-gate for (i = 0; i < number->size; i++) { 3840Sstevel@tonic-gate newptr[i] = number->value[i]; 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate number->value = newptr; 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 390*6557Sfr41279 if (number->value == NULL) { 3910Sstevel@tonic-gate return (BIG_NO_MEM); 392*6557Sfr41279 } 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate number->size = size; 3950Sstevel@tonic-gate number->malloced = 1; 3960Sstevel@tonic-gate return (BIG_OK); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate 400*6557Sfr41279 /* returns 1 if n == 0 */ 4010Sstevel@tonic-gate int 4020Sstevel@tonic-gate big_is_zero(BIGNUM *n) 4030Sstevel@tonic-gate { 404*6557Sfr41279 int i, result; 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate result = 1; 407*6557Sfr41279 for (i = 0; i < n->len; i++) { 408*6557Sfr41279 if (n->value[i] != 0) { 409*6557Sfr41279 result = 0; 410*6557Sfr41279 } 411*6557Sfr41279 } 4120Sstevel@tonic-gate return (result); 4130Sstevel@tonic-gate } 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate BIG_ERR_CODE 4170Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 4180Sstevel@tonic-gate { 419*6557Sfr41279 int i, shorter, longer; 420*6557Sfr41279 BIG_CHUNK_TYPE cy, ai; 421*6557Sfr41279 BIG_CHUNK_TYPE *r, *a, *b, *c; 422*6557Sfr41279 BIG_ERR_CODE err; 423*6557Sfr41279 BIGNUM *longerarg; 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate if (aa->len > bb->len) { 4260Sstevel@tonic-gate shorter = bb->len; 4270Sstevel@tonic-gate longer = aa->len; 428*6557Sfr41279 longerarg = aa; 4290Sstevel@tonic-gate } else { 4300Sstevel@tonic-gate shorter = aa->len; 4310Sstevel@tonic-gate longer = bb->len; 432*6557Sfr41279 longerarg = bb; 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate if (result->size < longer + 1) { 4350Sstevel@tonic-gate err = big_extend(result, longer + 1); 436*6557Sfr41279 if (err != BIG_OK) { 4370Sstevel@tonic-gate return (err); 438*6557Sfr41279 } 4390Sstevel@tonic-gate } 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate r = result->value; 4420Sstevel@tonic-gate a = aa->value; 4430Sstevel@tonic-gate b = bb->value; 444*6557Sfr41279 c = longerarg->value; 4450Sstevel@tonic-gate cy = 0; 4460Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 4470Sstevel@tonic-gate ai = a[i]; 4480Sstevel@tonic-gate r[i] = ai + b[i] + cy; 449*6557Sfr41279 if (r[i] > ai) { 450*6557Sfr41279 cy = 0; 451*6557Sfr41279 } else if (r[i] < ai) { 452*6557Sfr41279 cy = 1; 453*6557Sfr41279 } 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate for (; i < longer; i++) { 4560Sstevel@tonic-gate ai = c[i]; 4570Sstevel@tonic-gate r[i] = ai + cy; 458*6557Sfr41279 if (r[i] >= ai) { 459*6557Sfr41279 cy = 0; 460*6557Sfr41279 } 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate if (cy == 1) { 4630Sstevel@tonic-gate r[i] = cy; 4640Sstevel@tonic-gate result->len = longer + 1; 4650Sstevel@tonic-gate } else { 4660Sstevel@tonic-gate result->len = longer; 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate result->sign = 1; 4690Sstevel@tonic-gate return (BIG_OK); 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */ 4740Sstevel@tonic-gate void 475*6557Sfr41279 big_sub_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, BIG_CHUNK_TYPE *b, int len) 4760Sstevel@tonic-gate { 477*6557Sfr41279 int i; 478*6557Sfr41279 BIG_CHUNK_TYPE cy, ai; 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate cy = 1; 4810Sstevel@tonic-gate for (i = 0; i < len; i++) { 4820Sstevel@tonic-gate ai = a[i]; 4830Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 484*6557Sfr41279 if (r[i] > ai) { 485*6557Sfr41279 cy = 0; 486*6557Sfr41279 } else if (r[i] < ai) { 487*6557Sfr41279 cy = 1; 488*6557Sfr41279 } 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate /* result=aa-bb it is assumed that aa>=bb */ 4940Sstevel@tonic-gate BIG_ERR_CODE 4950Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 4960Sstevel@tonic-gate { 497*6557Sfr41279 int i, shorter; 498*6557Sfr41279 BIG_CHUNK_TYPE cy = 1, ai; 499*6557Sfr41279 BIG_CHUNK_TYPE *r, *a, *b; 500*6557Sfr41279 BIG_ERR_CODE err = BIG_OK; 501*6557Sfr41279 502*6557Sfr41279 if (aa->len > bb->len) { 503*6557Sfr41279 shorter = bb->len; 504*6557Sfr41279 } else { 505*6557Sfr41279 shorter = aa->len; 506*6557Sfr41279 } 5070Sstevel@tonic-gate if (result->size < aa->len) { 5080Sstevel@tonic-gate err = big_extend(result, aa->len); 509*6557Sfr41279 if (err != BIG_OK) { 5100Sstevel@tonic-gate return (err); 511*6557Sfr41279 } 5120Sstevel@tonic-gate } 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate r = result->value; 5150Sstevel@tonic-gate a = aa->value; 5160Sstevel@tonic-gate b = bb->value; 5170Sstevel@tonic-gate result->len = aa->len; 5180Sstevel@tonic-gate cy = 1; 5190Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 5200Sstevel@tonic-gate ai = a[i]; 5210Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 522*6557Sfr41279 if (r[i] > ai) { 523*6557Sfr41279 cy = 0; 524*6557Sfr41279 } else if (r[i] < ai) { 525*6557Sfr41279 cy = 1; 526*6557Sfr41279 } 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate for (; i < aa->len; i++) { 5290Sstevel@tonic-gate ai = a[i]; 5300Sstevel@tonic-gate r[i] = ai + (~0) + cy; 531*6557Sfr41279 if (r[i] < ai) { 532*6557Sfr41279 cy = 1; 533*6557Sfr41279 } 5340Sstevel@tonic-gate } 5350Sstevel@tonic-gate result->sign = 1; 536*6557Sfr41279 537*6557Sfr41279 if (cy == 0) { 5380Sstevel@tonic-gate return (BIG_INVALID_ARGS); 539*6557Sfr41279 } else { 5400Sstevel@tonic-gate return (BIG_OK); 541*6557Sfr41279 } 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */ 5460Sstevel@tonic-gate int 5470Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb) 5480Sstevel@tonic-gate { 549*6557Sfr41279 int i; 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate if (aa->len > bb->len) { 5520Sstevel@tonic-gate for (i = aa->len - 1; i > bb->len - 1; i--) { 553*6557Sfr41279 if (aa->value[i] > 0) { 5540Sstevel@tonic-gate return (1); 555*6557Sfr41279 } 5560Sstevel@tonic-gate } 5570Sstevel@tonic-gate } else if (aa->len < bb->len) { 5580Sstevel@tonic-gate for (i = bb->len - 1; i > aa->len - 1; i--) { 559*6557Sfr41279 if (bb->value[i] > 0) { 5600Sstevel@tonic-gate return (-1); 561*6557Sfr41279 } 5620Sstevel@tonic-gate } 563*6557Sfr41279 } else { 564*6557Sfr41279 i = aa->len-1; 565*6557Sfr41279 } 5660Sstevel@tonic-gate for (; i >= 0; i--) { 567*6557Sfr41279 if (aa->value[i] > bb->value[i]) { 5680Sstevel@tonic-gate return (1); 569*6557Sfr41279 } else if (aa->value[i] < bb->value[i]) { 5700Sstevel@tonic-gate return (-1); 571*6557Sfr41279 } 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate return (0); 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate BIG_ERR_CODE 5790Sstevel@tonic-gate big_sub(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 5800Sstevel@tonic-gate { 581*6557Sfr41279 BIG_ERR_CODE err; 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate if ((bb->sign == -1) && (aa->sign == 1)) { 584*6557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 5850Sstevel@tonic-gate return (err); 586*6557Sfr41279 } 5870Sstevel@tonic-gate result->sign = 1; 5880Sstevel@tonic-gate } else if ((aa->sign == -1) && (bb->sign == 1)) { 589*6557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 5900Sstevel@tonic-gate return (err); 591*6557Sfr41279 } 5920Sstevel@tonic-gate result->sign = -1; 5930Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == 1)) { 5940Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 595*6557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 5960Sstevel@tonic-gate return (err); 597*6557Sfr41279 } 5980Sstevel@tonic-gate result->sign = 1; 5990Sstevel@tonic-gate } else { 600*6557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6010Sstevel@tonic-gate return (err); 602*6557Sfr41279 } 6030Sstevel@tonic-gate result->sign = -1; 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate } else { 6060Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 607*6557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6080Sstevel@tonic-gate return (err); 609*6557Sfr41279 } 6100Sstevel@tonic-gate result->sign = -1; 6110Sstevel@tonic-gate } else { 612*6557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6130Sstevel@tonic-gate return (err); 614*6557Sfr41279 } 6150Sstevel@tonic-gate result->sign = 1; 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate return (BIG_OK); 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate BIG_ERR_CODE 6230Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 6240Sstevel@tonic-gate { 625*6557Sfr41279 BIG_ERR_CODE err; 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate if ((bb->sign == -1) && (aa->sign == -1)) { 628*6557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6290Sstevel@tonic-gate return (err); 630*6557Sfr41279 } 6310Sstevel@tonic-gate result->sign = -1; 6320Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == 1)) { 633*6557Sfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6340Sstevel@tonic-gate return (err); 635*6557Sfr41279 } 6360Sstevel@tonic-gate result->sign = 1; 6370Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == -1)) { 6380Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 639*6557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6400Sstevel@tonic-gate return (err); 641*6557Sfr41279 } 6420Sstevel@tonic-gate result->sign = 1; 6430Sstevel@tonic-gate } else { 644*6557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6450Sstevel@tonic-gate return (err); 646*6557Sfr41279 } 6470Sstevel@tonic-gate result->sign = -1; 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate } else { 6500Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 651*6557Sfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6520Sstevel@tonic-gate return (err); 653*6557Sfr41279 } 6540Sstevel@tonic-gate result->sign = -1; 6550Sstevel@tonic-gate } else { 656*6557Sfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6570Sstevel@tonic-gate return (err); 658*6557Sfr41279 } 6590Sstevel@tonic-gate result->sign = 1; 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate return (BIG_OK); 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate 666*6557Sfr41279 /* result = aa/2 */ 6670Sstevel@tonic-gate BIG_ERR_CODE 6680Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa) 6690Sstevel@tonic-gate { 670*6557Sfr41279 BIG_ERR_CODE err; 671*6557Sfr41279 int i; 672*6557Sfr41279 BIG_CHUNK_TYPE cy, cy1; 673*6557Sfr41279 BIG_CHUNK_TYPE *a, *r; 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate if (result->size < aa->len) { 6760Sstevel@tonic-gate err = big_extend(result, aa->len); 677*6557Sfr41279 if (err != BIG_OK) { 6780Sstevel@tonic-gate return (err); 679*6557Sfr41279 } 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate result->len = aa->len; 6830Sstevel@tonic-gate a = aa->value; 6840Sstevel@tonic-gate r = result->value; 6850Sstevel@tonic-gate cy = 0; 686*6557Sfr41279 for (i = aa->len - 1; i >= 0; i--) { 687*6557Sfr41279 cy1 = a[i] << (BIG_CHUNK_SIZE - 1); 688*6557Sfr41279 r[i] = (cy | (a[i] >> 1)); 6890Sstevel@tonic-gate cy = cy1; 6900Sstevel@tonic-gate } 691*6557Sfr41279 if (r[result->len - 1] == 0) { 692*6557Sfr41279 result->len--; 693*6557Sfr41279 } 694*6557Sfr41279 6950Sstevel@tonic-gate return (BIG_OK); 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate 698*6557Sfr41279 /* result = aa*2 */ 6990Sstevel@tonic-gate BIG_ERR_CODE 7000Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa) 7010Sstevel@tonic-gate { 702*6557Sfr41279 BIG_ERR_CODE err; 703*6557Sfr41279 int i, rsize; 704*6557Sfr41279 BIG_CHUNK_TYPE cy, cy1; 705*6557Sfr41279 BIG_CHUNK_TYPE *a, *r; 706*6557Sfr41279 707*6557Sfr41279 if ((aa->len > 0) && 708*6557Sfr41279 ((aa->value[aa->len - 1] & BIG_CHUNK_HIGHBIT) != 0)) { 7090Sstevel@tonic-gate rsize = aa->len + 1; 710*6557Sfr41279 } else { 711*6557Sfr41279 rsize = aa->len; 712*6557Sfr41279 } 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate if (result->size < rsize) { 7150Sstevel@tonic-gate err = big_extend(result, rsize); 7160Sstevel@tonic-gate if (err != BIG_OK) 7170Sstevel@tonic-gate return (err); 7180Sstevel@tonic-gate } 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate a = aa->value; 7210Sstevel@tonic-gate r = result->value; 722*6557Sfr41279 if (rsize == aa->len + 1) { 723*6557Sfr41279 r[rsize - 1] = 1; 724*6557Sfr41279 } 7250Sstevel@tonic-gate cy = 0; 7260Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 727*6557Sfr41279 cy1 = a[i] >> (BIG_CHUNK_SIZE - 1); 7280Sstevel@tonic-gate r[i] = (cy | (a[i] << 1)); 7290Sstevel@tonic-gate cy = cy1; 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate result->len = rsize; 7320Sstevel@tonic-gate return (BIG_OK); 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate 735*6557Sfr41279 736*6557Sfr41279 /* 737*6557Sfr41279 * returns aa mod b, aa must be nonneg, b must be a max 738*6557Sfr41279 * (BIG_CHUNK_SIZE / 2)-bit integer 739*6557Sfr41279 */ 740*6557Sfr41279 static uint32_t 741*6557Sfr41279 big_modhalf_pos(BIGNUM *aa, uint32_t b) 7420Sstevel@tonic-gate { 743*6557Sfr41279 int i; 744*6557Sfr41279 BIG_CHUNK_TYPE rem; 745*6557Sfr41279 746*6557Sfr41279 if (aa->len == 0) { 7470Sstevel@tonic-gate return (0); 748*6557Sfr41279 } 7490Sstevel@tonic-gate rem = aa->value[aa->len - 1] % b; 7500Sstevel@tonic-gate for (i = aa->len - 2; i >= 0; i--) { 751*6557Sfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 752*6557Sfr41279 (aa->value[i] >> (BIG_CHUNK_SIZE / 2))) % b; 753*6557Sfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 754*6557Sfr41279 (aa->value[i] & BIG_CHUNK_LOWHALFBITS)) % b; 7550Sstevel@tonic-gate } 756*6557Sfr41279 757*6557Sfr41279 return ((uint32_t)rem); 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate /* 762*6557Sfr41279 * result = aa - (2^BIG_CHUNK_SIZE)^lendiff * bb 7630Sstevel@tonic-gate * result->size should be at least aa->len at entry 7640Sstevel@tonic-gate * aa, bb, and result should be positive 7650Sstevel@tonic-gate */ 7660Sstevel@tonic-gate void 7670Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 7680Sstevel@tonic-gate { 7690Sstevel@tonic-gate int i, lendiff; 7700Sstevel@tonic-gate BIGNUM res1, aa1; 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate lendiff = aa->len - bb->len; 7730Sstevel@tonic-gate res1.size = result->size - lendiff; 7740Sstevel@tonic-gate res1.malloced = 0; 7750Sstevel@tonic-gate res1.value = result->value + lendiff; 7760Sstevel@tonic-gate aa1.size = aa->size - lendiff; 7770Sstevel@tonic-gate aa1.value = aa->value + lendiff; 7780Sstevel@tonic-gate aa1.len = bb->len; 7790Sstevel@tonic-gate aa1.sign = 1; 7800Sstevel@tonic-gate (void) big_sub_pos(&res1, &aa1, bb); 7810Sstevel@tonic-gate if (result->value != aa->value) { 7820Sstevel@tonic-gate for (i = 0; i < lendiff; i++) { 7830Sstevel@tonic-gate result->value[i] = aa->value[i]; 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate result->len = aa->len; 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate /* 7910Sstevel@tonic-gate * returns 1, 0, or -1 depending on whether |aa| > , ==, or < 792*6557Sfr41279 * (2^BIG_CHUNK_SIZE)^lendiff * |bb| 7930Sstevel@tonic-gate * aa->len should be >= bb->len 7940Sstevel@tonic-gate */ 7950Sstevel@tonic-gate int 7960Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb) 7970Sstevel@tonic-gate { 7980Sstevel@tonic-gate int lendiff; 7990Sstevel@tonic-gate BIGNUM aa1; 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate lendiff = aa->len - bb->len; 8020Sstevel@tonic-gate aa1.len = bb->len; 8030Sstevel@tonic-gate aa1.size = aa->size - lendiff; 8040Sstevel@tonic-gate aa1.malloced = 0; 8050Sstevel@tonic-gate aa1.value = aa->value + lendiff; 8060Sstevel@tonic-gate return (big_cmp_abs(&aa1, bb)); 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate /* 811*6557Sfr41279 * result = aa * b where b is a max. (BIG_CHUNK_SIZE / 2)-bit positive integer. 8120Sstevel@tonic-gate * result should have enough space allocated. 8130Sstevel@tonic-gate */ 814*6557Sfr41279 static void 815*6557Sfr41279 big_mulhalf_low(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 8160Sstevel@tonic-gate { 817*6557Sfr41279 int i; 818*6557Sfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy; 819*6557Sfr41279 BIG_CHUNK_TYPE *a, *r; 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate a = aa->value; 8220Sstevel@tonic-gate r = result->value; 8230Sstevel@tonic-gate cy = 0; 8240Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 8250Sstevel@tonic-gate ai = a[i]; 826*6557Sfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 827*6557Sfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 828*6557Sfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 829*6557Sfr41279 r[i] = (t1 & BIG_CHUNK_LOWHALFBITS) | 830*6557Sfr41279 (t2 << (BIG_CHUNK_SIZE / 2)); 831*6557Sfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 8320Sstevel@tonic-gate } 8330Sstevel@tonic-gate r[i] = cy; 8340Sstevel@tonic-gate result->len = aa->len + 1; 8350Sstevel@tonic-gate result->sign = aa->sign; 8360Sstevel@tonic-gate } 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate /* 840*6557Sfr41279 * result = aa * b * 2^(BIG_CHUNK_SIZE / 2) where b is a max. 841*6557Sfr41279 * (BIG_CHUNK_SIZE / 2)-bit positive integer. 8420Sstevel@tonic-gate * result should have enough space allocated. 8430Sstevel@tonic-gate */ 844*6557Sfr41279 static void 845*6557Sfr41279 big_mulhalf_high(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 8460Sstevel@tonic-gate { 847*6557Sfr41279 int i; 848*6557Sfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy, ri; 849*6557Sfr41279 BIG_CHUNK_TYPE *a, *r; 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate a = aa->value; 8520Sstevel@tonic-gate r = result->value; 8530Sstevel@tonic-gate cy = 0; 8540Sstevel@tonic-gate ri = 0; 8550Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 8560Sstevel@tonic-gate ai = a[i]; 857*6557Sfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 858*6557Sfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 859*6557Sfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 860*6557Sfr41279 r[i] = (t1 << (BIG_CHUNK_SIZE / 2)) + ri; 861*6557Sfr41279 ri = t2 & BIG_CHUNK_LOWHALFBITS; 862*6557Sfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 8630Sstevel@tonic-gate } 864*6557Sfr41279 r[i] = (cy << (BIG_CHUNK_SIZE / 2)) + ri; 8650Sstevel@tonic-gate result->len = aa->len + 1; 8660Sstevel@tonic-gate result->sign = aa->sign; 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate 869*6557Sfr41279 8700Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 8710Sstevel@tonic-gate void 8720Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs) 8730Sstevel@tonic-gate { 874*6557Sfr41279 int i; 875*6557Sfr41279 BIG_CHUNK_TYPE cy, ai; 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate if (offs == 0) { 8780Sstevel@tonic-gate if (result != aa) { 8790Sstevel@tonic-gate (void) big_copy(result, aa); 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate return; 8820Sstevel@tonic-gate } 8830Sstevel@tonic-gate cy = 0; 8840Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 8850Sstevel@tonic-gate ai = aa->value[i]; 8860Sstevel@tonic-gate result->value[i] = (ai << offs) | cy; 887*6557Sfr41279 cy = ai >> (BIG_CHUNK_SIZE - offs); 8880Sstevel@tonic-gate } 8890Sstevel@tonic-gate if (cy != 0) { 8900Sstevel@tonic-gate result->len = aa->len + 1; 8910Sstevel@tonic-gate result->value[result->len - 1] = cy; 8920Sstevel@tonic-gate } else { 8930Sstevel@tonic-gate result->len = aa->len; 8940Sstevel@tonic-gate } 8950Sstevel@tonic-gate result->sign = aa->sign; 8960Sstevel@tonic-gate } 8970Sstevel@tonic-gate 898*6557Sfr41279 8990Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 9000Sstevel@tonic-gate void 9010Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs) 9020Sstevel@tonic-gate { 903*6557Sfr41279 int i; 904*6557Sfr41279 BIG_CHUNK_TYPE cy, ai; 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate if (offs == 0) { 9070Sstevel@tonic-gate if (result != aa) { 9080Sstevel@tonic-gate (void) big_copy(result, aa); 9090Sstevel@tonic-gate } 9100Sstevel@tonic-gate return; 9110Sstevel@tonic-gate } 9120Sstevel@tonic-gate cy = aa->value[0] >> offs; 9130Sstevel@tonic-gate for (i = 1; i < aa->len; i++) { 9140Sstevel@tonic-gate ai = aa->value[i]; 915*6557Sfr41279 result->value[i-1] = (ai << (BIG_CHUNK_SIZE - offs)) | cy; 9160Sstevel@tonic-gate cy = ai >> offs; 9170Sstevel@tonic-gate } 9180Sstevel@tonic-gate result->len = aa->len; 9190Sstevel@tonic-gate result->value[result->len - 1] = cy; 9200Sstevel@tonic-gate result->sign = aa->sign; 9210Sstevel@tonic-gate } 9220Sstevel@tonic-gate 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate /* 9250Sstevel@tonic-gate * result = aa/bb remainder = aa mod bb 9260Sstevel@tonic-gate * it is assumed that aa and bb are positive 9270Sstevel@tonic-gate */ 9280Sstevel@tonic-gate BIG_ERR_CODE 9290Sstevel@tonic-gate big_div_pos_fast(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb) 9300Sstevel@tonic-gate { 931*6557Sfr41279 BIG_ERR_CODE err = BIG_OK; 932*6557Sfr41279 int i, alen, blen, tlen, rlen, offs; 933*6557Sfr41279 BIG_CHUNK_TYPE higha, highb, coeff; 934*6557Sfr41279 BIG_CHUNK_TYPE *a, *b; 935*6557Sfr41279 BIGNUM bbhigh, bblow, tresult, tmp1, tmp2; 936*6557Sfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 937*6557Sfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 938*6557Sfr41279 BIG_CHUNK_TYPE tresultvalue[BIGTMPSIZE]; 939*6557Sfr41279 BIG_CHUNK_TYPE bblowvalue[BIGTMPSIZE]; 940*6557Sfr41279 BIG_CHUNK_TYPE bbhighvalue[BIGTMPSIZE]; 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate a = aa->value; 9430Sstevel@tonic-gate b = bb->value; 9440Sstevel@tonic-gate alen = aa->len; 9450Sstevel@tonic-gate blen = bb->len; 946*6557Sfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 947*6557Sfr41279 alen = alen - 1; 948*6557Sfr41279 } 9490Sstevel@tonic-gate aa->len = alen; 950*6557Sfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 951*6557Sfr41279 blen = blen - 1; 952*6557Sfr41279 } 9530Sstevel@tonic-gate bb->len = blen; 954*6557Sfr41279 if ((blen == 1) && (b[0] == 0)) { 9550Sstevel@tonic-gate return (BIG_DIV_BY_0); 956*6557Sfr41279 } 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate if (big_cmp_abs(aa, bb) < 0) { 9590Sstevel@tonic-gate if ((remainder != NULL) && 960*6557Sfr41279 ((err = big_copy(remainder, aa)) != BIG_OK)) { 9610Sstevel@tonic-gate return (err); 962*6557Sfr41279 } 9630Sstevel@tonic-gate if (result != NULL) { 9640Sstevel@tonic-gate result->len = 1; 9650Sstevel@tonic-gate result->sign = 1; 9660Sstevel@tonic-gate result->value[0] = 0; 9670Sstevel@tonic-gate } 9680Sstevel@tonic-gate return (BIG_OK); 9690Sstevel@tonic-gate } 9700Sstevel@tonic-gate 9710Sstevel@tonic-gate if ((err = big_init1(&bblow, blen + 1, 9720Sstevel@tonic-gate bblowvalue, arraysize(bblowvalue))) != BIG_OK) 9730Sstevel@tonic-gate return (err); 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate if ((err = big_init1(&bbhigh, blen + 1, 9760Sstevel@tonic-gate bbhighvalue, arraysize(bbhighvalue))) != BIG_OK) 9770Sstevel@tonic-gate goto ret1; 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate if ((err = big_init1(&tmp1, alen + 2, 9800Sstevel@tonic-gate tmp1value, arraysize(tmp1value))) != BIG_OK) 9810Sstevel@tonic-gate goto ret2; 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate if ((err = big_init1(&tmp2, blen + 2, 9840Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 9850Sstevel@tonic-gate goto ret3; 9860Sstevel@tonic-gate 9870Sstevel@tonic-gate if ((err = big_init1(&tresult, alen - blen + 2, 9880Sstevel@tonic-gate tresultvalue, arraysize(tresultvalue))) != BIG_OK) 9890Sstevel@tonic-gate goto ret4; 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate offs = 0; 992*6557Sfr41279 highb = b[blen - 1]; 993*6557Sfr41279 if (highb >= (BIG_CHUNK_HALF_HIGHBIT << 1)) { 994*6557Sfr41279 highb = highb >> (BIG_CHUNK_SIZE / 2); 995*6557Sfr41279 offs = (BIG_CHUNK_SIZE / 2); 9960Sstevel@tonic-gate } 997*6557Sfr41279 while ((highb & BIG_CHUNK_HALF_HIGHBIT) == 0) { 998*6557Sfr41279 highb = highb << 1; 9990Sstevel@tonic-gate offs++; 10000Sstevel@tonic-gate } 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate big_shiftleft(&bblow, bb, offs); 1003*6557Sfr41279 1004*6557Sfr41279 if (offs <= (BIG_CHUNK_SIZE / 2 - 1)) { 1005*6557Sfr41279 big_shiftleft(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10060Sstevel@tonic-gate } else { 1007*6557Sfr41279 big_shiftright(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10080Sstevel@tonic-gate } 10090Sstevel@tonic-gate if (bbhigh.value[bbhigh.len - 1] == 0) { 10100Sstevel@tonic-gate bbhigh.len--; 10110Sstevel@tonic-gate } else { 10120Sstevel@tonic-gate bbhigh.value[bbhigh.len] = 0; 10130Sstevel@tonic-gate } 10140Sstevel@tonic-gate 1015*6557Sfr41279 highb = bblow.value[bblow.len - 1]; 1016*6557Sfr41279 10170Sstevel@tonic-gate big_shiftleft(&tmp1, aa, offs); 10180Sstevel@tonic-gate rlen = tmp1.len - bblow.len + 1; 10190Sstevel@tonic-gate tresult.len = rlen; 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate tmp1.len++; 10220Sstevel@tonic-gate tlen = tmp1.len; 10230Sstevel@tonic-gate tmp1.value[tmp1.len - 1] = 0; 10240Sstevel@tonic-gate for (i = 0; i < rlen; i++) { 1025*6557Sfr41279 higha = (tmp1.value[tlen - 1] << (BIG_CHUNK_SIZE / 2)) + 1026*6557Sfr41279 (tmp1.value[tlen - 2] >> (BIG_CHUNK_SIZE / 2)); 10270Sstevel@tonic-gate coeff = higha / (highb + 1); 1028*6557Sfr41279 big_mulhalf_high(&tmp2, &bblow, coeff); 10290Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 10300Sstevel@tonic-gate bbhigh.len++; 10310Sstevel@tonic-gate while (tmp1.value[tlen - 1] > 0) { 10320Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 10330Sstevel@tonic-gate coeff++; 10340Sstevel@tonic-gate } 10350Sstevel@tonic-gate bbhigh.len--; 10360Sstevel@tonic-gate tlen--; 10370Sstevel@tonic-gate tmp1.len--; 10380Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) { 10390Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 10400Sstevel@tonic-gate coeff++; 10410Sstevel@tonic-gate } 1042*6557Sfr41279 tresult.value[rlen - i - 1] = coeff << (BIG_CHUNK_SIZE / 2); 10430Sstevel@tonic-gate higha = tmp1.value[tlen - 1]; 10440Sstevel@tonic-gate coeff = higha / (highb + 1); 1045*6557Sfr41279 big_mulhalf_low(&tmp2, &bblow, coeff); 10460Sstevel@tonic-gate tmp2.len--; 10470Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 10480Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bblow) >= 0) { 10490Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bblow); 10500Sstevel@tonic-gate coeff++; 10510Sstevel@tonic-gate } 10520Sstevel@tonic-gate tresult.value[rlen - i - 1] = 10530Sstevel@tonic-gate tresult.value[rlen - i - 1] + coeff; 10540Sstevel@tonic-gate } 10550Sstevel@tonic-gate 10560Sstevel@tonic-gate big_shiftright(&tmp1, &tmp1, offs); 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate err = BIG_OK; 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate if ((remainder != NULL) && 10610Sstevel@tonic-gate ((err = big_copy(remainder, &tmp1)) != BIG_OK)) 10620Sstevel@tonic-gate goto ret; 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate if (result != NULL) 10650Sstevel@tonic-gate err = big_copy(result, &tresult); 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate ret: 10680Sstevel@tonic-gate big_finish(&tresult); 10690Sstevel@tonic-gate ret4: 10700Sstevel@tonic-gate big_finish(&tmp1); 10710Sstevel@tonic-gate ret3: 10720Sstevel@tonic-gate big_finish(&tmp2); 10730Sstevel@tonic-gate ret2: 10740Sstevel@tonic-gate big_finish(&bbhigh); 10750Sstevel@tonic-gate ret1: 10760Sstevel@tonic-gate big_finish(&bblow); 10770Sstevel@tonic-gate return (err); 10780Sstevel@tonic-gate } 10790Sstevel@tonic-gate 10800Sstevel@tonic-gate /* 10810Sstevel@tonic-gate * If there is no processor-specific integer implementation of 10820Sstevel@tonic-gate * the lower level multiply functions, then this code is provided 10830Sstevel@tonic-gate * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and 10840Sstevel@tonic-gate * big_sqr_vec(). 10850Sstevel@tonic-gate * 10860Sstevel@tonic-gate * There are two generic implementations. One that assumes that 10870Sstevel@tonic-gate * there is hardware and C compiler support for a 32 x 32 --> 64 10880Sstevel@tonic-gate * bit unsigned multiply, but otherwise is not specific to any 10890Sstevel@tonic-gate * processor, platform, or ISA. 10900Sstevel@tonic-gate * 10910Sstevel@tonic-gate * The other makes very few assumptions about hardware capabilities. 10920Sstevel@tonic-gate * It does not even assume that there is any implementation of a 10930Sstevel@tonic-gate * 32 x 32 --> 64 bit multiply that is accessible to C code and 10940Sstevel@tonic-gate * appropriate to use. It falls constructs 32 x 32 --> 64 bit 10950Sstevel@tonic-gate * multiplies from 16 x 16 --> 32 bit multiplies. 10960Sstevel@tonic-gate * 10970Sstevel@tonic-gate */ 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate #if !defined(PSR_MUL) 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate #ifdef UMUL64 11020Sstevel@tonic-gate 1103*6557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 1104*6557Sfr41279 11050Sstevel@tonic-gate #define UNROLL8 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_PREFETCH(R) \ 11080Sstevel@tonic-gate p = pf * d; \ 11090Sstevel@tonic-gate pf = (uint64_t)a[R+1]; \ 11100Sstevel@tonic-gate t = p + cy; \ 11110Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11120Sstevel@tonic-gate cy = t >> 32 11130Sstevel@tonic-gate 11140Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_NOPREFETCH(R) \ 11150Sstevel@tonic-gate p = pf * d; \ 11160Sstevel@tonic-gate t = p + cy; \ 11170Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11180Sstevel@tonic-gate cy = t >> 32 11190Sstevel@tonic-gate 11200Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_PREFETCH(R) \ 11210Sstevel@tonic-gate t = (uint64_t)r[R]; \ 11220Sstevel@tonic-gate p = pf * d; \ 11230Sstevel@tonic-gate pf = (uint64_t)a[R+1]; \ 11240Sstevel@tonic-gate t = p + t + cy; \ 11250Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11260Sstevel@tonic-gate cy = t >> 32 11270Sstevel@tonic-gate 11280Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_NOPREFETCH(R) \ 11290Sstevel@tonic-gate t = (uint64_t)r[R]; \ 11300Sstevel@tonic-gate p = pf * d; \ 11310Sstevel@tonic-gate t = p + t + cy; \ 11320Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11330Sstevel@tonic-gate cy = t >> 32 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate #ifdef UNROLL8 11360Sstevel@tonic-gate 11370Sstevel@tonic-gate #define UNROLL 8 11380Sstevel@tonic-gate 11390Sstevel@tonic-gate /* 11400Sstevel@tonic-gate * r = a * b 11410Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 11420Sstevel@tonic-gate */ 11430Sstevel@tonic-gate 11440Sstevel@tonic-gate uint32_t 11450Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 11460Sstevel@tonic-gate { 11470Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate if (len == 0) 11500Sstevel@tonic-gate return (0); 11510Sstevel@tonic-gate cy = 0; 11520Sstevel@tonic-gate d = (uint64_t)b; 11530Sstevel@tonic-gate pf = (uint64_t)a[0]; 11540Sstevel@tonic-gate while (len > UNROLL) { 11550Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 11560Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 11570Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 11580Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 11590Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 11600Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 11610Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 11620Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(7); 11630Sstevel@tonic-gate r += UNROLL; 11640Sstevel@tonic-gate a += UNROLL; 11650Sstevel@tonic-gate len -= UNROLL; 11660Sstevel@tonic-gate } 11670Sstevel@tonic-gate if (len == UNROLL) { 11680Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 11690Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 11700Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 11710Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 11720Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 11730Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 11740Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 11750Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(7); 11760Sstevel@tonic-gate return ((uint32_t)cy); 11770Sstevel@tonic-gate } 11780Sstevel@tonic-gate while (len > 1) { 11790Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 11800Sstevel@tonic-gate ++r; 11810Sstevel@tonic-gate ++a; 11820Sstevel@tonic-gate --len; 11830Sstevel@tonic-gate } 11840Sstevel@tonic-gate if (len > 0) { 11850Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(0); 11860Sstevel@tonic-gate } 11870Sstevel@tonic-gate return ((uint32_t)cy); 11880Sstevel@tonic-gate } 11890Sstevel@tonic-gate 11900Sstevel@tonic-gate /* 11910Sstevel@tonic-gate * r += a * b 11920Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 11930Sstevel@tonic-gate */ 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate uint32_t 11960Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 11970Sstevel@tonic-gate { 11980Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate if (len == 0) 12010Sstevel@tonic-gate return (0); 12020Sstevel@tonic-gate cy = 0; 12030Sstevel@tonic-gate d = (uint64_t)b; 12040Sstevel@tonic-gate pf = (uint64_t)a[0]; 12050Sstevel@tonic-gate while (len > 8) { 12060Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12070Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 12080Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 12090Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 12100Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 12110Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 12120Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 12130Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(7); 12140Sstevel@tonic-gate r += 8; 12150Sstevel@tonic-gate a += 8; 12160Sstevel@tonic-gate len -= 8; 12170Sstevel@tonic-gate } 12180Sstevel@tonic-gate if (len == 8) { 12190Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12200Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 12210Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 12220Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 12230Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 12240Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 12250Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 12260Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(7); 12270Sstevel@tonic-gate return ((uint32_t)cy); 12280Sstevel@tonic-gate } 12290Sstevel@tonic-gate while (len > 1) { 12300Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12310Sstevel@tonic-gate ++r; 12320Sstevel@tonic-gate ++a; 12330Sstevel@tonic-gate --len; 12340Sstevel@tonic-gate } 12350Sstevel@tonic-gate if (len > 0) { 12360Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(0); 12370Sstevel@tonic-gate } 12380Sstevel@tonic-gate return ((uint32_t)cy); 12390Sstevel@tonic-gate } 12400Sstevel@tonic-gate #endif /* UNROLL8 */ 12410Sstevel@tonic-gate 12420Sstevel@tonic-gate void 12430Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 12440Sstevel@tonic-gate { 12450Sstevel@tonic-gate uint32_t *tr, *ta; 12460Sstevel@tonic-gate int tlen, row, col; 12470Sstevel@tonic-gate uint64_t p, s, t, t2, cy; 12480Sstevel@tonic-gate uint32_t d; 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate tr = r + 1; 12510Sstevel@tonic-gate ta = a; 12520Sstevel@tonic-gate tlen = len - 1; 12530Sstevel@tonic-gate tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]); 12540Sstevel@tonic-gate while (--tlen > 0) { 12550Sstevel@tonic-gate tr += 2; 12560Sstevel@tonic-gate ++ta; 12570Sstevel@tonic-gate tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]); 12580Sstevel@tonic-gate } 12590Sstevel@tonic-gate s = (uint64_t)a[0]; 12600Sstevel@tonic-gate s = s * s; 12610Sstevel@tonic-gate r[0] = (uint32_t)s; 12620Sstevel@tonic-gate cy = s >> 32; 12630Sstevel@tonic-gate p = ((uint64_t)r[1] << 1) + cy; 12640Sstevel@tonic-gate r[1] = (uint32_t)p; 12650Sstevel@tonic-gate cy = p >> 32; 12660Sstevel@tonic-gate row = 1; 12670Sstevel@tonic-gate col = 2; 12680Sstevel@tonic-gate while (row < len) { 12690Sstevel@tonic-gate s = (uint64_t)a[row]; 12700Sstevel@tonic-gate s = s * s; 12710Sstevel@tonic-gate p = (uint64_t)r[col] << 1; 12720Sstevel@tonic-gate t = p + s; 12730Sstevel@tonic-gate d = (uint32_t)t; 12740Sstevel@tonic-gate t2 = (uint64_t)d + cy; 12750Sstevel@tonic-gate r[col] = (uint32_t)t2; 12760Sstevel@tonic-gate cy = (t >> 32) + (t2 >> 32); 12770Sstevel@tonic-gate if (row == len - 1) 12780Sstevel@tonic-gate break; 12790Sstevel@tonic-gate p = ((uint64_t)r[col+1] << 1) + cy; 12800Sstevel@tonic-gate r[col+1] = (uint32_t)p; 12810Sstevel@tonic-gate cy = p >> 32; 12820Sstevel@tonic-gate ++row; 12830Sstevel@tonic-gate col += 2; 12840Sstevel@tonic-gate } 12850Sstevel@tonic-gate r[col+1] = (uint32_t)cy; 12860Sstevel@tonic-gate } 12870Sstevel@tonic-gate 1288*6557Sfr41279 #else /* BIG_CHUNK_SIZE == 64 */ 1289*6557Sfr41279 1290*6557Sfr41279 /* 1291*6557Sfr41279 * r = r + a * digit, r and a are vectors of length len 1292*6557Sfr41279 * returns the carry digit 1293*6557Sfr41279 */ 1294*6557Sfr41279 BIG_CHUNK_TYPE 1295*6557Sfr41279 big_mul_add_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 1296*6557Sfr41279 BIG_CHUNK_TYPE digit) 1297*6557Sfr41279 { 1298*6557Sfr41279 BIG_CHUNK_TYPE cy, cy1, retcy, dlow, dhigh; 1299*6557Sfr41279 int i; 1300*6557Sfr41279 1301*6557Sfr41279 cy1 = 0; 1302*6557Sfr41279 dlow = digit & BIG_CHUNK_LOWHALFBITS; 1303*6557Sfr41279 dhigh = digit >> (BIG_CHUNK_SIZE / 2); 1304*6557Sfr41279 for (i = 0; i < len; i++) { 1305*6557Sfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 1306*6557Sfr41279 dlow * (a[i] & BIG_CHUNK_LOWHALFBITS) + 1307*6557Sfr41279 (r[i] & BIG_CHUNK_LOWHALFBITS); 1308*6557Sfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 1309*6557Sfr41279 dlow * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 1310*6557Sfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 1311*6557Sfr41279 r[i] = (cy & BIG_CHUNK_LOWHALFBITS) | 1312*6557Sfr41279 (cy1 << (BIG_CHUNK_SIZE / 2)); 1313*6557Sfr41279 } 1314*6557Sfr41279 retcy = cy1 >> (BIG_CHUNK_SIZE / 2); 1315*6557Sfr41279 1316*6557Sfr41279 cy1 = r[0] & BIG_CHUNK_LOWHALFBITS; 1317*6557Sfr41279 for (i = 0; i < len - 1; i++) { 1318*6557Sfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 1319*6557Sfr41279 dhigh * (a[i] & BIG_CHUNK_LOWHALFBITS) + 1320*6557Sfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 1321*6557Sfr41279 r[i] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 1322*6557Sfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 1323*6557Sfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 1324*6557Sfr41279 dhigh * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 1325*6557Sfr41279 (r[i + 1] & BIG_CHUNK_LOWHALFBITS); 1326*6557Sfr41279 } 1327*6557Sfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 1328*6557Sfr41279 dhigh * (a[len - 1] & BIG_CHUNK_LOWHALFBITS) + 1329*6557Sfr41279 (r[len - 1] >> (BIG_CHUNK_SIZE / 2)); 1330*6557Sfr41279 r[len - 1] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 1331*6557Sfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 1332*6557Sfr41279 retcy = (cy >> (BIG_CHUNK_SIZE / 2)) + 1333*6557Sfr41279 dhigh * (a[len - 1] >> (BIG_CHUNK_SIZE / 2)) + retcy; 1334*6557Sfr41279 1335*6557Sfr41279 return (retcy); 1336*6557Sfr41279 } 1337*6557Sfr41279 1338*6557Sfr41279 1339*6557Sfr41279 /* 1340*6557Sfr41279 * r = a * digit, r and a are vectors of length len 1341*6557Sfr41279 * returns the carry digit 1342*6557Sfr41279 */ 1343*6557Sfr41279 BIG_CHUNK_TYPE 1344*6557Sfr41279 big_mul_set_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 1345*6557Sfr41279 BIG_CHUNK_TYPE digit) 1346*6557Sfr41279 { 1347*6557Sfr41279 int i; 1348*6557Sfr41279 1349*6557Sfr41279 ASSERT(r != a); 1350*6557Sfr41279 for (i = 0; i < len; i++) { 1351*6557Sfr41279 r[i] = 0; 1352*6557Sfr41279 } 1353*6557Sfr41279 return (big_mul_add_vec(r, a, len, digit)); 1354*6557Sfr41279 } 1355*6557Sfr41279 1356*6557Sfr41279 void 1357*6557Sfr41279 big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len) 1358*6557Sfr41279 { 1359*6557Sfr41279 int i; 1360*6557Sfr41279 1361*6557Sfr41279 ASSERT(r != a); 1362*6557Sfr41279 r[len] = big_mul_set_vec(r, a, len, a[0]); 1363*6557Sfr41279 for (i = 1; i < len; ++i) 1364*6557Sfr41279 r[len + i] = big_mul_add_vec(r+i, a, len, a[i]); 1365*6557Sfr41279 } 1366*6557Sfr41279 1367*6557Sfr41279 #endif /* BIG_CHUNK_SIZE == 32/64 */ 1368*6557Sfr41279 13690Sstevel@tonic-gate #else /* ! UMUL64 */ 13700Sstevel@tonic-gate 1371*6557Sfr41279 #if (BIG_CHUNK_SIZE != 32) 1372*6557Sfr41279 #error Don't use 64-bit chunks without defining UMUL64 1373*6557Sfr41279 #endif 1374*6557Sfr41279 1375*6557Sfr41279 13760Sstevel@tonic-gate /* 13770Sstevel@tonic-gate * r = r + a * digit, r and a are vectors of length len 13780Sstevel@tonic-gate * returns the carry digit 13790Sstevel@tonic-gate */ 13800Sstevel@tonic-gate uint32_t 13810Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 13820Sstevel@tonic-gate { 13830Sstevel@tonic-gate uint32_t cy, cy1, retcy, dlow, dhigh; 13840Sstevel@tonic-gate int i; 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate cy1 = 0; 13870Sstevel@tonic-gate dlow = digit & 0xffff; 13880Sstevel@tonic-gate dhigh = digit >> 16; 13890Sstevel@tonic-gate for (i = 0; i < len; i++) { 13900Sstevel@tonic-gate cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff); 13910Sstevel@tonic-gate cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16); 13920Sstevel@tonic-gate r[i] = (cy & 0xffff) | (cy1 << 16); 13930Sstevel@tonic-gate } 13940Sstevel@tonic-gate retcy = cy1 >> 16; 13950Sstevel@tonic-gate 13960Sstevel@tonic-gate cy1 = r[0] & 0xffff; 13970Sstevel@tonic-gate for (i = 0; i < len - 1; i++) { 13980Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16); 13990Sstevel@tonic-gate r[i] = (cy1 & 0xffff) | (cy << 16); 14000Sstevel@tonic-gate cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff); 14010Sstevel@tonic-gate } 14020Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16); 14030Sstevel@tonic-gate r[len - 1] = (cy1 & 0xffff) | (cy << 16); 14040Sstevel@tonic-gate retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy; 14050Sstevel@tonic-gate 14060Sstevel@tonic-gate return (retcy); 14070Sstevel@tonic-gate } 14080Sstevel@tonic-gate 1409*6557Sfr41279 14100Sstevel@tonic-gate /* 14110Sstevel@tonic-gate * r = a * digit, r and a are vectors of length len 14120Sstevel@tonic-gate * returns the carry digit 14130Sstevel@tonic-gate */ 14140Sstevel@tonic-gate uint32_t 14150Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 14160Sstevel@tonic-gate { 1417*6557Sfr41279 int i; 1418*6557Sfr41279 1419*6557Sfr41279 ASSERT(r != a); 1420*6557Sfr41279 for (i = 0; i < len; i++) { 1421*6557Sfr41279 r[i] = 0; 1422*6557Sfr41279 } 1423*6557Sfr41279 14240Sstevel@tonic-gate return (big_mul_add_vec(r, a, len, digit)); 14250Sstevel@tonic-gate } 14260Sstevel@tonic-gate 14270Sstevel@tonic-gate void 14280Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 14290Sstevel@tonic-gate { 14300Sstevel@tonic-gate int i; 14310Sstevel@tonic-gate 1432*6557Sfr41279 ASSERT(r != a); 14330Sstevel@tonic-gate r[len] = big_mul_set_vec(r, a, len, a[0]); 14340Sstevel@tonic-gate for (i = 1; i < len; ++i) 14350Sstevel@tonic-gate r[len + i] = big_mul_add_vec(r+i, a, len, a[i]); 14360Sstevel@tonic-gate } 14370Sstevel@tonic-gate 14380Sstevel@tonic-gate #endif /* UMUL64 */ 14390Sstevel@tonic-gate 14400Sstevel@tonic-gate void 1441*6557Sfr41279 big_mul_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int alen, 1442*6557Sfr41279 BIG_CHUNK_TYPE *b, int blen) 14430Sstevel@tonic-gate { 14440Sstevel@tonic-gate int i; 14450Sstevel@tonic-gate 14460Sstevel@tonic-gate r[alen] = big_mul_set_vec(r, a, alen, b[0]); 14470Sstevel@tonic-gate for (i = 1; i < blen; ++i) 14480Sstevel@tonic-gate r[alen + i] = big_mul_add_vec(r+i, a, alen, b[i]); 14490Sstevel@tonic-gate } 14500Sstevel@tonic-gate 14510Sstevel@tonic-gate 14520Sstevel@tonic-gate #endif /* ! PSR_MUL */ 14530Sstevel@tonic-gate 14540Sstevel@tonic-gate 14550Sstevel@tonic-gate /* 14560Sstevel@tonic-gate * result = aa * bb result->value should be big enough to hold the result 14570Sstevel@tonic-gate * 14580Sstevel@tonic-gate * Implementation: Standard grammar school algorithm 14590Sstevel@tonic-gate * 14600Sstevel@tonic-gate */ 14610Sstevel@tonic-gate BIG_ERR_CODE 14620Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 14630Sstevel@tonic-gate { 1464*6557Sfr41279 BIGNUM tmp1; 1465*6557Sfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 1466*6557Sfr41279 BIG_CHUNK_TYPE *r, *t, *a, *b; 1467*6557Sfr41279 BIG_ERR_CODE err; 1468*6557Sfr41279 int i, alen, blen, rsize, sign, diff; 14690Sstevel@tonic-gate 14700Sstevel@tonic-gate if (aa == bb) { 14710Sstevel@tonic-gate diff = 0; 14720Sstevel@tonic-gate } else { 14730Sstevel@tonic-gate diff = big_cmp_abs(aa, bb); 14740Sstevel@tonic-gate if (diff < 0) { 14750Sstevel@tonic-gate BIGNUM *tt; 14760Sstevel@tonic-gate tt = aa; 14770Sstevel@tonic-gate aa = bb; 14780Sstevel@tonic-gate bb = tt; 14790Sstevel@tonic-gate } 14800Sstevel@tonic-gate } 14810Sstevel@tonic-gate a = aa->value; 14820Sstevel@tonic-gate b = bb->value; 14830Sstevel@tonic-gate alen = aa->len; 14840Sstevel@tonic-gate blen = bb->len; 1485*6557Sfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 1486*6557Sfr41279 alen--; 1487*6557Sfr41279 } 14880Sstevel@tonic-gate aa->len = alen; 1489*6557Sfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 1490*6557Sfr41279 blen--; 1491*6557Sfr41279 } 14920Sstevel@tonic-gate bb->len = blen; 14930Sstevel@tonic-gate 14940Sstevel@tonic-gate rsize = alen + blen; 14950Sstevel@tonic-gate if (result->size < rsize) { 14960Sstevel@tonic-gate err = big_extend(result, rsize); 1497*6557Sfr41279 if (err != BIG_OK) { 14980Sstevel@tonic-gate return (err); 1499*6557Sfr41279 } 15000Sstevel@tonic-gate /* aa or bb might be an alias to result */ 15010Sstevel@tonic-gate a = aa->value; 15020Sstevel@tonic-gate b = bb->value; 15030Sstevel@tonic-gate } 15040Sstevel@tonic-gate r = result->value; 15050Sstevel@tonic-gate 15060Sstevel@tonic-gate if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) { 15070Sstevel@tonic-gate result->len = 1; 15080Sstevel@tonic-gate result->sign = 1; 15090Sstevel@tonic-gate r[0] = 0; 15100Sstevel@tonic-gate return (BIG_OK); 15110Sstevel@tonic-gate } 15120Sstevel@tonic-gate sign = aa->sign * bb->sign; 15130Sstevel@tonic-gate if ((alen == 1) && (a[0] == 1)) { 1514*6557Sfr41279 for (i = 0; i < blen; i++) { 1515*6557Sfr41279 r[i] = b[i]; 1516*6557Sfr41279 } 15170Sstevel@tonic-gate result->len = blen; 15180Sstevel@tonic-gate result->sign = sign; 15190Sstevel@tonic-gate return (BIG_OK); 15200Sstevel@tonic-gate } 15210Sstevel@tonic-gate if ((blen == 1) && (b[0] == 1)) { 1522*6557Sfr41279 for (i = 0; i < alen; i++) { 1523*6557Sfr41279 r[i] = a[i]; 1524*6557Sfr41279 } 15250Sstevel@tonic-gate result->len = alen; 15260Sstevel@tonic-gate result->sign = sign; 15270Sstevel@tonic-gate return (BIG_OK); 15280Sstevel@tonic-gate } 15290Sstevel@tonic-gate 1530*6557Sfr41279 if ((err = big_init1(&tmp1, rsize, 1531*6557Sfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 15320Sstevel@tonic-gate return (err); 1533*6557Sfr41279 } 1534*6557Sfr41279 (void) big_copy(&tmp1, aa); 15350Sstevel@tonic-gate t = tmp1.value; 1536*6557Sfr41279 1537*6557Sfr41279 for (i = 0; i < rsize; i++) { 1538*6557Sfr41279 t[i] = 0; 1539*6557Sfr41279 } 1540*6557Sfr41279 1541*6557Sfr41279 if (diff == 0 && alen > 2) { 15420Sstevel@tonic-gate BIG_SQR_VEC(t, a, alen); 1543*6557Sfr41279 } else if (blen > 0) { 15440Sstevel@tonic-gate BIG_MUL_VEC(t, a, alen, b, blen); 1545*6557Sfr41279 } 1546*6557Sfr41279 1547*6557Sfr41279 if (t[rsize - 1] == 0) { 1548*6557Sfr41279 tmp1.len = rsize - 1; 1549*6557Sfr41279 } else { 1550*6557Sfr41279 tmp1.len = rsize; 1551*6557Sfr41279 } 1552*6557Sfr41279 if ((err = big_copy(result, &tmp1)) != BIG_OK) { 15530Sstevel@tonic-gate return (err); 1554*6557Sfr41279 } 15550Sstevel@tonic-gate result->sign = sign; 15560Sstevel@tonic-gate 1557*6557Sfr41279 big_finish(&tmp1); 15580Sstevel@tonic-gate 15590Sstevel@tonic-gate return (BIG_OK); 15600Sstevel@tonic-gate } 15610Sstevel@tonic-gate 15620Sstevel@tonic-gate 15630Sstevel@tonic-gate /* 15640Sstevel@tonic-gate * caller must ensure that a < n, b < n and ret->size >= 2 * n->len + 1 15650Sstevel@tonic-gate * and that ret is not n 15660Sstevel@tonic-gate */ 15670Sstevel@tonic-gate BIG_ERR_CODE 1568*6557Sfr41279 big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, BIG_CHUNK_TYPE n0) 15690Sstevel@tonic-gate { 1570*6557Sfr41279 int i, j, nlen, needsubtract; 1571*6557Sfr41279 BIG_CHUNK_TYPE *nn, *rr; 1572*6557Sfr41279 BIG_CHUNK_TYPE digit, c; 1573*6557Sfr41279 BIG_ERR_CODE err; 15740Sstevel@tonic-gate 15750Sstevel@tonic-gate nlen = n->len; 15760Sstevel@tonic-gate nn = n->value; 15770Sstevel@tonic-gate 15780Sstevel@tonic-gate rr = ret->value; 15790Sstevel@tonic-gate 1580*6557Sfr41279 if ((err = big_mul(ret, a, b)) != BIG_OK) { 15810Sstevel@tonic-gate return (err); 1582*6557Sfr41279 } 15830Sstevel@tonic-gate 15840Sstevel@tonic-gate rr = ret->value; 1585*6557Sfr41279 for (i = ret->len; i < 2 * nlen + 1; i++) { 1586*6557Sfr41279 rr[i] = 0; 1587*6557Sfr41279 } 15880Sstevel@tonic-gate for (i = 0; i < nlen; i++) { 15890Sstevel@tonic-gate digit = rr[i]; 15900Sstevel@tonic-gate digit = digit * n0; 15910Sstevel@tonic-gate 15920Sstevel@tonic-gate c = BIG_MUL_ADD_VEC(rr + i, nn, nlen, digit); 15930Sstevel@tonic-gate j = i + nlen; 15940Sstevel@tonic-gate rr[j] += c; 15950Sstevel@tonic-gate while (rr[j] < c) { 15960Sstevel@tonic-gate rr[j + 1] += 1; 15970Sstevel@tonic-gate j++; 15980Sstevel@tonic-gate c = 1; 15990Sstevel@tonic-gate } 16000Sstevel@tonic-gate } 16010Sstevel@tonic-gate 16020Sstevel@tonic-gate needsubtract = 0; 16030Sstevel@tonic-gate if ((rr[2 * nlen] != 0)) 16040Sstevel@tonic-gate needsubtract = 1; 16050Sstevel@tonic-gate else { 16060Sstevel@tonic-gate for (i = 2 * nlen - 1; i >= nlen; i--) { 16070Sstevel@tonic-gate if (rr[i] > nn[i - nlen]) { 16080Sstevel@tonic-gate needsubtract = 1; 16090Sstevel@tonic-gate break; 1610*6557Sfr41279 } else if (rr[i] < nn[i - nlen]) { 1611*6557Sfr41279 break; 1612*6557Sfr41279 } 16130Sstevel@tonic-gate } 16140Sstevel@tonic-gate } 16150Sstevel@tonic-gate if (needsubtract) 16160Sstevel@tonic-gate big_sub_vec(rr, rr + nlen, nn, nlen); 16170Sstevel@tonic-gate else { 1618*6557Sfr41279 for (i = 0; i < nlen; i++) { 16190Sstevel@tonic-gate rr[i] = rr[i + nlen]; 1620*6557Sfr41279 } 16210Sstevel@tonic-gate } 1622*6557Sfr41279 for (i = nlen - 1; (i >= 0) && (rr[i] == 0); i--) 1623*6557Sfr41279 ; 16240Sstevel@tonic-gate ret->len = i+1; 16250Sstevel@tonic-gate 16260Sstevel@tonic-gate return (BIG_OK); 16270Sstevel@tonic-gate } 16280Sstevel@tonic-gate 1629*6557Sfr41279 1630*6557Sfr41279 BIG_CHUNK_TYPE 1631*6557Sfr41279 big_n0(BIG_CHUNK_TYPE n) 16320Sstevel@tonic-gate { 1633*6557Sfr41279 int i; 1634*6557Sfr41279 BIG_CHUNK_TYPE result, tmp; 16350Sstevel@tonic-gate 16360Sstevel@tonic-gate result = 0; 1637*6557Sfr41279 tmp = BIG_CHUNK_ALLBITS; 1638*6557Sfr41279 for (i = 0; i < BIG_CHUNK_SIZE; i++) { 16390Sstevel@tonic-gate if ((tmp & 1) == 1) { 1640*6557Sfr41279 result = (result >> 1) | BIG_CHUNK_HIGHBIT; 16410Sstevel@tonic-gate tmp = tmp - n; 1642*6557Sfr41279 } else { 1643*6557Sfr41279 result = (result >> 1); 1644*6557Sfr41279 } 16450Sstevel@tonic-gate tmp = tmp >> 1; 16460Sstevel@tonic-gate } 16470Sstevel@tonic-gate 16480Sstevel@tonic-gate return (result); 16490Sstevel@tonic-gate } 16500Sstevel@tonic-gate 16510Sstevel@tonic-gate 16520Sstevel@tonic-gate int 16530Sstevel@tonic-gate big_numbits(BIGNUM *n) 16540Sstevel@tonic-gate { 1655*6557Sfr41279 int i, j; 1656*6557Sfr41279 BIG_CHUNK_TYPE t; 1657*6557Sfr41279 1658*6557Sfr41279 for (i = n->len - 1; i > 0; i--) { 1659*6557Sfr41279 if (n->value[i] != 0) { 1660*6557Sfr41279 break; 1661*6557Sfr41279 } 1662*6557Sfr41279 } 16630Sstevel@tonic-gate t = n->value[i]; 1664*6557Sfr41279 for (j = BIG_CHUNK_SIZE; j > 0; j--) { 1665*6557Sfr41279 if ((t & BIG_CHUNK_HIGHBIT) == 0) { 16660Sstevel@tonic-gate t = t << 1; 1667*6557Sfr41279 } else { 1668*6557Sfr41279 return (BIG_CHUNK_SIZE * i + j); 1669*6557Sfr41279 } 16700Sstevel@tonic-gate } 16710Sstevel@tonic-gate return (0); 16720Sstevel@tonic-gate } 16730Sstevel@tonic-gate 1674*6557Sfr41279 16750Sstevel@tonic-gate /* caller must make sure that a < n */ 16760Sstevel@tonic-gate BIG_ERR_CODE 16770Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n) 16780Sstevel@tonic-gate { 1679*6557Sfr41279 BIGNUM rr; 1680*6557Sfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 1681*6557Sfr41279 int len, i; 1682*6557Sfr41279 BIG_ERR_CODE err; 16830Sstevel@tonic-gate 16840Sstevel@tonic-gate rr.malloced = 0; 16850Sstevel@tonic-gate len = n->len; 16860Sstevel@tonic-gate 16870Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, 1688*6557Sfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 16890Sstevel@tonic-gate return (err); 1690*6557Sfr41279 } 1691*6557Sfr41279 1692*6557Sfr41279 for (i = 0; i < 2 * len; i++) { 1693*6557Sfr41279 rr.value[i] = 0; 1694*6557Sfr41279 } 16950Sstevel@tonic-gate rr.value[2 * len] = 1; 16960Sstevel@tonic-gate rr.len = 2 * len + 1; 1697*6557Sfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 16980Sstevel@tonic-gate goto ret; 1699*6557Sfr41279 } 17000Sstevel@tonic-gate err = big_copy(result, &rr); 17010Sstevel@tonic-gate ret: 1702*6557Sfr41279 big_finish(&rr); 17030Sstevel@tonic-gate return (err); 17040Sstevel@tonic-gate } 17050Sstevel@tonic-gate 1706*6557Sfr41279 17070Sstevel@tonic-gate /* caller must make sure that a < n */ 17080Sstevel@tonic-gate BIG_ERR_CODE 1709*6557Sfr41279 big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, BIG_CHUNK_TYPE n0, 1710*6557Sfr41279 BIGNUM *n_rr) 17110Sstevel@tonic-gate { 1712*6557Sfr41279 BIGNUM rr; 1713*6557Sfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 1714*6557Sfr41279 int len, i; 1715*6557Sfr41279 BIG_ERR_CODE err; 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate rr.malloced = 0; 17180Sstevel@tonic-gate len = n->len; 17190Sstevel@tonic-gate 17200Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue))) 1721*6557Sfr41279 != BIG_OK) { 1722*6557Sfr41279 return (err); 1723*6557Sfr41279 } 17240Sstevel@tonic-gate 17250Sstevel@tonic-gate if (n_rr == NULL) { 1726*6557Sfr41279 for (i = 0; i < 2 * len; i++) { 1727*6557Sfr41279 rr.value[i] = 0; 1728*6557Sfr41279 } 17290Sstevel@tonic-gate rr.value[2 * len] = 1; 17300Sstevel@tonic-gate rr.len = 2 * len + 1; 1731*6557Sfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 17320Sstevel@tonic-gate goto ret; 1733*6557Sfr41279 } 17340Sstevel@tonic-gate n_rr = &rr; 17350Sstevel@tonic-gate } 17360Sstevel@tonic-gate 1737*6557Sfr41279 if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK) { 17380Sstevel@tonic-gate goto ret; 1739*6557Sfr41279 } 17400Sstevel@tonic-gate err = big_copy(result, &rr); 1741*6557Sfr41279 17420Sstevel@tonic-gate ret: 1743*6557Sfr41279 big_finish(&rr); 17440Sstevel@tonic-gate return (err); 17450Sstevel@tonic-gate } 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate 1748*6557Sfr41279 #ifdef USE_FLOATING_POINT 1749*6557Sfr41279 #define big_modexp_ncp_float big_modexp_ncp_sw 1750*6557Sfr41279 #else 1751*6557Sfr41279 #define big_modexp_ncp_int big_modexp_ncp_sw 1752*6557Sfr41279 #endif 1753*6557Sfr41279 17540Sstevel@tonic-gate #define MAX_EXP_BIT_GROUP_SIZE 6 17550Sstevel@tonic-gate #define APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1)) 17560Sstevel@tonic-gate 1757*6557Sfr41279 /* ARGSUSED */ 17580Sstevel@tonic-gate static BIG_ERR_CODE 1759*6557Sfr41279 big_modexp_ncp_int(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 1760*6557Sfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 1761*6557Sfr41279 17620Sstevel@tonic-gate { 1763*6557Sfr41279 BIGNUM apowers[APOWERS_MAX_SIZE]; 1764*6557Sfr41279 BIGNUM tmp1; 1765*6557Sfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 1766*6557Sfr41279 int i, j, k, l, m, p; 1767*6557Sfr41279 int bit, bitind, bitcount, groupbits, apowerssize; 1768*6557Sfr41279 int nbits; 1769*6557Sfr41279 BIG_ERR_CODE err; 17700Sstevel@tonic-gate 17710Sstevel@tonic-gate nbits = big_numbits(e); 17720Sstevel@tonic-gate if (nbits < 50) { 17730Sstevel@tonic-gate groupbits = 1; 17740Sstevel@tonic-gate apowerssize = 1; 17750Sstevel@tonic-gate } else { 17760Sstevel@tonic-gate groupbits = MAX_EXP_BIT_GROUP_SIZE; 17770Sstevel@tonic-gate apowerssize = 1 << (groupbits - 1); 17780Sstevel@tonic-gate } 17790Sstevel@tonic-gate 1780*6557Sfr41279 1781*6557Sfr41279 if ((err = big_init1(&tmp1, 2 * n->len + 1, 1782*6557Sfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 17830Sstevel@tonic-gate return (err); 1784*6557Sfr41279 } 1785*6557Sfr41279 1786*6557Sfr41279 /* set the malloced bit to help cleanup */ 1787*6557Sfr41279 for (i = 0; i < apowerssize; i++) { 1788*6557Sfr41279 apowers[i].malloced = 0; 1789*6557Sfr41279 } 1790*6557Sfr41279 for (i = 0; i < apowerssize; i++) { 1791*6557Sfr41279 if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) != 1792*6557Sfr41279 BIG_OK) { 1793*6557Sfr41279 goto ret; 1794*6557Sfr41279 } 1795*6557Sfr41279 } 1796*6557Sfr41279 1797*6557Sfr41279 (void) big_copy(&(apowers[0]), ma); 1798*6557Sfr41279 1799*6557Sfr41279 if ((err = big_mont_mul(&tmp1, ma, ma, n, n0)) != BIG_OK) { 1800*6557Sfr41279 goto ret; 1801*6557Sfr41279 } 1802*6557Sfr41279 (void) big_copy(ma, &tmp1); 1803*6557Sfr41279 1804*6557Sfr41279 for (i = 1; i < apowerssize; i++) { 1805*6557Sfr41279 if ((err = big_mont_mul(&tmp1, ma, 1806*6557Sfr41279 &(apowers[i-1]), n, n0)) != BIG_OK) { 1807*6557Sfr41279 goto ret; 1808*6557Sfr41279 } 1809*6557Sfr41279 (void) big_copy(&apowers[i], &tmp1); 1810*6557Sfr41279 } 1811*6557Sfr41279 1812*6557Sfr41279 bitind = nbits % BIG_CHUNK_SIZE; 1813*6557Sfr41279 k = 0; 1814*6557Sfr41279 l = 0; 1815*6557Sfr41279 p = 0; 1816*6557Sfr41279 bitcount = 0; 1817*6557Sfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 1818*6557Sfr41279 for (j = bitind - 1; j >= 0; j--) { 1819*6557Sfr41279 bit = (e->value[i] >> j) & 1; 1820*6557Sfr41279 if ((bitcount == 0) && (bit == 0)) { 1821*6557Sfr41279 if ((err = big_mont_mul(tmp, 1822*6557Sfr41279 tmp, tmp, n, n0)) != BIG_OK) { 1823*6557Sfr41279 goto ret; 1824*6557Sfr41279 } 1825*6557Sfr41279 } else { 1826*6557Sfr41279 bitcount++; 1827*6557Sfr41279 p = p * 2 + bit; 1828*6557Sfr41279 if (bit == 1) { 1829*6557Sfr41279 k = k + l + 1; 1830*6557Sfr41279 l = 0; 1831*6557Sfr41279 } else { 1832*6557Sfr41279 l++; 1833*6557Sfr41279 } 1834*6557Sfr41279 if (bitcount == groupbits) { 1835*6557Sfr41279 for (m = 0; m < k; m++) { 1836*6557Sfr41279 if ((err = big_mont_mul(tmp, 1837*6557Sfr41279 tmp, tmp, n, n0)) != 1838*6557Sfr41279 BIG_OK) { 1839*6557Sfr41279 goto ret; 1840*6557Sfr41279 } 1841*6557Sfr41279 } 1842*6557Sfr41279 if ((err = big_mont_mul(tmp, tmp, 1843*6557Sfr41279 &(apowers[p >> (l + 1)]), 1844*6557Sfr41279 n, n0)) != BIG_OK) { 1845*6557Sfr41279 goto ret; 1846*6557Sfr41279 } 1847*6557Sfr41279 for (m = 0; m < l; m++) { 1848*6557Sfr41279 if ((err = big_mont_mul(tmp, 1849*6557Sfr41279 tmp, tmp, n, n0)) != 1850*6557Sfr41279 BIG_OK) { 1851*6557Sfr41279 goto ret; 1852*6557Sfr41279 } 1853*6557Sfr41279 } 1854*6557Sfr41279 k = 0; 1855*6557Sfr41279 l = 0; 1856*6557Sfr41279 p = 0; 1857*6557Sfr41279 bitcount = 0; 1858*6557Sfr41279 } 1859*6557Sfr41279 } 1860*6557Sfr41279 } 1861*6557Sfr41279 bitind = BIG_CHUNK_SIZE; 18620Sstevel@tonic-gate } 18630Sstevel@tonic-gate 1864*6557Sfr41279 for (m = 0; m < k; m++) { 1865*6557Sfr41279 if ((err = big_mont_mul(tmp, tmp, tmp, n, n0)) != BIG_OK) { 1866*6557Sfr41279 goto ret; 1867*6557Sfr41279 } 1868*6557Sfr41279 } 1869*6557Sfr41279 if (p != 0) { 1870*6557Sfr41279 if ((err = big_mont_mul(tmp, tmp, 1871*6557Sfr41279 &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK) { 1872*6557Sfr41279 goto ret; 1873*6557Sfr41279 } 1874*6557Sfr41279 } 1875*6557Sfr41279 for (m = 0; m < l; m++) { 1876*6557Sfr41279 if ((err = big_mont_mul(result, tmp, tmp, n, n0)) != BIG_OK) { 1877*6557Sfr41279 goto ret; 1878*6557Sfr41279 } 1879*6557Sfr41279 } 1880*6557Sfr41279 1881*6557Sfr41279 ret: 1882*6557Sfr41279 for (i = apowerssize - 1; i >= 0; i--) { 1883*6557Sfr41279 big_finish(&(apowers[i])); 18840Sstevel@tonic-gate } 1885*6557Sfr41279 big_finish(&tmp1); 1886*6557Sfr41279 1887*6557Sfr41279 return (err); 1888*6557Sfr41279 } 1889*6557Sfr41279 1890*6557Sfr41279 1891*6557Sfr41279 #ifdef USE_FLOATING_POINT 1892*6557Sfr41279 1893*6557Sfr41279 #ifdef _KERNEL 1894*6557Sfr41279 1895*6557Sfr41279 #include <sys/sysmacros.h> 1896*6557Sfr41279 #include <sys/regset.h> 1897*6557Sfr41279 #include <sys/fpu/fpusystm.h> 1898*6557Sfr41279 1899*6557Sfr41279 /* the alignment for block stores to save fp registers */ 1900*6557Sfr41279 #define FPR_ALIGN (64) 1901*6557Sfr41279 1902*6557Sfr41279 extern void big_savefp(kfpu_t *); 1903*6557Sfr41279 extern void big_restorefp(kfpu_t *); 1904*6557Sfr41279 1905*6557Sfr41279 #endif /* _KERNEL */ 1906*6557Sfr41279 1907*6557Sfr41279 /* 1908*6557Sfr41279 * This version makes use of floating point for performance 1909*6557Sfr41279 */ 1910*6557Sfr41279 static BIG_ERR_CODE 1911*6557Sfr41279 big_modexp_ncp_float(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 1912*6557Sfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 1913*6557Sfr41279 { 1914*6557Sfr41279 1915*6557Sfr41279 int i, j, k, l, m, p, bit, bitind, bitcount, nlen; 1916*6557Sfr41279 double dn0; 1917*6557Sfr41279 double *dn, *dt, *d16r, *d32r; 1918*6557Sfr41279 uint32_t *nint, *prod; 1919*6557Sfr41279 double *apowers[APOWERS_MAX_SIZE]; 1920*6557Sfr41279 int nbits, groupbits, apowerssize; 1921*6557Sfr41279 BIG_ERR_CODE err = BIG_OK; 1922*6557Sfr41279 1923*6557Sfr41279 #ifdef _KERNEL 1924*6557Sfr41279 uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN]; 1925*6557Sfr41279 kfpu_t *fpu; 1926*6557Sfr41279 1927*6557Sfr41279 #ifdef DEBUG 1928*6557Sfr41279 if (!fpu_exists) 1929*6557Sfr41279 return (BIG_GENERAL_ERR); 1930*6557Sfr41279 #endif 1931*6557Sfr41279 1932*6557Sfr41279 fpu = (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN); 1933*6557Sfr41279 big_savefp(fpu); 1934*6557Sfr41279 1935*6557Sfr41279 #endif /* _KERNEL */ 1936*6557Sfr41279 1937*6557Sfr41279 nbits = big_numbits(e); 1938*6557Sfr41279 if (nbits < 50) { 1939*6557Sfr41279 groupbits = 1; 1940*6557Sfr41279 apowerssize = 1; 1941*6557Sfr41279 } else { 1942*6557Sfr41279 groupbits = MAX_EXP_BIT_GROUP_SIZE; 1943*6557Sfr41279 apowerssize = 1 << (groupbits - 1); 1944*6557Sfr41279 } 1945*6557Sfr41279 1946*6557Sfr41279 nlen = (BIG_CHUNK_SIZE / 32) * n->len; 19470Sstevel@tonic-gate dn0 = (double)(n0 & 0xffff); 19480Sstevel@tonic-gate 19490Sstevel@tonic-gate dn = dt = d16r = d32r = NULL; 19500Sstevel@tonic-gate nint = prod = NULL; 19510Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 19520Sstevel@tonic-gate apowers[i] = NULL; 19530Sstevel@tonic-gate } 19540Sstevel@tonic-gate 19550Sstevel@tonic-gate if ((dn = big_malloc(nlen * sizeof (double))) == NULL) { 19560Sstevel@tonic-gate err = BIG_NO_MEM; 19570Sstevel@tonic-gate goto ret; 19580Sstevel@tonic-gate } 19590Sstevel@tonic-gate if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) { 19600Sstevel@tonic-gate err = BIG_NO_MEM; 19610Sstevel@tonic-gate goto ret; 19620Sstevel@tonic-gate } 19630Sstevel@tonic-gate if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) { 19640Sstevel@tonic-gate err = BIG_NO_MEM; 19650Sstevel@tonic-gate goto ret; 19660Sstevel@tonic-gate } 19670Sstevel@tonic-gate if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) { 19680Sstevel@tonic-gate err = BIG_NO_MEM; 19690Sstevel@tonic-gate goto ret; 19700Sstevel@tonic-gate } 19710Sstevel@tonic-gate if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) { 19720Sstevel@tonic-gate err = BIG_NO_MEM; 19730Sstevel@tonic-gate goto ret; 19740Sstevel@tonic-gate } 19750Sstevel@tonic-gate if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) { 19760Sstevel@tonic-gate err = BIG_NO_MEM; 19770Sstevel@tonic-gate goto ret; 19780Sstevel@tonic-gate } 19790Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 19800Sstevel@tonic-gate if ((apowers[i] = big_malloc((2 * nlen + 1) * 19810Sstevel@tonic-gate sizeof (double))) == NULL) { 19820Sstevel@tonic-gate err = BIG_NO_MEM; 19830Sstevel@tonic-gate goto ret; 19840Sstevel@tonic-gate } 19850Sstevel@tonic-gate } 19860Sstevel@tonic-gate 1987*6557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 1988*6557Sfr41279 for (i = 0; i < ma->len; i++) { 1989*6557Sfr41279 nint[i] = ma->value[i]; 1990*6557Sfr41279 } 1991*6557Sfr41279 for (; i < nlen; i++) { 1992*6557Sfr41279 nint[i] = 0; 1993*6557Sfr41279 } 1994*6557Sfr41279 #else 1995*6557Sfr41279 for (i = 0; i < ma->len; i++) { 1996*6557Sfr41279 nint[2 * i] = (uint32_t)(ma->value[i] & 0xffffffffULL); 1997*6557Sfr41279 nint[2 * i + 1] = (uint32_t)(ma->value[i] >> 32); 1998*6557Sfr41279 } 1999*6557Sfr41279 for (i = ma->len * 2; i < nlen; i++) { 2000*6557Sfr41279 nint[i] = 0; 2001*6557Sfr41279 } 2002*6557Sfr41279 #endif 20030Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen); 20040Sstevel@tonic-gate 2005*6557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 2006*6557Sfr41279 for (i = 0; i < n->len; i++) { 2007*6557Sfr41279 nint[i] = n->value[i]; 2008*6557Sfr41279 } 2009*6557Sfr41279 for (; i < nlen; i++) { 2010*6557Sfr41279 nint[i] = 0; 2011*6557Sfr41279 } 2012*6557Sfr41279 #else 2013*6557Sfr41279 for (i = 0; i < n->len; i++) { 2014*6557Sfr41279 nint[2 * i] = (uint32_t)(n->value[i] & 0xffffffffULL); 2015*6557Sfr41279 nint[2 * i + 1] = (uint32_t)(n->value[i] >> 32); 2016*6557Sfr41279 } 2017*6557Sfr41279 for (i = n->len * 2; i < nlen; i++) { 2018*6557Sfr41279 nint[i] = 0; 2019*6557Sfr41279 } 2020*6557Sfr41279 #endif 20210Sstevel@tonic-gate conv_i32_to_d32(dn, nint, nlen); 20220Sstevel@tonic-gate 20230Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0); 20240Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 20250Sstevel@tonic-gate for (i = 1; i < apowerssize; i++) { 20260Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[i - 1], 20270Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 20280Sstevel@tonic-gate conv_i32_to_d16(apowers[i], prod, nlen); 20290Sstevel@tonic-gate } 20300Sstevel@tonic-gate 2031*6557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 2032*6557Sfr41279 for (i = 0; i < tmp->len; i++) { 2033*6557Sfr41279 prod[i] = tmp->value[i]; 2034*6557Sfr41279 } 2035*6557Sfr41279 for (; i < nlen + 1; i++) { 2036*6557Sfr41279 prod[i] = 0; 2037*6557Sfr41279 } 2038*6557Sfr41279 #else 2039*6557Sfr41279 for (i = 0; i < tmp->len; i++) { 2040*6557Sfr41279 prod[2 * i] = (uint32_t)(tmp->value[i] & 0xffffffffULL); 2041*6557Sfr41279 prod[2 * i + 1] = (uint32_t)(tmp->value[i] >> 32); 2042*6557Sfr41279 } 2043*6557Sfr41279 for (i = tmp->len * 2; i < nlen + 1; i++) { 2044*6557Sfr41279 prod[i] = 0; 2045*6557Sfr41279 } 2046*6557Sfr41279 #endif 2047*6557Sfr41279 2048*6557Sfr41279 bitind = nbits % BIG_CHUNK_SIZE; 20490Sstevel@tonic-gate k = 0; 20500Sstevel@tonic-gate l = 0; 20510Sstevel@tonic-gate p = 0; 20520Sstevel@tonic-gate bitcount = 0; 2053*6557Sfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 20540Sstevel@tonic-gate for (j = bitind - 1; j >= 0; j--) { 20550Sstevel@tonic-gate bit = (e->value[i] >> j) & 1; 20560Sstevel@tonic-gate if ((bitcount == 0) && (bit == 0)) { 20570Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, 20580Sstevel@tonic-gate prod, nlen); 20590Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, 20600Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 20610Sstevel@tonic-gate } else { 20620Sstevel@tonic-gate bitcount++; 20630Sstevel@tonic-gate p = p * 2 + bit; 20640Sstevel@tonic-gate if (bit == 1) { 20650Sstevel@tonic-gate k = k + l + 1; 20660Sstevel@tonic-gate l = 0; 20670Sstevel@tonic-gate } else { 20680Sstevel@tonic-gate l++; 20690Sstevel@tonic-gate } 20700Sstevel@tonic-gate if (bitcount == groupbits) { 20710Sstevel@tonic-gate for (m = 0; m < k; m++) { 2072*6557Sfr41279 conv_i32_to_d32_and_d16(d32r, 2073*6557Sfr41279 d16r, prod, nlen); 20740Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 20750Sstevel@tonic-gate d16r, dt, dn, nint, 20760Sstevel@tonic-gate nlen, dn0); 20770Sstevel@tonic-gate } 20780Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 20790Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 20800Sstevel@tonic-gate apowers[p >> (l+1)], 20810Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 20820Sstevel@tonic-gate for (m = 0; m < l; m++) { 2083*6557Sfr41279 conv_i32_to_d32_and_d16(d32r, 2084*6557Sfr41279 d16r, prod, nlen); 20850Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 20860Sstevel@tonic-gate d16r, dt, dn, nint, 20870Sstevel@tonic-gate nlen, dn0); 20880Sstevel@tonic-gate } 20890Sstevel@tonic-gate k = 0; 20900Sstevel@tonic-gate l = 0; 20910Sstevel@tonic-gate p = 0; 20920Sstevel@tonic-gate bitcount = 0; 20930Sstevel@tonic-gate } 20940Sstevel@tonic-gate } 20950Sstevel@tonic-gate } 2096*6557Sfr41279 bitind = BIG_CHUNK_SIZE; 20970Sstevel@tonic-gate } 20980Sstevel@tonic-gate 20990Sstevel@tonic-gate for (m = 0; m < k; m++) { 21000Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 21010Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 21020Sstevel@tonic-gate } 21030Sstevel@tonic-gate if (p != 0) { 21040Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 21050Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)], 21060Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21070Sstevel@tonic-gate } 21080Sstevel@tonic-gate for (m = 0; m < l; m++) { 21090Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 21100Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 21110Sstevel@tonic-gate } 21120Sstevel@tonic-gate 2113*6557Sfr41279 #if (BIG_CHUNK_SIZE == 32) 2114*6557Sfr41279 for (i = 0; i < nlen; i++) { 2115*6557Sfr41279 result->value[i] = prod[i]; 2116*6557Sfr41279 } 2117*6557Sfr41279 for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--) 2118*6557Sfr41279 ; 2119*6557Sfr41279 #else 2120*6557Sfr41279 for (i = 0; i < nlen / 2; i++) { 2121*6557Sfr41279 result->value[i] = (uint64_t)(prod[2 * i]) + 2122*6557Sfr41279 (((uint64_t)(prod[2 * i + 1])) << 32); 2123*6557Sfr41279 } 2124*6557Sfr41279 for (i = nlen / 2 - 1; (i > 0) && (result->value[i] == 0); i--) 2125*6557Sfr41279 ; 2126*6557Sfr41279 #endif 2127*6557Sfr41279 result->len = i + 1; 2128*6557Sfr41279 21290Sstevel@tonic-gate ret: 21300Sstevel@tonic-gate for (i = apowerssize - 1; i >= 0; i--) { 21310Sstevel@tonic-gate if (apowers[i] != NULL) 21320Sstevel@tonic-gate big_free(apowers[i], (2 * nlen + 1) * sizeof (double)); 21330Sstevel@tonic-gate } 2134*6557Sfr41279 if (d32r != NULL) { 21350Sstevel@tonic-gate big_free(d32r, nlen * sizeof (double)); 2136*6557Sfr41279 } 2137*6557Sfr41279 if (d16r != NULL) { 21380Sstevel@tonic-gate big_free(d16r, (2 * nlen + 1) * sizeof (double)); 2139*6557Sfr41279 } 2140*6557Sfr41279 if (prod != NULL) { 21410Sstevel@tonic-gate big_free(prod, (nlen + 1) * sizeof (uint32_t)); 2142*6557Sfr41279 } 2143*6557Sfr41279 if (nint != NULL) { 21440Sstevel@tonic-gate big_free(nint, nlen * sizeof (uint32_t)); 2145*6557Sfr41279 } 2146*6557Sfr41279 if (dt != NULL) { 21470Sstevel@tonic-gate big_free(dt, (4 * nlen + 2) * sizeof (double)); 2148*6557Sfr41279 } 2149*6557Sfr41279 if (dn != NULL) { 21500Sstevel@tonic-gate big_free(dn, nlen * sizeof (double)); 2151*6557Sfr41279 } 21520Sstevel@tonic-gate 21530Sstevel@tonic-gate #ifdef _KERNEL 2154*6557Sfr41279 big_restorefp(fpu); 21550Sstevel@tonic-gate #endif 21560Sstevel@tonic-gate 21570Sstevel@tonic-gate return (err); 21580Sstevel@tonic-gate } 21590Sstevel@tonic-gate 21600Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */ 21610Sstevel@tonic-gate 21620Sstevel@tonic-gate 21630Sstevel@tonic-gate BIG_ERR_CODE 2164*6557Sfr41279 big_modexp_ext(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr, 2165*6557Sfr41279 big_modexp_ncp_info_t *info) 21660Sstevel@tonic-gate { 2167*6557Sfr41279 BIGNUM ma, tmp, rr; 2168*6557Sfr41279 BIG_CHUNK_TYPE mavalue[BIGTMPSIZE]; 2169*6557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 2170*6557Sfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 2171*6557Sfr41279 BIG_ERR_CODE err; 2172*6557Sfr41279 BIG_CHUNK_TYPE n0; 2173*6557Sfr41279 2174*6557Sfr41279 if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue))) != 2175*6557Sfr41279 BIG_OK) { 21760Sstevel@tonic-gate return (err); 2177*6557Sfr41279 } 2178*6557Sfr41279 ma.len = 1; 2179*6557Sfr41279 ma.value[0] = 0; 2180*6557Sfr41279 2181*6557Sfr41279 if ((err = big_init1(&tmp, 2 * n->len + 1, 2182*6557Sfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 21830Sstevel@tonic-gate goto ret1; 2184*6557Sfr41279 } 2185*6557Sfr41279 2186*6557Sfr41279 /* set the malloced bit to help cleanup */ 2187*6557Sfr41279 rr.malloced = 0; 2188*6557Sfr41279 if (n_rr == NULL) { 2189*6557Sfr41279 if ((err = big_init1(&rr, 2 * n->len + 1, 2190*6557Sfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 2191*6557Sfr41279 goto ret2; 2192*6557Sfr41279 } 2193*6557Sfr41279 if (big_mont_rr(&rr, n) != BIG_OK) { 2194*6557Sfr41279 goto ret; 2195*6557Sfr41279 } 2196*6557Sfr41279 n_rr = &rr; 2197*6557Sfr41279 } 2198*6557Sfr41279 2199*6557Sfr41279 n0 = big_n0(n->value[0]); 2200*6557Sfr41279 2201*6557Sfr41279 if (big_cmp_abs(a, n) > 0) { 2202*6557Sfr41279 if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK) { 2203*6557Sfr41279 goto ret; 2204*6557Sfr41279 } 2205*6557Sfr41279 err = big_mont_conv(&ma, &ma, n, n0, n_rr); 2206*6557Sfr41279 } else { 2207*6557Sfr41279 err = big_mont_conv(&ma, a, n, n0, n_rr); 2208*6557Sfr41279 } 2209*6557Sfr41279 if (err != BIG_OK) { 2210*6557Sfr41279 goto ret; 2211*6557Sfr41279 } 2212*6557Sfr41279 2213*6557Sfr41279 tmp.len = 1; 2214*6557Sfr41279 tmp.value[0] = 1; 2215*6557Sfr41279 if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK) { 2216*6557Sfr41279 goto ret; 2217*6557Sfr41279 } 2218*6557Sfr41279 2219*6557Sfr41279 if ((info != NULL) && (info->func != NULL)) { 2220*6557Sfr41279 err = (*(info->func))(&tmp, &ma, e, n, &tmp, n0, 2221*6557Sfr41279 info->ncp, info->reqp); 2222*6557Sfr41279 } else { 2223*6557Sfr41279 err = big_modexp_ncp_sw(&tmp, &ma, e, n, &tmp, n0); 2224*6557Sfr41279 } 2225*6557Sfr41279 if (err != BIG_OK) { 2226*6557Sfr41279 goto ret; 2227*6557Sfr41279 } 2228*6557Sfr41279 2229*6557Sfr41279 ma.value[0] = 1; 2230*6557Sfr41279 ma.len = 1; 2231*6557Sfr41279 if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK) { 2232*6557Sfr41279 goto ret; 2233*6557Sfr41279 } 2234*6557Sfr41279 err = big_copy(result, &tmp); 2235*6557Sfr41279 2236*6557Sfr41279 ret: 2237*6557Sfr41279 if (rr.malloced) { 2238*6557Sfr41279 big_finish(&rr); 2239*6557Sfr41279 } 2240*6557Sfr41279 ret2: 2241*6557Sfr41279 big_finish(&tmp); 2242*6557Sfr41279 ret1: 2243*6557Sfr41279 big_finish(&ma); 2244*6557Sfr41279 2245*6557Sfr41279 return (err); 2246*6557Sfr41279 } 2247*6557Sfr41279 2248*6557Sfr41279 BIG_ERR_CODE 2249*6557Sfr41279 big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr) 2250*6557Sfr41279 { 2251*6557Sfr41279 return (big_modexp_ext(result, a, e, n, n_rr, NULL)); 2252*6557Sfr41279 } 2253*6557Sfr41279 2254*6557Sfr41279 2255*6557Sfr41279 BIG_ERR_CODE 2256*6557Sfr41279 big_modexp_crt_ext(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 2257*6557Sfr41279 BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 2258*6557Sfr41279 BIGNUM *p_rr, BIGNUM *q_rr, big_modexp_ncp_info_t *info) 2259*6557Sfr41279 { 2260*6557Sfr41279 BIGNUM ap, aq, tmp; 2261*6557Sfr41279 int alen, biglen, sign; 2262*6557Sfr41279 BIG_ERR_CODE err; 2263*6557Sfr41279 2264*6557Sfr41279 if (p->len > q->len) { 2265*6557Sfr41279 biglen = p->len; 2266*6557Sfr41279 } else { 2267*6557Sfr41279 biglen = q->len; 2268*6557Sfr41279 } 2269*6557Sfr41279 2270*6557Sfr41279 if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK) { 2271*6557Sfr41279 return (err); 2272*6557Sfr41279 } 2273*6557Sfr41279 if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK) { 2274*6557Sfr41279 goto ret1; 2275*6557Sfr41279 } 2276*6557Sfr41279 if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK) { 22770Sstevel@tonic-gate goto ret2; 2278*6557Sfr41279 } 22790Sstevel@tonic-gate 22800Sstevel@tonic-gate /* 22810Sstevel@tonic-gate * check whether a is too short - to avoid timing attacks 22820Sstevel@tonic-gate */ 22830Sstevel@tonic-gate alen = a->len; 22840Sstevel@tonic-gate while ((alen > p->len) && (a->value[alen - 1] == 0)) { 22850Sstevel@tonic-gate alen--; 22860Sstevel@tonic-gate } 22870Sstevel@tonic-gate if (alen < p->len + q->len) { 22880Sstevel@tonic-gate /* 22890Sstevel@tonic-gate * a is too short, add p*q to it before 22900Sstevel@tonic-gate * taking it modulo p and q 22910Sstevel@tonic-gate * this will also affect timing, but this difference 22920Sstevel@tonic-gate * does not depend on p or q, only on a 22930Sstevel@tonic-gate * (in "normal" operation, this path will never be 22940Sstevel@tonic-gate * taken, so it is not a performance penalty 22950Sstevel@tonic-gate */ 2296*6557Sfr41279 if ((err = big_mul(&tmp, p, q)) != BIG_OK) { 22970Sstevel@tonic-gate goto ret; 2298*6557Sfr41279 } 2299*6557Sfr41279 if ((err = big_add(&tmp, &tmp, a)) != BIG_OK) { 2300*6557Sfr41279 goto ret; 2301*6557Sfr41279 } 2302*6557Sfr41279 if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK) { 23030Sstevel@tonic-gate goto ret; 2304*6557Sfr41279 } 2305*6557Sfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 23060Sstevel@tonic-gate goto ret; 2307*6557Sfr41279 } 2308*6557Sfr41279 } else { 2309*6557Sfr41279 if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK) { 23100Sstevel@tonic-gate goto ret; 2311*6557Sfr41279 } 2312*6557Sfr41279 if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK) { 23130Sstevel@tonic-gate goto ret; 2314*6557Sfr41279 } 23150Sstevel@tonic-gate } 23160Sstevel@tonic-gate 2317*6557Sfr41279 if ((err = big_modexp_ext(&ap, &ap, dmodpminus1, p, p_rr, info)) != 2318*6557Sfr41279 BIG_OK) { 23190Sstevel@tonic-gate goto ret; 2320*6557Sfr41279 } 2321*6557Sfr41279 if ((err = big_modexp_ext(&aq, &aq, dmodqminus1, q, q_rr, info)) != 2322*6557Sfr41279 BIG_OK) { 23230Sstevel@tonic-gate goto ret; 2324*6557Sfr41279 } 2325*6557Sfr41279 if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK) { 23260Sstevel@tonic-gate goto ret; 2327*6557Sfr41279 } 2328*6557Sfr41279 if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK) { 23290Sstevel@tonic-gate goto ret; 2330*6557Sfr41279 } 23310Sstevel@tonic-gate sign = tmp.sign; 23320Sstevel@tonic-gate tmp.sign = 1; 2333*6557Sfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 23340Sstevel@tonic-gate goto ret; 2335*6557Sfr41279 } 23360Sstevel@tonic-gate if ((sign == -1) && (!big_is_zero(&aq))) { 23370Sstevel@tonic-gate (void) big_sub_pos(&aq, q, &aq); 23380Sstevel@tonic-gate } 2339*6557Sfr41279 if ((err = big_mul(&tmp, &aq, p)) != BIG_OK) { 23400Sstevel@tonic-gate goto ret; 2341*6557Sfr41279 } 23420Sstevel@tonic-gate err = big_add_abs(result, &ap, &tmp); 23430Sstevel@tonic-gate 23440Sstevel@tonic-gate ret: 23450Sstevel@tonic-gate big_finish(&tmp); 23460Sstevel@tonic-gate ret2: 23470Sstevel@tonic-gate big_finish(&aq); 23480Sstevel@tonic-gate ret1: 23490Sstevel@tonic-gate big_finish(&ap); 23500Sstevel@tonic-gate 23510Sstevel@tonic-gate return (err); 23520Sstevel@tonic-gate } 23530Sstevel@tonic-gate 23540Sstevel@tonic-gate 2355*6557Sfr41279 BIG_ERR_CODE 2356*6557Sfr41279 big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 2357*6557Sfr41279 BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 2358*6557Sfr41279 BIGNUM *p_rr, BIGNUM *q_rr) 2359*6557Sfr41279 { 2360*6557Sfr41279 return (big_modexp_crt_ext(result, a, dmodpminus1, dmodqminus1, 2361*6557Sfr41279 p, q, pinvmodq, p_rr, q_rr, NULL)); 2362*6557Sfr41279 } 2363*6557Sfr41279 2364*6557Sfr41279 2365*6557Sfr41279 static BIG_CHUNK_TYPE onearr[1] = {(BIG_CHUNK_TYPE)1}; 2366*6557Sfr41279 BIGNUM big_One = {1, 1, 1, 0, onearr}; 2367*6557Sfr41279 2368*6557Sfr41279 static BIG_CHUNK_TYPE twoarr[1] = {(BIG_CHUNK_TYPE)2}; 2369*6557Sfr41279 BIGNUM big_Two = {1, 1, 1, 0, twoarr}; 2370*6557Sfr41279 2371*6557Sfr41279 static BIG_CHUNK_TYPE fourarr[1] = {(BIG_CHUNK_TYPE)4}; 2372*6557Sfr41279 static BIGNUM big_Four = {1, 1, 1, 0, fourarr}; 2373*6557Sfr41279 23740Sstevel@tonic-gate 23750Sstevel@tonic-gate BIG_ERR_CODE 23760Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n) 23770Sstevel@tonic-gate { 2378*6557Sfr41279 BIGNUM *high, *low, *mid, *t; 2379*6557Sfr41279 BIGNUM t1, t2, t3, prod; 2380*6557Sfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 2381*6557Sfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 2382*6557Sfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 2383*6557Sfr41279 BIG_CHUNK_TYPE prodvalue[BIGTMPSIZE]; 2384*6557Sfr41279 int i, nbits, diff, nrootbits, highbits; 2385*6557Sfr41279 BIG_ERR_CODE err; 23860Sstevel@tonic-gate 23870Sstevel@tonic-gate nbits = big_numbits(n); 23880Sstevel@tonic-gate 23890Sstevel@tonic-gate if ((err = big_init1(&t1, n->len + 1, 23900Sstevel@tonic-gate t1value, arraysize(t1value))) != BIG_OK) 23910Sstevel@tonic-gate return (err); 23920Sstevel@tonic-gate if ((err = big_init1(&t2, n->len + 1, 23930Sstevel@tonic-gate t2value, arraysize(t2value))) != BIG_OK) 23940Sstevel@tonic-gate goto ret1; 23950Sstevel@tonic-gate if ((err = big_init1(&t3, n->len + 1, 23960Sstevel@tonic-gate t3value, arraysize(t3value))) != BIG_OK) 23970Sstevel@tonic-gate goto ret2; 23980Sstevel@tonic-gate if ((err = big_init1(&prod, n->len + 1, 23990Sstevel@tonic-gate prodvalue, arraysize(prodvalue))) != BIG_OK) 24000Sstevel@tonic-gate goto ret3; 24010Sstevel@tonic-gate 24020Sstevel@tonic-gate nrootbits = (nbits + 1) / 2; 2403*6557Sfr41279 t1.len = t2.len = t3.len = (nrootbits - 1) / BIG_CHUNK_SIZE + 1; 24040Sstevel@tonic-gate for (i = 0; i < t1.len; i++) { 24050Sstevel@tonic-gate t1.value[i] = 0; 2406*6557Sfr41279 t2.value[i] = BIG_CHUNK_ALLBITS; 24070Sstevel@tonic-gate } 2408*6557Sfr41279 highbits = nrootbits - BIG_CHUNK_SIZE * (t1.len - 1); 2409*6557Sfr41279 if (highbits == BIG_CHUNK_SIZE) { 2410*6557Sfr41279 t1.value[t1.len - 1] = BIG_CHUNK_HIGHBIT; 2411*6557Sfr41279 t2.value[t2.len - 1] = BIG_CHUNK_ALLBITS; 24120Sstevel@tonic-gate } else { 2413*6557Sfr41279 t1.value[t1.len - 1] = (BIG_CHUNK_TYPE)1 << (highbits - 1); 24140Sstevel@tonic-gate t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1; 24150Sstevel@tonic-gate } 2416*6557Sfr41279 24170Sstevel@tonic-gate high = &t2; 24180Sstevel@tonic-gate low = &t1; 24190Sstevel@tonic-gate mid = &t3; 24200Sstevel@tonic-gate 2421*6557Sfr41279 if ((err = big_mul(&prod, high, high)) != BIG_OK) { 24220Sstevel@tonic-gate goto ret; 2423*6557Sfr41279 } 24240Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 24250Sstevel@tonic-gate if (diff <= 0) { 24260Sstevel@tonic-gate err = big_copy(result, high); 24270Sstevel@tonic-gate goto ret; 24280Sstevel@tonic-gate } 24290Sstevel@tonic-gate 24300Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 2431*6557Sfr41279 while (big_cmp_abs(&big_One, mid) != 0) { 24320Sstevel@tonic-gate (void) big_add_abs(mid, high, low); 24330Sstevel@tonic-gate (void) big_half_pos(mid, mid); 24340Sstevel@tonic-gate if ((err = big_mul(&prod, mid, mid)) != BIG_OK) 24350Sstevel@tonic-gate goto ret; 24360Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 24370Sstevel@tonic-gate if (diff > 0) { 24380Sstevel@tonic-gate t = high; 24390Sstevel@tonic-gate high = mid; 24400Sstevel@tonic-gate mid = t; 24410Sstevel@tonic-gate } else if (diff < 0) { 24420Sstevel@tonic-gate t = low; 24430Sstevel@tonic-gate low = mid; 24440Sstevel@tonic-gate mid = t; 24450Sstevel@tonic-gate } else { 24460Sstevel@tonic-gate err = big_copy(result, low); 24470Sstevel@tonic-gate goto ret; 24480Sstevel@tonic-gate } 24490Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 24500Sstevel@tonic-gate } 24510Sstevel@tonic-gate 24520Sstevel@tonic-gate err = big_copy(result, low); 24530Sstevel@tonic-gate ret: 24540Sstevel@tonic-gate if (prod.malloced) big_finish(&prod); 24550Sstevel@tonic-gate ret3: 24560Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 24570Sstevel@tonic-gate ret2: 24580Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 24590Sstevel@tonic-gate ret1: 24600Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 24610Sstevel@tonic-gate 24620Sstevel@tonic-gate return (err); 24630Sstevel@tonic-gate } 24640Sstevel@tonic-gate 24650Sstevel@tonic-gate 24660Sstevel@tonic-gate BIG_ERR_CODE 24670Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm) 24680Sstevel@tonic-gate { 2469*6557Sfr41279 BIGNUM *t, *tmp2, *m, *n; 2470*6557Sfr41279 BIGNUM t1, t2, t3; 2471*6557Sfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 2472*6557Sfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 2473*6557Sfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 2474*6557Sfr41279 int len, err; 24750Sstevel@tonic-gate 24760Sstevel@tonic-gate if (big_is_zero(nn) || 24770Sstevel@tonic-gate (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) { 24780Sstevel@tonic-gate *jac = 0; 24790Sstevel@tonic-gate return (BIG_OK); 24800Sstevel@tonic-gate } 24810Sstevel@tonic-gate 2482*6557Sfr41279 if (nn->len > mm->len) { 2483*6557Sfr41279 len = nn->len; 2484*6557Sfr41279 } else { 2485*6557Sfr41279 len = mm->len; 2486*6557Sfr41279 } 24870Sstevel@tonic-gate 24880Sstevel@tonic-gate if ((err = big_init1(&t1, len, 2489*6557Sfr41279 t1value, arraysize(t1value))) != BIG_OK) { 24900Sstevel@tonic-gate return (err); 2491*6557Sfr41279 } 24920Sstevel@tonic-gate if ((err = big_init1(&t2, len, 2493*6557Sfr41279 t2value, arraysize(t2value))) != BIG_OK) { 24940Sstevel@tonic-gate goto ret1; 2495*6557Sfr41279 } 24960Sstevel@tonic-gate if ((err = big_init1(&t3, len, 2497*6557Sfr41279 t3value, arraysize(t3value))) != BIG_OK) { 24980Sstevel@tonic-gate goto ret2; 2499*6557Sfr41279 } 25000Sstevel@tonic-gate 25010Sstevel@tonic-gate n = &t1; 25020Sstevel@tonic-gate m = &t2; 25030Sstevel@tonic-gate tmp2 = &t3; 25040Sstevel@tonic-gate 25050Sstevel@tonic-gate (void) big_copy(n, nn); 25060Sstevel@tonic-gate (void) big_copy(m, mm); 25070Sstevel@tonic-gate 25080Sstevel@tonic-gate *jac = 1; 2509*6557Sfr41279 while (big_cmp_abs(&big_One, m) != 0) { 25100Sstevel@tonic-gate if (big_is_zero(n)) { 25110Sstevel@tonic-gate *jac = 0; 25120Sstevel@tonic-gate goto ret; 25130Sstevel@tonic-gate } 25140Sstevel@tonic-gate if ((m->value[0] & 1) == 0) { 25150Sstevel@tonic-gate if (((n->value[0] & 7) == 3) || 2516*6557Sfr41279 ((n->value[0] & 7) == 5)) 2517*6557Sfr41279 *jac = -*jac; 25180Sstevel@tonic-gate (void) big_half_pos(m, m); 25190Sstevel@tonic-gate } else if ((n->value[0] & 1) == 0) { 25200Sstevel@tonic-gate if (((m->value[0] & 7) == 3) || 2521*6557Sfr41279 ((m->value[0] & 7) == 5)) 2522*6557Sfr41279 *jac = -*jac; 25230Sstevel@tonic-gate (void) big_half_pos(n, n); 25240Sstevel@tonic-gate } else { 25250Sstevel@tonic-gate if (((m->value[0] & 3) == 3) && 25260Sstevel@tonic-gate ((n->value[0] & 3) == 3)) { 25270Sstevel@tonic-gate *jac = -*jac; 25280Sstevel@tonic-gate } 2529*6557Sfr41279 if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK) { 25300Sstevel@tonic-gate goto ret; 2531*6557Sfr41279 } 25320Sstevel@tonic-gate t = tmp2; 25330Sstevel@tonic-gate tmp2 = m; 25340Sstevel@tonic-gate m = n; 25350Sstevel@tonic-gate n = t; 25360Sstevel@tonic-gate } 25370Sstevel@tonic-gate } 25380Sstevel@tonic-gate err = BIG_OK; 25390Sstevel@tonic-gate 25400Sstevel@tonic-gate ret: 25410Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 25420Sstevel@tonic-gate ret2: 25430Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 25440Sstevel@tonic-gate ret1: 25450Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 25460Sstevel@tonic-gate 25470Sstevel@tonic-gate return (err); 25480Sstevel@tonic-gate } 25490Sstevel@tonic-gate 25500Sstevel@tonic-gate 25510Sstevel@tonic-gate BIG_ERR_CODE 25520Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n) 25530Sstevel@tonic-gate { 2554*6557Sfr41279 int m, w, i; 2555*6557Sfr41279 BIG_CHUNK_TYPE bit; 2556*6557Sfr41279 BIGNUM ki, tmp, tmp2; 2557*6557Sfr41279 BIG_CHUNK_TYPE kivalue[BIGTMPSIZE]; 2558*6557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 2559*6557Sfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 2560*6557Sfr41279 BIG_ERR_CODE err; 2561*6557Sfr41279 2562*6557Sfr41279 if (big_cmp_abs(k, &big_One) == 0) { 25630Sstevel@tonic-gate (void) big_copy(Lk, p); 2564*6557Sfr41279 (void) big_copy(Lkminus1, &big_Two); 25650Sstevel@tonic-gate return (BIG_OK); 25660Sstevel@tonic-gate } 25670Sstevel@tonic-gate 25680Sstevel@tonic-gate if ((err = big_init1(&ki, k->len + 1, 25690Sstevel@tonic-gate kivalue, arraysize(kivalue))) != BIG_OK) 25700Sstevel@tonic-gate return (err); 25710Sstevel@tonic-gate 25720Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * n->len +1, 25730Sstevel@tonic-gate tmpvalue, arraysize(tmpvalue))) != BIG_OK) 25740Sstevel@tonic-gate goto ret1; 25750Sstevel@tonic-gate 25760Sstevel@tonic-gate if ((err = big_init1(&tmp2, n->len, 25770Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 25780Sstevel@tonic-gate goto ret2; 25790Sstevel@tonic-gate 25800Sstevel@tonic-gate m = big_numbits(k); 2581*6557Sfr41279 ki.len = (m - 1) / BIG_CHUNK_SIZE + 1; 2582*6557Sfr41279 w = (m - 1) / BIG_CHUNK_SIZE; 2583*6557Sfr41279 bit = (BIG_CHUNK_TYPE)1 << ((m - 1) % BIG_CHUNK_SIZE); 2584*6557Sfr41279 for (i = 0; i < ki.len; i++) { 2585*6557Sfr41279 ki.value[i] = 0; 2586*6557Sfr41279 } 25870Sstevel@tonic-gate ki.value[ki.len - 1] = bit; 2588*6557Sfr41279 if (big_cmp_abs(k, &ki) != 0) { 25890Sstevel@tonic-gate (void) big_double(&ki, &ki); 2590*6557Sfr41279 } 25910Sstevel@tonic-gate (void) big_sub_pos(&ki, &ki, k); 25920Sstevel@tonic-gate 25930Sstevel@tonic-gate (void) big_copy(Lk, p); 2594*6557Sfr41279 (void) big_copy(Lkminus1, &big_Two); 25950Sstevel@tonic-gate 25960Sstevel@tonic-gate for (i = 0; i < m; i++) { 2597*6557Sfr41279 if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK) { 25980Sstevel@tonic-gate goto ret; 2599*6557Sfr41279 } 26000Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 26010Sstevel@tonic-gate (void) big_sub_pos(&tmp, &tmp, p); 2602*6557Sfr41279 if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK) { 26030Sstevel@tonic-gate goto ret; 2604*6557Sfr41279 } 26050Sstevel@tonic-gate if ((ki.value[w] & bit) != 0) { 26060Sstevel@tonic-gate if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) != 2607*6557Sfr41279 BIG_OK) { 26080Sstevel@tonic-gate goto ret; 2609*6557Sfr41279 } 26100Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 2611*6557Sfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Two); 26120Sstevel@tonic-gate if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) != 2613*6557Sfr41279 BIG_OK) { 26140Sstevel@tonic-gate goto ret; 2615*6557Sfr41279 } 26160Sstevel@tonic-gate (void) big_copy(Lk, &tmp2); 26170Sstevel@tonic-gate } else { 2618*6557Sfr41279 if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK) { 26190Sstevel@tonic-gate goto ret; 2620*6557Sfr41279 } 26210Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 2622*6557Sfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Two); 2623*6557Sfr41279 if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK) { 26240Sstevel@tonic-gate goto ret; 2625*6557Sfr41279 } 26260Sstevel@tonic-gate (void) big_copy(Lkminus1, &tmp2); 26270Sstevel@tonic-gate } 26280Sstevel@tonic-gate bit = bit >> 1; 26290Sstevel@tonic-gate if (bit == 0) { 2630*6557Sfr41279 bit = BIG_CHUNK_HIGHBIT; 26310Sstevel@tonic-gate w--; 26320Sstevel@tonic-gate } 26330Sstevel@tonic-gate } 26340Sstevel@tonic-gate 26350Sstevel@tonic-gate err = BIG_OK; 26360Sstevel@tonic-gate 26370Sstevel@tonic-gate ret: 26380Sstevel@tonic-gate if (tmp2.malloced) big_finish(&tmp2); 26390Sstevel@tonic-gate ret2: 26400Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 26410Sstevel@tonic-gate ret1: 26420Sstevel@tonic-gate if (ki.malloced) big_finish(&ki); 26430Sstevel@tonic-gate 26440Sstevel@tonic-gate return (err); 26450Sstevel@tonic-gate } 26460Sstevel@tonic-gate 26470Sstevel@tonic-gate 26480Sstevel@tonic-gate BIG_ERR_CODE 2649*6557Sfr41279 big_isprime_pos_ext(BIGNUM *n, big_modexp_ncp_info_t *info) 26500Sstevel@tonic-gate { 2651*6557Sfr41279 BIGNUM o, nminus1, tmp, Lkminus1, Lk; 2652*6557Sfr41279 BIG_CHUNK_TYPE ovalue[BIGTMPSIZE]; 2653*6557Sfr41279 BIG_CHUNK_TYPE nminus1value[BIGTMPSIZE]; 2654*6557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 2655*6557Sfr41279 BIG_CHUNK_TYPE Lkminus1value[BIGTMPSIZE]; 2656*6557Sfr41279 BIG_CHUNK_TYPE Lkvalue[BIGTMPSIZE]; 2657*6557Sfr41279 BIG_ERR_CODE err; 2658*6557Sfr41279 int e, i, jac; 2659*6557Sfr41279 2660*6557Sfr41279 if (big_cmp_abs(n, &big_One) == 0) { 26610Sstevel@tonic-gate return (BIG_FALSE); 2662*6557Sfr41279 } 2663*6557Sfr41279 if (big_cmp_abs(n, &big_Two) == 0) { 26640Sstevel@tonic-gate return (BIG_TRUE); 2665*6557Sfr41279 } 2666*6557Sfr41279 if ((n->value[0] & 1) == 0) { 26670Sstevel@tonic-gate return (BIG_FALSE); 2668*6557Sfr41279 } 2669*6557Sfr41279 2670*6557Sfr41279 if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) != 2671*6557Sfr41279 BIG_OK) { 26720Sstevel@tonic-gate return (err); 2673*6557Sfr41279 } 26740Sstevel@tonic-gate 26750Sstevel@tonic-gate if ((err = big_init1(&nminus1, n->len, 2676*6557Sfr41279 nminus1value, arraysize(nminus1value))) != BIG_OK) { 26770Sstevel@tonic-gate goto ret1; 2678*6557Sfr41279 } 26790Sstevel@tonic-gate 26800Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * n->len, 2681*6557Sfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 26820Sstevel@tonic-gate goto ret2; 2683*6557Sfr41279 } 26840Sstevel@tonic-gate 26850Sstevel@tonic-gate if ((err = big_init1(&Lkminus1, n->len, 2686*6557Sfr41279 Lkminus1value, arraysize(Lkminus1value))) != BIG_OK) { 26870Sstevel@tonic-gate goto ret3; 2688*6557Sfr41279 } 26890Sstevel@tonic-gate 26900Sstevel@tonic-gate if ((err = big_init1(&Lk, n->len, 2691*6557Sfr41279 Lkvalue, arraysize(Lkvalue))) != BIG_OK) { 26920Sstevel@tonic-gate goto ret4; 2693*6557Sfr41279 } 2694*6557Sfr41279 2695*6557Sfr41279 (void) big_sub_pos(&o, n, &big_One); /* cannot fail */ 26960Sstevel@tonic-gate (void) big_copy(&nminus1, &o); /* cannot fail */ 26970Sstevel@tonic-gate e = 0; 26980Sstevel@tonic-gate while ((o.value[0] & 1) == 0) { 26990Sstevel@tonic-gate e++; 27000Sstevel@tonic-gate (void) big_half_pos(&o, &o); /* cannot fail */ 27010Sstevel@tonic-gate } 2702*6557Sfr41279 if ((err = big_modexp_ext(&tmp, &big_Two, &o, n, NULL, info)) != 2703*6557Sfr41279 BIG_OK) { 27040Sstevel@tonic-gate goto ret; 2705*6557Sfr41279 } 2706*6557Sfr41279 27070Sstevel@tonic-gate i = 0; 27080Sstevel@tonic-gate while ((i < e) && 2709*6557Sfr41279 (big_cmp_abs(&tmp, &big_One) != 0) && 27100Sstevel@tonic-gate (big_cmp_abs(&tmp, &nminus1) != 0)) { 2711*6557Sfr41279 if ((err = 2712*6557Sfr41279 big_modexp_ext(&tmp, &tmp, &big_Two, n, NULL, info)) != 2713*6557Sfr41279 BIG_OK) 27140Sstevel@tonic-gate goto ret; 27150Sstevel@tonic-gate i++; 27160Sstevel@tonic-gate } 2717*6557Sfr41279 27180Sstevel@tonic-gate if (!((big_cmp_abs(&tmp, &nminus1) == 0) || 2719*6557Sfr41279 ((i == 0) && (big_cmp_abs(&tmp, &big_One) == 0)))) { 27200Sstevel@tonic-gate err = BIG_FALSE; 27210Sstevel@tonic-gate goto ret; 27220Sstevel@tonic-gate } 27230Sstevel@tonic-gate 2724*6557Sfr41279 if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK) { 27250Sstevel@tonic-gate goto ret; 2726*6557Sfr41279 } 2727*6557Sfr41279 2728*6557Sfr41279 if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK) { 27290Sstevel@tonic-gate goto ret; 2730*6557Sfr41279 } 27310Sstevel@tonic-gate if (big_cmp_abs(&tmp, n) == 0) { 27320Sstevel@tonic-gate err = BIG_FALSE; 27330Sstevel@tonic-gate goto ret; 27340Sstevel@tonic-gate } 27350Sstevel@tonic-gate 2736*6557Sfr41279 (void) big_copy(&o, &big_Two); 27370Sstevel@tonic-gate do { 2738*6557Sfr41279 (void) big_add_abs(&o, &o, &big_One); 2739*6557Sfr41279 if ((err = big_mul(&tmp, &o, &o)) != BIG_OK) { 27400Sstevel@tonic-gate goto ret; 2741*6557Sfr41279 } 2742*6557Sfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Four); 2743*6557Sfr41279 if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK) { 27440Sstevel@tonic-gate goto ret; 2745*6557Sfr41279 } 27460Sstevel@tonic-gate } while (jac != -1); 27470Sstevel@tonic-gate 2748*6557Sfr41279 (void) big_add_abs(&tmp, n, &big_One); 2749*6557Sfr41279 if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK) { 27500Sstevel@tonic-gate goto ret; 2751*6557Sfr41279 } 2752*6557Sfr41279 2753*6557Sfr41279 if ((big_cmp_abs(&Lkminus1, &o) == 0) && 2754*6557Sfr41279 (big_cmp_abs(&Lk, &big_Two) == 0)) { 27550Sstevel@tonic-gate err = BIG_TRUE; 2756*6557Sfr41279 } else { 2757*6557Sfr41279 err = BIG_FALSE; 2758*6557Sfr41279 } 27590Sstevel@tonic-gate 27600Sstevel@tonic-gate ret: 27610Sstevel@tonic-gate if (Lk.malloced) big_finish(&Lk); 27620Sstevel@tonic-gate ret4: 27630Sstevel@tonic-gate if (Lkminus1.malloced) big_finish(&Lkminus1); 27640Sstevel@tonic-gate ret3: 27650Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 27660Sstevel@tonic-gate ret2: 27670Sstevel@tonic-gate if (nminus1.malloced) big_finish(&nminus1); 27680Sstevel@tonic-gate ret1: 27690Sstevel@tonic-gate if (o.malloced) big_finish(&o); 27700Sstevel@tonic-gate 27710Sstevel@tonic-gate return (err); 27720Sstevel@tonic-gate } 27730Sstevel@tonic-gate 27740Sstevel@tonic-gate 2775*6557Sfr41279 BIG_ERR_CODE 2776*6557Sfr41279 big_isprime_pos(BIGNUM *n) 2777*6557Sfr41279 { 2778*6557Sfr41279 return (big_isprime_pos_ext(n, NULL)); 2779*6557Sfr41279 } 2780*6557Sfr41279 2781*6557Sfr41279 27820Sstevel@tonic-gate #define SIEVESIZE 1000 27830Sstevel@tonic-gate 27840Sstevel@tonic-gate uint32_t smallprimes[] = 27850Sstevel@tonic-gate { 27860Sstevel@tonic-gate 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 27870Sstevel@tonic-gate 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97 27880Sstevel@tonic-gate }; 27890Sstevel@tonic-gate 27900Sstevel@tonic-gate 27910Sstevel@tonic-gate BIG_ERR_CODE 2792*6557Sfr41279 big_nextprime_pos_ext(BIGNUM *result, BIGNUM *n, big_modexp_ncp_info_t *info) 27930Sstevel@tonic-gate { 2794*6557Sfr41279 BIG_ERR_CODE err; 2795*6557Sfr41279 int sieve[SIEVESIZE]; 2796*6557Sfr41279 int i; 2797*6557Sfr41279 uint32_t off, p; 2798*6557Sfr41279 2799*6557Sfr41279 if ((err = big_copy(result, n)) != BIG_OK) { 28000Sstevel@tonic-gate return (err); 2801*6557Sfr41279 } 28020Sstevel@tonic-gate result->value[0] |= 1; 28031027Srobinson /* CONSTCOND */ 28040Sstevel@tonic-gate while (1) { 28050Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0; 28060Sstevel@tonic-gate for (i = 0; 2807*6557Sfr41279 i < sizeof (smallprimes) / sizeof (smallprimes[0]); i++) { 28080Sstevel@tonic-gate p = smallprimes[i]; 2809*6557Sfr41279 off = big_modhalf_pos(result, p); 28100Sstevel@tonic-gate off = p - off; 2811*6557Sfr41279 if ((off % 2) == 1) { 2812*6557Sfr41279 off = off + p; 2813*6557Sfr41279 } 2814*6557Sfr41279 off = off / 2; 28150Sstevel@tonic-gate while (off < SIEVESIZE) { 28160Sstevel@tonic-gate sieve[off] = 1; 28170Sstevel@tonic-gate off = off + p; 28180Sstevel@tonic-gate } 28190Sstevel@tonic-gate } 28200Sstevel@tonic-gate 28210Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) { 28220Sstevel@tonic-gate if (sieve[i] == 0) { 2823*6557Sfr41279 err = big_isprime_pos_ext(result, info); 28240Sstevel@tonic-gate if (err != BIG_FALSE) { 2825*6557Sfr41279 if (err != BIG_TRUE) { 28260Sstevel@tonic-gate return (err); 2827*6557Sfr41279 } else { 2828*6557Sfr41279 goto out; 2829*6557Sfr41279 } 28300Sstevel@tonic-gate } 28310Sstevel@tonic-gate 28320Sstevel@tonic-gate } 2833*6557Sfr41279 if ((err = big_add_abs(result, result, &big_Two)) != 2834*6557Sfr41279 BIG_OK) { 28350Sstevel@tonic-gate return (err); 2836*6557Sfr41279 } 28370Sstevel@tonic-gate } 28380Sstevel@tonic-gate } 2839*6557Sfr41279 2840*6557Sfr41279 out: 2841*6557Sfr41279 return (BIG_OK); 2842*6557Sfr41279 } 2843*6557Sfr41279 2844*6557Sfr41279 2845*6557Sfr41279 BIG_ERR_CODE 2846*6557Sfr41279 big_nextprime_pos(BIGNUM *result, BIGNUM *n) 2847*6557Sfr41279 { 2848*6557Sfr41279 return (big_nextprime_pos_ext(result, n, NULL)); 28490Sstevel@tonic-gate } 28500Sstevel@tonic-gate 28510Sstevel@tonic-gate 28520Sstevel@tonic-gate BIG_ERR_CODE 28530Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n) 28540Sstevel@tonic-gate { 28550Sstevel@tonic-gate BIG_ERR_CODE err; 28560Sstevel@tonic-gate 28570Sstevel@tonic-gate 28580Sstevel@tonic-gate if ((err = big_copy(result, n)) != BIG_OK) 28590Sstevel@tonic-gate return (err); 28600Sstevel@tonic-gate result->value[0] |= 1; 2861*6557Sfr41279 while ((err = big_isprime_pos_ext(result, NULL)) != BIG_TRUE) { 28620Sstevel@tonic-gate if (err != BIG_FALSE) 28630Sstevel@tonic-gate return (err); 2864*6557Sfr41279 if ((err = big_add_abs(result, result, &big_Two)) != BIG_OK) 28650Sstevel@tonic-gate return (err); 28660Sstevel@tonic-gate } 28670Sstevel@tonic-gate return (BIG_OK); 28680Sstevel@tonic-gate } 28690Sstevel@tonic-gate 28700Sstevel@tonic-gate 28710Sstevel@tonic-gate /* 28720Sstevel@tonic-gate * given m and e, computes the rest in the equation 28730Sstevel@tonic-gate * gcd(m, e) = cm * m + ce * e 28740Sstevel@tonic-gate */ 28750Sstevel@tonic-gate BIG_ERR_CODE 28760Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e) 28770Sstevel@tonic-gate { 2878*6557Sfr41279 BIGNUM *xi, *ri, *riminus1, *riminus2, *t; 2879*6557Sfr41279 BIGNUM *vmi, *vei, *vmiminus1, *veiminus1; 2880*6557Sfr41279 BIGNUM t1, t2, t3, t4, t5, t6, t7, t8, tmp; 2881*6557Sfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 2882*6557Sfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 2883*6557Sfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 2884*6557Sfr41279 BIG_CHUNK_TYPE t4value[BIGTMPSIZE]; 2885*6557Sfr41279 BIG_CHUNK_TYPE t5value[BIGTMPSIZE]; 2886*6557Sfr41279 BIG_CHUNK_TYPE t6value[BIGTMPSIZE]; 2887*6557Sfr41279 BIG_CHUNK_TYPE t7value[BIGTMPSIZE]; 2888*6557Sfr41279 BIG_CHUNK_TYPE t8value[BIGTMPSIZE]; 2889*6557Sfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 2890*6557Sfr41279 BIG_ERR_CODE err; 2891*6557Sfr41279 int len; 2892*6557Sfr41279 2893*6557Sfr41279 if (big_cmp_abs(m, e) >= 0) { 2894*6557Sfr41279 len = m->len; 2895*6557Sfr41279 } else { 2896*6557Sfr41279 len = e->len; 2897*6557Sfr41279 } 28980Sstevel@tonic-gate 28990Sstevel@tonic-gate if ((err = big_init1(&t1, len, 2900*6557Sfr41279 t1value, arraysize(t1value))) != BIG_OK) { 29010Sstevel@tonic-gate return (err); 2902*6557Sfr41279 } 29030Sstevel@tonic-gate if ((err = big_init1(&t2, len, 2904*6557Sfr41279 t2value, arraysize(t2value))) != BIG_OK) { 2905*6557Sfr41279 goto ret1; 2906*6557Sfr41279 } 29070Sstevel@tonic-gate if ((err = big_init1(&t3, len, 2908*6557Sfr41279 t3value, arraysize(t3value))) != BIG_OK) { 2909*6557Sfr41279 goto ret2; 2910*6557Sfr41279 } 29110Sstevel@tonic-gate if ((err = big_init1(&t4, len, 2912*6557Sfr41279 t4value, arraysize(t3value))) != BIG_OK) { 2913*6557Sfr41279 goto ret3; 2914*6557Sfr41279 } 29150Sstevel@tonic-gate if ((err = big_init1(&t5, len, 2916*6557Sfr41279 t5value, arraysize(t5value))) != BIG_OK) { 2917*6557Sfr41279 goto ret4; 2918*6557Sfr41279 } 29190Sstevel@tonic-gate if ((err = big_init1(&t6, len, 2920*6557Sfr41279 t6value, arraysize(t6value))) != BIG_OK) { 2921*6557Sfr41279 goto ret5; 2922*6557Sfr41279 } 29230Sstevel@tonic-gate if ((err = big_init1(&t7, len, 2924*6557Sfr41279 t7value, arraysize(t7value))) != BIG_OK) { 2925*6557Sfr41279 goto ret6; 2926*6557Sfr41279 } 29270Sstevel@tonic-gate if ((err = big_init1(&t8, len, 2928*6557Sfr41279 t8value, arraysize(t8value))) != BIG_OK) { 2929*6557Sfr41279 goto ret7; 2930*6557Sfr41279 } 29310Sstevel@tonic-gate 29320Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * len, 2933*6557Sfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 29340Sstevel@tonic-gate goto ret8; 2935*6557Sfr41279 } 29360Sstevel@tonic-gate 29370Sstevel@tonic-gate ri = &t1; 29380Sstevel@tonic-gate ri->value[0] = 1; 29390Sstevel@tonic-gate ri->len = 1; 29400Sstevel@tonic-gate xi = &t2; 29410Sstevel@tonic-gate riminus1 = &t3; 29420Sstevel@tonic-gate riminus2 = &t4; 29430Sstevel@tonic-gate vmi = &t5; 29440Sstevel@tonic-gate vei = &t6; 29450Sstevel@tonic-gate vmiminus1 = &t7; 29460Sstevel@tonic-gate veiminus1 = &t8; 29470Sstevel@tonic-gate 2948*6557Sfr41279 (void) big_copy(vmiminus1, &big_One); 2949*6557Sfr41279 (void) big_copy(vmi, &big_One); 2950*6557Sfr41279 (void) big_copy(veiminus1, &big_One); 2951*6557Sfr41279 (void) big_copy(xi, &big_One); 29520Sstevel@tonic-gate vei->len = 1; 29530Sstevel@tonic-gate vei->value[0] = 0; 29540Sstevel@tonic-gate 29550Sstevel@tonic-gate (void) big_copy(riminus1, m); 29560Sstevel@tonic-gate (void) big_copy(ri, e); 29570Sstevel@tonic-gate 29580Sstevel@tonic-gate while (!big_is_zero(ri)) { 29590Sstevel@tonic-gate t = riminus2; 29600Sstevel@tonic-gate riminus2 = riminus1; 29610Sstevel@tonic-gate riminus1 = ri; 29620Sstevel@tonic-gate ri = t; 2963*6557Sfr41279 if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK) { 29640Sstevel@tonic-gate goto ret; 2965*6557Sfr41279 } 2966*6557Sfr41279 if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK) { 29670Sstevel@tonic-gate goto ret; 2968*6557Sfr41279 } 29690Sstevel@tonic-gate t = vmiminus1; 29700Sstevel@tonic-gate vmiminus1 = vmi; 29710Sstevel@tonic-gate vmi = t; 2972*6557Sfr41279 if ((err = big_mul(&tmp, vei, xi)) != BIG_OK) { 29730Sstevel@tonic-gate goto ret; 2974*6557Sfr41279 } 2975*6557Sfr41279 if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK) { 29760Sstevel@tonic-gate goto ret; 2977*6557Sfr41279 } 29780Sstevel@tonic-gate t = veiminus1; 29790Sstevel@tonic-gate veiminus1 = vei; 29800Sstevel@tonic-gate vei = t; 2981*6557Sfr41279 if ((err = big_div_pos(xi, ri, riminus2, riminus1)) != 2982*6557Sfr41279 BIG_OK) { 29830Sstevel@tonic-gate goto ret; 2984*6557Sfr41279 } 29850Sstevel@tonic-gate } 2986*6557Sfr41279 if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK)) { 29870Sstevel@tonic-gate goto ret; 2988*6557Sfr41279 } 2989*6557Sfr41279 if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK)) { 29900Sstevel@tonic-gate goto ret; 2991*6557Sfr41279 } 2992*6557Sfr41279 if (ce != NULL) { 29930Sstevel@tonic-gate err = big_copy(ce, vei); 2994*6557Sfr41279 } 29950Sstevel@tonic-gate ret: 29960Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 29970Sstevel@tonic-gate ret8: 29980Sstevel@tonic-gate if (t8.malloced) big_finish(&t8); 29990Sstevel@tonic-gate ret7: 30000Sstevel@tonic-gate if (t7.malloced) big_finish(&t7); 30010Sstevel@tonic-gate ret6: 30020Sstevel@tonic-gate if (t6.malloced) big_finish(&t6); 30030Sstevel@tonic-gate ret5: 30040Sstevel@tonic-gate if (t5.malloced) big_finish(&t5); 30050Sstevel@tonic-gate ret4: 30060Sstevel@tonic-gate if (t4.malloced) big_finish(&t4); 30070Sstevel@tonic-gate ret3: 30080Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 30090Sstevel@tonic-gate ret2: 30100Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 30110Sstevel@tonic-gate ret1: 30120Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 30130Sstevel@tonic-gate 30140Sstevel@tonic-gate return (err); 30150Sstevel@tonic-gate } 3016