17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5b60f2a0bSfr41279 * Common Development and Distribution License (the "License"). 6b60f2a0bSfr41279 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*8475e043SDan OpenSolaris Anderson * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * Configuration guide 287c478bd9Sstevel@tonic-gate * ------------------- 297c478bd9Sstevel@tonic-gate * 307c478bd9Sstevel@tonic-gate * There are 4 preprocessor symbols used to configure the bignum 317c478bd9Sstevel@tonic-gate * implementation. This file contains no logic to configure based on 327c478bd9Sstevel@tonic-gate * processor; we leave that to the Makefiles to specify. 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * USE_FLOATING_POINT 357c478bd9Sstevel@tonic-gate * Meaning: There is support for a fast floating-point implementation of 367c478bd9Sstevel@tonic-gate * Montgomery multiply. 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * PSR_MUL 397c478bd9Sstevel@tonic-gate * Meaning: There are processor-specific versions of the low level 407c478bd9Sstevel@tonic-gate * functions to implement big_mul. Those functions are: big_mul_set_vec, 417c478bd9Sstevel@tonic-gate * big_mul_add_vec, big_mul_vec, and big_sqr_vec. PSR_MUL implies support 427c478bd9Sstevel@tonic-gate * for all 4 functions. You cannot pick and choose which subset of these 437c478bd9Sstevel@tonic-gate * functions to support; that would lead to a rat's nest of #ifdefs. 447c478bd9Sstevel@tonic-gate * 457c478bd9Sstevel@tonic-gate * HWCAP 467c478bd9Sstevel@tonic-gate * Meaning: Call multiply support functions through a function pointer. 47*8475e043SDan OpenSolaris Anderson * On x86, there are multiple implementations for different hardware 487c478bd9Sstevel@tonic-gate * capabilities, such as MMX, SSE2, etc. Tests are made at run-time, when 497c478bd9Sstevel@tonic-gate * a function is first used. So, the support functions are called through 507c478bd9Sstevel@tonic-gate * a function pointer. There is no need for that on Sparc, because there 517c478bd9Sstevel@tonic-gate * is only one implementation; support functions are called directly. 527c478bd9Sstevel@tonic-gate * Later, if there were some new VIS instruction, or something, and a 537c478bd9Sstevel@tonic-gate * run-time test were needed, rather than variant kernel modules and 547c478bd9Sstevel@tonic-gate * libraries, then HWCAP would be defined for Sparc, as well. 557c478bd9Sstevel@tonic-gate * 567c478bd9Sstevel@tonic-gate * UMUL64 577c478bd9Sstevel@tonic-gate * Meaning: It is safe to use generic C code that assumes the existence 587c478bd9Sstevel@tonic-gate * of a 32 x 32 --> 64 bit unsigned multiply. If this is not defined, 597c478bd9Sstevel@tonic-gate * then the generic code for big_mul_add_vec() must necessarily be very slow, 607c478bd9Sstevel@tonic-gate * because it must fall back to using 16 x 16 --> 32 bit multiplication. 617c478bd9Sstevel@tonic-gate * 627c478bd9Sstevel@tonic-gate */ 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate 65*8475e043SDan OpenSolaris Anderson #include <sys/types.h> 66*8475e043SDan OpenSolaris Anderson #include "bignum.h" 67*8475e043SDan OpenSolaris Anderson 687c478bd9Sstevel@tonic-gate #ifdef _KERNEL 69b60f2a0bSfr41279 #include <sys/ddi.h> 70b60f2a0bSfr41279 #include <sys/mdesc.h> 71b60f2a0bSfr41279 #include <sys/crypto/common.h> 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 747c478bd9Sstevel@tonic-gate #include <sys/param.h> 757c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 767c478bd9Sstevel@tonic-gate 77*8475e043SDan OpenSolaris Anderson #else 78*8475e043SDan OpenSolaris Anderson #include <stdlib.h> 79*8475e043SDan OpenSolaris Anderson #include <stdio.h> 80*8475e043SDan OpenSolaris Anderson #include <assert.h> 81*8475e043SDan OpenSolaris Anderson #define ASSERT assert 82*8475e043SDan OpenSolaris Anderson #endif /* _KERNEL */ 83*8475e043SDan OpenSolaris Anderson 84*8475e043SDan OpenSolaris Anderson #ifdef _LP64 /* truncate 64-bit size_t to 32-bits */ 85*8475e043SDan OpenSolaris Anderson #define UI32(ui) ((uint32_t)ui) 86*8475e043SDan OpenSolaris Anderson #else /* size_t already 32-bits */ 87*8475e043SDan OpenSolaris Anderson #define UI32(ui) (ui) 88*8475e043SDan OpenSolaris Anderson #endif 89*8475e043SDan OpenSolaris Anderson 90*8475e043SDan OpenSolaris Anderson 91*8475e043SDan OpenSolaris Anderson #ifdef _KERNEL 927c478bd9Sstevel@tonic-gate #define big_malloc(size) kmem_alloc(size, KM_NOSLEEP) 937c478bd9Sstevel@tonic-gate #define big_free(ptr, size) kmem_free(ptr, size) 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate void * 967c478bd9Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize) 977c478bd9Sstevel@tonic-gate { 987c478bd9Sstevel@tonic-gate void *rv; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate rv = kmem_alloc(newsize, KM_NOSLEEP); 1017c478bd9Sstevel@tonic-gate if (rv != NULL) 1027c478bd9Sstevel@tonic-gate bcopy(from, rv, oldsize); 1037c478bd9Sstevel@tonic-gate kmem_free(from, oldsize); 1047c478bd9Sstevel@tonic-gate return (rv); 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate #else /* _KERNEL */ 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate #ifndef MALLOC_DEBUG 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate #define big_malloc(size) malloc(size) 1127c478bd9Sstevel@tonic-gate #define big_free(ptr, size) free(ptr) 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate #else 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate void 1177c478bd9Sstevel@tonic-gate big_free(void *ptr, size_t size) 1187c478bd9Sstevel@tonic-gate { 1197c478bd9Sstevel@tonic-gate printf("freed %d bytes at %p\n", size, ptr); 1207c478bd9Sstevel@tonic-gate free(ptr); 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate void * 1247c478bd9Sstevel@tonic-gate big_malloc(size_t size) 1257c478bd9Sstevel@tonic-gate { 1267c478bd9Sstevel@tonic-gate void *rv; 1277c478bd9Sstevel@tonic-gate rv = malloc(size); 1287c478bd9Sstevel@tonic-gate printf("malloced %d bytes, addr:%p\n", size, rv); 1297c478bd9Sstevel@tonic-gate return (rv); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate #endif /* MALLOC_DEBUG */ 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate #define big_realloc(x, y, z) realloc((x), (z)) 1347c478bd9Sstevel@tonic-gate 135*8475e043SDan OpenSolaris Anderson 136*8475e043SDan OpenSolaris Anderson /* 137*8475e043SDan OpenSolaris Anderson * printbignum() 138*8475e043SDan OpenSolaris Anderson * Print a BIGNUM type to stdout. 139*8475e043SDan OpenSolaris Anderson */ 1407c478bd9Sstevel@tonic-gate void 1417c478bd9Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a) 1427c478bd9Sstevel@tonic-gate { 1437c478bd9Sstevel@tonic-gate int i; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate (void) printf("\n%s\n%d\n", aname, a->sign*a->len); 1467c478bd9Sstevel@tonic-gate for (i = a->len - 1; i >= 0; i--) { 147b60f2a0bSfr41279 #ifdef BIGNUM_CHUNK_32 1487c478bd9Sstevel@tonic-gate (void) printf("%08x ", a->value[i]); 149*8475e043SDan OpenSolaris Anderson if (((i & (BITSINBYTE - 1)) == 0) && (i != 0)) { 1507c478bd9Sstevel@tonic-gate (void) printf("\n"); 1517c478bd9Sstevel@tonic-gate } 152b60f2a0bSfr41279 #else 153b60f2a0bSfr41279 (void) printf("%08x %08x ", (uint32_t)((a->value[i]) >> 32), 154b60f2a0bSfr41279 (uint32_t)((a->value[i]) & 0xffffffff)); 155*8475e043SDan OpenSolaris Anderson if (((i & 3) == 0) && (i != 0)) { /* end of this chunk */ 156b60f2a0bSfr41279 (void) printf("\n"); 157b60f2a0bSfr41279 } 158b60f2a0bSfr41279 #endif 159b60f2a0bSfr41279 } 1607c478bd9Sstevel@tonic-gate (void) printf("\n"); 1617c478bd9Sstevel@tonic-gate } 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate 166*8475e043SDan OpenSolaris Anderson /* 167*8475e043SDan OpenSolaris Anderson * big_init() 168*8475e043SDan OpenSolaris Anderson * Initialize and allocate memory for a BIGNUM type. 169*8475e043SDan OpenSolaris Anderson * 170*8475e043SDan OpenSolaris Anderson * big_init(number, size) is equivalent to big_init1(number, size, NULL, 0) 171*8475e043SDan OpenSolaris Anderson * 172*8475e043SDan OpenSolaris Anderson * Note: call big_finish() to free memory allocated by big_init(). 173*8475e043SDan OpenSolaris Anderson * 174*8475e043SDan OpenSolaris Anderson * Input: 175*8475e043SDan OpenSolaris Anderson * number Uninitialized memory for BIGNUM 176*8475e043SDan OpenSolaris Anderson * size Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM 177*8475e043SDan OpenSolaris Anderson * 178*8475e043SDan OpenSolaris Anderson * Output: 179*8475e043SDan OpenSolaris Anderson * number Initialized BIGNUM 180*8475e043SDan OpenSolaris Anderson * 181*8475e043SDan OpenSolaris Anderson * Return BIG_OK on success or BIG_NO_MEM for an allocation error. 182*8475e043SDan OpenSolaris Anderson */ 1837c478bd9Sstevel@tonic-gate BIG_ERR_CODE 1847c478bd9Sstevel@tonic-gate big_init(BIGNUM *number, int size) 1857c478bd9Sstevel@tonic-gate { 186*8475e043SDan OpenSolaris Anderson number->value = big_malloc(BIGNUM_WORDSIZE * size); 1877c478bd9Sstevel@tonic-gate if (number->value == NULL) { 1887c478bd9Sstevel@tonic-gate return (BIG_NO_MEM); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate number->size = size; 1917c478bd9Sstevel@tonic-gate number->len = 0; 1927c478bd9Sstevel@tonic-gate number->sign = 1; 1937c478bd9Sstevel@tonic-gate number->malloced = 1; 1947c478bd9Sstevel@tonic-gate return (BIG_OK); 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 197*8475e043SDan OpenSolaris Anderson 198*8475e043SDan OpenSolaris Anderson /* 199*8475e043SDan OpenSolaris Anderson * big_init1() 200*8475e043SDan OpenSolaris Anderson * Initialize and, if needed, allocate memory for a BIGNUM type. 201*8475e043SDan OpenSolaris Anderson * Use the buffer passed, buf, if any, instad of allocating memory 202*8475e043SDan OpenSolaris Anderson * if it's at least "size" bytes. 203*8475e043SDan OpenSolaris Anderson * 204*8475e043SDan OpenSolaris Anderson * Note: call big_finish() to free memory allocated by big_init(). 205*8475e043SDan OpenSolaris Anderson * 206*8475e043SDan OpenSolaris Anderson * Input: 207*8475e043SDan OpenSolaris Anderson * number Uninitialized memory for BIGNUM 208*8475e043SDan OpenSolaris Anderson * size Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM 209*8475e043SDan OpenSolaris Anderson * buf Buffer for storing a BIGNUM. 210*8475e043SDan OpenSolaris Anderson * If NULL, big_init1() will allocate a buffer 211*8475e043SDan OpenSolaris Anderson * bufsize Size, in BIG_CHUNK_SIZE_bit words, of buf 212*8475e043SDan OpenSolaris Anderson * 213*8475e043SDan OpenSolaris Anderson * Output: 214*8475e043SDan OpenSolaris Anderson * number Initialized BIGNUM 215*8475e043SDan OpenSolaris Anderson * 216*8475e043SDan OpenSolaris Anderson * Return BIG_OK on success or BIG_NO_MEM for an allocation error. 217*8475e043SDan OpenSolaris Anderson */ 2187c478bd9Sstevel@tonic-gate BIG_ERR_CODE 219b60f2a0bSfr41279 big_init1(BIGNUM *number, int size, BIG_CHUNK_TYPE *buf, int bufsize) 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate if ((buf == NULL) || (size > bufsize)) { 222*8475e043SDan OpenSolaris Anderson number->value = big_malloc(BIGNUM_WORDSIZE * size); 2237c478bd9Sstevel@tonic-gate if (number->value == NULL) { 2247c478bd9Sstevel@tonic-gate return (BIG_NO_MEM); 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate number->size = size; 2277c478bd9Sstevel@tonic-gate number->malloced = 1; 2287c478bd9Sstevel@tonic-gate } else { 2297c478bd9Sstevel@tonic-gate number->value = buf; 2307c478bd9Sstevel@tonic-gate number->size = bufsize; 2317c478bd9Sstevel@tonic-gate number->malloced = 0; 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate number->len = 0; 2347c478bd9Sstevel@tonic-gate number->sign = 1; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate return (BIG_OK); 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 239*8475e043SDan OpenSolaris Anderson 240*8475e043SDan OpenSolaris Anderson /* 241*8475e043SDan OpenSolaris Anderson * big_finish() 242*8475e043SDan OpenSolaris Anderson * Free memory, if any, allocated by big_init() or big_init1(). 243*8475e043SDan OpenSolaris Anderson */ 2447c478bd9Sstevel@tonic-gate void 2457c478bd9Sstevel@tonic-gate big_finish(BIGNUM *number) 2467c478bd9Sstevel@tonic-gate { 2477c478bd9Sstevel@tonic-gate if (number->malloced == 1) { 248*8475e043SDan OpenSolaris Anderson big_free(number->value, BIGNUM_WORDSIZE * number->size); 2497c478bd9Sstevel@tonic-gate number->malloced = 0; 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate 253b60f2a0bSfr41279 2547c478bd9Sstevel@tonic-gate /* 255b60f2a0bSfr41279 * bn->size should be at least 256*8475e043SDan OpenSolaris Anderson * (len + BIGNUM_WORDSIZE - 1) / BIGNUM_WORDSIZE bytes 2577c478bd9Sstevel@tonic-gate * converts from byte-big-endian format to bignum format (words in 2587c478bd9Sstevel@tonic-gate * little endian order, but bytes within the words big endian) 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate void 2617c478bd9Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len) 2627c478bd9Sstevel@tonic-gate { 263*8475e043SDan OpenSolaris Anderson int i, j; 264*8475e043SDan OpenSolaris Anderson uint32_t offs; 265*8475e043SDan OpenSolaris Anderson const uint32_t slen = UI32(len); 266b60f2a0bSfr41279 BIG_CHUNK_TYPE word; 2677c478bd9Sstevel@tonic-gate uchar_t *knwordp; 2687c478bd9Sstevel@tonic-gate 269*8475e043SDan OpenSolaris Anderson if (slen == 0) { 270*8475e043SDan OpenSolaris Anderson bn->len = 1; 271*8475e043SDan OpenSolaris Anderson bn->value[0] = 0; 272*8475e043SDan OpenSolaris Anderson return; 273*8475e043SDan OpenSolaris Anderson } 274b60f2a0bSfr41279 275*8475e043SDan OpenSolaris Anderson offs = slen % BIGNUM_WORDSIZE; 276*8475e043SDan OpenSolaris Anderson bn->len = slen / BIGNUM_WORDSIZE; 277*8475e043SDan OpenSolaris Anderson 278*8475e043SDan OpenSolaris Anderson for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) { 279*8475e043SDan OpenSolaris Anderson knwordp = &(kn[slen - BIGNUM_WORDSIZE * (i + 1)]); 2807c478bd9Sstevel@tonic-gate word = knwordp[0]; 281*8475e043SDan OpenSolaris Anderson for (j = 1; j < BIGNUM_WORDSIZE; j++) { 282*8475e043SDan OpenSolaris Anderson word = (word << BITSINBYTE) + knwordp[j]; 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate bn->value[i] = word; 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate if (offs > 0) { 2877c478bd9Sstevel@tonic-gate word = kn[0]; 288*8475e043SDan OpenSolaris Anderson for (i = 1; i < offs; i++) word = (word << BITSINBYTE) + kn[i]; 2897c478bd9Sstevel@tonic-gate bn->value[bn->len++] = word; 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate while ((bn->len > 1) && (bn->value[bn->len - 1] == 0)) { 2927c478bd9Sstevel@tonic-gate bn->len --; 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 296*8475e043SDan OpenSolaris Anderson 2977c478bd9Sstevel@tonic-gate /* 2987c478bd9Sstevel@tonic-gate * copies the least significant len bytes if 299*8475e043SDan OpenSolaris Anderson * len < bn->len * BIGNUM_WORDSIZE 3007c478bd9Sstevel@tonic-gate * converts from bignum format to byte-big-endian format. 301b60f2a0bSfr41279 * bignum format is words of type BIG_CHUNK_TYPE in little endian order. 3027c478bd9Sstevel@tonic-gate */ 3037c478bd9Sstevel@tonic-gate void 3047c478bd9Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len) 3057c478bd9Sstevel@tonic-gate { 306*8475e043SDan OpenSolaris Anderson int i, j; 307*8475e043SDan OpenSolaris Anderson uint32_t offs; 308*8475e043SDan OpenSolaris Anderson const uint32_t slen = UI32(len); 309b60f2a0bSfr41279 BIG_CHUNK_TYPE word; 3107c478bd9Sstevel@tonic-gate 311*8475e043SDan OpenSolaris Anderson if (len < BIGNUM_WORDSIZE * bn->len) { 312*8475e043SDan OpenSolaris Anderson for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) { 3137c478bd9Sstevel@tonic-gate word = bn->value[i]; 314*8475e043SDan OpenSolaris Anderson for (j = 0; j < BIGNUM_WORDSIZE; j++) { 315*8475e043SDan OpenSolaris Anderson kn[slen - BIGNUM_WORDSIZE * i - j - 1] = 3167c478bd9Sstevel@tonic-gate word & 0xff; 317*8475e043SDan OpenSolaris Anderson word = word >> BITSINBYTE; 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate } 320*8475e043SDan OpenSolaris Anderson offs = slen % BIGNUM_WORDSIZE; 3217c478bd9Sstevel@tonic-gate if (offs > 0) { 322*8475e043SDan OpenSolaris Anderson word = bn->value[slen / BIGNUM_WORDSIZE]; 323*8475e043SDan OpenSolaris Anderson for (i = slen % BIGNUM_WORDSIZE; i > 0; i --) { 3247c478bd9Sstevel@tonic-gate kn[i - 1] = word & 0xff; 325*8475e043SDan OpenSolaris Anderson word = word >> BITSINBYTE; 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate } else { 3297c478bd9Sstevel@tonic-gate for (i = 0; i < bn->len; i++) { 3307c478bd9Sstevel@tonic-gate word = bn->value[i]; 331*8475e043SDan OpenSolaris Anderson for (j = 0; j < BIGNUM_WORDSIZE; j++) { 332*8475e043SDan OpenSolaris Anderson kn[slen - BIGNUM_WORDSIZE * i - j - 1] = 3337c478bd9Sstevel@tonic-gate word & 0xff; 334*8475e043SDan OpenSolaris Anderson word = word >> BITSINBYTE; 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate } 337*8475e043SDan OpenSolaris Anderson for (i = 0; i < slen - BIGNUM_WORDSIZE * bn->len; i++) { 3387c478bd9Sstevel@tonic-gate kn[i] = 0; 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate int 3457c478bd9Sstevel@tonic-gate big_bitlength(BIGNUM *a) 3467c478bd9Sstevel@tonic-gate { 347b60f2a0bSfr41279 int l = 0, b = 0; 348b60f2a0bSfr41279 BIG_CHUNK_TYPE c; 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate l = a->len - 1; 3517c478bd9Sstevel@tonic-gate while ((l > 0) && (a->value[l] == 0)) { 3527c478bd9Sstevel@tonic-gate l--; 3537c478bd9Sstevel@tonic-gate } 354*8475e043SDan OpenSolaris Anderson b = BIG_CHUNK_SIZE; 3557c478bd9Sstevel@tonic-gate c = a->value[l]; 356b60f2a0bSfr41279 while ((b > 1) && ((c & BIG_CHUNK_HIGHBIT) == 0)) { 3577c478bd9Sstevel@tonic-gate c = c << 1; 3587c478bd9Sstevel@tonic-gate b--; 3597c478bd9Sstevel@tonic-gate } 360b60f2a0bSfr41279 361*8475e043SDan OpenSolaris Anderson return (l * BIG_CHUNK_SIZE + b); 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate BIG_ERR_CODE 3667c478bd9Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src) 3677c478bd9Sstevel@tonic-gate { 368b60f2a0bSfr41279 BIG_CHUNK_TYPE *newptr; 3697c478bd9Sstevel@tonic-gate int i, len; 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate len = src->len; 372b60f2a0bSfr41279 while ((len > 1) && (src->value[len - 1] == 0)) { 3737c478bd9Sstevel@tonic-gate len--; 374b60f2a0bSfr41279 } 3757c478bd9Sstevel@tonic-gate src->len = len; 3767c478bd9Sstevel@tonic-gate if (dest->size < len) { 3777c478bd9Sstevel@tonic-gate if (dest->malloced == 1) { 378b60f2a0bSfr41279 newptr = (BIG_CHUNK_TYPE *)big_realloc(dest->value, 379*8475e043SDan OpenSolaris Anderson BIGNUM_WORDSIZE * dest->size, 380*8475e043SDan OpenSolaris Anderson BIGNUM_WORDSIZE * len); 3817c478bd9Sstevel@tonic-gate } else { 382b60f2a0bSfr41279 newptr = (BIG_CHUNK_TYPE *) 383*8475e043SDan OpenSolaris Anderson big_malloc(BIGNUM_WORDSIZE * len); 384b60f2a0bSfr41279 if (newptr != NULL) { 385b60f2a0bSfr41279 dest->malloced = 1; 3867c478bd9Sstevel@tonic-gate } 387b60f2a0bSfr41279 } 388b60f2a0bSfr41279 if (newptr == NULL) { 3897c478bd9Sstevel@tonic-gate return (BIG_NO_MEM); 390b60f2a0bSfr41279 } 3917c478bd9Sstevel@tonic-gate dest->value = newptr; 3927c478bd9Sstevel@tonic-gate dest->size = len; 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate dest->len = len; 3957c478bd9Sstevel@tonic-gate dest->sign = src->sign; 396b60f2a0bSfr41279 for (i = 0; i < len; i++) { 397b60f2a0bSfr41279 dest->value[i] = src->value[i]; 398b60f2a0bSfr41279 } 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate return (BIG_OK); 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate BIG_ERR_CODE 4057c478bd9Sstevel@tonic-gate big_extend(BIGNUM *number, int size) 4067c478bd9Sstevel@tonic-gate { 407b60f2a0bSfr41279 BIG_CHUNK_TYPE *newptr; 4087c478bd9Sstevel@tonic-gate int i; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate if (number->size >= size) 4117c478bd9Sstevel@tonic-gate return (BIG_OK); 4127c478bd9Sstevel@tonic-gate if (number->malloced) { 413b60f2a0bSfr41279 number->value = big_realloc(number->value, 414*8475e043SDan OpenSolaris Anderson BIGNUM_WORDSIZE * number->size, 415*8475e043SDan OpenSolaris Anderson BIGNUM_WORDSIZE * size); 4167c478bd9Sstevel@tonic-gate } else { 417*8475e043SDan OpenSolaris Anderson newptr = big_malloc(BIGNUM_WORDSIZE * size); 4187c478bd9Sstevel@tonic-gate if (newptr != NULL) { 4197c478bd9Sstevel@tonic-gate for (i = 0; i < number->size; i++) { 4207c478bd9Sstevel@tonic-gate newptr[i] = number->value[i]; 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate number->value = newptr; 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 426b60f2a0bSfr41279 if (number->value == NULL) { 4277c478bd9Sstevel@tonic-gate return (BIG_NO_MEM); 428b60f2a0bSfr41279 } 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate number->size = size; 4317c478bd9Sstevel@tonic-gate number->malloced = 1; 4327c478bd9Sstevel@tonic-gate return (BIG_OK); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate 436b60f2a0bSfr41279 /* returns 1 if n == 0 */ 4377c478bd9Sstevel@tonic-gate int 4387c478bd9Sstevel@tonic-gate big_is_zero(BIGNUM *n) 4397c478bd9Sstevel@tonic-gate { 4407c478bd9Sstevel@tonic-gate int i, result; 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate result = 1; 443b60f2a0bSfr41279 for (i = 0; i < n->len; i++) { 444b60f2a0bSfr41279 if (n->value[i] != 0) { 445b60f2a0bSfr41279 result = 0; 446b60f2a0bSfr41279 } 447b60f2a0bSfr41279 } 4487c478bd9Sstevel@tonic-gate return (result); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate BIG_ERR_CODE 4537c478bd9Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 4547c478bd9Sstevel@tonic-gate { 4557c478bd9Sstevel@tonic-gate int i, shorter, longer; 456b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, ai; 457b60f2a0bSfr41279 BIG_CHUNK_TYPE *r, *a, *b, *c; 4587c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 459b60f2a0bSfr41279 BIGNUM *longerarg; 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate if (aa->len > bb->len) { 4627c478bd9Sstevel@tonic-gate shorter = bb->len; 4637c478bd9Sstevel@tonic-gate longer = aa->len; 464b60f2a0bSfr41279 longerarg = aa; 4657c478bd9Sstevel@tonic-gate } else { 4667c478bd9Sstevel@tonic-gate shorter = aa->len; 4677c478bd9Sstevel@tonic-gate longer = bb->len; 468b60f2a0bSfr41279 longerarg = bb; 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate if (result->size < longer + 1) { 4717c478bd9Sstevel@tonic-gate err = big_extend(result, longer + 1); 472b60f2a0bSfr41279 if (err != BIG_OK) { 4737c478bd9Sstevel@tonic-gate return (err); 4747c478bd9Sstevel@tonic-gate } 475b60f2a0bSfr41279 } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate r = result->value; 4787c478bd9Sstevel@tonic-gate a = aa->value; 4797c478bd9Sstevel@tonic-gate b = bb->value; 480b60f2a0bSfr41279 c = longerarg->value; 4817c478bd9Sstevel@tonic-gate cy = 0; 4827c478bd9Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 4837c478bd9Sstevel@tonic-gate ai = a[i]; 4847c478bd9Sstevel@tonic-gate r[i] = ai + b[i] + cy; 485b60f2a0bSfr41279 if (r[i] > ai) { 486b60f2a0bSfr41279 cy = 0; 487b60f2a0bSfr41279 } else if (r[i] < ai) { 488b60f2a0bSfr41279 cy = 1; 489b60f2a0bSfr41279 } 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate for (; i < longer; i++) { 4927c478bd9Sstevel@tonic-gate ai = c[i]; 4937c478bd9Sstevel@tonic-gate r[i] = ai + cy; 494b60f2a0bSfr41279 if (r[i] >= ai) { 495b60f2a0bSfr41279 cy = 0; 496b60f2a0bSfr41279 } 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate if (cy == 1) { 4997c478bd9Sstevel@tonic-gate r[i] = cy; 5007c478bd9Sstevel@tonic-gate result->len = longer + 1; 5017c478bd9Sstevel@tonic-gate } else { 5027c478bd9Sstevel@tonic-gate result->len = longer; 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate result->sign = 1; 5057c478bd9Sstevel@tonic-gate return (BIG_OK); 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */ 5107c478bd9Sstevel@tonic-gate void 511b60f2a0bSfr41279 big_sub_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, BIG_CHUNK_TYPE *b, int len) 5127c478bd9Sstevel@tonic-gate { 5137c478bd9Sstevel@tonic-gate int i; 514b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, ai; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate cy = 1; 5177c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) { 5187c478bd9Sstevel@tonic-gate ai = a[i]; 5197c478bd9Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 520b60f2a0bSfr41279 if (r[i] > ai) { 521b60f2a0bSfr41279 cy = 0; 522b60f2a0bSfr41279 } else if (r[i] < ai) { 523b60f2a0bSfr41279 cy = 1; 524b60f2a0bSfr41279 } 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate /* result=aa-bb it is assumed that aa>=bb */ 5307c478bd9Sstevel@tonic-gate BIG_ERR_CODE 5317c478bd9Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 5327c478bd9Sstevel@tonic-gate { 5337c478bd9Sstevel@tonic-gate int i, shorter; 534b60f2a0bSfr41279 BIG_CHUNK_TYPE cy = 1, ai; 535b60f2a0bSfr41279 BIG_CHUNK_TYPE *r, *a, *b; 536b60f2a0bSfr41279 BIG_ERR_CODE err = BIG_OK; 5377c478bd9Sstevel@tonic-gate 538b60f2a0bSfr41279 if (aa->len > bb->len) { 539b60f2a0bSfr41279 shorter = bb->len; 540b60f2a0bSfr41279 } else { 541b60f2a0bSfr41279 shorter = aa->len; 542b60f2a0bSfr41279 } 5437c478bd9Sstevel@tonic-gate if (result->size < aa->len) { 5447c478bd9Sstevel@tonic-gate err = big_extend(result, aa->len); 545b60f2a0bSfr41279 if (err != BIG_OK) { 5467c478bd9Sstevel@tonic-gate return (err); 5477c478bd9Sstevel@tonic-gate } 548b60f2a0bSfr41279 } 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate r = result->value; 5517c478bd9Sstevel@tonic-gate a = aa->value; 5527c478bd9Sstevel@tonic-gate b = bb->value; 5537c478bd9Sstevel@tonic-gate result->len = aa->len; 5547c478bd9Sstevel@tonic-gate cy = 1; 5557c478bd9Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 5567c478bd9Sstevel@tonic-gate ai = a[i]; 5577c478bd9Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 558b60f2a0bSfr41279 if (r[i] > ai) { 559b60f2a0bSfr41279 cy = 0; 560b60f2a0bSfr41279 } else if (r[i] < ai) { 561b60f2a0bSfr41279 cy = 1; 562b60f2a0bSfr41279 } 5637c478bd9Sstevel@tonic-gate } 5647c478bd9Sstevel@tonic-gate for (; i < aa->len; i++) { 5657c478bd9Sstevel@tonic-gate ai = a[i]; 5667c478bd9Sstevel@tonic-gate r[i] = ai + (~0) + cy; 567b60f2a0bSfr41279 if (r[i] < ai) { 568b60f2a0bSfr41279 cy = 1; 569b60f2a0bSfr41279 } 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate result->sign = 1; 572b60f2a0bSfr41279 573b60f2a0bSfr41279 if (cy == 0) { 5747c478bd9Sstevel@tonic-gate return (BIG_INVALID_ARGS); 575b60f2a0bSfr41279 } else { 5767c478bd9Sstevel@tonic-gate return (BIG_OK); 5777c478bd9Sstevel@tonic-gate } 578b60f2a0bSfr41279 } 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */ 5827c478bd9Sstevel@tonic-gate int 5837c478bd9Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb) 5847c478bd9Sstevel@tonic-gate { 5857c478bd9Sstevel@tonic-gate int i; 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate if (aa->len > bb->len) { 5887c478bd9Sstevel@tonic-gate for (i = aa->len - 1; i > bb->len - 1; i--) { 589b60f2a0bSfr41279 if (aa->value[i] > 0) { 5907c478bd9Sstevel@tonic-gate return (1); 5917c478bd9Sstevel@tonic-gate } 592b60f2a0bSfr41279 } 5937c478bd9Sstevel@tonic-gate } else if (aa->len < bb->len) { 5947c478bd9Sstevel@tonic-gate for (i = bb->len - 1; i > aa->len - 1; i--) { 595b60f2a0bSfr41279 if (bb->value[i] > 0) { 5967c478bd9Sstevel@tonic-gate return (-1); 5977c478bd9Sstevel@tonic-gate } 598b60f2a0bSfr41279 } 599b60f2a0bSfr41279 } else { 600b60f2a0bSfr41279 i = aa->len - 1; 601b60f2a0bSfr41279 } 6027c478bd9Sstevel@tonic-gate for (; i >= 0; i--) { 603b60f2a0bSfr41279 if (aa->value[i] > bb->value[i]) { 6047c478bd9Sstevel@tonic-gate return (1); 605b60f2a0bSfr41279 } else if (aa->value[i] < bb->value[i]) { 6067c478bd9Sstevel@tonic-gate return (-1); 6077c478bd9Sstevel@tonic-gate } 608b60f2a0bSfr41279 } 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate return (0); 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate BIG_ERR_CODE 6157c478bd9Sstevel@tonic-gate big_sub(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 6167c478bd9Sstevel@tonic-gate { 6177c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate if ((bb->sign == -1) && (aa->sign == 1)) { 620b60f2a0bSfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6217c478bd9Sstevel@tonic-gate return (err); 622b60f2a0bSfr41279 } 6237c478bd9Sstevel@tonic-gate result->sign = 1; 6247c478bd9Sstevel@tonic-gate } else if ((aa->sign == -1) && (bb->sign == 1)) { 625b60f2a0bSfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6267c478bd9Sstevel@tonic-gate return (err); 627b60f2a0bSfr41279 } 6287c478bd9Sstevel@tonic-gate result->sign = -1; 6297c478bd9Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == 1)) { 6307c478bd9Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 631b60f2a0bSfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6327c478bd9Sstevel@tonic-gate return (err); 633b60f2a0bSfr41279 } 6347c478bd9Sstevel@tonic-gate result->sign = 1; 6357c478bd9Sstevel@tonic-gate } else { 636b60f2a0bSfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6377c478bd9Sstevel@tonic-gate return (err); 638b60f2a0bSfr41279 } 6397c478bd9Sstevel@tonic-gate result->sign = -1; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate } else { 6427c478bd9Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 643b60f2a0bSfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6447c478bd9Sstevel@tonic-gate return (err); 645b60f2a0bSfr41279 } 6467c478bd9Sstevel@tonic-gate result->sign = -1; 6477c478bd9Sstevel@tonic-gate } else { 648b60f2a0bSfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6497c478bd9Sstevel@tonic-gate return (err); 650b60f2a0bSfr41279 } 6517c478bd9Sstevel@tonic-gate result->sign = 1; 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate return (BIG_OK); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate BIG_ERR_CODE 6597c478bd9Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 6607c478bd9Sstevel@tonic-gate { 6617c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate if ((bb->sign == -1) && (aa->sign == -1)) { 664b60f2a0bSfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6657c478bd9Sstevel@tonic-gate return (err); 666b60f2a0bSfr41279 } 6677c478bd9Sstevel@tonic-gate result->sign = -1; 6687c478bd9Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == 1)) { 669b60f2a0bSfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6707c478bd9Sstevel@tonic-gate return (err); 671b60f2a0bSfr41279 } 6727c478bd9Sstevel@tonic-gate result->sign = 1; 6737c478bd9Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == -1)) { 6747c478bd9Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 675b60f2a0bSfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6767c478bd9Sstevel@tonic-gate return (err); 677b60f2a0bSfr41279 } 6787c478bd9Sstevel@tonic-gate result->sign = 1; 6797c478bd9Sstevel@tonic-gate } else { 680b60f2a0bSfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6817c478bd9Sstevel@tonic-gate return (err); 682b60f2a0bSfr41279 } 6837c478bd9Sstevel@tonic-gate result->sign = -1; 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate } else { 6867c478bd9Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 687b60f2a0bSfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6887c478bd9Sstevel@tonic-gate return (err); 689b60f2a0bSfr41279 } 6907c478bd9Sstevel@tonic-gate result->sign = -1; 6917c478bd9Sstevel@tonic-gate } else { 692b60f2a0bSfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6937c478bd9Sstevel@tonic-gate return (err); 694b60f2a0bSfr41279 } 6957c478bd9Sstevel@tonic-gate result->sign = 1; 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate return (BIG_OK); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate 702b60f2a0bSfr41279 /* result = aa/2 */ 7037c478bd9Sstevel@tonic-gate BIG_ERR_CODE 7047c478bd9Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa) 7057c478bd9Sstevel@tonic-gate { 7067c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 7077c478bd9Sstevel@tonic-gate int i; 708b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, cy1; 709b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *r; 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate if (result->size < aa->len) { 7127c478bd9Sstevel@tonic-gate err = big_extend(result, aa->len); 713b60f2a0bSfr41279 if (err != BIG_OK) { 7147c478bd9Sstevel@tonic-gate return (err); 7157c478bd9Sstevel@tonic-gate } 716b60f2a0bSfr41279 } 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate result->len = aa->len; 7197c478bd9Sstevel@tonic-gate a = aa->value; 7207c478bd9Sstevel@tonic-gate r = result->value; 7217c478bd9Sstevel@tonic-gate cy = 0; 7227c478bd9Sstevel@tonic-gate for (i = aa->len - 1; i >= 0; i--) { 723b60f2a0bSfr41279 cy1 = a[i] << (BIG_CHUNK_SIZE - 1); 7247c478bd9Sstevel@tonic-gate r[i] = (cy | (a[i] >> 1)); 7257c478bd9Sstevel@tonic-gate cy = cy1; 7267c478bd9Sstevel@tonic-gate } 727b60f2a0bSfr41279 if (r[result->len - 1] == 0) { 728b60f2a0bSfr41279 result->len--; 729b60f2a0bSfr41279 } 730b60f2a0bSfr41279 7317c478bd9Sstevel@tonic-gate return (BIG_OK); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate 734b60f2a0bSfr41279 /* result = aa*2 */ 7357c478bd9Sstevel@tonic-gate BIG_ERR_CODE 7367c478bd9Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa) 7377c478bd9Sstevel@tonic-gate { 7387c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 7397c478bd9Sstevel@tonic-gate int i, rsize; 740b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, cy1; 741b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *r; 7427c478bd9Sstevel@tonic-gate 743b60f2a0bSfr41279 if ((aa->len > 0) && 744b60f2a0bSfr41279 ((aa->value[aa->len - 1] & BIG_CHUNK_HIGHBIT) != 0)) { 7457c478bd9Sstevel@tonic-gate rsize = aa->len + 1; 746b60f2a0bSfr41279 } else { 747b60f2a0bSfr41279 rsize = aa->len; 748b60f2a0bSfr41279 } 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate if (result->size < rsize) { 7517c478bd9Sstevel@tonic-gate err = big_extend(result, rsize); 7527c478bd9Sstevel@tonic-gate if (err != BIG_OK) 7537c478bd9Sstevel@tonic-gate return (err); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate a = aa->value; 7577c478bd9Sstevel@tonic-gate r = result->value; 758b60f2a0bSfr41279 if (rsize == aa->len + 1) { 759b60f2a0bSfr41279 r[rsize - 1] = 1; 760b60f2a0bSfr41279 } 7617c478bd9Sstevel@tonic-gate cy = 0; 7627c478bd9Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 763b60f2a0bSfr41279 cy1 = a[i] >> (BIG_CHUNK_SIZE - 1); 7647c478bd9Sstevel@tonic-gate r[i] = (cy | (a[i] << 1)); 7657c478bd9Sstevel@tonic-gate cy = cy1; 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate result->len = rsize; 7687c478bd9Sstevel@tonic-gate return (BIG_OK); 7697c478bd9Sstevel@tonic-gate } 7707c478bd9Sstevel@tonic-gate 771b60f2a0bSfr41279 772b60f2a0bSfr41279 /* 773b60f2a0bSfr41279 * returns aa mod b, aa must be nonneg, b must be a max 774b60f2a0bSfr41279 * (BIG_CHUNK_SIZE / 2)-bit integer 775b60f2a0bSfr41279 */ 776b60f2a0bSfr41279 static uint32_t 777b60f2a0bSfr41279 big_modhalf_pos(BIGNUM *aa, uint32_t b) 7787c478bd9Sstevel@tonic-gate { 7797c478bd9Sstevel@tonic-gate int i; 780b60f2a0bSfr41279 BIG_CHUNK_TYPE rem; 7817c478bd9Sstevel@tonic-gate 782b60f2a0bSfr41279 if (aa->len == 0) { 7837c478bd9Sstevel@tonic-gate return (0); 784b60f2a0bSfr41279 } 7857c478bd9Sstevel@tonic-gate rem = aa->value[aa->len - 1] % b; 7867c478bd9Sstevel@tonic-gate for (i = aa->len - 2; i >= 0; i--) { 787b60f2a0bSfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 788b60f2a0bSfr41279 (aa->value[i] >> (BIG_CHUNK_SIZE / 2))) % b; 789b60f2a0bSfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 790b60f2a0bSfr41279 (aa->value[i] & BIG_CHUNK_LOWHALFBITS)) % b; 7917c478bd9Sstevel@tonic-gate } 792b60f2a0bSfr41279 793b60f2a0bSfr41279 return ((uint32_t)rem); 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate /* 798b60f2a0bSfr41279 * result = aa - (2^BIG_CHUNK_SIZE)^lendiff * bb 7997c478bd9Sstevel@tonic-gate * result->size should be at least aa->len at entry 8007c478bd9Sstevel@tonic-gate * aa, bb, and result should be positive 8017c478bd9Sstevel@tonic-gate */ 8027c478bd9Sstevel@tonic-gate void 8037c478bd9Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 8047c478bd9Sstevel@tonic-gate { 8057c478bd9Sstevel@tonic-gate int i, lendiff; 8067c478bd9Sstevel@tonic-gate BIGNUM res1, aa1; 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate lendiff = aa->len - bb->len; 8097c478bd9Sstevel@tonic-gate res1.size = result->size - lendiff; 8107c478bd9Sstevel@tonic-gate res1.malloced = 0; 8117c478bd9Sstevel@tonic-gate res1.value = result->value + lendiff; 8127c478bd9Sstevel@tonic-gate aa1.size = aa->size - lendiff; 8137c478bd9Sstevel@tonic-gate aa1.value = aa->value + lendiff; 8147c478bd9Sstevel@tonic-gate aa1.len = bb->len; 8157c478bd9Sstevel@tonic-gate aa1.sign = 1; 8167c478bd9Sstevel@tonic-gate (void) big_sub_pos(&res1, &aa1, bb); 8177c478bd9Sstevel@tonic-gate if (result->value != aa->value) { 8187c478bd9Sstevel@tonic-gate for (i = 0; i < lendiff; i++) { 8197c478bd9Sstevel@tonic-gate result->value[i] = aa->value[i]; 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate result->len = aa->len; 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate /* 8277c478bd9Sstevel@tonic-gate * returns 1, 0, or -1 depending on whether |aa| > , ==, or < 828b60f2a0bSfr41279 * (2^BIG_CHUNK_SIZE)^lendiff * |bb| 8297c478bd9Sstevel@tonic-gate * aa->len should be >= bb->len 8307c478bd9Sstevel@tonic-gate */ 8317c478bd9Sstevel@tonic-gate int 8327c478bd9Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb) 8337c478bd9Sstevel@tonic-gate { 8347c478bd9Sstevel@tonic-gate int lendiff; 8357c478bd9Sstevel@tonic-gate BIGNUM aa1; 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate lendiff = aa->len - bb->len; 8387c478bd9Sstevel@tonic-gate aa1.len = bb->len; 8397c478bd9Sstevel@tonic-gate aa1.size = aa->size - lendiff; 8407c478bd9Sstevel@tonic-gate aa1.malloced = 0; 8417c478bd9Sstevel@tonic-gate aa1.value = aa->value + lendiff; 8427c478bd9Sstevel@tonic-gate return (big_cmp_abs(&aa1, bb)); 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate /* 847b60f2a0bSfr41279 * result = aa * b where b is a max. (BIG_CHUNK_SIZE / 2)-bit positive integer. 8487c478bd9Sstevel@tonic-gate * result should have enough space allocated. 8497c478bd9Sstevel@tonic-gate */ 850b60f2a0bSfr41279 static void 851b60f2a0bSfr41279 big_mulhalf_low(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 8527c478bd9Sstevel@tonic-gate { 8537c478bd9Sstevel@tonic-gate int i; 854b60f2a0bSfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy; 855b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *r; 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate a = aa->value; 8587c478bd9Sstevel@tonic-gate r = result->value; 8597c478bd9Sstevel@tonic-gate cy = 0; 8607c478bd9Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 8617c478bd9Sstevel@tonic-gate ai = a[i]; 862b60f2a0bSfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 863b60f2a0bSfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 864b60f2a0bSfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 865b60f2a0bSfr41279 r[i] = (t1 & BIG_CHUNK_LOWHALFBITS) | 866b60f2a0bSfr41279 (t2 << (BIG_CHUNK_SIZE / 2)); 867b60f2a0bSfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate r[i] = cy; 8707c478bd9Sstevel@tonic-gate result->len = aa->len + 1; 8717c478bd9Sstevel@tonic-gate result->sign = aa->sign; 8727c478bd9Sstevel@tonic-gate } 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate /* 876b60f2a0bSfr41279 * result = aa * b * 2^(BIG_CHUNK_SIZE / 2) where b is a max. 877b60f2a0bSfr41279 * (BIG_CHUNK_SIZE / 2)-bit positive integer. 8787c478bd9Sstevel@tonic-gate * result should have enough space allocated. 8797c478bd9Sstevel@tonic-gate */ 880b60f2a0bSfr41279 static void 881b60f2a0bSfr41279 big_mulhalf_high(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 8827c478bd9Sstevel@tonic-gate { 8837c478bd9Sstevel@tonic-gate int i; 884b60f2a0bSfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy, ri; 885b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *r; 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate a = aa->value; 8887c478bd9Sstevel@tonic-gate r = result->value; 8897c478bd9Sstevel@tonic-gate cy = 0; 8907c478bd9Sstevel@tonic-gate ri = 0; 8917c478bd9Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 8927c478bd9Sstevel@tonic-gate ai = a[i]; 893b60f2a0bSfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 894b60f2a0bSfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 895b60f2a0bSfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 896b60f2a0bSfr41279 r[i] = (t1 << (BIG_CHUNK_SIZE / 2)) + ri; 897b60f2a0bSfr41279 ri = t2 & BIG_CHUNK_LOWHALFBITS; 898b60f2a0bSfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 8997c478bd9Sstevel@tonic-gate } 900b60f2a0bSfr41279 r[i] = (cy << (BIG_CHUNK_SIZE / 2)) + ri; 9017c478bd9Sstevel@tonic-gate result->len = aa->len + 1; 9027c478bd9Sstevel@tonic-gate result->sign = aa->sign; 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate 905b60f2a0bSfr41279 9067c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 9077c478bd9Sstevel@tonic-gate void 9087c478bd9Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs) 9097c478bd9Sstevel@tonic-gate { 9107c478bd9Sstevel@tonic-gate int i; 911b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, ai; 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate if (offs == 0) { 9147c478bd9Sstevel@tonic-gate if (result != aa) { 9157c478bd9Sstevel@tonic-gate (void) big_copy(result, aa); 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate return; 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate cy = 0; 9207c478bd9Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 9217c478bd9Sstevel@tonic-gate ai = aa->value[i]; 9227c478bd9Sstevel@tonic-gate result->value[i] = (ai << offs) | cy; 923b60f2a0bSfr41279 cy = ai >> (BIG_CHUNK_SIZE - offs); 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate if (cy != 0) { 9267c478bd9Sstevel@tonic-gate result->len = aa->len + 1; 9277c478bd9Sstevel@tonic-gate result->value[result->len - 1] = cy; 9287c478bd9Sstevel@tonic-gate } else { 9297c478bd9Sstevel@tonic-gate result->len = aa->len; 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate result->sign = aa->sign; 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 934b60f2a0bSfr41279 9357c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 9367c478bd9Sstevel@tonic-gate void 9377c478bd9Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs) 9387c478bd9Sstevel@tonic-gate { 9397c478bd9Sstevel@tonic-gate int i; 940b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, ai; 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate if (offs == 0) { 9437c478bd9Sstevel@tonic-gate if (result != aa) { 9447c478bd9Sstevel@tonic-gate (void) big_copy(result, aa); 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate return; 9477c478bd9Sstevel@tonic-gate } 9487c478bd9Sstevel@tonic-gate cy = aa->value[0] >> offs; 9497c478bd9Sstevel@tonic-gate for (i = 1; i < aa->len; i++) { 9507c478bd9Sstevel@tonic-gate ai = aa->value[i]; 951b60f2a0bSfr41279 result->value[i - 1] = (ai << (BIG_CHUNK_SIZE - offs)) | cy; 9527c478bd9Sstevel@tonic-gate cy = ai >> offs; 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate result->len = aa->len; 9557c478bd9Sstevel@tonic-gate result->value[result->len - 1] = cy; 9567c478bd9Sstevel@tonic-gate result->sign = aa->sign; 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate /* 9617c478bd9Sstevel@tonic-gate * result = aa/bb remainder = aa mod bb 9627c478bd9Sstevel@tonic-gate * it is assumed that aa and bb are positive 9637c478bd9Sstevel@tonic-gate */ 9647c478bd9Sstevel@tonic-gate BIG_ERR_CODE 965*8475e043SDan OpenSolaris Anderson big_div_pos(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb) 9667c478bd9Sstevel@tonic-gate { 967b60f2a0bSfr41279 BIG_ERR_CODE err = BIG_OK; 9687c478bd9Sstevel@tonic-gate int i, alen, blen, tlen, rlen, offs; 969b60f2a0bSfr41279 BIG_CHUNK_TYPE higha, highb, coeff; 970b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *b; 9717c478bd9Sstevel@tonic-gate BIGNUM bbhigh, bblow, tresult, tmp1, tmp2; 972b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 973b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 974b60f2a0bSfr41279 BIG_CHUNK_TYPE tresultvalue[BIGTMPSIZE]; 975b60f2a0bSfr41279 BIG_CHUNK_TYPE bblowvalue[BIGTMPSIZE]; 976b60f2a0bSfr41279 BIG_CHUNK_TYPE bbhighvalue[BIGTMPSIZE]; 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate a = aa->value; 9797c478bd9Sstevel@tonic-gate b = bb->value; 9807c478bd9Sstevel@tonic-gate alen = aa->len; 9817c478bd9Sstevel@tonic-gate blen = bb->len; 982b60f2a0bSfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 983b60f2a0bSfr41279 alen = alen - 1; 984b60f2a0bSfr41279 } 9857c478bd9Sstevel@tonic-gate aa->len = alen; 986b60f2a0bSfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 987b60f2a0bSfr41279 blen = blen - 1; 988b60f2a0bSfr41279 } 9897c478bd9Sstevel@tonic-gate bb->len = blen; 990b60f2a0bSfr41279 if ((blen == 1) && (b[0] == 0)) { 9917c478bd9Sstevel@tonic-gate return (BIG_DIV_BY_0); 992b60f2a0bSfr41279 } 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate if (big_cmp_abs(aa, bb) < 0) { 9957c478bd9Sstevel@tonic-gate if ((remainder != NULL) && 996b60f2a0bSfr41279 ((err = big_copy(remainder, aa)) != BIG_OK)) { 9977c478bd9Sstevel@tonic-gate return (err); 998b60f2a0bSfr41279 } 9997c478bd9Sstevel@tonic-gate if (result != NULL) { 10007c478bd9Sstevel@tonic-gate result->len = 1; 10017c478bd9Sstevel@tonic-gate result->sign = 1; 10027c478bd9Sstevel@tonic-gate result->value[0] = 0; 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate return (BIG_OK); 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate if ((err = big_init1(&bblow, blen + 1, 10087c478bd9Sstevel@tonic-gate bblowvalue, arraysize(bblowvalue))) != BIG_OK) 10097c478bd9Sstevel@tonic-gate return (err); 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate if ((err = big_init1(&bbhigh, blen + 1, 10127c478bd9Sstevel@tonic-gate bbhighvalue, arraysize(bbhighvalue))) != BIG_OK) 10137c478bd9Sstevel@tonic-gate goto ret1; 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp1, alen + 2, 10167c478bd9Sstevel@tonic-gate tmp1value, arraysize(tmp1value))) != BIG_OK) 10177c478bd9Sstevel@tonic-gate goto ret2; 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp2, blen + 2, 10207c478bd9Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 10217c478bd9Sstevel@tonic-gate goto ret3; 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate if ((err = big_init1(&tresult, alen - blen + 2, 10247c478bd9Sstevel@tonic-gate tresultvalue, arraysize(tresultvalue))) != BIG_OK) 10257c478bd9Sstevel@tonic-gate goto ret4; 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate offs = 0; 1028b60f2a0bSfr41279 highb = b[blen - 1]; 1029b60f2a0bSfr41279 if (highb >= (BIG_CHUNK_HALF_HIGHBIT << 1)) { 1030b60f2a0bSfr41279 highb = highb >> (BIG_CHUNK_SIZE / 2); 1031b60f2a0bSfr41279 offs = (BIG_CHUNK_SIZE / 2); 10327c478bd9Sstevel@tonic-gate } 1033b60f2a0bSfr41279 while ((highb & BIG_CHUNK_HALF_HIGHBIT) == 0) { 1034b60f2a0bSfr41279 highb = highb << 1; 10357c478bd9Sstevel@tonic-gate offs++; 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate big_shiftleft(&bblow, bb, offs); 1039b60f2a0bSfr41279 1040b60f2a0bSfr41279 if (offs <= (BIG_CHUNK_SIZE / 2 - 1)) { 1041b60f2a0bSfr41279 big_shiftleft(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10427c478bd9Sstevel@tonic-gate } else { 1043b60f2a0bSfr41279 big_shiftright(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate if (bbhigh.value[bbhigh.len - 1] == 0) { 10467c478bd9Sstevel@tonic-gate bbhigh.len--; 10477c478bd9Sstevel@tonic-gate } else { 10487c478bd9Sstevel@tonic-gate bbhigh.value[bbhigh.len] = 0; 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate 1051b60f2a0bSfr41279 highb = bblow.value[bblow.len - 1]; 1052b60f2a0bSfr41279 10537c478bd9Sstevel@tonic-gate big_shiftleft(&tmp1, aa, offs); 10547c478bd9Sstevel@tonic-gate rlen = tmp1.len - bblow.len + 1; 10557c478bd9Sstevel@tonic-gate tresult.len = rlen; 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate tmp1.len++; 10587c478bd9Sstevel@tonic-gate tlen = tmp1.len; 10597c478bd9Sstevel@tonic-gate tmp1.value[tmp1.len - 1] = 0; 10607c478bd9Sstevel@tonic-gate for (i = 0; i < rlen; i++) { 1061b60f2a0bSfr41279 higha = (tmp1.value[tlen - 1] << (BIG_CHUNK_SIZE / 2)) + 1062b60f2a0bSfr41279 (tmp1.value[tlen - 2] >> (BIG_CHUNK_SIZE / 2)); 10637c478bd9Sstevel@tonic-gate coeff = higha / (highb + 1); 1064b60f2a0bSfr41279 big_mulhalf_high(&tmp2, &bblow, coeff); 10657c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 10667c478bd9Sstevel@tonic-gate bbhigh.len++; 10677c478bd9Sstevel@tonic-gate while (tmp1.value[tlen - 1] > 0) { 10687c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 10697c478bd9Sstevel@tonic-gate coeff++; 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate bbhigh.len--; 10727c478bd9Sstevel@tonic-gate tlen--; 10737c478bd9Sstevel@tonic-gate tmp1.len--; 10747c478bd9Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) { 10757c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 10767c478bd9Sstevel@tonic-gate coeff++; 10777c478bd9Sstevel@tonic-gate } 1078b60f2a0bSfr41279 tresult.value[rlen - i - 1] = coeff << (BIG_CHUNK_SIZE / 2); 10797c478bd9Sstevel@tonic-gate higha = tmp1.value[tlen - 1]; 10807c478bd9Sstevel@tonic-gate coeff = higha / (highb + 1); 1081b60f2a0bSfr41279 big_mulhalf_low(&tmp2, &bblow, coeff); 10827c478bd9Sstevel@tonic-gate tmp2.len--; 10837c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 10847c478bd9Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bblow) >= 0) { 10857c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bblow); 10867c478bd9Sstevel@tonic-gate coeff++; 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate tresult.value[rlen - i - 1] = 10897c478bd9Sstevel@tonic-gate tresult.value[rlen - i - 1] + coeff; 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate big_shiftright(&tmp1, &tmp1, offs); 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate err = BIG_OK; 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate if ((remainder != NULL) && 10977c478bd9Sstevel@tonic-gate ((err = big_copy(remainder, &tmp1)) != BIG_OK)) 10987c478bd9Sstevel@tonic-gate goto ret; 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate if (result != NULL) 11017c478bd9Sstevel@tonic-gate err = big_copy(result, &tresult); 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate ret: 11047c478bd9Sstevel@tonic-gate big_finish(&tresult); 11057c478bd9Sstevel@tonic-gate ret4: 11067c478bd9Sstevel@tonic-gate big_finish(&tmp1); 11077c478bd9Sstevel@tonic-gate ret3: 11087c478bd9Sstevel@tonic-gate big_finish(&tmp2); 11097c478bd9Sstevel@tonic-gate ret2: 11107c478bd9Sstevel@tonic-gate big_finish(&bbhigh); 11117c478bd9Sstevel@tonic-gate ret1: 11127c478bd9Sstevel@tonic-gate big_finish(&bblow); 11137c478bd9Sstevel@tonic-gate return (err); 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 1116*8475e043SDan OpenSolaris Anderson 11177c478bd9Sstevel@tonic-gate /* 11187c478bd9Sstevel@tonic-gate * If there is no processor-specific integer implementation of 11197c478bd9Sstevel@tonic-gate * the lower level multiply functions, then this code is provided 11207c478bd9Sstevel@tonic-gate * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and 11217c478bd9Sstevel@tonic-gate * big_sqr_vec(). 11227c478bd9Sstevel@tonic-gate * 11237c478bd9Sstevel@tonic-gate * There are two generic implementations. One that assumes that 11247c478bd9Sstevel@tonic-gate * there is hardware and C compiler support for a 32 x 32 --> 64 11257c478bd9Sstevel@tonic-gate * bit unsigned multiply, but otherwise is not specific to any 11267c478bd9Sstevel@tonic-gate * processor, platform, or ISA. 11277c478bd9Sstevel@tonic-gate * 11287c478bd9Sstevel@tonic-gate * The other makes very few assumptions about hardware capabilities. 11297c478bd9Sstevel@tonic-gate * It does not even assume that there is any implementation of a 11307c478bd9Sstevel@tonic-gate * 32 x 32 --> 64 bit multiply that is accessible to C code and 11317c478bd9Sstevel@tonic-gate * appropriate to use. It falls constructs 32 x 32 --> 64 bit 11327c478bd9Sstevel@tonic-gate * multiplies from 16 x 16 --> 32 bit multiplies. 11337c478bd9Sstevel@tonic-gate * 11347c478bd9Sstevel@tonic-gate */ 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate #if !defined(PSR_MUL) 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate #ifdef UMUL64 11397c478bd9Sstevel@tonic-gate 1140b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 1141b60f2a0bSfr41279 11427c478bd9Sstevel@tonic-gate #define UNROLL8 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_PREFETCH(R) \ 11457c478bd9Sstevel@tonic-gate p = pf * d; \ 11467c478bd9Sstevel@tonic-gate pf = (uint64_t)a[R + 1]; \ 11477c478bd9Sstevel@tonic-gate t = p + cy; \ 11487c478bd9Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11497c478bd9Sstevel@tonic-gate cy = t >> 32 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_NOPREFETCH(R) \ 11527c478bd9Sstevel@tonic-gate p = pf * d; \ 11537c478bd9Sstevel@tonic-gate t = p + cy; \ 11547c478bd9Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11557c478bd9Sstevel@tonic-gate cy = t >> 32 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_PREFETCH(R) \ 11587c478bd9Sstevel@tonic-gate t = (uint64_t)r[R]; \ 11597c478bd9Sstevel@tonic-gate p = pf * d; \ 11607c478bd9Sstevel@tonic-gate pf = (uint64_t)a[R + 1]; \ 11617c478bd9Sstevel@tonic-gate t = p + t + cy; \ 11627c478bd9Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11637c478bd9Sstevel@tonic-gate cy = t >> 32 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_NOPREFETCH(R) \ 11667c478bd9Sstevel@tonic-gate t = (uint64_t)r[R]; \ 11677c478bd9Sstevel@tonic-gate p = pf * d; \ 11687c478bd9Sstevel@tonic-gate t = p + t + cy; \ 11697c478bd9Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11707c478bd9Sstevel@tonic-gate cy = t >> 32 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate #ifdef UNROLL8 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate #define UNROLL 8 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate /* 11777c478bd9Sstevel@tonic-gate * r = a * b 11787c478bd9Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 11797c478bd9Sstevel@tonic-gate */ 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate uint32_t 11827c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 11837c478bd9Sstevel@tonic-gate { 11847c478bd9Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate if (len == 0) 11877c478bd9Sstevel@tonic-gate return (0); 11887c478bd9Sstevel@tonic-gate cy = 0; 11897c478bd9Sstevel@tonic-gate d = (uint64_t)b; 11907c478bd9Sstevel@tonic-gate pf = (uint64_t)a[0]; 11917c478bd9Sstevel@tonic-gate while (len > UNROLL) { 11927c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 11937c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 11947c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 11957c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 11967c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 11977c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 11987c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 11997c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(7); 12007c478bd9Sstevel@tonic-gate r += UNROLL; 12017c478bd9Sstevel@tonic-gate a += UNROLL; 12027c478bd9Sstevel@tonic-gate len -= UNROLL; 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate if (len == UNROLL) { 12057c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 12067c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 12077c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 12087c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 12097c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 12107c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 12117c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 12127c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(7); 12137c478bd9Sstevel@tonic-gate return ((uint32_t)cy); 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate while (len > 1) { 12167c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 12177c478bd9Sstevel@tonic-gate ++r; 12187c478bd9Sstevel@tonic-gate ++a; 12197c478bd9Sstevel@tonic-gate --len; 12207c478bd9Sstevel@tonic-gate } 12217c478bd9Sstevel@tonic-gate if (len > 0) { 12227c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(0); 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate return ((uint32_t)cy); 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate /* 12287c478bd9Sstevel@tonic-gate * r += a * b 12297c478bd9Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 12307c478bd9Sstevel@tonic-gate */ 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate uint32_t 12337c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 12347c478bd9Sstevel@tonic-gate { 12357c478bd9Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate if (len == 0) 12387c478bd9Sstevel@tonic-gate return (0); 12397c478bd9Sstevel@tonic-gate cy = 0; 12407c478bd9Sstevel@tonic-gate d = (uint64_t)b; 12417c478bd9Sstevel@tonic-gate pf = (uint64_t)a[0]; 12427c478bd9Sstevel@tonic-gate while (len > 8) { 12437c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12447c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 12457c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 12467c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 12477c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 12487c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 12497c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 12507c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(7); 12517c478bd9Sstevel@tonic-gate r += 8; 12527c478bd9Sstevel@tonic-gate a += 8; 12537c478bd9Sstevel@tonic-gate len -= 8; 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate if (len == 8) { 12567c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12577c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 12587c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 12597c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 12607c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 12617c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 12627c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 12637c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(7); 12647c478bd9Sstevel@tonic-gate return ((uint32_t)cy); 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate while (len > 1) { 12677c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12687c478bd9Sstevel@tonic-gate ++r; 12697c478bd9Sstevel@tonic-gate ++a; 12707c478bd9Sstevel@tonic-gate --len; 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate if (len > 0) { 12737c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(0); 12747c478bd9Sstevel@tonic-gate } 12757c478bd9Sstevel@tonic-gate return ((uint32_t)cy); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate #endif /* UNROLL8 */ 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate void 12807c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 12817c478bd9Sstevel@tonic-gate { 12827c478bd9Sstevel@tonic-gate uint32_t *tr, *ta; 12837c478bd9Sstevel@tonic-gate int tlen, row, col; 12847c478bd9Sstevel@tonic-gate uint64_t p, s, t, t2, cy; 12857c478bd9Sstevel@tonic-gate uint32_t d; 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate tr = r + 1; 12887c478bd9Sstevel@tonic-gate ta = a; 12897c478bd9Sstevel@tonic-gate tlen = len - 1; 12907c478bd9Sstevel@tonic-gate tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]); 12917c478bd9Sstevel@tonic-gate while (--tlen > 0) { 12927c478bd9Sstevel@tonic-gate tr += 2; 12937c478bd9Sstevel@tonic-gate ++ta; 12947c478bd9Sstevel@tonic-gate tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]); 12957c478bd9Sstevel@tonic-gate } 12967c478bd9Sstevel@tonic-gate s = (uint64_t)a[0]; 12977c478bd9Sstevel@tonic-gate s = s * s; 12987c478bd9Sstevel@tonic-gate r[0] = (uint32_t)s; 12997c478bd9Sstevel@tonic-gate cy = s >> 32; 13007c478bd9Sstevel@tonic-gate p = ((uint64_t)r[1] << 1) + cy; 13017c478bd9Sstevel@tonic-gate r[1] = (uint32_t)p; 13027c478bd9Sstevel@tonic-gate cy = p >> 32; 13037c478bd9Sstevel@tonic-gate row = 1; 13047c478bd9Sstevel@tonic-gate col = 2; 13057c478bd9Sstevel@tonic-gate while (row < len) { 13067c478bd9Sstevel@tonic-gate s = (uint64_t)a[row]; 13077c478bd9Sstevel@tonic-gate s = s * s; 13087c478bd9Sstevel@tonic-gate p = (uint64_t)r[col] << 1; 13097c478bd9Sstevel@tonic-gate t = p + s; 13107c478bd9Sstevel@tonic-gate d = (uint32_t)t; 13117c478bd9Sstevel@tonic-gate t2 = (uint64_t)d + cy; 13127c478bd9Sstevel@tonic-gate r[col] = (uint32_t)t2; 13137c478bd9Sstevel@tonic-gate cy = (t >> 32) + (t2 >> 32); 13147c478bd9Sstevel@tonic-gate if (row == len - 1) 13157c478bd9Sstevel@tonic-gate break; 13167c478bd9Sstevel@tonic-gate p = ((uint64_t)r[col + 1] << 1) + cy; 13177c478bd9Sstevel@tonic-gate r[col + 1] = (uint32_t)p; 13187c478bd9Sstevel@tonic-gate cy = p >> 32; 13197c478bd9Sstevel@tonic-gate ++row; 13207c478bd9Sstevel@tonic-gate col += 2; 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate r[col + 1] = (uint32_t)cy; 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate 1325b60f2a0bSfr41279 #else /* BIG_CHUNK_SIZE == 64 */ 1326b60f2a0bSfr41279 1327b60f2a0bSfr41279 /* 1328b60f2a0bSfr41279 * r = r + a * digit, r and a are vectors of length len 1329b60f2a0bSfr41279 * returns the carry digit 1330b60f2a0bSfr41279 */ 1331b60f2a0bSfr41279 BIG_CHUNK_TYPE 1332b60f2a0bSfr41279 big_mul_add_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 1333b60f2a0bSfr41279 BIG_CHUNK_TYPE digit) 1334b60f2a0bSfr41279 { 1335b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, cy1, retcy, dlow, dhigh; 1336b60f2a0bSfr41279 int i; 1337b60f2a0bSfr41279 1338b60f2a0bSfr41279 cy1 = 0; 1339b60f2a0bSfr41279 dlow = digit & BIG_CHUNK_LOWHALFBITS; 1340b60f2a0bSfr41279 dhigh = digit >> (BIG_CHUNK_SIZE / 2); 1341b60f2a0bSfr41279 for (i = 0; i < len; i++) { 1342b60f2a0bSfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 1343b60f2a0bSfr41279 dlow * (a[i] & BIG_CHUNK_LOWHALFBITS) + 1344b60f2a0bSfr41279 (r[i] & BIG_CHUNK_LOWHALFBITS); 1345b60f2a0bSfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 1346b60f2a0bSfr41279 dlow * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 1347b60f2a0bSfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 1348b60f2a0bSfr41279 r[i] = (cy & BIG_CHUNK_LOWHALFBITS) | 1349b60f2a0bSfr41279 (cy1 << (BIG_CHUNK_SIZE / 2)); 1350b60f2a0bSfr41279 } 1351b60f2a0bSfr41279 retcy = cy1 >> (BIG_CHUNK_SIZE / 2); 1352b60f2a0bSfr41279 1353b60f2a0bSfr41279 cy1 = r[0] & BIG_CHUNK_LOWHALFBITS; 1354b60f2a0bSfr41279 for (i = 0; i < len - 1; i++) { 1355b60f2a0bSfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 1356b60f2a0bSfr41279 dhigh * (a[i] & BIG_CHUNK_LOWHALFBITS) + 1357b60f2a0bSfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 1358b60f2a0bSfr41279 r[i] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 1359b60f2a0bSfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 1360b60f2a0bSfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 1361b60f2a0bSfr41279 dhigh * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 1362b60f2a0bSfr41279 (r[i + 1] & BIG_CHUNK_LOWHALFBITS); 1363b60f2a0bSfr41279 } 1364b60f2a0bSfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 1365b60f2a0bSfr41279 dhigh * (a[len - 1] & BIG_CHUNK_LOWHALFBITS) + 1366b60f2a0bSfr41279 (r[len - 1] >> (BIG_CHUNK_SIZE / 2)); 1367b60f2a0bSfr41279 r[len - 1] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 1368b60f2a0bSfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 1369b60f2a0bSfr41279 retcy = (cy >> (BIG_CHUNK_SIZE / 2)) + 1370b60f2a0bSfr41279 dhigh * (a[len - 1] >> (BIG_CHUNK_SIZE / 2)) + retcy; 1371b60f2a0bSfr41279 1372b60f2a0bSfr41279 return (retcy); 1373b60f2a0bSfr41279 } 1374b60f2a0bSfr41279 1375b60f2a0bSfr41279 1376b60f2a0bSfr41279 /* 1377b60f2a0bSfr41279 * r = a * digit, r and a are vectors of length len 1378b60f2a0bSfr41279 * returns the carry digit 1379b60f2a0bSfr41279 */ 1380b60f2a0bSfr41279 BIG_CHUNK_TYPE 1381b60f2a0bSfr41279 big_mul_set_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 1382b60f2a0bSfr41279 BIG_CHUNK_TYPE digit) 1383b60f2a0bSfr41279 { 1384b60f2a0bSfr41279 int i; 1385b60f2a0bSfr41279 1386b60f2a0bSfr41279 ASSERT(r != a); 1387b60f2a0bSfr41279 for (i = 0; i < len; i++) { 1388b60f2a0bSfr41279 r[i] = 0; 1389b60f2a0bSfr41279 } 1390b60f2a0bSfr41279 return (big_mul_add_vec(r, a, len, digit)); 1391b60f2a0bSfr41279 } 1392b60f2a0bSfr41279 1393b60f2a0bSfr41279 void 1394b60f2a0bSfr41279 big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len) 1395b60f2a0bSfr41279 { 1396b60f2a0bSfr41279 int i; 1397b60f2a0bSfr41279 1398b60f2a0bSfr41279 ASSERT(r != a); 1399b60f2a0bSfr41279 r[len] = big_mul_set_vec(r, a, len, a[0]); 1400b60f2a0bSfr41279 for (i = 1; i < len; ++i) 1401b60f2a0bSfr41279 r[len + i] = big_mul_add_vec(r + i, a, len, a[i]); 1402b60f2a0bSfr41279 } 1403b60f2a0bSfr41279 1404b60f2a0bSfr41279 #endif /* BIG_CHUNK_SIZE == 32/64 */ 1405b60f2a0bSfr41279 1406*8475e043SDan OpenSolaris Anderson 14077c478bd9Sstevel@tonic-gate #else /* ! UMUL64 */ 14087c478bd9Sstevel@tonic-gate 1409b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE != 32) 1410b60f2a0bSfr41279 #error Don't use 64-bit chunks without defining UMUL64 1411b60f2a0bSfr41279 #endif 1412b60f2a0bSfr41279 1413b60f2a0bSfr41279 14147c478bd9Sstevel@tonic-gate /* 14157c478bd9Sstevel@tonic-gate * r = r + a * digit, r and a are vectors of length len 14167c478bd9Sstevel@tonic-gate * returns the carry digit 14177c478bd9Sstevel@tonic-gate */ 14187c478bd9Sstevel@tonic-gate uint32_t 14197c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 14207c478bd9Sstevel@tonic-gate { 14217c478bd9Sstevel@tonic-gate uint32_t cy, cy1, retcy, dlow, dhigh; 14227c478bd9Sstevel@tonic-gate int i; 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate cy1 = 0; 14257c478bd9Sstevel@tonic-gate dlow = digit & 0xffff; 14267c478bd9Sstevel@tonic-gate dhigh = digit >> 16; 14277c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) { 14287c478bd9Sstevel@tonic-gate cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff); 14297c478bd9Sstevel@tonic-gate cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16); 14307c478bd9Sstevel@tonic-gate r[i] = (cy & 0xffff) | (cy1 << 16); 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate retcy = cy1 >> 16; 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate cy1 = r[0] & 0xffff; 14357c478bd9Sstevel@tonic-gate for (i = 0; i < len - 1; i++) { 14367c478bd9Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16); 14377c478bd9Sstevel@tonic-gate r[i] = (cy1 & 0xffff) | (cy << 16); 14387c478bd9Sstevel@tonic-gate cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff); 14397c478bd9Sstevel@tonic-gate } 14407c478bd9Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16); 14417c478bd9Sstevel@tonic-gate r[len - 1] = (cy1 & 0xffff) | (cy << 16); 14427c478bd9Sstevel@tonic-gate retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy; 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate return (retcy); 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate 1447b60f2a0bSfr41279 14487c478bd9Sstevel@tonic-gate /* 14497c478bd9Sstevel@tonic-gate * r = a * digit, r and a are vectors of length len 14507c478bd9Sstevel@tonic-gate * returns the carry digit 14517c478bd9Sstevel@tonic-gate */ 14527c478bd9Sstevel@tonic-gate uint32_t 14537c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 14547c478bd9Sstevel@tonic-gate { 1455b60f2a0bSfr41279 int i; 1456b60f2a0bSfr41279 1457b60f2a0bSfr41279 ASSERT(r != a); 1458b60f2a0bSfr41279 for (i = 0; i < len; i++) { 1459b60f2a0bSfr41279 r[i] = 0; 1460b60f2a0bSfr41279 } 1461b60f2a0bSfr41279 14627c478bd9Sstevel@tonic-gate return (big_mul_add_vec(r, a, len, digit)); 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate void 14667c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 14677c478bd9Sstevel@tonic-gate { 14687c478bd9Sstevel@tonic-gate int i; 14697c478bd9Sstevel@tonic-gate 1470b60f2a0bSfr41279 ASSERT(r != a); 14717c478bd9Sstevel@tonic-gate r[len] = big_mul_set_vec(r, a, len, a[0]); 14727c478bd9Sstevel@tonic-gate for (i = 1; i < len; ++i) 14737c478bd9Sstevel@tonic-gate r[len + i] = big_mul_add_vec(r + i, a, len, a[i]); 14747c478bd9Sstevel@tonic-gate } 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate #endif /* UMUL64 */ 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate void 1479b60f2a0bSfr41279 big_mul_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int alen, 1480b60f2a0bSfr41279 BIG_CHUNK_TYPE *b, int blen) 14817c478bd9Sstevel@tonic-gate { 14827c478bd9Sstevel@tonic-gate int i; 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate r[alen] = big_mul_set_vec(r, a, alen, b[0]); 14857c478bd9Sstevel@tonic-gate for (i = 1; i < blen; ++i) 14867c478bd9Sstevel@tonic-gate r[alen + i] = big_mul_add_vec(r + i, a, alen, b[i]); 14877c478bd9Sstevel@tonic-gate } 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate #endif /* ! PSR_MUL */ 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate /* 14947c478bd9Sstevel@tonic-gate * result = aa * bb result->value should be big enough to hold the result 14957c478bd9Sstevel@tonic-gate * 14967c478bd9Sstevel@tonic-gate * Implementation: Standard grammar school algorithm 14977c478bd9Sstevel@tonic-gate * 14987c478bd9Sstevel@tonic-gate */ 14997c478bd9Sstevel@tonic-gate BIG_ERR_CODE 15007c478bd9Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 15017c478bd9Sstevel@tonic-gate { 15027c478bd9Sstevel@tonic-gate BIGNUM tmp1; 1503b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 1504b60f2a0bSfr41279 BIG_CHUNK_TYPE *r, *t, *a, *b; 15057c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 15067c478bd9Sstevel@tonic-gate int i, alen, blen, rsize, sign, diff; 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate if (aa == bb) { 15097c478bd9Sstevel@tonic-gate diff = 0; 15107c478bd9Sstevel@tonic-gate } else { 15117c478bd9Sstevel@tonic-gate diff = big_cmp_abs(aa, bb); 15127c478bd9Sstevel@tonic-gate if (diff < 0) { 15137c478bd9Sstevel@tonic-gate BIGNUM *tt; 15147c478bd9Sstevel@tonic-gate tt = aa; 15157c478bd9Sstevel@tonic-gate aa = bb; 15167c478bd9Sstevel@tonic-gate bb = tt; 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate a = aa->value; 15207c478bd9Sstevel@tonic-gate b = bb->value; 15217c478bd9Sstevel@tonic-gate alen = aa->len; 15227c478bd9Sstevel@tonic-gate blen = bb->len; 1523b60f2a0bSfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 1524b60f2a0bSfr41279 alen--; 1525b60f2a0bSfr41279 } 15267c478bd9Sstevel@tonic-gate aa->len = alen; 1527b60f2a0bSfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 1528b60f2a0bSfr41279 blen--; 1529b60f2a0bSfr41279 } 15307c478bd9Sstevel@tonic-gate bb->len = blen; 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate rsize = alen + blen; 1533*8475e043SDan OpenSolaris Anderson ASSERT(rsize > 0); 15347c478bd9Sstevel@tonic-gate if (result->size < rsize) { 15357c478bd9Sstevel@tonic-gate err = big_extend(result, rsize); 1536b60f2a0bSfr41279 if (err != BIG_OK) { 15377c478bd9Sstevel@tonic-gate return (err); 1538b60f2a0bSfr41279 } 15397c478bd9Sstevel@tonic-gate /* aa or bb might be an alias to result */ 15407c478bd9Sstevel@tonic-gate a = aa->value; 15417c478bd9Sstevel@tonic-gate b = bb->value; 15427c478bd9Sstevel@tonic-gate } 15437c478bd9Sstevel@tonic-gate r = result->value; 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) { 15467c478bd9Sstevel@tonic-gate result->len = 1; 15477c478bd9Sstevel@tonic-gate result->sign = 1; 15487c478bd9Sstevel@tonic-gate r[0] = 0; 15497c478bd9Sstevel@tonic-gate return (BIG_OK); 15507c478bd9Sstevel@tonic-gate } 15517c478bd9Sstevel@tonic-gate sign = aa->sign * bb->sign; 15527c478bd9Sstevel@tonic-gate if ((alen == 1) && (a[0] == 1)) { 1553b60f2a0bSfr41279 for (i = 0; i < blen; i++) { 1554b60f2a0bSfr41279 r[i] = b[i]; 1555b60f2a0bSfr41279 } 15567c478bd9Sstevel@tonic-gate result->len = blen; 15577c478bd9Sstevel@tonic-gate result->sign = sign; 15587c478bd9Sstevel@tonic-gate return (BIG_OK); 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate if ((blen == 1) && (b[0] == 1)) { 1561b60f2a0bSfr41279 for (i = 0; i < alen; i++) { 1562b60f2a0bSfr41279 r[i] = a[i]; 1563b60f2a0bSfr41279 } 15647c478bd9Sstevel@tonic-gate result->len = alen; 15657c478bd9Sstevel@tonic-gate result->sign = sign; 15667c478bd9Sstevel@tonic-gate return (BIG_OK); 15677c478bd9Sstevel@tonic-gate } 15687c478bd9Sstevel@tonic-gate 1569b60f2a0bSfr41279 if ((err = big_init1(&tmp1, rsize, 1570b60f2a0bSfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 15717c478bd9Sstevel@tonic-gate return (err); 1572b60f2a0bSfr41279 } 1573b60f2a0bSfr41279 (void) big_copy(&tmp1, aa); 15747c478bd9Sstevel@tonic-gate t = tmp1.value; 15757c478bd9Sstevel@tonic-gate 1576b60f2a0bSfr41279 for (i = 0; i < rsize; i++) { 1577b60f2a0bSfr41279 t[i] = 0; 1578b60f2a0bSfr41279 } 1579b60f2a0bSfr41279 1580b60f2a0bSfr41279 if (diff == 0 && alen > 2) { 15817c478bd9Sstevel@tonic-gate BIG_SQR_VEC(t, a, alen); 1582b60f2a0bSfr41279 } else if (blen > 0) { 15837c478bd9Sstevel@tonic-gate BIG_MUL_VEC(t, a, alen, b, blen); 1584b60f2a0bSfr41279 } 15857c478bd9Sstevel@tonic-gate 1586b60f2a0bSfr41279 if (t[rsize - 1] == 0) { 1587b60f2a0bSfr41279 tmp1.len = rsize - 1; 1588b60f2a0bSfr41279 } else { 1589b60f2a0bSfr41279 tmp1.len = rsize; 1590b60f2a0bSfr41279 } 1591*8475e043SDan OpenSolaris Anderson 1592*8475e043SDan OpenSolaris Anderson err = big_copy(result, &tmp1); 1593*8475e043SDan OpenSolaris Anderson 15947c478bd9Sstevel@tonic-gate result->sign = sign; 15957c478bd9Sstevel@tonic-gate 1596b60f2a0bSfr41279 big_finish(&tmp1); 15977c478bd9Sstevel@tonic-gate 1598*8475e043SDan OpenSolaris Anderson return (err); 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate /* 16037c478bd9Sstevel@tonic-gate * caller must ensure that a < n, b < n and ret->size >= 2 * n->len + 1 16047c478bd9Sstevel@tonic-gate * and that ret is not n 16057c478bd9Sstevel@tonic-gate */ 16067c478bd9Sstevel@tonic-gate BIG_ERR_CODE 1607b60f2a0bSfr41279 big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, BIG_CHUNK_TYPE n0) 16087c478bd9Sstevel@tonic-gate { 16097c478bd9Sstevel@tonic-gate int i, j, nlen, needsubtract; 1610b60f2a0bSfr41279 BIG_CHUNK_TYPE *nn, *rr; 1611b60f2a0bSfr41279 BIG_CHUNK_TYPE digit, c; 16127c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 16137c478bd9Sstevel@tonic-gate 16147c478bd9Sstevel@tonic-gate nlen = n->len; 16157c478bd9Sstevel@tonic-gate nn = n->value; 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate rr = ret->value; 16187c478bd9Sstevel@tonic-gate 1619b60f2a0bSfr41279 if ((err = big_mul(ret, a, b)) != BIG_OK) { 16207c478bd9Sstevel@tonic-gate return (err); 1621b60f2a0bSfr41279 } 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate rr = ret->value; 1624b60f2a0bSfr41279 for (i = ret->len; i < 2 * nlen + 1; i++) { 1625b60f2a0bSfr41279 rr[i] = 0; 1626b60f2a0bSfr41279 } 16277c478bd9Sstevel@tonic-gate for (i = 0; i < nlen; i++) { 16287c478bd9Sstevel@tonic-gate digit = rr[i]; 16297c478bd9Sstevel@tonic-gate digit = digit * n0; 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate c = BIG_MUL_ADD_VEC(rr + i, nn, nlen, digit); 16327c478bd9Sstevel@tonic-gate j = i + nlen; 16337c478bd9Sstevel@tonic-gate rr[j] += c; 16347c478bd9Sstevel@tonic-gate while (rr[j] < c) { 16357c478bd9Sstevel@tonic-gate rr[j + 1] += 1; 16367c478bd9Sstevel@tonic-gate j++; 16377c478bd9Sstevel@tonic-gate c = 1; 16387c478bd9Sstevel@tonic-gate } 16397c478bd9Sstevel@tonic-gate } 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate needsubtract = 0; 16427c478bd9Sstevel@tonic-gate if ((rr[2 * nlen] != 0)) 16437c478bd9Sstevel@tonic-gate needsubtract = 1; 16447c478bd9Sstevel@tonic-gate else { 16457c478bd9Sstevel@tonic-gate for (i = 2 * nlen - 1; i >= nlen; i--) { 16467c478bd9Sstevel@tonic-gate if (rr[i] > nn[i - nlen]) { 16477c478bd9Sstevel@tonic-gate needsubtract = 1; 16487c478bd9Sstevel@tonic-gate break; 1649b60f2a0bSfr41279 } else if (rr[i] < nn[i - nlen]) { 1650b60f2a0bSfr41279 break; 1651b60f2a0bSfr41279 } 16527c478bd9Sstevel@tonic-gate } 16537c478bd9Sstevel@tonic-gate } 16547c478bd9Sstevel@tonic-gate if (needsubtract) 16557c478bd9Sstevel@tonic-gate big_sub_vec(rr, rr + nlen, nn, nlen); 16567c478bd9Sstevel@tonic-gate else { 1657b60f2a0bSfr41279 for (i = 0; i < nlen; i++) { 16587c478bd9Sstevel@tonic-gate rr[i] = rr[i + nlen]; 16597c478bd9Sstevel@tonic-gate } 1660b60f2a0bSfr41279 } 1661*8475e043SDan OpenSolaris Anderson 1662*8475e043SDan OpenSolaris Anderson /* Remove leading zeros, but keep at least 1 digit: */ 1663*8475e043SDan OpenSolaris Anderson for (i = nlen - 1; (i > 0) && (rr[i] == 0); i--) 1664b60f2a0bSfr41279 ; 16657c478bd9Sstevel@tonic-gate ret->len = i + 1; 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate return (BIG_OK); 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate 1670b60f2a0bSfr41279 1671b60f2a0bSfr41279 BIG_CHUNK_TYPE 1672b60f2a0bSfr41279 big_n0(BIG_CHUNK_TYPE n) 16737c478bd9Sstevel@tonic-gate { 16747c478bd9Sstevel@tonic-gate int i; 1675b60f2a0bSfr41279 BIG_CHUNK_TYPE result, tmp; 16767c478bd9Sstevel@tonic-gate 16777c478bd9Sstevel@tonic-gate result = 0; 1678b60f2a0bSfr41279 tmp = BIG_CHUNK_ALLBITS; 1679b60f2a0bSfr41279 for (i = 0; i < BIG_CHUNK_SIZE; i++) { 16807c478bd9Sstevel@tonic-gate if ((tmp & 1) == 1) { 1681b60f2a0bSfr41279 result = (result >> 1) | BIG_CHUNK_HIGHBIT; 16827c478bd9Sstevel@tonic-gate tmp = tmp - n; 1683b60f2a0bSfr41279 } else { 1684b60f2a0bSfr41279 result = (result >> 1); 1685b60f2a0bSfr41279 } 16867c478bd9Sstevel@tonic-gate tmp = tmp >> 1; 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate return (result); 16907c478bd9Sstevel@tonic-gate } 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate 16937c478bd9Sstevel@tonic-gate int 16947c478bd9Sstevel@tonic-gate big_numbits(BIGNUM *n) 16957c478bd9Sstevel@tonic-gate { 16967c478bd9Sstevel@tonic-gate int i, j; 1697b60f2a0bSfr41279 BIG_CHUNK_TYPE t; 16987c478bd9Sstevel@tonic-gate 1699b60f2a0bSfr41279 for (i = n->len - 1; i > 0; i--) { 1700b60f2a0bSfr41279 if (n->value[i] != 0) { 1701b60f2a0bSfr41279 break; 1702b60f2a0bSfr41279 } 1703b60f2a0bSfr41279 } 17047c478bd9Sstevel@tonic-gate t = n->value[i]; 1705b60f2a0bSfr41279 for (j = BIG_CHUNK_SIZE; j > 0; j--) { 1706b60f2a0bSfr41279 if ((t & BIG_CHUNK_HIGHBIT) == 0) { 17077c478bd9Sstevel@tonic-gate t = t << 1; 1708b60f2a0bSfr41279 } else { 1709b60f2a0bSfr41279 return (BIG_CHUNK_SIZE * i + j); 1710b60f2a0bSfr41279 } 17117c478bd9Sstevel@tonic-gate } 17127c478bd9Sstevel@tonic-gate return (0); 17137c478bd9Sstevel@tonic-gate } 17147c478bd9Sstevel@tonic-gate 1715b60f2a0bSfr41279 17167c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */ 17177c478bd9Sstevel@tonic-gate BIG_ERR_CODE 17187c478bd9Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n) 17197c478bd9Sstevel@tonic-gate { 17207c478bd9Sstevel@tonic-gate BIGNUM rr; 1721b60f2a0bSfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 17227c478bd9Sstevel@tonic-gate int len, i; 17237c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate rr.malloced = 0; 17267c478bd9Sstevel@tonic-gate len = n->len; 17277c478bd9Sstevel@tonic-gate 17287c478bd9Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, 1729b60f2a0bSfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 17307c478bd9Sstevel@tonic-gate return (err); 17317c478bd9Sstevel@tonic-gate } 17327c478bd9Sstevel@tonic-gate 1733b60f2a0bSfr41279 for (i = 0; i < 2 * len; i++) { 1734b60f2a0bSfr41279 rr.value[i] = 0; 1735b60f2a0bSfr41279 } 1736b60f2a0bSfr41279 rr.value[2 * len] = 1; 1737b60f2a0bSfr41279 rr.len = 2 * len + 1; 1738b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 1739b60f2a0bSfr41279 goto ret; 1740b60f2a0bSfr41279 } 1741b60f2a0bSfr41279 err = big_copy(result, &rr); 1742b60f2a0bSfr41279 ret: 1743b60f2a0bSfr41279 big_finish(&rr); 1744b60f2a0bSfr41279 return (err); 1745b60f2a0bSfr41279 } 1746b60f2a0bSfr41279 1747b60f2a0bSfr41279 17487c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */ 17497c478bd9Sstevel@tonic-gate BIG_ERR_CODE 1750b60f2a0bSfr41279 big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, BIG_CHUNK_TYPE n0, 1751b60f2a0bSfr41279 BIGNUM *n_rr) 17527c478bd9Sstevel@tonic-gate { 17537c478bd9Sstevel@tonic-gate BIGNUM rr; 1754b60f2a0bSfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 17557c478bd9Sstevel@tonic-gate int len, i; 17567c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate rr.malloced = 0; 17597c478bd9Sstevel@tonic-gate len = n->len; 17607c478bd9Sstevel@tonic-gate 17617c478bd9Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue))) 1762b60f2a0bSfr41279 != BIG_OK) { 17637c478bd9Sstevel@tonic-gate return (err); 1764b60f2a0bSfr41279 } 17657c478bd9Sstevel@tonic-gate 17667c478bd9Sstevel@tonic-gate if (n_rr == NULL) { 1767b60f2a0bSfr41279 for (i = 0; i < 2 * len; i++) { 1768b60f2a0bSfr41279 rr.value[i] = 0; 1769b60f2a0bSfr41279 } 17707c478bd9Sstevel@tonic-gate rr.value[2 * len] = 1; 17717c478bd9Sstevel@tonic-gate rr.len = 2 * len + 1; 1772b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 17737c478bd9Sstevel@tonic-gate goto ret; 1774b60f2a0bSfr41279 } 17757c478bd9Sstevel@tonic-gate n_rr = &rr; 17767c478bd9Sstevel@tonic-gate } 17777c478bd9Sstevel@tonic-gate 1778b60f2a0bSfr41279 if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK) { 17797c478bd9Sstevel@tonic-gate goto ret; 1780b60f2a0bSfr41279 } 17817c478bd9Sstevel@tonic-gate err = big_copy(result, &rr); 1782b60f2a0bSfr41279 17837c478bd9Sstevel@tonic-gate ret: 1784b60f2a0bSfr41279 big_finish(&rr); 17857c478bd9Sstevel@tonic-gate return (err); 17867c478bd9Sstevel@tonic-gate } 17877c478bd9Sstevel@tonic-gate 17887c478bd9Sstevel@tonic-gate 1789b60f2a0bSfr41279 #ifdef USE_FLOATING_POINT 1790b60f2a0bSfr41279 #define big_modexp_ncp_float big_modexp_ncp_sw 1791b60f2a0bSfr41279 #else 1792b60f2a0bSfr41279 #define big_modexp_ncp_int big_modexp_ncp_sw 1793b60f2a0bSfr41279 #endif 1794b60f2a0bSfr41279 17957c478bd9Sstevel@tonic-gate #define MAX_EXP_BIT_GROUP_SIZE 6 17967c478bd9Sstevel@tonic-gate #define APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1)) 17977c478bd9Sstevel@tonic-gate 1798b60f2a0bSfr41279 /* ARGSUSED */ 17997c478bd9Sstevel@tonic-gate static BIG_ERR_CODE 1800b60f2a0bSfr41279 big_modexp_ncp_int(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 1801b60f2a0bSfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 1802b60f2a0bSfr41279 18037c478bd9Sstevel@tonic-gate { 1804b60f2a0bSfr41279 BIGNUM apowers[APOWERS_MAX_SIZE]; 1805b60f2a0bSfr41279 BIGNUM tmp1; 1806b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 1807b60f2a0bSfr41279 int i, j, k, l, m, p; 1808*8475e043SDan OpenSolaris Anderson uint32_t bit, bitind, bitcount, groupbits, apowerssize; 1809*8475e043SDan OpenSolaris Anderson uint32_t nbits; 18107c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate nbits = big_numbits(e); 18137c478bd9Sstevel@tonic-gate if (nbits < 50) { 18147c478bd9Sstevel@tonic-gate groupbits = 1; 18157c478bd9Sstevel@tonic-gate apowerssize = 1; 18167c478bd9Sstevel@tonic-gate } else { 18177c478bd9Sstevel@tonic-gate groupbits = MAX_EXP_BIT_GROUP_SIZE; 18187c478bd9Sstevel@tonic-gate apowerssize = 1 << (groupbits - 1); 18197c478bd9Sstevel@tonic-gate } 18207c478bd9Sstevel@tonic-gate 1821b60f2a0bSfr41279 1822b60f2a0bSfr41279 if ((err = big_init1(&tmp1, 2 * n->len + 1, 1823b60f2a0bSfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 18247c478bd9Sstevel@tonic-gate return (err); 18257c478bd9Sstevel@tonic-gate } 18267c478bd9Sstevel@tonic-gate 1827*8475e043SDan OpenSolaris Anderson /* clear the malloced bit to help cleanup */ 1828b60f2a0bSfr41279 for (i = 0; i < apowerssize; i++) { 1829b60f2a0bSfr41279 apowers[i].malloced = 0; 1830b60f2a0bSfr41279 } 1831*8475e043SDan OpenSolaris Anderson 1832b60f2a0bSfr41279 for (i = 0; i < apowerssize; i++) { 1833b60f2a0bSfr41279 if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) != 1834b60f2a0bSfr41279 BIG_OK) { 1835b60f2a0bSfr41279 goto ret; 1836b60f2a0bSfr41279 } 1837b60f2a0bSfr41279 } 18387c478bd9Sstevel@tonic-gate 1839b60f2a0bSfr41279 (void) big_copy(&(apowers[0]), ma); 1840b60f2a0bSfr41279 1841b60f2a0bSfr41279 if ((err = big_mont_mul(&tmp1, ma, ma, n, n0)) != BIG_OK) { 1842b60f2a0bSfr41279 goto ret; 1843b60f2a0bSfr41279 } 1844b60f2a0bSfr41279 (void) big_copy(ma, &tmp1); 1845b60f2a0bSfr41279 1846b60f2a0bSfr41279 for (i = 1; i < apowerssize; i++) { 1847b60f2a0bSfr41279 if ((err = big_mont_mul(&tmp1, ma, 1848b60f2a0bSfr41279 &(apowers[i - 1]), n, n0)) != BIG_OK) { 1849b60f2a0bSfr41279 goto ret; 1850b60f2a0bSfr41279 } 1851b60f2a0bSfr41279 (void) big_copy(&apowers[i], &tmp1); 1852b60f2a0bSfr41279 } 1853b60f2a0bSfr41279 1854b60f2a0bSfr41279 bitind = nbits % BIG_CHUNK_SIZE; 1855b60f2a0bSfr41279 k = 0; 1856b60f2a0bSfr41279 l = 0; 1857b60f2a0bSfr41279 p = 0; 1858b60f2a0bSfr41279 bitcount = 0; 1859b60f2a0bSfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 1860b60f2a0bSfr41279 for (j = bitind - 1; j >= 0; j--) { 1861b60f2a0bSfr41279 bit = (e->value[i] >> j) & 1; 1862b60f2a0bSfr41279 if ((bitcount == 0) && (bit == 0)) { 1863b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, 1864b60f2a0bSfr41279 tmp, tmp, n, n0)) != BIG_OK) { 1865b60f2a0bSfr41279 goto ret; 1866b60f2a0bSfr41279 } 18677c478bd9Sstevel@tonic-gate } else { 1868b60f2a0bSfr41279 bitcount++; 1869b60f2a0bSfr41279 p = p * 2 + bit; 1870b60f2a0bSfr41279 if (bit == 1) { 1871b60f2a0bSfr41279 k = k + l + 1; 1872b60f2a0bSfr41279 l = 0; 1873b60f2a0bSfr41279 } else { 1874b60f2a0bSfr41279 l++; 18757c478bd9Sstevel@tonic-gate } 1876b60f2a0bSfr41279 if (bitcount == groupbits) { 1877b60f2a0bSfr41279 for (m = 0; m < k; m++) { 1878b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, 1879b60f2a0bSfr41279 tmp, tmp, n, n0)) != 1880b60f2a0bSfr41279 BIG_OK) { 1881b60f2a0bSfr41279 goto ret; 1882b60f2a0bSfr41279 } 1883b60f2a0bSfr41279 } 1884b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, tmp, 1885b60f2a0bSfr41279 &(apowers[p >> (l + 1)]), 1886b60f2a0bSfr41279 n, n0)) != BIG_OK) { 1887b60f2a0bSfr41279 goto ret; 1888b60f2a0bSfr41279 } 1889b60f2a0bSfr41279 for (m = 0; m < l; m++) { 1890b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, 1891b60f2a0bSfr41279 tmp, tmp, n, n0)) != 1892b60f2a0bSfr41279 BIG_OK) { 1893b60f2a0bSfr41279 goto ret; 1894b60f2a0bSfr41279 } 1895b60f2a0bSfr41279 } 1896b60f2a0bSfr41279 k = 0; 1897b60f2a0bSfr41279 l = 0; 1898b60f2a0bSfr41279 p = 0; 1899b60f2a0bSfr41279 bitcount = 0; 1900b60f2a0bSfr41279 } 1901b60f2a0bSfr41279 } 1902b60f2a0bSfr41279 } 1903b60f2a0bSfr41279 bitind = BIG_CHUNK_SIZE; 1904b60f2a0bSfr41279 } 19057c478bd9Sstevel@tonic-gate 1906b60f2a0bSfr41279 for (m = 0; m < k; m++) { 1907b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, tmp, tmp, n, n0)) != BIG_OK) { 1908b60f2a0bSfr41279 goto ret; 1909b60f2a0bSfr41279 } 1910b60f2a0bSfr41279 } 1911b60f2a0bSfr41279 if (p != 0) { 1912b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, tmp, 1913b60f2a0bSfr41279 &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK) { 1914b60f2a0bSfr41279 goto ret; 1915b60f2a0bSfr41279 } 1916b60f2a0bSfr41279 } 1917b60f2a0bSfr41279 for (m = 0; m < l; m++) { 1918b60f2a0bSfr41279 if ((err = big_mont_mul(result, tmp, tmp, n, n0)) != BIG_OK) { 1919b60f2a0bSfr41279 goto ret; 1920b60f2a0bSfr41279 } 1921b60f2a0bSfr41279 } 19227c478bd9Sstevel@tonic-gate 1923b60f2a0bSfr41279 ret: 1924b60f2a0bSfr41279 for (i = apowerssize - 1; i >= 0; i--) { 1925b60f2a0bSfr41279 big_finish(&(apowers[i])); 1926b60f2a0bSfr41279 } 1927b60f2a0bSfr41279 big_finish(&tmp1); 1928b60f2a0bSfr41279 1929b60f2a0bSfr41279 return (err); 1930b60f2a0bSfr41279 } 1931b60f2a0bSfr41279 1932b60f2a0bSfr41279 1933b60f2a0bSfr41279 #ifdef USE_FLOATING_POINT 1934b60f2a0bSfr41279 1935b60f2a0bSfr41279 #ifdef _KERNEL 1936b60f2a0bSfr41279 1937b60f2a0bSfr41279 #include <sys/sysmacros.h> 1938b60f2a0bSfr41279 #include <sys/regset.h> 1939b60f2a0bSfr41279 #include <sys/fpu/fpusystm.h> 1940b60f2a0bSfr41279 1941b60f2a0bSfr41279 /* the alignment for block stores to save fp registers */ 1942b60f2a0bSfr41279 #define FPR_ALIGN (64) 1943b60f2a0bSfr41279 1944b60f2a0bSfr41279 extern void big_savefp(kfpu_t *); 1945b60f2a0bSfr41279 extern void big_restorefp(kfpu_t *); 1946b60f2a0bSfr41279 1947b60f2a0bSfr41279 #endif /* _KERNEL */ 1948b60f2a0bSfr41279 1949b60f2a0bSfr41279 /* 1950b60f2a0bSfr41279 * This version makes use of floating point for performance 1951b60f2a0bSfr41279 */ 1952b60f2a0bSfr41279 static BIG_ERR_CODE 1953b60f2a0bSfr41279 big_modexp_ncp_float(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 1954b60f2a0bSfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 1955b60f2a0bSfr41279 { 1956b60f2a0bSfr41279 1957*8475e043SDan OpenSolaris Anderson int i, j, k, l, m, p; 1958*8475e043SDan OpenSolaris Anderson uint32_t bit, bitind, bitcount, nlen; 1959b60f2a0bSfr41279 double dn0; 1960b60f2a0bSfr41279 double *dn, *dt, *d16r, *d32r; 1961b60f2a0bSfr41279 uint32_t *nint, *prod; 1962b60f2a0bSfr41279 double *apowers[APOWERS_MAX_SIZE]; 1963*8475e043SDan OpenSolaris Anderson uint32_t nbits, groupbits, apowerssize; 1964b60f2a0bSfr41279 BIG_ERR_CODE err = BIG_OK; 1965b60f2a0bSfr41279 1966b60f2a0bSfr41279 #ifdef _KERNEL 1967b60f2a0bSfr41279 uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN]; 1968b60f2a0bSfr41279 kfpu_t *fpu; 1969b60f2a0bSfr41279 1970b60f2a0bSfr41279 #ifdef DEBUG 1971b60f2a0bSfr41279 if (!fpu_exists) 1972b60f2a0bSfr41279 return (BIG_GENERAL_ERR); 1973b60f2a0bSfr41279 #endif 1974b60f2a0bSfr41279 1975b60f2a0bSfr41279 fpu = (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN); 1976b60f2a0bSfr41279 big_savefp(fpu); 1977b60f2a0bSfr41279 1978b60f2a0bSfr41279 #endif /* _KERNEL */ 1979b60f2a0bSfr41279 1980b60f2a0bSfr41279 nbits = big_numbits(e); 1981b60f2a0bSfr41279 if (nbits < 50) { 1982b60f2a0bSfr41279 groupbits = 1; 1983b60f2a0bSfr41279 apowerssize = 1; 1984b60f2a0bSfr41279 } else { 1985b60f2a0bSfr41279 groupbits = MAX_EXP_BIT_GROUP_SIZE; 1986b60f2a0bSfr41279 apowerssize = 1 << (groupbits - 1); 1987b60f2a0bSfr41279 } 1988b60f2a0bSfr41279 1989b60f2a0bSfr41279 nlen = (BIG_CHUNK_SIZE / 32) * n->len; 19907c478bd9Sstevel@tonic-gate dn0 = (double)(n0 & 0xffff); 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate dn = dt = d16r = d32r = NULL; 19937c478bd9Sstevel@tonic-gate nint = prod = NULL; 19947c478bd9Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 19957c478bd9Sstevel@tonic-gate apowers[i] = NULL; 19967c478bd9Sstevel@tonic-gate } 19977c478bd9Sstevel@tonic-gate 19987c478bd9Sstevel@tonic-gate if ((dn = big_malloc(nlen * sizeof (double))) == NULL) { 19997c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 20007c478bd9Sstevel@tonic-gate goto ret; 20017c478bd9Sstevel@tonic-gate } 20027c478bd9Sstevel@tonic-gate if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) { 20037c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 20047c478bd9Sstevel@tonic-gate goto ret; 20057c478bd9Sstevel@tonic-gate } 20067c478bd9Sstevel@tonic-gate if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) { 20077c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 20087c478bd9Sstevel@tonic-gate goto ret; 20097c478bd9Sstevel@tonic-gate } 20107c478bd9Sstevel@tonic-gate if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) { 20117c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 20127c478bd9Sstevel@tonic-gate goto ret; 20137c478bd9Sstevel@tonic-gate } 20147c478bd9Sstevel@tonic-gate if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) { 20157c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 20167c478bd9Sstevel@tonic-gate goto ret; 20177c478bd9Sstevel@tonic-gate } 20187c478bd9Sstevel@tonic-gate if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) { 20197c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 20207c478bd9Sstevel@tonic-gate goto ret; 20217c478bd9Sstevel@tonic-gate } 20227c478bd9Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 20237c478bd9Sstevel@tonic-gate if ((apowers[i] = big_malloc((2 * nlen + 1) * 20247c478bd9Sstevel@tonic-gate sizeof (double))) == NULL) { 20257c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 20267c478bd9Sstevel@tonic-gate goto ret; 20277c478bd9Sstevel@tonic-gate } 20287c478bd9Sstevel@tonic-gate } 20297c478bd9Sstevel@tonic-gate 2030b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 2031b60f2a0bSfr41279 for (i = 0; i < ma->len; i++) { 2032b60f2a0bSfr41279 nint[i] = ma->value[i]; 2033b60f2a0bSfr41279 } 2034b60f2a0bSfr41279 for (; i < nlen; i++) { 2035b60f2a0bSfr41279 nint[i] = 0; 2036b60f2a0bSfr41279 } 2037b60f2a0bSfr41279 #else 2038b60f2a0bSfr41279 for (i = 0; i < ma->len; i++) { 2039b60f2a0bSfr41279 nint[2 * i] = (uint32_t)(ma->value[i] & 0xffffffffULL); 2040b60f2a0bSfr41279 nint[2 * i + 1] = (uint32_t)(ma->value[i] >> 32); 2041b60f2a0bSfr41279 } 2042b60f2a0bSfr41279 for (i = ma->len * 2; i < nlen; i++) { 2043b60f2a0bSfr41279 nint[i] = 0; 2044b60f2a0bSfr41279 } 2045b60f2a0bSfr41279 #endif 20467c478bd9Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen); 20477c478bd9Sstevel@tonic-gate 2048b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 2049b60f2a0bSfr41279 for (i = 0; i < n->len; i++) { 2050b60f2a0bSfr41279 nint[i] = n->value[i]; 2051b60f2a0bSfr41279 } 2052b60f2a0bSfr41279 for (; i < nlen; i++) { 2053b60f2a0bSfr41279 nint[i] = 0; 2054b60f2a0bSfr41279 } 2055b60f2a0bSfr41279 #else 2056b60f2a0bSfr41279 for (i = 0; i < n->len; i++) { 2057b60f2a0bSfr41279 nint[2 * i] = (uint32_t)(n->value[i] & 0xffffffffULL); 2058b60f2a0bSfr41279 nint[2 * i + 1] = (uint32_t)(n->value[i] >> 32); 2059b60f2a0bSfr41279 } 2060b60f2a0bSfr41279 for (i = n->len * 2; i < nlen; i++) { 2061b60f2a0bSfr41279 nint[i] = 0; 2062b60f2a0bSfr41279 } 2063b60f2a0bSfr41279 #endif 20647c478bd9Sstevel@tonic-gate conv_i32_to_d32(dn, nint, nlen); 20657c478bd9Sstevel@tonic-gate 20667c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0); 20677c478bd9Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 20687c478bd9Sstevel@tonic-gate for (i = 1; i < apowerssize; i++) { 20697c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[i - 1], 20707c478bd9Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 20717c478bd9Sstevel@tonic-gate conv_i32_to_d16(apowers[i], prod, nlen); 20727c478bd9Sstevel@tonic-gate } 20737c478bd9Sstevel@tonic-gate 2074b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 2075b60f2a0bSfr41279 for (i = 0; i < tmp->len; i++) { 2076b60f2a0bSfr41279 prod[i] = tmp->value[i]; 2077b60f2a0bSfr41279 } 2078b60f2a0bSfr41279 for (; i < nlen + 1; i++) { 2079b60f2a0bSfr41279 prod[i] = 0; 2080b60f2a0bSfr41279 } 2081b60f2a0bSfr41279 #else 2082b60f2a0bSfr41279 for (i = 0; i < tmp->len; i++) { 2083b60f2a0bSfr41279 prod[2 * i] = (uint32_t)(tmp->value[i] & 0xffffffffULL); 2084b60f2a0bSfr41279 prod[2 * i + 1] = (uint32_t)(tmp->value[i] >> 32); 2085b60f2a0bSfr41279 } 2086b60f2a0bSfr41279 for (i = tmp->len * 2; i < nlen + 1; i++) { 2087b60f2a0bSfr41279 prod[i] = 0; 2088b60f2a0bSfr41279 } 2089b60f2a0bSfr41279 #endif 20907c478bd9Sstevel@tonic-gate 2091b60f2a0bSfr41279 bitind = nbits % BIG_CHUNK_SIZE; 20927c478bd9Sstevel@tonic-gate k = 0; 20937c478bd9Sstevel@tonic-gate l = 0; 20947c478bd9Sstevel@tonic-gate p = 0; 20957c478bd9Sstevel@tonic-gate bitcount = 0; 2096b60f2a0bSfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 20977c478bd9Sstevel@tonic-gate for (j = bitind - 1; j >= 0; j--) { 20987c478bd9Sstevel@tonic-gate bit = (e->value[i] >> j) & 1; 20997c478bd9Sstevel@tonic-gate if ((bitcount == 0) && (bit == 0)) { 21007c478bd9Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, 21017c478bd9Sstevel@tonic-gate prod, nlen); 21027c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, 21037c478bd9Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21047c478bd9Sstevel@tonic-gate } else { 21057c478bd9Sstevel@tonic-gate bitcount++; 21067c478bd9Sstevel@tonic-gate p = p * 2 + bit; 21077c478bd9Sstevel@tonic-gate if (bit == 1) { 21087c478bd9Sstevel@tonic-gate k = k + l + 1; 21097c478bd9Sstevel@tonic-gate l = 0; 21107c478bd9Sstevel@tonic-gate } else { 21117c478bd9Sstevel@tonic-gate l++; 21127c478bd9Sstevel@tonic-gate } 21137c478bd9Sstevel@tonic-gate if (bitcount == groupbits) { 21147c478bd9Sstevel@tonic-gate for (m = 0; m < k; m++) { 2115b60f2a0bSfr41279 conv_i32_to_d32_and_d16(d32r, 2116b60f2a0bSfr41279 d16r, prod, nlen); 21177c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 21187c478bd9Sstevel@tonic-gate d16r, dt, dn, nint, 21197c478bd9Sstevel@tonic-gate nlen, dn0); 21207c478bd9Sstevel@tonic-gate } 21217c478bd9Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 21227c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 21237c478bd9Sstevel@tonic-gate apowers[p >> (l + 1)], 21247c478bd9Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21257c478bd9Sstevel@tonic-gate for (m = 0; m < l; m++) { 2126b60f2a0bSfr41279 conv_i32_to_d32_and_d16(d32r, 2127b60f2a0bSfr41279 d16r, prod, nlen); 21287c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 21297c478bd9Sstevel@tonic-gate d16r, dt, dn, nint, 21307c478bd9Sstevel@tonic-gate nlen, dn0); 21317c478bd9Sstevel@tonic-gate } 21327c478bd9Sstevel@tonic-gate k = 0; 21337c478bd9Sstevel@tonic-gate l = 0; 21347c478bd9Sstevel@tonic-gate p = 0; 21357c478bd9Sstevel@tonic-gate bitcount = 0; 21367c478bd9Sstevel@tonic-gate } 21377c478bd9Sstevel@tonic-gate } 21387c478bd9Sstevel@tonic-gate } 2139b60f2a0bSfr41279 bitind = BIG_CHUNK_SIZE; 21407c478bd9Sstevel@tonic-gate } 21417c478bd9Sstevel@tonic-gate 21427c478bd9Sstevel@tonic-gate for (m = 0; m < k; m++) { 21437c478bd9Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 21447c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 21457c478bd9Sstevel@tonic-gate } 21467c478bd9Sstevel@tonic-gate if (p != 0) { 21477c478bd9Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 21487c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)], 21497c478bd9Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21507c478bd9Sstevel@tonic-gate } 21517c478bd9Sstevel@tonic-gate for (m = 0; m < l; m++) { 21527c478bd9Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 21537c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 21547c478bd9Sstevel@tonic-gate } 21557c478bd9Sstevel@tonic-gate 2156b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 2157b60f2a0bSfr41279 for (i = 0; i < nlen; i++) { 2158b60f2a0bSfr41279 result->value[i] = prod[i]; 2159b60f2a0bSfr41279 } 2160b60f2a0bSfr41279 for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--) 2161b60f2a0bSfr41279 ; 2162b60f2a0bSfr41279 #else 2163b60f2a0bSfr41279 for (i = 0; i < nlen / 2; i++) { 2164b60f2a0bSfr41279 result->value[i] = (uint64_t)(prod[2 * i]) + 2165b60f2a0bSfr41279 (((uint64_t)(prod[2 * i + 1])) << 32); 2166b60f2a0bSfr41279 } 2167b60f2a0bSfr41279 for (i = nlen / 2 - 1; (i > 0) && (result->value[i] == 0); i--) 2168b60f2a0bSfr41279 ; 2169b60f2a0bSfr41279 #endif 2170b60f2a0bSfr41279 result->len = i + 1; 2171b60f2a0bSfr41279 21727c478bd9Sstevel@tonic-gate ret: 21737c478bd9Sstevel@tonic-gate for (i = apowerssize - 1; i >= 0; i--) { 21747c478bd9Sstevel@tonic-gate if (apowers[i] != NULL) 21757c478bd9Sstevel@tonic-gate big_free(apowers[i], (2 * nlen + 1) * sizeof (double)); 21767c478bd9Sstevel@tonic-gate } 2177b60f2a0bSfr41279 if (d32r != NULL) { 21787c478bd9Sstevel@tonic-gate big_free(d32r, nlen * sizeof (double)); 2179b60f2a0bSfr41279 } 2180b60f2a0bSfr41279 if (d16r != NULL) { 21817c478bd9Sstevel@tonic-gate big_free(d16r, (2 * nlen + 1) * sizeof (double)); 2182b60f2a0bSfr41279 } 2183b60f2a0bSfr41279 if (prod != NULL) { 21847c478bd9Sstevel@tonic-gate big_free(prod, (nlen + 1) * sizeof (uint32_t)); 2185b60f2a0bSfr41279 } 2186b60f2a0bSfr41279 if (nint != NULL) { 21877c478bd9Sstevel@tonic-gate big_free(nint, nlen * sizeof (uint32_t)); 2188b60f2a0bSfr41279 } 2189b60f2a0bSfr41279 if (dt != NULL) { 21907c478bd9Sstevel@tonic-gate big_free(dt, (4 * nlen + 2) * sizeof (double)); 2191b60f2a0bSfr41279 } 2192b60f2a0bSfr41279 if (dn != NULL) { 21937c478bd9Sstevel@tonic-gate big_free(dn, nlen * sizeof (double)); 21947c478bd9Sstevel@tonic-gate } 21957c478bd9Sstevel@tonic-gate 21967c478bd9Sstevel@tonic-gate #ifdef _KERNEL 2197b60f2a0bSfr41279 big_restorefp(fpu); 21987c478bd9Sstevel@tonic-gate #endif 21997c478bd9Sstevel@tonic-gate 22007c478bd9Sstevel@tonic-gate return (err); 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate 22037c478bd9Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */ 22047c478bd9Sstevel@tonic-gate 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate BIG_ERR_CODE 2207b60f2a0bSfr41279 big_modexp_ext(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr, 2208b60f2a0bSfr41279 big_modexp_ncp_info_t *info) 2209b60f2a0bSfr41279 { 2210b60f2a0bSfr41279 BIGNUM ma, tmp, rr; 2211b60f2a0bSfr41279 BIG_CHUNK_TYPE mavalue[BIGTMPSIZE]; 2212b60f2a0bSfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 2213b60f2a0bSfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 2214b60f2a0bSfr41279 BIG_ERR_CODE err; 2215b60f2a0bSfr41279 BIG_CHUNK_TYPE n0; 2216b60f2a0bSfr41279 2217b60f2a0bSfr41279 if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue))) != 2218b60f2a0bSfr41279 BIG_OK) { 2219b60f2a0bSfr41279 return (err); 2220b60f2a0bSfr41279 } 2221b60f2a0bSfr41279 ma.len = 1; 2222b60f2a0bSfr41279 ma.value[0] = 0; 2223b60f2a0bSfr41279 2224b60f2a0bSfr41279 if ((err = big_init1(&tmp, 2 * n->len + 1, 2225b60f2a0bSfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 2226b60f2a0bSfr41279 goto ret1; 2227b60f2a0bSfr41279 } 2228b60f2a0bSfr41279 2229*8475e043SDan OpenSolaris Anderson /* clear the malloced bit to help cleanup */ 2230b60f2a0bSfr41279 rr.malloced = 0; 2231*8475e043SDan OpenSolaris Anderson 2232b60f2a0bSfr41279 if (n_rr == NULL) { 2233b60f2a0bSfr41279 if ((err = big_init1(&rr, 2 * n->len + 1, 2234b60f2a0bSfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 2235b60f2a0bSfr41279 goto ret2; 2236b60f2a0bSfr41279 } 2237b60f2a0bSfr41279 if (big_mont_rr(&rr, n) != BIG_OK) { 2238b60f2a0bSfr41279 goto ret; 2239b60f2a0bSfr41279 } 2240b60f2a0bSfr41279 n_rr = &rr; 2241b60f2a0bSfr41279 } 2242b60f2a0bSfr41279 2243b60f2a0bSfr41279 n0 = big_n0(n->value[0]); 2244b60f2a0bSfr41279 2245b60f2a0bSfr41279 if (big_cmp_abs(a, n) > 0) { 2246b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK) { 2247b60f2a0bSfr41279 goto ret; 2248b60f2a0bSfr41279 } 2249b60f2a0bSfr41279 err = big_mont_conv(&ma, &ma, n, n0, n_rr); 2250b60f2a0bSfr41279 } else { 2251b60f2a0bSfr41279 err = big_mont_conv(&ma, a, n, n0, n_rr); 2252b60f2a0bSfr41279 } 2253b60f2a0bSfr41279 if (err != BIG_OK) { 2254b60f2a0bSfr41279 goto ret; 2255b60f2a0bSfr41279 } 2256b60f2a0bSfr41279 2257b60f2a0bSfr41279 tmp.len = 1; 2258b60f2a0bSfr41279 tmp.value[0] = 1; 2259b60f2a0bSfr41279 if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK) { 2260b60f2a0bSfr41279 goto ret; 2261b60f2a0bSfr41279 } 2262b60f2a0bSfr41279 2263b60f2a0bSfr41279 if ((info != NULL) && (info->func != NULL)) { 2264b60f2a0bSfr41279 err = (*(info->func))(&tmp, &ma, e, n, &tmp, n0, 2265b60f2a0bSfr41279 info->ncp, info->reqp); 2266b60f2a0bSfr41279 } else { 2267b60f2a0bSfr41279 err = big_modexp_ncp_sw(&tmp, &ma, e, n, &tmp, n0); 2268b60f2a0bSfr41279 } 2269b60f2a0bSfr41279 if (err != BIG_OK) { 2270b60f2a0bSfr41279 goto ret; 2271b60f2a0bSfr41279 } 2272b60f2a0bSfr41279 2273b60f2a0bSfr41279 ma.value[0] = 1; 2274b60f2a0bSfr41279 ma.len = 1; 2275b60f2a0bSfr41279 if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK) { 2276b60f2a0bSfr41279 goto ret; 2277b60f2a0bSfr41279 } 2278b60f2a0bSfr41279 err = big_copy(result, &tmp); 2279b60f2a0bSfr41279 2280b60f2a0bSfr41279 ret: 2281b60f2a0bSfr41279 if (rr.malloced) { 2282b60f2a0bSfr41279 big_finish(&rr); 2283b60f2a0bSfr41279 } 2284b60f2a0bSfr41279 ret2: 2285b60f2a0bSfr41279 big_finish(&tmp); 2286b60f2a0bSfr41279 ret1: 2287b60f2a0bSfr41279 big_finish(&ma); 2288b60f2a0bSfr41279 2289b60f2a0bSfr41279 return (err); 2290b60f2a0bSfr41279 } 2291b60f2a0bSfr41279 2292b60f2a0bSfr41279 BIG_ERR_CODE 2293b60f2a0bSfr41279 big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr) 2294b60f2a0bSfr41279 { 2295b60f2a0bSfr41279 return (big_modexp_ext(result, a, e, n, n_rr, NULL)); 2296b60f2a0bSfr41279 } 2297b60f2a0bSfr41279 2298b60f2a0bSfr41279 2299b60f2a0bSfr41279 BIG_ERR_CODE 2300b60f2a0bSfr41279 big_modexp_crt_ext(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 23017c478bd9Sstevel@tonic-gate BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 2302b60f2a0bSfr41279 BIGNUM *p_rr, BIGNUM *q_rr, big_modexp_ncp_info_t *info) 23037c478bd9Sstevel@tonic-gate { 23047c478bd9Sstevel@tonic-gate BIGNUM ap, aq, tmp; 23057c478bd9Sstevel@tonic-gate int alen, biglen, sign; 23067c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 23077c478bd9Sstevel@tonic-gate 2308b60f2a0bSfr41279 if (p->len > q->len) { 2309b60f2a0bSfr41279 biglen = p->len; 2310b60f2a0bSfr41279 } else { 2311b60f2a0bSfr41279 biglen = q->len; 2312b60f2a0bSfr41279 } 23137c478bd9Sstevel@tonic-gate 2314b60f2a0bSfr41279 if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK) { 23157c478bd9Sstevel@tonic-gate return (err); 2316b60f2a0bSfr41279 } 2317b60f2a0bSfr41279 if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK) { 23187c478bd9Sstevel@tonic-gate goto ret1; 2319b60f2a0bSfr41279 } 2320b60f2a0bSfr41279 if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK) { 23217c478bd9Sstevel@tonic-gate goto ret2; 2322b60f2a0bSfr41279 } 23237c478bd9Sstevel@tonic-gate 23247c478bd9Sstevel@tonic-gate /* 23257c478bd9Sstevel@tonic-gate * check whether a is too short - to avoid timing attacks 23267c478bd9Sstevel@tonic-gate */ 23277c478bd9Sstevel@tonic-gate alen = a->len; 23287c478bd9Sstevel@tonic-gate while ((alen > p->len) && (a->value[alen - 1] == 0)) { 23297c478bd9Sstevel@tonic-gate alen--; 23307c478bd9Sstevel@tonic-gate } 23317c478bd9Sstevel@tonic-gate if (alen < p->len + q->len) { 23327c478bd9Sstevel@tonic-gate /* 23337c478bd9Sstevel@tonic-gate * a is too short, add p*q to it before 23347c478bd9Sstevel@tonic-gate * taking it modulo p and q 23357c478bd9Sstevel@tonic-gate * this will also affect timing, but this difference 23367c478bd9Sstevel@tonic-gate * does not depend on p or q, only on a 23377c478bd9Sstevel@tonic-gate * (in "normal" operation, this path will never be 23387c478bd9Sstevel@tonic-gate * taken, so it is not a performance penalty 23397c478bd9Sstevel@tonic-gate */ 2340b60f2a0bSfr41279 if ((err = big_mul(&tmp, p, q)) != BIG_OK) { 23417c478bd9Sstevel@tonic-gate goto ret; 23427c478bd9Sstevel@tonic-gate } 2343b60f2a0bSfr41279 if ((err = big_add(&tmp, &tmp, a)) != BIG_OK) { 2344b60f2a0bSfr41279 goto ret; 2345b60f2a0bSfr41279 } 2346b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK) { 2347b60f2a0bSfr41279 goto ret; 2348b60f2a0bSfr41279 } 2349b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 2350b60f2a0bSfr41279 goto ret; 2351b60f2a0bSfr41279 } 2352b60f2a0bSfr41279 } else { 2353b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK) { 2354b60f2a0bSfr41279 goto ret; 2355b60f2a0bSfr41279 } 2356b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK) { 2357b60f2a0bSfr41279 goto ret; 2358b60f2a0bSfr41279 } 2359b60f2a0bSfr41279 } 23607c478bd9Sstevel@tonic-gate 2361b60f2a0bSfr41279 if ((err = big_modexp_ext(&ap, &ap, dmodpminus1, p, p_rr, info)) != 2362b60f2a0bSfr41279 BIG_OK) { 23637c478bd9Sstevel@tonic-gate goto ret; 2364b60f2a0bSfr41279 } 2365b60f2a0bSfr41279 if ((err = big_modexp_ext(&aq, &aq, dmodqminus1, q, q_rr, info)) != 2366b60f2a0bSfr41279 BIG_OK) { 23677c478bd9Sstevel@tonic-gate goto ret; 2368b60f2a0bSfr41279 } 2369b60f2a0bSfr41279 if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK) { 23707c478bd9Sstevel@tonic-gate goto ret; 2371b60f2a0bSfr41279 } 2372b60f2a0bSfr41279 if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK) { 23737c478bd9Sstevel@tonic-gate goto ret; 2374b60f2a0bSfr41279 } 23757c478bd9Sstevel@tonic-gate sign = tmp.sign; 23767c478bd9Sstevel@tonic-gate tmp.sign = 1; 2377b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 23787c478bd9Sstevel@tonic-gate goto ret; 2379b60f2a0bSfr41279 } 23807c478bd9Sstevel@tonic-gate if ((sign == -1) && (!big_is_zero(&aq))) { 23817c478bd9Sstevel@tonic-gate (void) big_sub_pos(&aq, q, &aq); 23827c478bd9Sstevel@tonic-gate } 2383b60f2a0bSfr41279 if ((err = big_mul(&tmp, &aq, p)) != BIG_OK) { 23847c478bd9Sstevel@tonic-gate goto ret; 2385b60f2a0bSfr41279 } 23867c478bd9Sstevel@tonic-gate err = big_add_abs(result, &ap, &tmp); 23877c478bd9Sstevel@tonic-gate 23887c478bd9Sstevel@tonic-gate ret: 23897c478bd9Sstevel@tonic-gate big_finish(&tmp); 23907c478bd9Sstevel@tonic-gate ret2: 23917c478bd9Sstevel@tonic-gate big_finish(&aq); 23927c478bd9Sstevel@tonic-gate ret1: 23937c478bd9Sstevel@tonic-gate big_finish(&ap); 23947c478bd9Sstevel@tonic-gate 23957c478bd9Sstevel@tonic-gate return (err); 23967c478bd9Sstevel@tonic-gate } 23977c478bd9Sstevel@tonic-gate 23987c478bd9Sstevel@tonic-gate 2399b60f2a0bSfr41279 BIG_ERR_CODE 2400b60f2a0bSfr41279 big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 2401b60f2a0bSfr41279 BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 2402b60f2a0bSfr41279 BIGNUM *p_rr, BIGNUM *q_rr) 2403b60f2a0bSfr41279 { 2404b60f2a0bSfr41279 return (big_modexp_crt_ext(result, a, dmodpminus1, dmodqminus1, 2405b60f2a0bSfr41279 p, q, pinvmodq, p_rr, q_rr, NULL)); 2406b60f2a0bSfr41279 } 24077c478bd9Sstevel@tonic-gate 24087c478bd9Sstevel@tonic-gate 2409b60f2a0bSfr41279 static BIG_CHUNK_TYPE onearr[1] = {(BIG_CHUNK_TYPE)1}; 2410b60f2a0bSfr41279 BIGNUM big_One = {1, 1, 1, 0, onearr}; 2411b60f2a0bSfr41279 2412b60f2a0bSfr41279 static BIG_CHUNK_TYPE twoarr[1] = {(BIG_CHUNK_TYPE)2}; 2413b60f2a0bSfr41279 BIGNUM big_Two = {1, 1, 1, 0, twoarr}; 2414b60f2a0bSfr41279 2415b60f2a0bSfr41279 static BIG_CHUNK_TYPE fourarr[1] = {(BIG_CHUNK_TYPE)4}; 2416b60f2a0bSfr41279 static BIGNUM big_Four = {1, 1, 1, 0, fourarr}; 2417b60f2a0bSfr41279 24187c478bd9Sstevel@tonic-gate 24197c478bd9Sstevel@tonic-gate BIG_ERR_CODE 24207c478bd9Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n) 24217c478bd9Sstevel@tonic-gate { 24227c478bd9Sstevel@tonic-gate BIGNUM *high, *low, *mid, *t; 24237c478bd9Sstevel@tonic-gate BIGNUM t1, t2, t3, prod; 2424b60f2a0bSfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 2425b60f2a0bSfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 2426b60f2a0bSfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 2427b60f2a0bSfr41279 BIG_CHUNK_TYPE prodvalue[BIGTMPSIZE]; 2428*8475e043SDan OpenSolaris Anderson int i, diff; 2429*8475e043SDan OpenSolaris Anderson uint32_t nbits, nrootbits, highbits; 24307c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 24317c478bd9Sstevel@tonic-gate 24327c478bd9Sstevel@tonic-gate nbits = big_numbits(n); 24337c478bd9Sstevel@tonic-gate 24347c478bd9Sstevel@tonic-gate if ((err = big_init1(&t1, n->len + 1, 24357c478bd9Sstevel@tonic-gate t1value, arraysize(t1value))) != BIG_OK) 24367c478bd9Sstevel@tonic-gate return (err); 24377c478bd9Sstevel@tonic-gate if ((err = big_init1(&t2, n->len + 1, 24387c478bd9Sstevel@tonic-gate t2value, arraysize(t2value))) != BIG_OK) 24397c478bd9Sstevel@tonic-gate goto ret1; 24407c478bd9Sstevel@tonic-gate if ((err = big_init1(&t3, n->len + 1, 24417c478bd9Sstevel@tonic-gate t3value, arraysize(t3value))) != BIG_OK) 24427c478bd9Sstevel@tonic-gate goto ret2; 24437c478bd9Sstevel@tonic-gate if ((err = big_init1(&prod, n->len + 1, 24447c478bd9Sstevel@tonic-gate prodvalue, arraysize(prodvalue))) != BIG_OK) 24457c478bd9Sstevel@tonic-gate goto ret3; 24467c478bd9Sstevel@tonic-gate 24477c478bd9Sstevel@tonic-gate nrootbits = (nbits + 1) / 2; 2448b60f2a0bSfr41279 t1.len = t2.len = t3.len = (nrootbits - 1) / BIG_CHUNK_SIZE + 1; 24497c478bd9Sstevel@tonic-gate for (i = 0; i < t1.len; i++) { 24507c478bd9Sstevel@tonic-gate t1.value[i] = 0; 2451b60f2a0bSfr41279 t2.value[i] = BIG_CHUNK_ALLBITS; 24527c478bd9Sstevel@tonic-gate } 2453b60f2a0bSfr41279 highbits = nrootbits - BIG_CHUNK_SIZE * (t1.len - 1); 2454b60f2a0bSfr41279 if (highbits == BIG_CHUNK_SIZE) { 2455b60f2a0bSfr41279 t1.value[t1.len - 1] = BIG_CHUNK_HIGHBIT; 2456b60f2a0bSfr41279 t2.value[t2.len - 1] = BIG_CHUNK_ALLBITS; 24577c478bd9Sstevel@tonic-gate } else { 2458b60f2a0bSfr41279 t1.value[t1.len - 1] = (BIG_CHUNK_TYPE)1 << (highbits - 1); 24597c478bd9Sstevel@tonic-gate t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1; 24607c478bd9Sstevel@tonic-gate } 2461b60f2a0bSfr41279 24627c478bd9Sstevel@tonic-gate high = &t2; 24637c478bd9Sstevel@tonic-gate low = &t1; 24647c478bd9Sstevel@tonic-gate mid = &t3; 24657c478bd9Sstevel@tonic-gate 2466b60f2a0bSfr41279 if ((err = big_mul(&prod, high, high)) != BIG_OK) { 24677c478bd9Sstevel@tonic-gate goto ret; 2468b60f2a0bSfr41279 } 24697c478bd9Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 24707c478bd9Sstevel@tonic-gate if (diff <= 0) { 24717c478bd9Sstevel@tonic-gate err = big_copy(result, high); 24727c478bd9Sstevel@tonic-gate goto ret; 24737c478bd9Sstevel@tonic-gate } 24747c478bd9Sstevel@tonic-gate 24757c478bd9Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 2476b60f2a0bSfr41279 while (big_cmp_abs(&big_One, mid) != 0) { 24777c478bd9Sstevel@tonic-gate (void) big_add_abs(mid, high, low); 24787c478bd9Sstevel@tonic-gate (void) big_half_pos(mid, mid); 24797c478bd9Sstevel@tonic-gate if ((err = big_mul(&prod, mid, mid)) != BIG_OK) 24807c478bd9Sstevel@tonic-gate goto ret; 24817c478bd9Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 24827c478bd9Sstevel@tonic-gate if (diff > 0) { 24837c478bd9Sstevel@tonic-gate t = high; 24847c478bd9Sstevel@tonic-gate high = mid; 24857c478bd9Sstevel@tonic-gate mid = t; 24867c478bd9Sstevel@tonic-gate } else if (diff < 0) { 24877c478bd9Sstevel@tonic-gate t = low; 24887c478bd9Sstevel@tonic-gate low = mid; 24897c478bd9Sstevel@tonic-gate mid = t; 24907c478bd9Sstevel@tonic-gate } else { 24917c478bd9Sstevel@tonic-gate err = big_copy(result, low); 24927c478bd9Sstevel@tonic-gate goto ret; 24937c478bd9Sstevel@tonic-gate } 24947c478bd9Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 24957c478bd9Sstevel@tonic-gate } 24967c478bd9Sstevel@tonic-gate 24977c478bd9Sstevel@tonic-gate err = big_copy(result, low); 24987c478bd9Sstevel@tonic-gate ret: 24997c478bd9Sstevel@tonic-gate if (prod.malloced) big_finish(&prod); 25007c478bd9Sstevel@tonic-gate ret3: 25017c478bd9Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 25027c478bd9Sstevel@tonic-gate ret2: 25037c478bd9Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 25047c478bd9Sstevel@tonic-gate ret1: 25057c478bd9Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 25067c478bd9Sstevel@tonic-gate 25077c478bd9Sstevel@tonic-gate return (err); 25087c478bd9Sstevel@tonic-gate } 25097c478bd9Sstevel@tonic-gate 25107c478bd9Sstevel@tonic-gate 25117c478bd9Sstevel@tonic-gate BIG_ERR_CODE 25127c478bd9Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm) 25137c478bd9Sstevel@tonic-gate { 25147c478bd9Sstevel@tonic-gate BIGNUM *t, *tmp2, *m, *n; 25157c478bd9Sstevel@tonic-gate BIGNUM t1, t2, t3; 2516b60f2a0bSfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 2517b60f2a0bSfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 2518b60f2a0bSfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 25197c478bd9Sstevel@tonic-gate int len, err; 25207c478bd9Sstevel@tonic-gate 25217c478bd9Sstevel@tonic-gate if (big_is_zero(nn) || 25227c478bd9Sstevel@tonic-gate (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) { 25237c478bd9Sstevel@tonic-gate *jac = 0; 25247c478bd9Sstevel@tonic-gate return (BIG_OK); 25257c478bd9Sstevel@tonic-gate } 25267c478bd9Sstevel@tonic-gate 2527b60f2a0bSfr41279 if (nn->len > mm->len) { 2528b60f2a0bSfr41279 len = nn->len; 2529b60f2a0bSfr41279 } else { 2530b60f2a0bSfr41279 len = mm->len; 2531b60f2a0bSfr41279 } 25327c478bd9Sstevel@tonic-gate 25337c478bd9Sstevel@tonic-gate if ((err = big_init1(&t1, len, 2534b60f2a0bSfr41279 t1value, arraysize(t1value))) != BIG_OK) { 25357c478bd9Sstevel@tonic-gate return (err); 2536b60f2a0bSfr41279 } 25377c478bd9Sstevel@tonic-gate if ((err = big_init1(&t2, len, 2538b60f2a0bSfr41279 t2value, arraysize(t2value))) != BIG_OK) { 25397c478bd9Sstevel@tonic-gate goto ret1; 2540b60f2a0bSfr41279 } 25417c478bd9Sstevel@tonic-gate if ((err = big_init1(&t3, len, 2542b60f2a0bSfr41279 t3value, arraysize(t3value))) != BIG_OK) { 25437c478bd9Sstevel@tonic-gate goto ret2; 2544b60f2a0bSfr41279 } 25457c478bd9Sstevel@tonic-gate 25467c478bd9Sstevel@tonic-gate n = &t1; 25477c478bd9Sstevel@tonic-gate m = &t2; 25487c478bd9Sstevel@tonic-gate tmp2 = &t3; 25497c478bd9Sstevel@tonic-gate 25507c478bd9Sstevel@tonic-gate (void) big_copy(n, nn); 25517c478bd9Sstevel@tonic-gate (void) big_copy(m, mm); 25527c478bd9Sstevel@tonic-gate 25537c478bd9Sstevel@tonic-gate *jac = 1; 2554b60f2a0bSfr41279 while (big_cmp_abs(&big_One, m) != 0) { 25557c478bd9Sstevel@tonic-gate if (big_is_zero(n)) { 25567c478bd9Sstevel@tonic-gate *jac = 0; 25577c478bd9Sstevel@tonic-gate goto ret; 25587c478bd9Sstevel@tonic-gate } 25597c478bd9Sstevel@tonic-gate if ((m->value[0] & 1) == 0) { 25607c478bd9Sstevel@tonic-gate if (((n->value[0] & 7) == 3) || 2561b60f2a0bSfr41279 ((n->value[0] & 7) == 5)) 2562b60f2a0bSfr41279 *jac = -*jac; 25637c478bd9Sstevel@tonic-gate (void) big_half_pos(m, m); 25647c478bd9Sstevel@tonic-gate } else if ((n->value[0] & 1) == 0) { 25657c478bd9Sstevel@tonic-gate if (((m->value[0] & 7) == 3) || 2566b60f2a0bSfr41279 ((m->value[0] & 7) == 5)) 2567b60f2a0bSfr41279 *jac = -*jac; 25687c478bd9Sstevel@tonic-gate (void) big_half_pos(n, n); 25697c478bd9Sstevel@tonic-gate } else { 25707c478bd9Sstevel@tonic-gate if (((m->value[0] & 3) == 3) && 25717c478bd9Sstevel@tonic-gate ((n->value[0] & 3) == 3)) { 25727c478bd9Sstevel@tonic-gate *jac = -*jac; 25737c478bd9Sstevel@tonic-gate } 2574b60f2a0bSfr41279 if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK) { 25757c478bd9Sstevel@tonic-gate goto ret; 2576b60f2a0bSfr41279 } 25777c478bd9Sstevel@tonic-gate t = tmp2; 25787c478bd9Sstevel@tonic-gate tmp2 = m; 25797c478bd9Sstevel@tonic-gate m = n; 25807c478bd9Sstevel@tonic-gate n = t; 25817c478bd9Sstevel@tonic-gate } 25827c478bd9Sstevel@tonic-gate } 25837c478bd9Sstevel@tonic-gate err = BIG_OK; 25847c478bd9Sstevel@tonic-gate 25857c478bd9Sstevel@tonic-gate ret: 25867c478bd9Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 25877c478bd9Sstevel@tonic-gate ret2: 25887c478bd9Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 25897c478bd9Sstevel@tonic-gate ret1: 25907c478bd9Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 25917c478bd9Sstevel@tonic-gate 25927c478bd9Sstevel@tonic-gate return (err); 25937c478bd9Sstevel@tonic-gate } 25947c478bd9Sstevel@tonic-gate 25957c478bd9Sstevel@tonic-gate 25967c478bd9Sstevel@tonic-gate BIG_ERR_CODE 25977c478bd9Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n) 25987c478bd9Sstevel@tonic-gate { 2599*8475e043SDan OpenSolaris Anderson int i; 2600*8475e043SDan OpenSolaris Anderson uint32_t m, w; 2601b60f2a0bSfr41279 BIG_CHUNK_TYPE bit; 26027c478bd9Sstevel@tonic-gate BIGNUM ki, tmp, tmp2; 2603b60f2a0bSfr41279 BIG_CHUNK_TYPE kivalue[BIGTMPSIZE]; 2604b60f2a0bSfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 2605b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 26067c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 26077c478bd9Sstevel@tonic-gate 2608b60f2a0bSfr41279 if (big_cmp_abs(k, &big_One) == 0) { 26097c478bd9Sstevel@tonic-gate (void) big_copy(Lk, p); 2610b60f2a0bSfr41279 (void) big_copy(Lkminus1, &big_Two); 26117c478bd9Sstevel@tonic-gate return (BIG_OK); 26127c478bd9Sstevel@tonic-gate } 26137c478bd9Sstevel@tonic-gate 26147c478bd9Sstevel@tonic-gate if ((err = big_init1(&ki, k->len + 1, 26157c478bd9Sstevel@tonic-gate kivalue, arraysize(kivalue))) != BIG_OK) 26167c478bd9Sstevel@tonic-gate return (err); 26177c478bd9Sstevel@tonic-gate 26187c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * n->len + 1, 26197c478bd9Sstevel@tonic-gate tmpvalue, arraysize(tmpvalue))) != BIG_OK) 26207c478bd9Sstevel@tonic-gate goto ret1; 26217c478bd9Sstevel@tonic-gate 26227c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp2, n->len, 26237c478bd9Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 26247c478bd9Sstevel@tonic-gate goto ret2; 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate m = big_numbits(k); 2627b60f2a0bSfr41279 ki.len = (m - 1) / BIG_CHUNK_SIZE + 1; 2628b60f2a0bSfr41279 w = (m - 1) / BIG_CHUNK_SIZE; 2629b60f2a0bSfr41279 bit = (BIG_CHUNK_TYPE)1 << ((m - 1) % BIG_CHUNK_SIZE); 2630b60f2a0bSfr41279 for (i = 0; i < ki.len; i++) { 2631b60f2a0bSfr41279 ki.value[i] = 0; 2632b60f2a0bSfr41279 } 26337c478bd9Sstevel@tonic-gate ki.value[ki.len - 1] = bit; 2634b60f2a0bSfr41279 if (big_cmp_abs(k, &ki) != 0) { 26357c478bd9Sstevel@tonic-gate (void) big_double(&ki, &ki); 2636b60f2a0bSfr41279 } 26377c478bd9Sstevel@tonic-gate (void) big_sub_pos(&ki, &ki, k); 26387c478bd9Sstevel@tonic-gate 26397c478bd9Sstevel@tonic-gate (void) big_copy(Lk, p); 2640b60f2a0bSfr41279 (void) big_copy(Lkminus1, &big_Two); 26417c478bd9Sstevel@tonic-gate 26427c478bd9Sstevel@tonic-gate for (i = 0; i < m; i++) { 2643b60f2a0bSfr41279 if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK) { 26447c478bd9Sstevel@tonic-gate goto ret; 2645b60f2a0bSfr41279 } 26467c478bd9Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 26477c478bd9Sstevel@tonic-gate (void) big_sub_pos(&tmp, &tmp, p); 2648b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK) { 26497c478bd9Sstevel@tonic-gate goto ret; 2650b60f2a0bSfr41279 } 26517c478bd9Sstevel@tonic-gate if ((ki.value[w] & bit) != 0) { 26527c478bd9Sstevel@tonic-gate if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) != 2653b60f2a0bSfr41279 BIG_OK) { 26547c478bd9Sstevel@tonic-gate goto ret; 2655b60f2a0bSfr41279 } 26567c478bd9Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 2657b60f2a0bSfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Two); 26587c478bd9Sstevel@tonic-gate if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) != 2659b60f2a0bSfr41279 BIG_OK) { 26607c478bd9Sstevel@tonic-gate goto ret; 2661b60f2a0bSfr41279 } 26627c478bd9Sstevel@tonic-gate (void) big_copy(Lk, &tmp2); 26637c478bd9Sstevel@tonic-gate } else { 2664b60f2a0bSfr41279 if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK) { 26657c478bd9Sstevel@tonic-gate goto ret; 2666b60f2a0bSfr41279 } 26677c478bd9Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 2668b60f2a0bSfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Two); 2669b60f2a0bSfr41279 if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK) { 26707c478bd9Sstevel@tonic-gate goto ret; 2671b60f2a0bSfr41279 } 26727c478bd9Sstevel@tonic-gate (void) big_copy(Lkminus1, &tmp2); 26737c478bd9Sstevel@tonic-gate } 26747c478bd9Sstevel@tonic-gate bit = bit >> 1; 26757c478bd9Sstevel@tonic-gate if (bit == 0) { 2676b60f2a0bSfr41279 bit = BIG_CHUNK_HIGHBIT; 26777c478bd9Sstevel@tonic-gate w--; 26787c478bd9Sstevel@tonic-gate } 26797c478bd9Sstevel@tonic-gate } 26807c478bd9Sstevel@tonic-gate 26817c478bd9Sstevel@tonic-gate err = BIG_OK; 26827c478bd9Sstevel@tonic-gate 26837c478bd9Sstevel@tonic-gate ret: 26847c478bd9Sstevel@tonic-gate if (tmp2.malloced) big_finish(&tmp2); 26857c478bd9Sstevel@tonic-gate ret2: 26867c478bd9Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 26877c478bd9Sstevel@tonic-gate ret1: 26887c478bd9Sstevel@tonic-gate if (ki.malloced) big_finish(&ki); 26897c478bd9Sstevel@tonic-gate 26907c478bd9Sstevel@tonic-gate return (err); 26917c478bd9Sstevel@tonic-gate } 26927c478bd9Sstevel@tonic-gate 26937c478bd9Sstevel@tonic-gate 26947c478bd9Sstevel@tonic-gate BIG_ERR_CODE 2695b60f2a0bSfr41279 big_isprime_pos_ext(BIGNUM *n, big_modexp_ncp_info_t *info) 26967c478bd9Sstevel@tonic-gate { 26977c478bd9Sstevel@tonic-gate BIGNUM o, nminus1, tmp, Lkminus1, Lk; 2698b60f2a0bSfr41279 BIG_CHUNK_TYPE ovalue[BIGTMPSIZE]; 2699b60f2a0bSfr41279 BIG_CHUNK_TYPE nminus1value[BIGTMPSIZE]; 2700b60f2a0bSfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 2701b60f2a0bSfr41279 BIG_CHUNK_TYPE Lkminus1value[BIGTMPSIZE]; 2702b60f2a0bSfr41279 BIG_CHUNK_TYPE Lkvalue[BIGTMPSIZE]; 27037c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 27047c478bd9Sstevel@tonic-gate int e, i, jac; 27057c478bd9Sstevel@tonic-gate 2706b60f2a0bSfr41279 if (big_cmp_abs(n, &big_One) == 0) { 27077c478bd9Sstevel@tonic-gate return (BIG_FALSE); 2708b60f2a0bSfr41279 } 2709b60f2a0bSfr41279 if (big_cmp_abs(n, &big_Two) == 0) { 27107c478bd9Sstevel@tonic-gate return (BIG_TRUE); 2711b60f2a0bSfr41279 } 2712b60f2a0bSfr41279 if ((n->value[0] & 1) == 0) { 27137c478bd9Sstevel@tonic-gate return (BIG_FALSE); 2714b60f2a0bSfr41279 } 27157c478bd9Sstevel@tonic-gate 2716b60f2a0bSfr41279 if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) != 2717b60f2a0bSfr41279 BIG_OK) { 27187c478bd9Sstevel@tonic-gate return (err); 2719b60f2a0bSfr41279 } 27207c478bd9Sstevel@tonic-gate 27217c478bd9Sstevel@tonic-gate if ((err = big_init1(&nminus1, n->len, 2722b60f2a0bSfr41279 nminus1value, arraysize(nminus1value))) != BIG_OK) { 27237c478bd9Sstevel@tonic-gate goto ret1; 2724b60f2a0bSfr41279 } 27257c478bd9Sstevel@tonic-gate 27267c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * n->len, 2727b60f2a0bSfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 27287c478bd9Sstevel@tonic-gate goto ret2; 2729b60f2a0bSfr41279 } 27307c478bd9Sstevel@tonic-gate 27317c478bd9Sstevel@tonic-gate if ((err = big_init1(&Lkminus1, n->len, 2732b60f2a0bSfr41279 Lkminus1value, arraysize(Lkminus1value))) != BIG_OK) { 27337c478bd9Sstevel@tonic-gate goto ret3; 2734b60f2a0bSfr41279 } 27357c478bd9Sstevel@tonic-gate 27367c478bd9Sstevel@tonic-gate if ((err = big_init1(&Lk, n->len, 2737b60f2a0bSfr41279 Lkvalue, arraysize(Lkvalue))) != BIG_OK) { 27387c478bd9Sstevel@tonic-gate goto ret4; 2739b60f2a0bSfr41279 } 27407c478bd9Sstevel@tonic-gate 2741b60f2a0bSfr41279 (void) big_sub_pos(&o, n, &big_One); /* cannot fail */ 27427c478bd9Sstevel@tonic-gate (void) big_copy(&nminus1, &o); /* cannot fail */ 27437c478bd9Sstevel@tonic-gate e = 0; 27447c478bd9Sstevel@tonic-gate while ((o.value[0] & 1) == 0) { 27457c478bd9Sstevel@tonic-gate e++; 27467c478bd9Sstevel@tonic-gate (void) big_half_pos(&o, &o); /* cannot fail */ 27477c478bd9Sstevel@tonic-gate } 2748b60f2a0bSfr41279 if ((err = big_modexp_ext(&tmp, &big_Two, &o, n, NULL, info)) != 2749b60f2a0bSfr41279 BIG_OK) { 27507c478bd9Sstevel@tonic-gate goto ret; 2751b60f2a0bSfr41279 } 2752b60f2a0bSfr41279 27537c478bd9Sstevel@tonic-gate i = 0; 27547c478bd9Sstevel@tonic-gate while ((i < e) && 2755b60f2a0bSfr41279 (big_cmp_abs(&tmp, &big_One) != 0) && 27567c478bd9Sstevel@tonic-gate (big_cmp_abs(&tmp, &nminus1) != 0)) { 2757b60f2a0bSfr41279 if ((err = 2758b60f2a0bSfr41279 big_modexp_ext(&tmp, &tmp, &big_Two, n, NULL, info)) != 2759b60f2a0bSfr41279 BIG_OK) 27607c478bd9Sstevel@tonic-gate goto ret; 27617c478bd9Sstevel@tonic-gate i++; 27627c478bd9Sstevel@tonic-gate } 2763b60f2a0bSfr41279 27647c478bd9Sstevel@tonic-gate if (!((big_cmp_abs(&tmp, &nminus1) == 0) || 2765b60f2a0bSfr41279 ((i == 0) && (big_cmp_abs(&tmp, &big_One) == 0)))) { 27667c478bd9Sstevel@tonic-gate err = BIG_FALSE; 27677c478bd9Sstevel@tonic-gate goto ret; 27687c478bd9Sstevel@tonic-gate } 27697c478bd9Sstevel@tonic-gate 2770b60f2a0bSfr41279 if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK) { 27717c478bd9Sstevel@tonic-gate goto ret; 2772b60f2a0bSfr41279 } 2773b60f2a0bSfr41279 2774b60f2a0bSfr41279 if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK) { 27757c478bd9Sstevel@tonic-gate goto ret; 2776b60f2a0bSfr41279 } 27777c478bd9Sstevel@tonic-gate if (big_cmp_abs(&tmp, n) == 0) { 27787c478bd9Sstevel@tonic-gate err = BIG_FALSE; 27797c478bd9Sstevel@tonic-gate goto ret; 27807c478bd9Sstevel@tonic-gate } 27817c478bd9Sstevel@tonic-gate 2782b60f2a0bSfr41279 (void) big_copy(&o, &big_Two); 27837c478bd9Sstevel@tonic-gate do { 2784b60f2a0bSfr41279 (void) big_add_abs(&o, &o, &big_One); 2785b60f2a0bSfr41279 if ((err = big_mul(&tmp, &o, &o)) != BIG_OK) { 27867c478bd9Sstevel@tonic-gate goto ret; 2787b60f2a0bSfr41279 } 2788b60f2a0bSfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Four); 2789b60f2a0bSfr41279 if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK) { 27907c478bd9Sstevel@tonic-gate goto ret; 2791b60f2a0bSfr41279 } 27927c478bd9Sstevel@tonic-gate } while (jac != -1); 27937c478bd9Sstevel@tonic-gate 2794b60f2a0bSfr41279 (void) big_add_abs(&tmp, n, &big_One); 2795b60f2a0bSfr41279 if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK) { 27967c478bd9Sstevel@tonic-gate goto ret; 2797b60f2a0bSfr41279 } 2798b60f2a0bSfr41279 2799b60f2a0bSfr41279 if ((big_cmp_abs(&Lkminus1, &o) == 0) && 2800b60f2a0bSfr41279 (big_cmp_abs(&Lk, &big_Two) == 0)) { 28017c478bd9Sstevel@tonic-gate err = BIG_TRUE; 2802b60f2a0bSfr41279 } else { 2803b60f2a0bSfr41279 err = BIG_FALSE; 2804b60f2a0bSfr41279 } 28057c478bd9Sstevel@tonic-gate 28067c478bd9Sstevel@tonic-gate ret: 28077c478bd9Sstevel@tonic-gate if (Lk.malloced) big_finish(&Lk); 28087c478bd9Sstevel@tonic-gate ret4: 28097c478bd9Sstevel@tonic-gate if (Lkminus1.malloced) big_finish(&Lkminus1); 28107c478bd9Sstevel@tonic-gate ret3: 28117c478bd9Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 28127c478bd9Sstevel@tonic-gate ret2: 28137c478bd9Sstevel@tonic-gate if (nminus1.malloced) big_finish(&nminus1); 28147c478bd9Sstevel@tonic-gate ret1: 28157c478bd9Sstevel@tonic-gate if (o.malloced) big_finish(&o); 28167c478bd9Sstevel@tonic-gate 28177c478bd9Sstevel@tonic-gate return (err); 28187c478bd9Sstevel@tonic-gate } 28197c478bd9Sstevel@tonic-gate 28207c478bd9Sstevel@tonic-gate 2821b60f2a0bSfr41279 BIG_ERR_CODE 2822b60f2a0bSfr41279 big_isprime_pos(BIGNUM *n) 2823b60f2a0bSfr41279 { 2824b60f2a0bSfr41279 return (big_isprime_pos_ext(n, NULL)); 2825b60f2a0bSfr41279 } 2826b60f2a0bSfr41279 2827b60f2a0bSfr41279 28287c478bd9Sstevel@tonic-gate #define SIEVESIZE 1000 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate 28317c478bd9Sstevel@tonic-gate BIG_ERR_CODE 2832b60f2a0bSfr41279 big_nextprime_pos_ext(BIGNUM *result, BIGNUM *n, big_modexp_ncp_info_t *info) 28337c478bd9Sstevel@tonic-gate { 2834*8475e043SDan OpenSolaris Anderson static const uint32_t smallprimes[] = { 2835*8475e043SDan OpenSolaris Anderson 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 2836*8475e043SDan OpenSolaris Anderson 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97 }; 28377c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 28387c478bd9Sstevel@tonic-gate int sieve[SIEVESIZE]; 28397c478bd9Sstevel@tonic-gate int i; 28407c478bd9Sstevel@tonic-gate uint32_t off, p; 28417c478bd9Sstevel@tonic-gate 2842b60f2a0bSfr41279 if ((err = big_copy(result, n)) != BIG_OK) { 28437c478bd9Sstevel@tonic-gate return (err); 2844b60f2a0bSfr41279 } 28457c478bd9Sstevel@tonic-gate result->value[0] |= 1; 2846f56c1286Srobinson /* CONSTCOND */ 28477c478bd9Sstevel@tonic-gate while (1) { 28487c478bd9Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0; 28497c478bd9Sstevel@tonic-gate for (i = 0; 2850b60f2a0bSfr41279 i < sizeof (smallprimes) / sizeof (smallprimes[0]); i++) { 28517c478bd9Sstevel@tonic-gate p = smallprimes[i]; 2852b60f2a0bSfr41279 off = big_modhalf_pos(result, p); 28537c478bd9Sstevel@tonic-gate off = p - off; 2854b60f2a0bSfr41279 if ((off % 2) == 1) { 2855b60f2a0bSfr41279 off = off + p; 2856b60f2a0bSfr41279 } 28577c478bd9Sstevel@tonic-gate off = off / 2; 28587c478bd9Sstevel@tonic-gate while (off < SIEVESIZE) { 28597c478bd9Sstevel@tonic-gate sieve[off] = 1; 28607c478bd9Sstevel@tonic-gate off = off + p; 28617c478bd9Sstevel@tonic-gate } 28627c478bd9Sstevel@tonic-gate } 28637c478bd9Sstevel@tonic-gate 28647c478bd9Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) { 28657c478bd9Sstevel@tonic-gate if (sieve[i] == 0) { 2866b60f2a0bSfr41279 err = big_isprime_pos_ext(result, info); 28677c478bd9Sstevel@tonic-gate if (err != BIG_FALSE) { 2868b60f2a0bSfr41279 if (err != BIG_TRUE) { 28697c478bd9Sstevel@tonic-gate return (err); 2870b60f2a0bSfr41279 } else { 2871b60f2a0bSfr41279 goto out; 2872b60f2a0bSfr41279 } 28737c478bd9Sstevel@tonic-gate } 28747c478bd9Sstevel@tonic-gate 28757c478bd9Sstevel@tonic-gate } 2876b60f2a0bSfr41279 if ((err = big_add_abs(result, result, &big_Two)) != 2877b60f2a0bSfr41279 BIG_OK) { 28787c478bd9Sstevel@tonic-gate return (err); 28797c478bd9Sstevel@tonic-gate } 28807c478bd9Sstevel@tonic-gate } 2881b60f2a0bSfr41279 } 2882b60f2a0bSfr41279 2883b60f2a0bSfr41279 out: 2884b60f2a0bSfr41279 return (BIG_OK); 2885b60f2a0bSfr41279 } 2886b60f2a0bSfr41279 2887b60f2a0bSfr41279 2888b60f2a0bSfr41279 BIG_ERR_CODE 2889b60f2a0bSfr41279 big_nextprime_pos(BIGNUM *result, BIGNUM *n) 2890b60f2a0bSfr41279 { 2891b60f2a0bSfr41279 return (big_nextprime_pos_ext(result, n, NULL)); 28927c478bd9Sstevel@tonic-gate } 28937c478bd9Sstevel@tonic-gate 28947c478bd9Sstevel@tonic-gate 28957c478bd9Sstevel@tonic-gate BIG_ERR_CODE 28967c478bd9Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n) 28977c478bd9Sstevel@tonic-gate { 28987c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 28997c478bd9Sstevel@tonic-gate 29007c478bd9Sstevel@tonic-gate 29017c478bd9Sstevel@tonic-gate if ((err = big_copy(result, n)) != BIG_OK) 29027c478bd9Sstevel@tonic-gate return (err); 29037c478bd9Sstevel@tonic-gate result->value[0] |= 1; 2904b60f2a0bSfr41279 while ((err = big_isprime_pos_ext(result, NULL)) != BIG_TRUE) { 29057c478bd9Sstevel@tonic-gate if (err != BIG_FALSE) 29067c478bd9Sstevel@tonic-gate return (err); 2907b60f2a0bSfr41279 if ((err = big_add_abs(result, result, &big_Two)) != BIG_OK) 29087c478bd9Sstevel@tonic-gate return (err); 29097c478bd9Sstevel@tonic-gate } 29107c478bd9Sstevel@tonic-gate return (BIG_OK); 29117c478bd9Sstevel@tonic-gate } 29127c478bd9Sstevel@tonic-gate 29137c478bd9Sstevel@tonic-gate 29147c478bd9Sstevel@tonic-gate /* 29157c478bd9Sstevel@tonic-gate * given m and e, computes the rest in the equation 29167c478bd9Sstevel@tonic-gate * gcd(m, e) = cm * m + ce * e 29177c478bd9Sstevel@tonic-gate */ 29187c478bd9Sstevel@tonic-gate BIG_ERR_CODE 29197c478bd9Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e) 29207c478bd9Sstevel@tonic-gate { 2921b60f2a0bSfr41279 BIGNUM *xi, *ri, *riminus1, *riminus2, *t; 2922b60f2a0bSfr41279 BIGNUM *vmi, *vei, *vmiminus1, *veiminus1; 29237c478bd9Sstevel@tonic-gate BIGNUM t1, t2, t3, t4, t5, t6, t7, t8, tmp; 2924b60f2a0bSfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 2925b60f2a0bSfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 2926b60f2a0bSfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 2927b60f2a0bSfr41279 BIG_CHUNK_TYPE t4value[BIGTMPSIZE]; 2928b60f2a0bSfr41279 BIG_CHUNK_TYPE t5value[BIGTMPSIZE]; 2929b60f2a0bSfr41279 BIG_CHUNK_TYPE t6value[BIGTMPSIZE]; 2930b60f2a0bSfr41279 BIG_CHUNK_TYPE t7value[BIGTMPSIZE]; 2931b60f2a0bSfr41279 BIG_CHUNK_TYPE t8value[BIGTMPSIZE]; 2932b60f2a0bSfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 29337c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 29347c478bd9Sstevel@tonic-gate int len; 29357c478bd9Sstevel@tonic-gate 2936b60f2a0bSfr41279 if (big_cmp_abs(m, e) >= 0) { 2937b60f2a0bSfr41279 len = m->len; 2938b60f2a0bSfr41279 } else { 2939b60f2a0bSfr41279 len = e->len; 2940b60f2a0bSfr41279 } 29417c478bd9Sstevel@tonic-gate 29427c478bd9Sstevel@tonic-gate if ((err = big_init1(&t1, len, 2943b60f2a0bSfr41279 t1value, arraysize(t1value))) != BIG_OK) { 29447c478bd9Sstevel@tonic-gate return (err); 2945b60f2a0bSfr41279 } 29467c478bd9Sstevel@tonic-gate if ((err = big_init1(&t2, len, 2947b60f2a0bSfr41279 t2value, arraysize(t2value))) != BIG_OK) { 29487c478bd9Sstevel@tonic-gate goto ret1; 2949b60f2a0bSfr41279 } 29507c478bd9Sstevel@tonic-gate if ((err = big_init1(&t3, len, 2951b60f2a0bSfr41279 t3value, arraysize(t3value))) != BIG_OK) { 29527c478bd9Sstevel@tonic-gate goto ret2; 2953b60f2a0bSfr41279 } 29547c478bd9Sstevel@tonic-gate if ((err = big_init1(&t4, len, 2955b60f2a0bSfr41279 t4value, arraysize(t3value))) != BIG_OK) { 29567c478bd9Sstevel@tonic-gate goto ret3; 2957b60f2a0bSfr41279 } 29587c478bd9Sstevel@tonic-gate if ((err = big_init1(&t5, len, 2959b60f2a0bSfr41279 t5value, arraysize(t5value))) != BIG_OK) { 29607c478bd9Sstevel@tonic-gate goto ret4; 2961b60f2a0bSfr41279 } 29627c478bd9Sstevel@tonic-gate if ((err = big_init1(&t6, len, 2963b60f2a0bSfr41279 t6value, arraysize(t6value))) != BIG_OK) { 29647c478bd9Sstevel@tonic-gate goto ret5; 2965b60f2a0bSfr41279 } 29667c478bd9Sstevel@tonic-gate if ((err = big_init1(&t7, len, 2967b60f2a0bSfr41279 t7value, arraysize(t7value))) != BIG_OK) { 29687c478bd9Sstevel@tonic-gate goto ret6; 2969b60f2a0bSfr41279 } 29707c478bd9Sstevel@tonic-gate if ((err = big_init1(&t8, len, 2971b60f2a0bSfr41279 t8value, arraysize(t8value))) != BIG_OK) { 29727c478bd9Sstevel@tonic-gate goto ret7; 2973b60f2a0bSfr41279 } 29747c478bd9Sstevel@tonic-gate 29757c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * len, 2976b60f2a0bSfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 29777c478bd9Sstevel@tonic-gate goto ret8; 2978b60f2a0bSfr41279 } 29797c478bd9Sstevel@tonic-gate 29807c478bd9Sstevel@tonic-gate ri = &t1; 29817c478bd9Sstevel@tonic-gate ri->value[0] = 1; 29827c478bd9Sstevel@tonic-gate ri->len = 1; 29837c478bd9Sstevel@tonic-gate xi = &t2; 29847c478bd9Sstevel@tonic-gate riminus1 = &t3; 29857c478bd9Sstevel@tonic-gate riminus2 = &t4; 29867c478bd9Sstevel@tonic-gate vmi = &t5; 29877c478bd9Sstevel@tonic-gate vei = &t6; 29887c478bd9Sstevel@tonic-gate vmiminus1 = &t7; 29897c478bd9Sstevel@tonic-gate veiminus1 = &t8; 29907c478bd9Sstevel@tonic-gate 2991b60f2a0bSfr41279 (void) big_copy(vmiminus1, &big_One); 2992b60f2a0bSfr41279 (void) big_copy(vmi, &big_One); 2993b60f2a0bSfr41279 (void) big_copy(veiminus1, &big_One); 2994b60f2a0bSfr41279 (void) big_copy(xi, &big_One); 29957c478bd9Sstevel@tonic-gate vei->len = 1; 29967c478bd9Sstevel@tonic-gate vei->value[0] = 0; 29977c478bd9Sstevel@tonic-gate 29987c478bd9Sstevel@tonic-gate (void) big_copy(riminus1, m); 29997c478bd9Sstevel@tonic-gate (void) big_copy(ri, e); 30007c478bd9Sstevel@tonic-gate 30017c478bd9Sstevel@tonic-gate while (!big_is_zero(ri)) { 30027c478bd9Sstevel@tonic-gate t = riminus2; 30037c478bd9Sstevel@tonic-gate riminus2 = riminus1; 30047c478bd9Sstevel@tonic-gate riminus1 = ri; 30057c478bd9Sstevel@tonic-gate ri = t; 3006b60f2a0bSfr41279 if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK) { 30077c478bd9Sstevel@tonic-gate goto ret; 3008b60f2a0bSfr41279 } 3009b60f2a0bSfr41279 if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK) { 30107c478bd9Sstevel@tonic-gate goto ret; 3011b60f2a0bSfr41279 } 30127c478bd9Sstevel@tonic-gate t = vmiminus1; 30137c478bd9Sstevel@tonic-gate vmiminus1 = vmi; 30147c478bd9Sstevel@tonic-gate vmi = t; 3015b60f2a0bSfr41279 if ((err = big_mul(&tmp, vei, xi)) != BIG_OK) { 30167c478bd9Sstevel@tonic-gate goto ret; 3017b60f2a0bSfr41279 } 3018b60f2a0bSfr41279 if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK) { 30197c478bd9Sstevel@tonic-gate goto ret; 3020b60f2a0bSfr41279 } 30217c478bd9Sstevel@tonic-gate t = veiminus1; 30227c478bd9Sstevel@tonic-gate veiminus1 = vei; 30237c478bd9Sstevel@tonic-gate vei = t; 3024b60f2a0bSfr41279 if ((err = big_div_pos(xi, ri, riminus2, riminus1)) != 3025b60f2a0bSfr41279 BIG_OK) { 30267c478bd9Sstevel@tonic-gate goto ret; 30277c478bd9Sstevel@tonic-gate } 3028b60f2a0bSfr41279 } 3029b60f2a0bSfr41279 if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK)) { 30307c478bd9Sstevel@tonic-gate goto ret; 3031b60f2a0bSfr41279 } 3032b60f2a0bSfr41279 if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK)) { 30337c478bd9Sstevel@tonic-gate goto ret; 3034b60f2a0bSfr41279 } 3035b60f2a0bSfr41279 if (ce != NULL) { 30367c478bd9Sstevel@tonic-gate err = big_copy(ce, vei); 3037b60f2a0bSfr41279 } 30387c478bd9Sstevel@tonic-gate ret: 30397c478bd9Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 30407c478bd9Sstevel@tonic-gate ret8: 30417c478bd9Sstevel@tonic-gate if (t8.malloced) big_finish(&t8); 30427c478bd9Sstevel@tonic-gate ret7: 30437c478bd9Sstevel@tonic-gate if (t7.malloced) big_finish(&t7); 30447c478bd9Sstevel@tonic-gate ret6: 30457c478bd9Sstevel@tonic-gate if (t6.malloced) big_finish(&t6); 30467c478bd9Sstevel@tonic-gate ret5: 30477c478bd9Sstevel@tonic-gate if (t5.malloced) big_finish(&t5); 30487c478bd9Sstevel@tonic-gate ret4: 30497c478bd9Sstevel@tonic-gate if (t4.malloced) big_finish(&t4); 30507c478bd9Sstevel@tonic-gate ret3: 30517c478bd9Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 30527c478bd9Sstevel@tonic-gate ret2: 30537c478bd9Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 30547c478bd9Sstevel@tonic-gate ret1: 30557c478bd9Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 30567c478bd9Sstevel@tonic-gate 30577c478bd9Sstevel@tonic-gate return (err); 30587c478bd9Sstevel@tonic-gate } 3059