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 /* 228475e043SDan 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. 478475e043SDan 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 658475e043SDan OpenSolaris Anderson #include <sys/types.h> 668475e043SDan OpenSolaris Anderson #include "bignum.h" 678475e043SDan 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 778475e043SDan OpenSolaris Anderson #else 788475e043SDan OpenSolaris Anderson #include <stdlib.h> 798475e043SDan OpenSolaris Anderson #include <stdio.h> 808475e043SDan OpenSolaris Anderson #include <assert.h> 818475e043SDan OpenSolaris Anderson #define ASSERT assert 828475e043SDan OpenSolaris Anderson #endif /* _KERNEL */ 838475e043SDan OpenSolaris Anderson 84*0a1ad920SDan OpenSolaris Anderson #ifdef __amd64 85*0a1ad920SDan OpenSolaris Anderson #ifdef _KERNEL 86*0a1ad920SDan OpenSolaris Anderson #include <sys/x86_archext.h> /* cpuid_getvendor() */ 87*0a1ad920SDan OpenSolaris Anderson #include <sys/cpuvar.h> 88*0a1ad920SDan OpenSolaris Anderson #else 89*0a1ad920SDan OpenSolaris Anderson #include <sys/auxv.h> /* getisax() */ 90*0a1ad920SDan OpenSolaris Anderson #endif /* _KERNEL */ 91*0a1ad920SDan OpenSolaris Anderson #endif /* __amd64 */ 92*0a1ad920SDan OpenSolaris Anderson 93*0a1ad920SDan OpenSolaris Anderson 948475e043SDan OpenSolaris Anderson #ifdef _LP64 /* truncate 64-bit size_t to 32-bits */ 958475e043SDan OpenSolaris Anderson #define UI32(ui) ((uint32_t)ui) 968475e043SDan OpenSolaris Anderson #else /* size_t already 32-bits */ 978475e043SDan OpenSolaris Anderson #define UI32(ui) (ui) 988475e043SDan OpenSolaris Anderson #endif 998475e043SDan OpenSolaris Anderson 1008475e043SDan OpenSolaris Anderson 1018475e043SDan OpenSolaris Anderson #ifdef _KERNEL 1027c478bd9Sstevel@tonic-gate #define big_malloc(size) kmem_alloc(size, KM_NOSLEEP) 1037c478bd9Sstevel@tonic-gate #define big_free(ptr, size) kmem_free(ptr, size) 1047c478bd9Sstevel@tonic-gate 105*0a1ad920SDan OpenSolaris Anderson /* 106*0a1ad920SDan OpenSolaris Anderson * big_realloc() 107*0a1ad920SDan OpenSolaris Anderson * Allocate memory of newsize bytes and copy oldsize bytes 108*0a1ad920SDan OpenSolaris Anderson * to the newly-allocated memory, then free the 109*0a1ad920SDan OpenSolaris Anderson * previously-allocated memory. 110*0a1ad920SDan OpenSolaris Anderson * Note: newsize must be > oldsize 111*0a1ad920SDan OpenSolaris Anderson */ 1127c478bd9Sstevel@tonic-gate void * 1137c478bd9Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize) 1147c478bd9Sstevel@tonic-gate { 1157c478bd9Sstevel@tonic-gate void *rv; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate rv = kmem_alloc(newsize, KM_NOSLEEP); 1187c478bd9Sstevel@tonic-gate if (rv != NULL) 1197c478bd9Sstevel@tonic-gate bcopy(from, rv, oldsize); 1207c478bd9Sstevel@tonic-gate kmem_free(from, oldsize); 1217c478bd9Sstevel@tonic-gate return (rv); 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate #else /* _KERNEL */ 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate #ifndef MALLOC_DEBUG 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate #define big_malloc(size) malloc(size) 1297c478bd9Sstevel@tonic-gate #define big_free(ptr, size) free(ptr) 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate #else 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate void 1347c478bd9Sstevel@tonic-gate big_free(void *ptr, size_t size) 1357c478bd9Sstevel@tonic-gate { 1367c478bd9Sstevel@tonic-gate printf("freed %d bytes at %p\n", size, ptr); 1377c478bd9Sstevel@tonic-gate free(ptr); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate void * 1417c478bd9Sstevel@tonic-gate big_malloc(size_t size) 1427c478bd9Sstevel@tonic-gate { 1437c478bd9Sstevel@tonic-gate void *rv; 1447c478bd9Sstevel@tonic-gate rv = malloc(size); 1457c478bd9Sstevel@tonic-gate printf("malloced %d bytes, addr:%p\n", size, rv); 1467c478bd9Sstevel@tonic-gate return (rv); 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate #endif /* MALLOC_DEBUG */ 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate #define big_realloc(x, y, z) realloc((x), (z)) 1517c478bd9Sstevel@tonic-gate 1528475e043SDan OpenSolaris Anderson 1538475e043SDan OpenSolaris Anderson /* 1548475e043SDan OpenSolaris Anderson * printbignum() 1558475e043SDan OpenSolaris Anderson * Print a BIGNUM type to stdout. 1568475e043SDan OpenSolaris Anderson */ 1577c478bd9Sstevel@tonic-gate void 1587c478bd9Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a) 1597c478bd9Sstevel@tonic-gate { 1607c478bd9Sstevel@tonic-gate int i; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate (void) printf("\n%s\n%d\n", aname, a->sign*a->len); 1637c478bd9Sstevel@tonic-gate for (i = a->len - 1; i >= 0; i--) { 164b60f2a0bSfr41279 #ifdef BIGNUM_CHUNK_32 1657c478bd9Sstevel@tonic-gate (void) printf("%08x ", a->value[i]); 1668475e043SDan OpenSolaris Anderson if (((i & (BITSINBYTE - 1)) == 0) && (i != 0)) { 1677c478bd9Sstevel@tonic-gate (void) printf("\n"); 1687c478bd9Sstevel@tonic-gate } 169b60f2a0bSfr41279 #else 170b60f2a0bSfr41279 (void) printf("%08x %08x ", (uint32_t)((a->value[i]) >> 32), 171b60f2a0bSfr41279 (uint32_t)((a->value[i]) & 0xffffffff)); 1728475e043SDan OpenSolaris Anderson if (((i & 3) == 0) && (i != 0)) { /* end of this chunk */ 173b60f2a0bSfr41279 (void) printf("\n"); 174b60f2a0bSfr41279 } 175b60f2a0bSfr41279 #endif 176b60f2a0bSfr41279 } 1777c478bd9Sstevel@tonic-gate (void) printf("\n"); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate 183*0a1ad920SDan OpenSolaris Anderson #ifdef __amd64 184*0a1ad920SDan OpenSolaris Anderson /* 185*0a1ad920SDan OpenSolaris Anderson * Return 1 if executing on Intel, otherwise 0 (e.g., AMD64). 186*0a1ad920SDan OpenSolaris Anderson */ 187*0a1ad920SDan OpenSolaris Anderson static int 188*0a1ad920SDan OpenSolaris Anderson bignum_on_intel(void) 189*0a1ad920SDan OpenSolaris Anderson { 190*0a1ad920SDan OpenSolaris Anderson #ifdef _KERNEL 191*0a1ad920SDan OpenSolaris Anderson return (cpuid_getvendor(CPU) == X86_VENDOR_Intel); 192*0a1ad920SDan OpenSolaris Anderson #else 193*0a1ad920SDan OpenSolaris Anderson uint_t ui; 194*0a1ad920SDan OpenSolaris Anderson (void) getisax(&ui, 1); 195*0a1ad920SDan OpenSolaris Anderson return ((ui & AV_386_AMD_MMX) == 0); 196*0a1ad920SDan OpenSolaris Anderson #endif /* _KERNEL */ 197*0a1ad920SDan OpenSolaris Anderson } 198*0a1ad920SDan OpenSolaris Anderson #endif /* __amd64 */ 199*0a1ad920SDan OpenSolaris Anderson 200*0a1ad920SDan OpenSolaris Anderson 2018475e043SDan OpenSolaris Anderson /* 2028475e043SDan OpenSolaris Anderson * big_init() 2038475e043SDan OpenSolaris Anderson * Initialize and allocate memory for a BIGNUM type. 2048475e043SDan OpenSolaris Anderson * 2058475e043SDan OpenSolaris Anderson * big_init(number, size) is equivalent to big_init1(number, size, NULL, 0) 2068475e043SDan OpenSolaris Anderson * 2078475e043SDan OpenSolaris Anderson * Note: call big_finish() to free memory allocated by big_init(). 2088475e043SDan OpenSolaris Anderson * 2098475e043SDan OpenSolaris Anderson * Input: 2108475e043SDan OpenSolaris Anderson * number Uninitialized memory for BIGNUM 2118475e043SDan OpenSolaris Anderson * size Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM 2128475e043SDan OpenSolaris Anderson * 2138475e043SDan OpenSolaris Anderson * Output: 2148475e043SDan OpenSolaris Anderson * number Initialized BIGNUM 2158475e043SDan OpenSolaris Anderson * 2168475e043SDan OpenSolaris Anderson * Return BIG_OK on success or BIG_NO_MEM for an allocation error. 2178475e043SDan OpenSolaris Anderson */ 2187c478bd9Sstevel@tonic-gate BIG_ERR_CODE 2197c478bd9Sstevel@tonic-gate big_init(BIGNUM *number, int size) 2207c478bd9Sstevel@tonic-gate { 2218475e043SDan OpenSolaris Anderson number->value = big_malloc(BIGNUM_WORDSIZE * size); 2227c478bd9Sstevel@tonic-gate if (number->value == NULL) { 2237c478bd9Sstevel@tonic-gate return (BIG_NO_MEM); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate number->size = size; 2267c478bd9Sstevel@tonic-gate number->len = 0; 2277c478bd9Sstevel@tonic-gate number->sign = 1; 2287c478bd9Sstevel@tonic-gate number->malloced = 1; 2297c478bd9Sstevel@tonic-gate return (BIG_OK); 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate 2328475e043SDan OpenSolaris Anderson 2338475e043SDan OpenSolaris Anderson /* 2348475e043SDan OpenSolaris Anderson * big_init1() 2358475e043SDan OpenSolaris Anderson * Initialize and, if needed, allocate memory for a BIGNUM type. 2368475e043SDan OpenSolaris Anderson * Use the buffer passed, buf, if any, instad of allocating memory 2378475e043SDan OpenSolaris Anderson * if it's at least "size" bytes. 2388475e043SDan OpenSolaris Anderson * 2398475e043SDan OpenSolaris Anderson * Note: call big_finish() to free memory allocated by big_init(). 2408475e043SDan OpenSolaris Anderson * 2418475e043SDan OpenSolaris Anderson * Input: 2428475e043SDan OpenSolaris Anderson * number Uninitialized memory for BIGNUM 2438475e043SDan OpenSolaris Anderson * size Minimum size, in BIG_CHUNK_SIZE-bit words, required for BIGNUM 2448475e043SDan OpenSolaris Anderson * buf Buffer for storing a BIGNUM. 2458475e043SDan OpenSolaris Anderson * If NULL, big_init1() will allocate a buffer 2468475e043SDan OpenSolaris Anderson * bufsize Size, in BIG_CHUNK_SIZE_bit words, of buf 2478475e043SDan OpenSolaris Anderson * 2488475e043SDan OpenSolaris Anderson * Output: 2498475e043SDan OpenSolaris Anderson * number Initialized BIGNUM 2508475e043SDan OpenSolaris Anderson * 2518475e043SDan OpenSolaris Anderson * Return BIG_OK on success or BIG_NO_MEM for an allocation error. 2528475e043SDan OpenSolaris Anderson */ 2537c478bd9Sstevel@tonic-gate BIG_ERR_CODE 254b60f2a0bSfr41279 big_init1(BIGNUM *number, int size, BIG_CHUNK_TYPE *buf, int bufsize) 2557c478bd9Sstevel@tonic-gate { 2567c478bd9Sstevel@tonic-gate if ((buf == NULL) || (size > bufsize)) { 2578475e043SDan OpenSolaris Anderson number->value = big_malloc(BIGNUM_WORDSIZE * size); 2587c478bd9Sstevel@tonic-gate if (number->value == NULL) { 2597c478bd9Sstevel@tonic-gate return (BIG_NO_MEM); 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate number->size = size; 2627c478bd9Sstevel@tonic-gate number->malloced = 1; 2637c478bd9Sstevel@tonic-gate } else { 2647c478bd9Sstevel@tonic-gate number->value = buf; 2657c478bd9Sstevel@tonic-gate number->size = bufsize; 2667c478bd9Sstevel@tonic-gate number->malloced = 0; 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate number->len = 0; 2697c478bd9Sstevel@tonic-gate number->sign = 1; 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate return (BIG_OK); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2748475e043SDan OpenSolaris Anderson 2758475e043SDan OpenSolaris Anderson /* 2768475e043SDan OpenSolaris Anderson * big_finish() 2778475e043SDan OpenSolaris Anderson * Free memory, if any, allocated by big_init() or big_init1(). 2788475e043SDan OpenSolaris Anderson */ 2797c478bd9Sstevel@tonic-gate void 2807c478bd9Sstevel@tonic-gate big_finish(BIGNUM *number) 2817c478bd9Sstevel@tonic-gate { 2827c478bd9Sstevel@tonic-gate if (number->malloced == 1) { 2838475e043SDan OpenSolaris Anderson big_free(number->value, BIGNUM_WORDSIZE * number->size); 2847c478bd9Sstevel@tonic-gate number->malloced = 0; 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 288b60f2a0bSfr41279 2897c478bd9Sstevel@tonic-gate /* 290b60f2a0bSfr41279 * bn->size should be at least 2918475e043SDan OpenSolaris Anderson * (len + BIGNUM_WORDSIZE - 1) / BIGNUM_WORDSIZE bytes 2927c478bd9Sstevel@tonic-gate * converts from byte-big-endian format to bignum format (words in 2937c478bd9Sstevel@tonic-gate * little endian order, but bytes within the words big endian) 2947c478bd9Sstevel@tonic-gate */ 2957c478bd9Sstevel@tonic-gate void 2967c478bd9Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len) 2977c478bd9Sstevel@tonic-gate { 2988475e043SDan OpenSolaris Anderson int i, j; 2998475e043SDan OpenSolaris Anderson uint32_t offs; 3008475e043SDan OpenSolaris Anderson const uint32_t slen = UI32(len); 301b60f2a0bSfr41279 BIG_CHUNK_TYPE word; 3027c478bd9Sstevel@tonic-gate uchar_t *knwordp; 3037c478bd9Sstevel@tonic-gate 3048475e043SDan OpenSolaris Anderson if (slen == 0) { 3058475e043SDan OpenSolaris Anderson bn->len = 1; 3068475e043SDan OpenSolaris Anderson bn->value[0] = 0; 3078475e043SDan OpenSolaris Anderson return; 3088475e043SDan OpenSolaris Anderson } 309b60f2a0bSfr41279 3108475e043SDan OpenSolaris Anderson offs = slen % BIGNUM_WORDSIZE; 3118475e043SDan OpenSolaris Anderson bn->len = slen / BIGNUM_WORDSIZE; 3128475e043SDan OpenSolaris Anderson 3138475e043SDan OpenSolaris Anderson for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) { 3148475e043SDan OpenSolaris Anderson knwordp = &(kn[slen - BIGNUM_WORDSIZE * (i + 1)]); 3157c478bd9Sstevel@tonic-gate word = knwordp[0]; 3168475e043SDan OpenSolaris Anderson for (j = 1; j < BIGNUM_WORDSIZE; j++) { 3178475e043SDan OpenSolaris Anderson word = (word << BITSINBYTE) + knwordp[j]; 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate bn->value[i] = word; 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate if (offs > 0) { 3227c478bd9Sstevel@tonic-gate word = kn[0]; 3238475e043SDan OpenSolaris Anderson for (i = 1; i < offs; i++) word = (word << BITSINBYTE) + kn[i]; 3247c478bd9Sstevel@tonic-gate bn->value[bn->len++] = word; 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate while ((bn->len > 1) && (bn->value[bn->len - 1] == 0)) { 3277c478bd9Sstevel@tonic-gate bn->len --; 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate 3318475e043SDan OpenSolaris Anderson 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * copies the least significant len bytes if 3348475e043SDan OpenSolaris Anderson * len < bn->len * BIGNUM_WORDSIZE 3357c478bd9Sstevel@tonic-gate * converts from bignum format to byte-big-endian format. 336b60f2a0bSfr41279 * bignum format is words of type BIG_CHUNK_TYPE in little endian order. 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate void 3397c478bd9Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len) 3407c478bd9Sstevel@tonic-gate { 3418475e043SDan OpenSolaris Anderson int i, j; 3428475e043SDan OpenSolaris Anderson uint32_t offs; 3438475e043SDan OpenSolaris Anderson const uint32_t slen = UI32(len); 344b60f2a0bSfr41279 BIG_CHUNK_TYPE word; 3457c478bd9Sstevel@tonic-gate 3468475e043SDan OpenSolaris Anderson if (len < BIGNUM_WORDSIZE * bn->len) { 3478475e043SDan OpenSolaris Anderson for (i = 0; i < slen / BIGNUM_WORDSIZE; i++) { 3487c478bd9Sstevel@tonic-gate word = bn->value[i]; 3498475e043SDan OpenSolaris Anderson for (j = 0; j < BIGNUM_WORDSIZE; j++) { 3508475e043SDan OpenSolaris Anderson kn[slen - BIGNUM_WORDSIZE * i - j - 1] = 3517c478bd9Sstevel@tonic-gate word & 0xff; 3528475e043SDan OpenSolaris Anderson word = word >> BITSINBYTE; 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate } 3558475e043SDan OpenSolaris Anderson offs = slen % BIGNUM_WORDSIZE; 3567c478bd9Sstevel@tonic-gate if (offs > 0) { 3578475e043SDan OpenSolaris Anderson word = bn->value[slen / BIGNUM_WORDSIZE]; 3588475e043SDan OpenSolaris Anderson for (i = slen % BIGNUM_WORDSIZE; i > 0; i --) { 3597c478bd9Sstevel@tonic-gate kn[i - 1] = word & 0xff; 3608475e043SDan OpenSolaris Anderson word = word >> BITSINBYTE; 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate } else { 3647c478bd9Sstevel@tonic-gate for (i = 0; i < bn->len; i++) { 3657c478bd9Sstevel@tonic-gate word = bn->value[i]; 3668475e043SDan OpenSolaris Anderson for (j = 0; j < BIGNUM_WORDSIZE; j++) { 3678475e043SDan OpenSolaris Anderson kn[slen - BIGNUM_WORDSIZE * i - j - 1] = 3687c478bd9Sstevel@tonic-gate word & 0xff; 3698475e043SDan OpenSolaris Anderson word = word >> BITSINBYTE; 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate } 3728475e043SDan OpenSolaris Anderson for (i = 0; i < slen - BIGNUM_WORDSIZE * bn->len; i++) { 3737c478bd9Sstevel@tonic-gate kn[i] = 0; 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate int 3807c478bd9Sstevel@tonic-gate big_bitlength(BIGNUM *a) 3817c478bd9Sstevel@tonic-gate { 382b60f2a0bSfr41279 int l = 0, b = 0; 383b60f2a0bSfr41279 BIG_CHUNK_TYPE c; 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate l = a->len - 1; 3867c478bd9Sstevel@tonic-gate while ((l > 0) && (a->value[l] == 0)) { 3877c478bd9Sstevel@tonic-gate l--; 3887c478bd9Sstevel@tonic-gate } 3898475e043SDan OpenSolaris Anderson b = BIG_CHUNK_SIZE; 3907c478bd9Sstevel@tonic-gate c = a->value[l]; 391b60f2a0bSfr41279 while ((b > 1) && ((c & BIG_CHUNK_HIGHBIT) == 0)) { 3927c478bd9Sstevel@tonic-gate c = c << 1; 3937c478bd9Sstevel@tonic-gate b--; 3947c478bd9Sstevel@tonic-gate } 395b60f2a0bSfr41279 3968475e043SDan OpenSolaris Anderson return (l * BIG_CHUNK_SIZE + b); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate 400*0a1ad920SDan OpenSolaris Anderson /* 401*0a1ad920SDan OpenSolaris Anderson * big_copy() 402*0a1ad920SDan OpenSolaris Anderson * Copy BIGNUM src to dest, allocating memory if needed. 403*0a1ad920SDan OpenSolaris Anderson */ 4047c478bd9Sstevel@tonic-gate BIG_ERR_CODE 4057c478bd9Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src) 4067c478bd9Sstevel@tonic-gate { 407b60f2a0bSfr41279 BIG_CHUNK_TYPE *newptr; 4087c478bd9Sstevel@tonic-gate int i, len; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate len = src->len; 411b60f2a0bSfr41279 while ((len > 1) && (src->value[len - 1] == 0)) { 4127c478bd9Sstevel@tonic-gate len--; 413b60f2a0bSfr41279 } 4147c478bd9Sstevel@tonic-gate src->len = len; 4157c478bd9Sstevel@tonic-gate if (dest->size < len) { 4167c478bd9Sstevel@tonic-gate if (dest->malloced == 1) { 417b60f2a0bSfr41279 newptr = (BIG_CHUNK_TYPE *)big_realloc(dest->value, 4188475e043SDan OpenSolaris Anderson BIGNUM_WORDSIZE * dest->size, 4198475e043SDan OpenSolaris Anderson BIGNUM_WORDSIZE * len); 4207c478bd9Sstevel@tonic-gate } else { 421b60f2a0bSfr41279 newptr = (BIG_CHUNK_TYPE *) 4228475e043SDan OpenSolaris Anderson big_malloc(BIGNUM_WORDSIZE * len); 423b60f2a0bSfr41279 if (newptr != NULL) { 424b60f2a0bSfr41279 dest->malloced = 1; 4257c478bd9Sstevel@tonic-gate } 426b60f2a0bSfr41279 } 427b60f2a0bSfr41279 if (newptr == NULL) { 4287c478bd9Sstevel@tonic-gate return (BIG_NO_MEM); 429b60f2a0bSfr41279 } 4307c478bd9Sstevel@tonic-gate dest->value = newptr; 4317c478bd9Sstevel@tonic-gate dest->size = len; 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate dest->len = len; 4347c478bd9Sstevel@tonic-gate dest->sign = src->sign; 435b60f2a0bSfr41279 for (i = 0; i < len; i++) { 436b60f2a0bSfr41279 dest->value[i] = src->value[i]; 437b60f2a0bSfr41279 } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate return (BIG_OK); 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate 443*0a1ad920SDan OpenSolaris Anderson /* 444*0a1ad920SDan OpenSolaris Anderson * big_extend() 445*0a1ad920SDan OpenSolaris Anderson * Allocate memory to extend BIGNUM number to size bignum chunks, 446*0a1ad920SDan OpenSolaris Anderson * if not at least that size already. 447*0a1ad920SDan OpenSolaris Anderson */ 4487c478bd9Sstevel@tonic-gate BIG_ERR_CODE 4497c478bd9Sstevel@tonic-gate big_extend(BIGNUM *number, int size) 4507c478bd9Sstevel@tonic-gate { 451b60f2a0bSfr41279 BIG_CHUNK_TYPE *newptr; 4527c478bd9Sstevel@tonic-gate int i; 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate if (number->size >= size) 4557c478bd9Sstevel@tonic-gate return (BIG_OK); 4567c478bd9Sstevel@tonic-gate if (number->malloced) { 457b60f2a0bSfr41279 number->value = big_realloc(number->value, 4588475e043SDan OpenSolaris Anderson BIGNUM_WORDSIZE * number->size, 4598475e043SDan OpenSolaris Anderson BIGNUM_WORDSIZE * size); 4607c478bd9Sstevel@tonic-gate } else { 4618475e043SDan OpenSolaris Anderson newptr = big_malloc(BIGNUM_WORDSIZE * size); 4627c478bd9Sstevel@tonic-gate if (newptr != NULL) { 4637c478bd9Sstevel@tonic-gate for (i = 0; i < number->size; i++) { 4647c478bd9Sstevel@tonic-gate newptr[i] = number->value[i]; 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate number->value = newptr; 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate 470b60f2a0bSfr41279 if (number->value == NULL) { 4717c478bd9Sstevel@tonic-gate return (BIG_NO_MEM); 472b60f2a0bSfr41279 } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate number->size = size; 4757c478bd9Sstevel@tonic-gate number->malloced = 1; 4767c478bd9Sstevel@tonic-gate return (BIG_OK); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate 480b60f2a0bSfr41279 /* returns 1 if n == 0 */ 4817c478bd9Sstevel@tonic-gate int 4827c478bd9Sstevel@tonic-gate big_is_zero(BIGNUM *n) 4837c478bd9Sstevel@tonic-gate { 4847c478bd9Sstevel@tonic-gate int i, result; 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate result = 1; 487b60f2a0bSfr41279 for (i = 0; i < n->len; i++) { 488b60f2a0bSfr41279 if (n->value[i] != 0) { 489b60f2a0bSfr41279 result = 0; 490b60f2a0bSfr41279 } 491b60f2a0bSfr41279 } 4927c478bd9Sstevel@tonic-gate return (result); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate BIG_ERR_CODE 4977c478bd9Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 4987c478bd9Sstevel@tonic-gate { 4997c478bd9Sstevel@tonic-gate int i, shorter, longer; 500b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, ai; 501b60f2a0bSfr41279 BIG_CHUNK_TYPE *r, *a, *b, *c; 5027c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 503b60f2a0bSfr41279 BIGNUM *longerarg; 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate if (aa->len > bb->len) { 5067c478bd9Sstevel@tonic-gate shorter = bb->len; 5077c478bd9Sstevel@tonic-gate longer = aa->len; 508b60f2a0bSfr41279 longerarg = aa; 5097c478bd9Sstevel@tonic-gate } else { 5107c478bd9Sstevel@tonic-gate shorter = aa->len; 5117c478bd9Sstevel@tonic-gate longer = bb->len; 512b60f2a0bSfr41279 longerarg = bb; 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate if (result->size < longer + 1) { 5157c478bd9Sstevel@tonic-gate err = big_extend(result, longer + 1); 516b60f2a0bSfr41279 if (err != BIG_OK) { 5177c478bd9Sstevel@tonic-gate return (err); 5187c478bd9Sstevel@tonic-gate } 519b60f2a0bSfr41279 } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate r = result->value; 5227c478bd9Sstevel@tonic-gate a = aa->value; 5237c478bd9Sstevel@tonic-gate b = bb->value; 524b60f2a0bSfr41279 c = longerarg->value; 5257c478bd9Sstevel@tonic-gate cy = 0; 5267c478bd9Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 5277c478bd9Sstevel@tonic-gate ai = a[i]; 5287c478bd9Sstevel@tonic-gate r[i] = ai + b[i] + cy; 529b60f2a0bSfr41279 if (r[i] > ai) { 530b60f2a0bSfr41279 cy = 0; 531b60f2a0bSfr41279 } else if (r[i] < ai) { 532b60f2a0bSfr41279 cy = 1; 533b60f2a0bSfr41279 } 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate for (; i < longer; i++) { 5367c478bd9Sstevel@tonic-gate ai = c[i]; 5377c478bd9Sstevel@tonic-gate r[i] = ai + cy; 538b60f2a0bSfr41279 if (r[i] >= ai) { 539b60f2a0bSfr41279 cy = 0; 540b60f2a0bSfr41279 } 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate if (cy == 1) { 5437c478bd9Sstevel@tonic-gate r[i] = cy; 5447c478bd9Sstevel@tonic-gate result->len = longer + 1; 5457c478bd9Sstevel@tonic-gate } else { 5467c478bd9Sstevel@tonic-gate result->len = longer; 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate result->sign = 1; 5497c478bd9Sstevel@tonic-gate return (BIG_OK); 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */ 5547c478bd9Sstevel@tonic-gate void 555b60f2a0bSfr41279 big_sub_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, BIG_CHUNK_TYPE *b, int len) 5567c478bd9Sstevel@tonic-gate { 5577c478bd9Sstevel@tonic-gate int i; 558b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, ai; 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate cy = 1; 5617c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) { 5627c478bd9Sstevel@tonic-gate ai = a[i]; 5637c478bd9Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 564b60f2a0bSfr41279 if (r[i] > ai) { 565b60f2a0bSfr41279 cy = 0; 566b60f2a0bSfr41279 } else if (r[i] < ai) { 567b60f2a0bSfr41279 cy = 1; 568b60f2a0bSfr41279 } 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate /* result=aa-bb it is assumed that aa>=bb */ 5747c478bd9Sstevel@tonic-gate BIG_ERR_CODE 5757c478bd9Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 5767c478bd9Sstevel@tonic-gate { 5777c478bd9Sstevel@tonic-gate int i, shorter; 578b60f2a0bSfr41279 BIG_CHUNK_TYPE cy = 1, ai; 579b60f2a0bSfr41279 BIG_CHUNK_TYPE *r, *a, *b; 580b60f2a0bSfr41279 BIG_ERR_CODE err = BIG_OK; 5817c478bd9Sstevel@tonic-gate 582b60f2a0bSfr41279 if (aa->len > bb->len) { 583b60f2a0bSfr41279 shorter = bb->len; 584b60f2a0bSfr41279 } else { 585b60f2a0bSfr41279 shorter = aa->len; 586b60f2a0bSfr41279 } 5877c478bd9Sstevel@tonic-gate if (result->size < aa->len) { 5887c478bd9Sstevel@tonic-gate err = big_extend(result, aa->len); 589b60f2a0bSfr41279 if (err != BIG_OK) { 5907c478bd9Sstevel@tonic-gate return (err); 5917c478bd9Sstevel@tonic-gate } 592b60f2a0bSfr41279 } 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate r = result->value; 5957c478bd9Sstevel@tonic-gate a = aa->value; 5967c478bd9Sstevel@tonic-gate b = bb->value; 5977c478bd9Sstevel@tonic-gate result->len = aa->len; 5987c478bd9Sstevel@tonic-gate cy = 1; 5997c478bd9Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 6007c478bd9Sstevel@tonic-gate ai = a[i]; 6017c478bd9Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 602b60f2a0bSfr41279 if (r[i] > ai) { 603b60f2a0bSfr41279 cy = 0; 604b60f2a0bSfr41279 } else if (r[i] < ai) { 605b60f2a0bSfr41279 cy = 1; 606b60f2a0bSfr41279 } 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate for (; i < aa->len; i++) { 6097c478bd9Sstevel@tonic-gate ai = a[i]; 6107c478bd9Sstevel@tonic-gate r[i] = ai + (~0) + cy; 611b60f2a0bSfr41279 if (r[i] < ai) { 612b60f2a0bSfr41279 cy = 1; 613b60f2a0bSfr41279 } 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate result->sign = 1; 616b60f2a0bSfr41279 617b60f2a0bSfr41279 if (cy == 0) { 6187c478bd9Sstevel@tonic-gate return (BIG_INVALID_ARGS); 619b60f2a0bSfr41279 } else { 6207c478bd9Sstevel@tonic-gate return (BIG_OK); 6217c478bd9Sstevel@tonic-gate } 622b60f2a0bSfr41279 } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */ 6267c478bd9Sstevel@tonic-gate int 6277c478bd9Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb) 6287c478bd9Sstevel@tonic-gate { 6297c478bd9Sstevel@tonic-gate int i; 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate if (aa->len > bb->len) { 6327c478bd9Sstevel@tonic-gate for (i = aa->len - 1; i > bb->len - 1; i--) { 633b60f2a0bSfr41279 if (aa->value[i] > 0) { 6347c478bd9Sstevel@tonic-gate return (1); 6357c478bd9Sstevel@tonic-gate } 636b60f2a0bSfr41279 } 6377c478bd9Sstevel@tonic-gate } else if (aa->len < bb->len) { 6387c478bd9Sstevel@tonic-gate for (i = bb->len - 1; i > aa->len - 1; i--) { 639b60f2a0bSfr41279 if (bb->value[i] > 0) { 6407c478bd9Sstevel@tonic-gate return (-1); 6417c478bd9Sstevel@tonic-gate } 642b60f2a0bSfr41279 } 643b60f2a0bSfr41279 } else { 644b60f2a0bSfr41279 i = aa->len - 1; 645b60f2a0bSfr41279 } 6467c478bd9Sstevel@tonic-gate for (; i >= 0; i--) { 647b60f2a0bSfr41279 if (aa->value[i] > bb->value[i]) { 6487c478bd9Sstevel@tonic-gate return (1); 649b60f2a0bSfr41279 } else if (aa->value[i] < bb->value[i]) { 6507c478bd9Sstevel@tonic-gate return (-1); 6517c478bd9Sstevel@tonic-gate } 652b60f2a0bSfr41279 } 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate return (0); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate BIG_ERR_CODE 6597c478bd9Sstevel@tonic-gate big_sub(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 7027c478bd9Sstevel@tonic-gate BIG_ERR_CODE 7037c478bd9Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 7047c478bd9Sstevel@tonic-gate { 7057c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate if ((bb->sign == -1) && (aa->sign == -1)) { 708b60f2a0bSfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 7097c478bd9Sstevel@tonic-gate return (err); 710b60f2a0bSfr41279 } 7117c478bd9Sstevel@tonic-gate result->sign = -1; 7127c478bd9Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == 1)) { 713b60f2a0bSfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 7147c478bd9Sstevel@tonic-gate return (err); 715b60f2a0bSfr41279 } 7167c478bd9Sstevel@tonic-gate result->sign = 1; 7177c478bd9Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == -1)) { 7187c478bd9Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 719b60f2a0bSfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 7207c478bd9Sstevel@tonic-gate return (err); 721b60f2a0bSfr41279 } 7227c478bd9Sstevel@tonic-gate result->sign = 1; 7237c478bd9Sstevel@tonic-gate } else { 724b60f2a0bSfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 7257c478bd9Sstevel@tonic-gate return (err); 726b60f2a0bSfr41279 } 7277c478bd9Sstevel@tonic-gate result->sign = -1; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate } else { 7307c478bd9Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 731b60f2a0bSfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 7327c478bd9Sstevel@tonic-gate return (err); 733b60f2a0bSfr41279 } 7347c478bd9Sstevel@tonic-gate result->sign = -1; 7357c478bd9Sstevel@tonic-gate } else { 736b60f2a0bSfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 7377c478bd9Sstevel@tonic-gate return (err); 738b60f2a0bSfr41279 } 7397c478bd9Sstevel@tonic-gate result->sign = 1; 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate return (BIG_OK); 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate 746b60f2a0bSfr41279 /* result = aa/2 */ 7477c478bd9Sstevel@tonic-gate BIG_ERR_CODE 7487c478bd9Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa) 7497c478bd9Sstevel@tonic-gate { 7507c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 7517c478bd9Sstevel@tonic-gate int i; 752b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, cy1; 753b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *r; 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate if (result->size < aa->len) { 7567c478bd9Sstevel@tonic-gate err = big_extend(result, aa->len); 757b60f2a0bSfr41279 if (err != BIG_OK) { 7587c478bd9Sstevel@tonic-gate return (err); 7597c478bd9Sstevel@tonic-gate } 760b60f2a0bSfr41279 } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate result->len = aa->len; 7637c478bd9Sstevel@tonic-gate a = aa->value; 7647c478bd9Sstevel@tonic-gate r = result->value; 7657c478bd9Sstevel@tonic-gate cy = 0; 7667c478bd9Sstevel@tonic-gate for (i = aa->len - 1; i >= 0; i--) { 767b60f2a0bSfr41279 cy1 = a[i] << (BIG_CHUNK_SIZE - 1); 7687c478bd9Sstevel@tonic-gate r[i] = (cy | (a[i] >> 1)); 7697c478bd9Sstevel@tonic-gate cy = cy1; 7707c478bd9Sstevel@tonic-gate } 771b60f2a0bSfr41279 if (r[result->len - 1] == 0) { 772b60f2a0bSfr41279 result->len--; 773b60f2a0bSfr41279 } 774b60f2a0bSfr41279 7757c478bd9Sstevel@tonic-gate return (BIG_OK); 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 778b60f2a0bSfr41279 /* result = aa*2 */ 7797c478bd9Sstevel@tonic-gate BIG_ERR_CODE 7807c478bd9Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa) 7817c478bd9Sstevel@tonic-gate { 7827c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 7837c478bd9Sstevel@tonic-gate int i, rsize; 784b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, cy1; 785b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *r; 7867c478bd9Sstevel@tonic-gate 787b60f2a0bSfr41279 if ((aa->len > 0) && 788b60f2a0bSfr41279 ((aa->value[aa->len - 1] & BIG_CHUNK_HIGHBIT) != 0)) { 7897c478bd9Sstevel@tonic-gate rsize = aa->len + 1; 790b60f2a0bSfr41279 } else { 791b60f2a0bSfr41279 rsize = aa->len; 792b60f2a0bSfr41279 } 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate if (result->size < rsize) { 7957c478bd9Sstevel@tonic-gate err = big_extend(result, rsize); 7967c478bd9Sstevel@tonic-gate if (err != BIG_OK) 7977c478bd9Sstevel@tonic-gate return (err); 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate a = aa->value; 8017c478bd9Sstevel@tonic-gate r = result->value; 802b60f2a0bSfr41279 if (rsize == aa->len + 1) { 803b60f2a0bSfr41279 r[rsize - 1] = 1; 804b60f2a0bSfr41279 } 8057c478bd9Sstevel@tonic-gate cy = 0; 8067c478bd9Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 807b60f2a0bSfr41279 cy1 = a[i] >> (BIG_CHUNK_SIZE - 1); 8087c478bd9Sstevel@tonic-gate r[i] = (cy | (a[i] << 1)); 8097c478bd9Sstevel@tonic-gate cy = cy1; 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate result->len = rsize; 8127c478bd9Sstevel@tonic-gate return (BIG_OK); 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate 815b60f2a0bSfr41279 816b60f2a0bSfr41279 /* 817b60f2a0bSfr41279 * returns aa mod b, aa must be nonneg, b must be a max 818b60f2a0bSfr41279 * (BIG_CHUNK_SIZE / 2)-bit integer 819b60f2a0bSfr41279 */ 820b60f2a0bSfr41279 static uint32_t 821b60f2a0bSfr41279 big_modhalf_pos(BIGNUM *aa, uint32_t b) 8227c478bd9Sstevel@tonic-gate { 8237c478bd9Sstevel@tonic-gate int i; 824b60f2a0bSfr41279 BIG_CHUNK_TYPE rem; 8257c478bd9Sstevel@tonic-gate 826b60f2a0bSfr41279 if (aa->len == 0) { 8277c478bd9Sstevel@tonic-gate return (0); 828b60f2a0bSfr41279 } 8297c478bd9Sstevel@tonic-gate rem = aa->value[aa->len - 1] % b; 8307c478bd9Sstevel@tonic-gate for (i = aa->len - 2; i >= 0; i--) { 831b60f2a0bSfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 832b60f2a0bSfr41279 (aa->value[i] >> (BIG_CHUNK_SIZE / 2))) % b; 833b60f2a0bSfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 834b60f2a0bSfr41279 (aa->value[i] & BIG_CHUNK_LOWHALFBITS)) % b; 8357c478bd9Sstevel@tonic-gate } 836b60f2a0bSfr41279 837b60f2a0bSfr41279 return ((uint32_t)rem); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate /* 842b60f2a0bSfr41279 * result = aa - (2^BIG_CHUNK_SIZE)^lendiff * bb 8437c478bd9Sstevel@tonic-gate * result->size should be at least aa->len at entry 8447c478bd9Sstevel@tonic-gate * aa, bb, and result should be positive 8457c478bd9Sstevel@tonic-gate */ 8467c478bd9Sstevel@tonic-gate void 8477c478bd9Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 8487c478bd9Sstevel@tonic-gate { 8497c478bd9Sstevel@tonic-gate int i, lendiff; 8507c478bd9Sstevel@tonic-gate BIGNUM res1, aa1; 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate lendiff = aa->len - bb->len; 8537c478bd9Sstevel@tonic-gate res1.size = result->size - lendiff; 8547c478bd9Sstevel@tonic-gate res1.malloced = 0; 8557c478bd9Sstevel@tonic-gate res1.value = result->value + lendiff; 8567c478bd9Sstevel@tonic-gate aa1.size = aa->size - lendiff; 8577c478bd9Sstevel@tonic-gate aa1.value = aa->value + lendiff; 8587c478bd9Sstevel@tonic-gate aa1.len = bb->len; 8597c478bd9Sstevel@tonic-gate aa1.sign = 1; 8607c478bd9Sstevel@tonic-gate (void) big_sub_pos(&res1, &aa1, bb); 8617c478bd9Sstevel@tonic-gate if (result->value != aa->value) { 8627c478bd9Sstevel@tonic-gate for (i = 0; i < lendiff; i++) { 8637c478bd9Sstevel@tonic-gate result->value[i] = aa->value[i]; 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate result->len = aa->len; 8677c478bd9Sstevel@tonic-gate } 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate /* 8717c478bd9Sstevel@tonic-gate * returns 1, 0, or -1 depending on whether |aa| > , ==, or < 872b60f2a0bSfr41279 * (2^BIG_CHUNK_SIZE)^lendiff * |bb| 8737c478bd9Sstevel@tonic-gate * aa->len should be >= bb->len 8747c478bd9Sstevel@tonic-gate */ 8757c478bd9Sstevel@tonic-gate int 8767c478bd9Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb) 8777c478bd9Sstevel@tonic-gate { 8787c478bd9Sstevel@tonic-gate int lendiff; 8797c478bd9Sstevel@tonic-gate BIGNUM aa1; 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate lendiff = aa->len - bb->len; 8827c478bd9Sstevel@tonic-gate aa1.len = bb->len; 8837c478bd9Sstevel@tonic-gate aa1.size = aa->size - lendiff; 8847c478bd9Sstevel@tonic-gate aa1.malloced = 0; 8857c478bd9Sstevel@tonic-gate aa1.value = aa->value + lendiff; 8867c478bd9Sstevel@tonic-gate return (big_cmp_abs(&aa1, bb)); 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate /* 891b60f2a0bSfr41279 * result = aa * b where b is a max. (BIG_CHUNK_SIZE / 2)-bit positive integer. 8927c478bd9Sstevel@tonic-gate * result should have enough space allocated. 8937c478bd9Sstevel@tonic-gate */ 894b60f2a0bSfr41279 static void 895b60f2a0bSfr41279 big_mulhalf_low(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 8967c478bd9Sstevel@tonic-gate { 8977c478bd9Sstevel@tonic-gate int i; 898b60f2a0bSfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy; 899b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *r; 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate a = aa->value; 9027c478bd9Sstevel@tonic-gate r = result->value; 9037c478bd9Sstevel@tonic-gate cy = 0; 9047c478bd9Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 9057c478bd9Sstevel@tonic-gate ai = a[i]; 906b60f2a0bSfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 907b60f2a0bSfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 908b60f2a0bSfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 909b60f2a0bSfr41279 r[i] = (t1 & BIG_CHUNK_LOWHALFBITS) | 910b60f2a0bSfr41279 (t2 << (BIG_CHUNK_SIZE / 2)); 911b60f2a0bSfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate r[i] = cy; 9147c478bd9Sstevel@tonic-gate result->len = aa->len + 1; 9157c478bd9Sstevel@tonic-gate result->sign = aa->sign; 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate /* 920b60f2a0bSfr41279 * result = aa * b * 2^(BIG_CHUNK_SIZE / 2) where b is a max. 921b60f2a0bSfr41279 * (BIG_CHUNK_SIZE / 2)-bit positive integer. 9227c478bd9Sstevel@tonic-gate * result should have enough space allocated. 9237c478bd9Sstevel@tonic-gate */ 924b60f2a0bSfr41279 static void 925b60f2a0bSfr41279 big_mulhalf_high(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 9267c478bd9Sstevel@tonic-gate { 9277c478bd9Sstevel@tonic-gate int i; 928b60f2a0bSfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy, ri; 929b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *r; 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate a = aa->value; 9327c478bd9Sstevel@tonic-gate r = result->value; 9337c478bd9Sstevel@tonic-gate cy = 0; 9347c478bd9Sstevel@tonic-gate ri = 0; 9357c478bd9Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 9367c478bd9Sstevel@tonic-gate ai = a[i]; 937b60f2a0bSfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 938b60f2a0bSfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 939b60f2a0bSfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 940b60f2a0bSfr41279 r[i] = (t1 << (BIG_CHUNK_SIZE / 2)) + ri; 941b60f2a0bSfr41279 ri = t2 & BIG_CHUNK_LOWHALFBITS; 942b60f2a0bSfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 9437c478bd9Sstevel@tonic-gate } 944b60f2a0bSfr41279 r[i] = (cy << (BIG_CHUNK_SIZE / 2)) + ri; 9457c478bd9Sstevel@tonic-gate result->len = aa->len + 1; 9467c478bd9Sstevel@tonic-gate result->sign = aa->sign; 9477c478bd9Sstevel@tonic-gate } 9487c478bd9Sstevel@tonic-gate 949b60f2a0bSfr41279 9507c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 9517c478bd9Sstevel@tonic-gate void 9527c478bd9Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs) 9537c478bd9Sstevel@tonic-gate { 9547c478bd9Sstevel@tonic-gate int i; 955b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, ai; 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate if (offs == 0) { 9587c478bd9Sstevel@tonic-gate if (result != aa) { 9597c478bd9Sstevel@tonic-gate (void) big_copy(result, aa); 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate return; 9627c478bd9Sstevel@tonic-gate } 9637c478bd9Sstevel@tonic-gate cy = 0; 9647c478bd9Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 9657c478bd9Sstevel@tonic-gate ai = aa->value[i]; 9667c478bd9Sstevel@tonic-gate result->value[i] = (ai << offs) | cy; 967b60f2a0bSfr41279 cy = ai >> (BIG_CHUNK_SIZE - offs); 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate if (cy != 0) { 9707c478bd9Sstevel@tonic-gate result->len = aa->len + 1; 9717c478bd9Sstevel@tonic-gate result->value[result->len - 1] = cy; 9727c478bd9Sstevel@tonic-gate } else { 9737c478bd9Sstevel@tonic-gate result->len = aa->len; 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate result->sign = aa->sign; 9767c478bd9Sstevel@tonic-gate } 9777c478bd9Sstevel@tonic-gate 978b60f2a0bSfr41279 9797c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 9807c478bd9Sstevel@tonic-gate void 9817c478bd9Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs) 9827c478bd9Sstevel@tonic-gate { 9837c478bd9Sstevel@tonic-gate int i; 984b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, ai; 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate if (offs == 0) { 9877c478bd9Sstevel@tonic-gate if (result != aa) { 9887c478bd9Sstevel@tonic-gate (void) big_copy(result, aa); 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate return; 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate cy = aa->value[0] >> offs; 9937c478bd9Sstevel@tonic-gate for (i = 1; i < aa->len; i++) { 9947c478bd9Sstevel@tonic-gate ai = aa->value[i]; 995b60f2a0bSfr41279 result->value[i - 1] = (ai << (BIG_CHUNK_SIZE - offs)) | cy; 9967c478bd9Sstevel@tonic-gate cy = ai >> offs; 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate result->len = aa->len; 9997c478bd9Sstevel@tonic-gate result->value[result->len - 1] = cy; 10007c478bd9Sstevel@tonic-gate result->sign = aa->sign; 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /* 10057c478bd9Sstevel@tonic-gate * result = aa/bb remainder = aa mod bb 10067c478bd9Sstevel@tonic-gate * it is assumed that aa and bb are positive 10077c478bd9Sstevel@tonic-gate */ 10087c478bd9Sstevel@tonic-gate BIG_ERR_CODE 10098475e043SDan OpenSolaris Anderson big_div_pos(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb) 10107c478bd9Sstevel@tonic-gate { 1011b60f2a0bSfr41279 BIG_ERR_CODE err = BIG_OK; 10127c478bd9Sstevel@tonic-gate int i, alen, blen, tlen, rlen, offs; 1013b60f2a0bSfr41279 BIG_CHUNK_TYPE higha, highb, coeff; 1014b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *b; 10157c478bd9Sstevel@tonic-gate BIGNUM bbhigh, bblow, tresult, tmp1, tmp2; 1016b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 1017b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 1018b60f2a0bSfr41279 BIG_CHUNK_TYPE tresultvalue[BIGTMPSIZE]; 1019b60f2a0bSfr41279 BIG_CHUNK_TYPE bblowvalue[BIGTMPSIZE]; 1020b60f2a0bSfr41279 BIG_CHUNK_TYPE bbhighvalue[BIGTMPSIZE]; 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate a = aa->value; 10237c478bd9Sstevel@tonic-gate b = bb->value; 10247c478bd9Sstevel@tonic-gate alen = aa->len; 10257c478bd9Sstevel@tonic-gate blen = bb->len; 1026b60f2a0bSfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 1027b60f2a0bSfr41279 alen = alen - 1; 1028b60f2a0bSfr41279 } 10297c478bd9Sstevel@tonic-gate aa->len = alen; 1030b60f2a0bSfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 1031b60f2a0bSfr41279 blen = blen - 1; 1032b60f2a0bSfr41279 } 10337c478bd9Sstevel@tonic-gate bb->len = blen; 1034b60f2a0bSfr41279 if ((blen == 1) && (b[0] == 0)) { 10357c478bd9Sstevel@tonic-gate return (BIG_DIV_BY_0); 1036b60f2a0bSfr41279 } 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate if (big_cmp_abs(aa, bb) < 0) { 10397c478bd9Sstevel@tonic-gate if ((remainder != NULL) && 1040b60f2a0bSfr41279 ((err = big_copy(remainder, aa)) != BIG_OK)) { 10417c478bd9Sstevel@tonic-gate return (err); 1042b60f2a0bSfr41279 } 10437c478bd9Sstevel@tonic-gate if (result != NULL) { 10447c478bd9Sstevel@tonic-gate result->len = 1; 10457c478bd9Sstevel@tonic-gate result->sign = 1; 10467c478bd9Sstevel@tonic-gate result->value[0] = 0; 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate return (BIG_OK); 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate if ((err = big_init1(&bblow, blen + 1, 10527c478bd9Sstevel@tonic-gate bblowvalue, arraysize(bblowvalue))) != BIG_OK) 10537c478bd9Sstevel@tonic-gate return (err); 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate if ((err = big_init1(&bbhigh, blen + 1, 10567c478bd9Sstevel@tonic-gate bbhighvalue, arraysize(bbhighvalue))) != BIG_OK) 10577c478bd9Sstevel@tonic-gate goto ret1; 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp1, alen + 2, 10607c478bd9Sstevel@tonic-gate tmp1value, arraysize(tmp1value))) != BIG_OK) 10617c478bd9Sstevel@tonic-gate goto ret2; 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp2, blen + 2, 10647c478bd9Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 10657c478bd9Sstevel@tonic-gate goto ret3; 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate if ((err = big_init1(&tresult, alen - blen + 2, 10687c478bd9Sstevel@tonic-gate tresultvalue, arraysize(tresultvalue))) != BIG_OK) 10697c478bd9Sstevel@tonic-gate goto ret4; 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate offs = 0; 1072b60f2a0bSfr41279 highb = b[blen - 1]; 1073b60f2a0bSfr41279 if (highb >= (BIG_CHUNK_HALF_HIGHBIT << 1)) { 1074b60f2a0bSfr41279 highb = highb >> (BIG_CHUNK_SIZE / 2); 1075b60f2a0bSfr41279 offs = (BIG_CHUNK_SIZE / 2); 10767c478bd9Sstevel@tonic-gate } 1077b60f2a0bSfr41279 while ((highb & BIG_CHUNK_HALF_HIGHBIT) == 0) { 1078b60f2a0bSfr41279 highb = highb << 1; 10797c478bd9Sstevel@tonic-gate offs++; 10807c478bd9Sstevel@tonic-gate } 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate big_shiftleft(&bblow, bb, offs); 1083b60f2a0bSfr41279 1084b60f2a0bSfr41279 if (offs <= (BIG_CHUNK_SIZE / 2 - 1)) { 1085b60f2a0bSfr41279 big_shiftleft(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10867c478bd9Sstevel@tonic-gate } else { 1087b60f2a0bSfr41279 big_shiftright(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate if (bbhigh.value[bbhigh.len - 1] == 0) { 10907c478bd9Sstevel@tonic-gate bbhigh.len--; 10917c478bd9Sstevel@tonic-gate } else { 10927c478bd9Sstevel@tonic-gate bbhigh.value[bbhigh.len] = 0; 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate 1095b60f2a0bSfr41279 highb = bblow.value[bblow.len - 1]; 1096b60f2a0bSfr41279 10977c478bd9Sstevel@tonic-gate big_shiftleft(&tmp1, aa, offs); 10987c478bd9Sstevel@tonic-gate rlen = tmp1.len - bblow.len + 1; 10997c478bd9Sstevel@tonic-gate tresult.len = rlen; 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate tmp1.len++; 11027c478bd9Sstevel@tonic-gate tlen = tmp1.len; 11037c478bd9Sstevel@tonic-gate tmp1.value[tmp1.len - 1] = 0; 11047c478bd9Sstevel@tonic-gate for (i = 0; i < rlen; i++) { 1105b60f2a0bSfr41279 higha = (tmp1.value[tlen - 1] << (BIG_CHUNK_SIZE / 2)) + 1106b60f2a0bSfr41279 (tmp1.value[tlen - 2] >> (BIG_CHUNK_SIZE / 2)); 11077c478bd9Sstevel@tonic-gate coeff = higha / (highb + 1); 1108b60f2a0bSfr41279 big_mulhalf_high(&tmp2, &bblow, coeff); 11097c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 11107c478bd9Sstevel@tonic-gate bbhigh.len++; 11117c478bd9Sstevel@tonic-gate while (tmp1.value[tlen - 1] > 0) { 11127c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 11137c478bd9Sstevel@tonic-gate coeff++; 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate bbhigh.len--; 11167c478bd9Sstevel@tonic-gate tlen--; 11177c478bd9Sstevel@tonic-gate tmp1.len--; 11187c478bd9Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) { 11197c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 11207c478bd9Sstevel@tonic-gate coeff++; 11217c478bd9Sstevel@tonic-gate } 1122b60f2a0bSfr41279 tresult.value[rlen - i - 1] = coeff << (BIG_CHUNK_SIZE / 2); 11237c478bd9Sstevel@tonic-gate higha = tmp1.value[tlen - 1]; 11247c478bd9Sstevel@tonic-gate coeff = higha / (highb + 1); 1125b60f2a0bSfr41279 big_mulhalf_low(&tmp2, &bblow, coeff); 11267c478bd9Sstevel@tonic-gate tmp2.len--; 11277c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 11287c478bd9Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bblow) >= 0) { 11297c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bblow); 11307c478bd9Sstevel@tonic-gate coeff++; 11317c478bd9Sstevel@tonic-gate } 11327c478bd9Sstevel@tonic-gate tresult.value[rlen - i - 1] = 11337c478bd9Sstevel@tonic-gate tresult.value[rlen - i - 1] + coeff; 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate big_shiftright(&tmp1, &tmp1, offs); 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate err = BIG_OK; 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate if ((remainder != NULL) && 11417c478bd9Sstevel@tonic-gate ((err = big_copy(remainder, &tmp1)) != BIG_OK)) 11427c478bd9Sstevel@tonic-gate goto ret; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate if (result != NULL) 11457c478bd9Sstevel@tonic-gate err = big_copy(result, &tresult); 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate ret: 11487c478bd9Sstevel@tonic-gate big_finish(&tresult); 11497c478bd9Sstevel@tonic-gate ret4: 11507c478bd9Sstevel@tonic-gate big_finish(&tmp1); 11517c478bd9Sstevel@tonic-gate ret3: 11527c478bd9Sstevel@tonic-gate big_finish(&tmp2); 11537c478bd9Sstevel@tonic-gate ret2: 11547c478bd9Sstevel@tonic-gate big_finish(&bbhigh); 11557c478bd9Sstevel@tonic-gate ret1: 11567c478bd9Sstevel@tonic-gate big_finish(&bblow); 11577c478bd9Sstevel@tonic-gate return (err); 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate 11608475e043SDan OpenSolaris Anderson 11617c478bd9Sstevel@tonic-gate /* 11627c478bd9Sstevel@tonic-gate * If there is no processor-specific integer implementation of 11637c478bd9Sstevel@tonic-gate * the lower level multiply functions, then this code is provided 11647c478bd9Sstevel@tonic-gate * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and 11657c478bd9Sstevel@tonic-gate * big_sqr_vec(). 11667c478bd9Sstevel@tonic-gate * 11677c478bd9Sstevel@tonic-gate * There are two generic implementations. One that assumes that 11687c478bd9Sstevel@tonic-gate * there is hardware and C compiler support for a 32 x 32 --> 64 11697c478bd9Sstevel@tonic-gate * bit unsigned multiply, but otherwise is not specific to any 11707c478bd9Sstevel@tonic-gate * processor, platform, or ISA. 11717c478bd9Sstevel@tonic-gate * 11727c478bd9Sstevel@tonic-gate * The other makes very few assumptions about hardware capabilities. 11737c478bd9Sstevel@tonic-gate * It does not even assume that there is any implementation of a 11747c478bd9Sstevel@tonic-gate * 32 x 32 --> 64 bit multiply that is accessible to C code and 11757c478bd9Sstevel@tonic-gate * appropriate to use. It falls constructs 32 x 32 --> 64 bit 11767c478bd9Sstevel@tonic-gate * multiplies from 16 x 16 --> 32 bit multiplies. 11777c478bd9Sstevel@tonic-gate * 11787c478bd9Sstevel@tonic-gate */ 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate #if !defined(PSR_MUL) 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate #ifdef UMUL64 11837c478bd9Sstevel@tonic-gate 1184b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 1185b60f2a0bSfr41279 11867c478bd9Sstevel@tonic-gate #define UNROLL8 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_PREFETCH(R) \ 11897c478bd9Sstevel@tonic-gate p = pf * d; \ 11907c478bd9Sstevel@tonic-gate pf = (uint64_t)a[R + 1]; \ 11917c478bd9Sstevel@tonic-gate t = p + cy; \ 11927c478bd9Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11937c478bd9Sstevel@tonic-gate cy = t >> 32 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_NOPREFETCH(R) \ 11967c478bd9Sstevel@tonic-gate p = pf * d; \ 11977c478bd9Sstevel@tonic-gate t = p + cy; \ 11987c478bd9Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11997c478bd9Sstevel@tonic-gate cy = t >> 32 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_PREFETCH(R) \ 12027c478bd9Sstevel@tonic-gate t = (uint64_t)r[R]; \ 12037c478bd9Sstevel@tonic-gate p = pf * d; \ 12047c478bd9Sstevel@tonic-gate pf = (uint64_t)a[R + 1]; \ 12057c478bd9Sstevel@tonic-gate t = p + t + cy; \ 12067c478bd9Sstevel@tonic-gate r[R] = (uint32_t)t; \ 12077c478bd9Sstevel@tonic-gate cy = t >> 32 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_NOPREFETCH(R) \ 12107c478bd9Sstevel@tonic-gate t = (uint64_t)r[R]; \ 12117c478bd9Sstevel@tonic-gate p = pf * d; \ 12127c478bd9Sstevel@tonic-gate t = p + t + cy; \ 12137c478bd9Sstevel@tonic-gate r[R] = (uint32_t)t; \ 12147c478bd9Sstevel@tonic-gate cy = t >> 32 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate #ifdef UNROLL8 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate #define UNROLL 8 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate /* 12217c478bd9Sstevel@tonic-gate * r = a * b 12227c478bd9Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 12237c478bd9Sstevel@tonic-gate */ 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate uint32_t 12267c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 12277c478bd9Sstevel@tonic-gate { 12287c478bd9Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate if (len == 0) 12317c478bd9Sstevel@tonic-gate return (0); 12327c478bd9Sstevel@tonic-gate cy = 0; 12337c478bd9Sstevel@tonic-gate d = (uint64_t)b; 12347c478bd9Sstevel@tonic-gate pf = (uint64_t)a[0]; 12357c478bd9Sstevel@tonic-gate while (len > UNROLL) { 12367c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 12377c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 12387c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 12397c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 12407c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 12417c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 12427c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 12437c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(7); 12447c478bd9Sstevel@tonic-gate r += UNROLL; 12457c478bd9Sstevel@tonic-gate a += UNROLL; 12467c478bd9Sstevel@tonic-gate len -= UNROLL; 12477c478bd9Sstevel@tonic-gate } 12487c478bd9Sstevel@tonic-gate if (len == UNROLL) { 12497c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 12507c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 12517c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 12527c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 12537c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 12547c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 12557c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 12567c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(7); 12577c478bd9Sstevel@tonic-gate return ((uint32_t)cy); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate while (len > 1) { 12607c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 12617c478bd9Sstevel@tonic-gate ++r; 12627c478bd9Sstevel@tonic-gate ++a; 12637c478bd9Sstevel@tonic-gate --len; 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate if (len > 0) { 12667c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(0); 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate return ((uint32_t)cy); 12697c478bd9Sstevel@tonic-gate } 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate /* 12727c478bd9Sstevel@tonic-gate * r += a * b 12737c478bd9Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 12747c478bd9Sstevel@tonic-gate */ 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate uint32_t 12777c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 12787c478bd9Sstevel@tonic-gate { 12797c478bd9Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate if (len == 0) 12827c478bd9Sstevel@tonic-gate return (0); 12837c478bd9Sstevel@tonic-gate cy = 0; 12847c478bd9Sstevel@tonic-gate d = (uint64_t)b; 12857c478bd9Sstevel@tonic-gate pf = (uint64_t)a[0]; 12867c478bd9Sstevel@tonic-gate while (len > 8) { 12877c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12887c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 12897c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 12907c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 12917c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 12927c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 12937c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 12947c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(7); 12957c478bd9Sstevel@tonic-gate r += 8; 12967c478bd9Sstevel@tonic-gate a += 8; 12977c478bd9Sstevel@tonic-gate len -= 8; 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate if (len == 8) { 13007c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 13017c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 13027c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 13037c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 13047c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 13057c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 13067c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 13077c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(7); 13087c478bd9Sstevel@tonic-gate return ((uint32_t)cy); 13097c478bd9Sstevel@tonic-gate } 13107c478bd9Sstevel@tonic-gate while (len > 1) { 13117c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 13127c478bd9Sstevel@tonic-gate ++r; 13137c478bd9Sstevel@tonic-gate ++a; 13147c478bd9Sstevel@tonic-gate --len; 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate if (len > 0) { 13177c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(0); 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate return ((uint32_t)cy); 13207c478bd9Sstevel@tonic-gate } 13217c478bd9Sstevel@tonic-gate #endif /* UNROLL8 */ 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate void 13247c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 13257c478bd9Sstevel@tonic-gate { 13267c478bd9Sstevel@tonic-gate uint32_t *tr, *ta; 13277c478bd9Sstevel@tonic-gate int tlen, row, col; 13287c478bd9Sstevel@tonic-gate uint64_t p, s, t, t2, cy; 13297c478bd9Sstevel@tonic-gate uint32_t d; 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate tr = r + 1; 13327c478bd9Sstevel@tonic-gate ta = a; 13337c478bd9Sstevel@tonic-gate tlen = len - 1; 13347c478bd9Sstevel@tonic-gate tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]); 13357c478bd9Sstevel@tonic-gate while (--tlen > 0) { 13367c478bd9Sstevel@tonic-gate tr += 2; 13377c478bd9Sstevel@tonic-gate ++ta; 13387c478bd9Sstevel@tonic-gate tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]); 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate s = (uint64_t)a[0]; 13417c478bd9Sstevel@tonic-gate s = s * s; 13427c478bd9Sstevel@tonic-gate r[0] = (uint32_t)s; 13437c478bd9Sstevel@tonic-gate cy = s >> 32; 13447c478bd9Sstevel@tonic-gate p = ((uint64_t)r[1] << 1) + cy; 13457c478bd9Sstevel@tonic-gate r[1] = (uint32_t)p; 13467c478bd9Sstevel@tonic-gate cy = p >> 32; 13477c478bd9Sstevel@tonic-gate row = 1; 13487c478bd9Sstevel@tonic-gate col = 2; 13497c478bd9Sstevel@tonic-gate while (row < len) { 13507c478bd9Sstevel@tonic-gate s = (uint64_t)a[row]; 13517c478bd9Sstevel@tonic-gate s = s * s; 13527c478bd9Sstevel@tonic-gate p = (uint64_t)r[col] << 1; 13537c478bd9Sstevel@tonic-gate t = p + s; 13547c478bd9Sstevel@tonic-gate d = (uint32_t)t; 13557c478bd9Sstevel@tonic-gate t2 = (uint64_t)d + cy; 13567c478bd9Sstevel@tonic-gate r[col] = (uint32_t)t2; 13577c478bd9Sstevel@tonic-gate cy = (t >> 32) + (t2 >> 32); 13587c478bd9Sstevel@tonic-gate if (row == len - 1) 13597c478bd9Sstevel@tonic-gate break; 13607c478bd9Sstevel@tonic-gate p = ((uint64_t)r[col + 1] << 1) + cy; 13617c478bd9Sstevel@tonic-gate r[col + 1] = (uint32_t)p; 13627c478bd9Sstevel@tonic-gate cy = p >> 32; 13637c478bd9Sstevel@tonic-gate ++row; 13647c478bd9Sstevel@tonic-gate col += 2; 13657c478bd9Sstevel@tonic-gate } 13667c478bd9Sstevel@tonic-gate r[col + 1] = (uint32_t)cy; 13677c478bd9Sstevel@tonic-gate } 13687c478bd9Sstevel@tonic-gate 1369b60f2a0bSfr41279 #else /* BIG_CHUNK_SIZE == 64 */ 1370b60f2a0bSfr41279 1371b60f2a0bSfr41279 /* 1372b60f2a0bSfr41279 * r = r + a * digit, r and a are vectors of length len 1373b60f2a0bSfr41279 * returns the carry digit 1374b60f2a0bSfr41279 */ 1375b60f2a0bSfr41279 BIG_CHUNK_TYPE 1376b60f2a0bSfr41279 big_mul_add_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 1377b60f2a0bSfr41279 BIG_CHUNK_TYPE digit) 1378b60f2a0bSfr41279 { 1379b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, cy1, retcy, dlow, dhigh; 1380b60f2a0bSfr41279 int i; 1381b60f2a0bSfr41279 1382b60f2a0bSfr41279 cy1 = 0; 1383b60f2a0bSfr41279 dlow = digit & BIG_CHUNK_LOWHALFBITS; 1384b60f2a0bSfr41279 dhigh = digit >> (BIG_CHUNK_SIZE / 2); 1385b60f2a0bSfr41279 for (i = 0; i < len; i++) { 1386b60f2a0bSfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 1387b60f2a0bSfr41279 dlow * (a[i] & BIG_CHUNK_LOWHALFBITS) + 1388b60f2a0bSfr41279 (r[i] & BIG_CHUNK_LOWHALFBITS); 1389b60f2a0bSfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 1390b60f2a0bSfr41279 dlow * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 1391b60f2a0bSfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 1392b60f2a0bSfr41279 r[i] = (cy & BIG_CHUNK_LOWHALFBITS) | 1393b60f2a0bSfr41279 (cy1 << (BIG_CHUNK_SIZE / 2)); 1394b60f2a0bSfr41279 } 1395b60f2a0bSfr41279 retcy = cy1 >> (BIG_CHUNK_SIZE / 2); 1396b60f2a0bSfr41279 1397b60f2a0bSfr41279 cy1 = r[0] & BIG_CHUNK_LOWHALFBITS; 1398b60f2a0bSfr41279 for (i = 0; i < len - 1; i++) { 1399b60f2a0bSfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 1400b60f2a0bSfr41279 dhigh * (a[i] & BIG_CHUNK_LOWHALFBITS) + 1401b60f2a0bSfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 1402b60f2a0bSfr41279 r[i] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 1403b60f2a0bSfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 1404b60f2a0bSfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 1405b60f2a0bSfr41279 dhigh * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 1406b60f2a0bSfr41279 (r[i + 1] & BIG_CHUNK_LOWHALFBITS); 1407b60f2a0bSfr41279 } 1408b60f2a0bSfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 1409b60f2a0bSfr41279 dhigh * (a[len - 1] & BIG_CHUNK_LOWHALFBITS) + 1410b60f2a0bSfr41279 (r[len - 1] >> (BIG_CHUNK_SIZE / 2)); 1411b60f2a0bSfr41279 r[len - 1] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 1412b60f2a0bSfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 1413b60f2a0bSfr41279 retcy = (cy >> (BIG_CHUNK_SIZE / 2)) + 1414b60f2a0bSfr41279 dhigh * (a[len - 1] >> (BIG_CHUNK_SIZE / 2)) + retcy; 1415b60f2a0bSfr41279 1416b60f2a0bSfr41279 return (retcy); 1417b60f2a0bSfr41279 } 1418b60f2a0bSfr41279 1419b60f2a0bSfr41279 1420b60f2a0bSfr41279 /* 1421b60f2a0bSfr41279 * r = a * digit, r and a are vectors of length len 1422b60f2a0bSfr41279 * returns the carry digit 1423b60f2a0bSfr41279 */ 1424b60f2a0bSfr41279 BIG_CHUNK_TYPE 1425b60f2a0bSfr41279 big_mul_set_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 1426b60f2a0bSfr41279 BIG_CHUNK_TYPE digit) 1427b60f2a0bSfr41279 { 1428b60f2a0bSfr41279 int i; 1429b60f2a0bSfr41279 1430b60f2a0bSfr41279 ASSERT(r != a); 1431b60f2a0bSfr41279 for (i = 0; i < len; i++) { 1432b60f2a0bSfr41279 r[i] = 0; 1433b60f2a0bSfr41279 } 1434b60f2a0bSfr41279 return (big_mul_add_vec(r, a, len, digit)); 1435b60f2a0bSfr41279 } 1436b60f2a0bSfr41279 1437b60f2a0bSfr41279 void 1438b60f2a0bSfr41279 big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len) 1439b60f2a0bSfr41279 { 1440b60f2a0bSfr41279 int i; 1441b60f2a0bSfr41279 1442b60f2a0bSfr41279 ASSERT(r != a); 1443b60f2a0bSfr41279 r[len] = big_mul_set_vec(r, a, len, a[0]); 1444b60f2a0bSfr41279 for (i = 1; i < len; ++i) 1445b60f2a0bSfr41279 r[len + i] = big_mul_add_vec(r + i, a, len, a[i]); 1446b60f2a0bSfr41279 } 1447b60f2a0bSfr41279 1448b60f2a0bSfr41279 #endif /* BIG_CHUNK_SIZE == 32/64 */ 1449b60f2a0bSfr41279 14508475e043SDan OpenSolaris Anderson 14517c478bd9Sstevel@tonic-gate #else /* ! UMUL64 */ 14527c478bd9Sstevel@tonic-gate 1453b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE != 32) 1454b60f2a0bSfr41279 #error Don't use 64-bit chunks without defining UMUL64 1455b60f2a0bSfr41279 #endif 1456b60f2a0bSfr41279 1457b60f2a0bSfr41279 14587c478bd9Sstevel@tonic-gate /* 14597c478bd9Sstevel@tonic-gate * r = r + a * digit, r and a are vectors of length len 14607c478bd9Sstevel@tonic-gate * returns the carry digit 14617c478bd9Sstevel@tonic-gate */ 14627c478bd9Sstevel@tonic-gate uint32_t 14637c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 14647c478bd9Sstevel@tonic-gate { 14657c478bd9Sstevel@tonic-gate uint32_t cy, cy1, retcy, dlow, dhigh; 14667c478bd9Sstevel@tonic-gate int i; 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate cy1 = 0; 14697c478bd9Sstevel@tonic-gate dlow = digit & 0xffff; 14707c478bd9Sstevel@tonic-gate dhigh = digit >> 16; 14717c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) { 14727c478bd9Sstevel@tonic-gate cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff); 14737c478bd9Sstevel@tonic-gate cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16); 14747c478bd9Sstevel@tonic-gate r[i] = (cy & 0xffff) | (cy1 << 16); 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate retcy = cy1 >> 16; 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate cy1 = r[0] & 0xffff; 14797c478bd9Sstevel@tonic-gate for (i = 0; i < len - 1; i++) { 14807c478bd9Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16); 14817c478bd9Sstevel@tonic-gate r[i] = (cy1 & 0xffff) | (cy << 16); 14827c478bd9Sstevel@tonic-gate cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff); 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16); 14857c478bd9Sstevel@tonic-gate r[len - 1] = (cy1 & 0xffff) | (cy << 16); 14867c478bd9Sstevel@tonic-gate retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy; 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate return (retcy); 14897c478bd9Sstevel@tonic-gate } 14907c478bd9Sstevel@tonic-gate 1491b60f2a0bSfr41279 14927c478bd9Sstevel@tonic-gate /* 14937c478bd9Sstevel@tonic-gate * r = a * digit, r and a are vectors of length len 14947c478bd9Sstevel@tonic-gate * returns the carry digit 14957c478bd9Sstevel@tonic-gate */ 14967c478bd9Sstevel@tonic-gate uint32_t 14977c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 14987c478bd9Sstevel@tonic-gate { 1499b60f2a0bSfr41279 int i; 1500b60f2a0bSfr41279 1501b60f2a0bSfr41279 ASSERT(r != a); 1502b60f2a0bSfr41279 for (i = 0; i < len; i++) { 1503b60f2a0bSfr41279 r[i] = 0; 1504b60f2a0bSfr41279 } 1505b60f2a0bSfr41279 15067c478bd9Sstevel@tonic-gate return (big_mul_add_vec(r, a, len, digit)); 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate void 15107c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 15117c478bd9Sstevel@tonic-gate { 15127c478bd9Sstevel@tonic-gate int i; 15137c478bd9Sstevel@tonic-gate 1514b60f2a0bSfr41279 ASSERT(r != a); 15157c478bd9Sstevel@tonic-gate r[len] = big_mul_set_vec(r, a, len, a[0]); 15167c478bd9Sstevel@tonic-gate for (i = 1; i < len; ++i) 15177c478bd9Sstevel@tonic-gate r[len + i] = big_mul_add_vec(r + i, a, len, a[i]); 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate #endif /* UMUL64 */ 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate void 1523b60f2a0bSfr41279 big_mul_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int alen, 1524b60f2a0bSfr41279 BIG_CHUNK_TYPE *b, int blen) 15257c478bd9Sstevel@tonic-gate { 15267c478bd9Sstevel@tonic-gate int i; 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate r[alen] = big_mul_set_vec(r, a, alen, b[0]); 15297c478bd9Sstevel@tonic-gate for (i = 1; i < blen; ++i) 15307c478bd9Sstevel@tonic-gate r[alen + i] = big_mul_add_vec(r + i, a, alen, b[i]); 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate #endif /* ! PSR_MUL */ 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate /* 15387c478bd9Sstevel@tonic-gate * result = aa * bb result->value should be big enough to hold the result 15397c478bd9Sstevel@tonic-gate * 15407c478bd9Sstevel@tonic-gate * Implementation: Standard grammar school algorithm 15417c478bd9Sstevel@tonic-gate * 15427c478bd9Sstevel@tonic-gate */ 15437c478bd9Sstevel@tonic-gate BIG_ERR_CODE 15447c478bd9Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 15457c478bd9Sstevel@tonic-gate { 15467c478bd9Sstevel@tonic-gate BIGNUM tmp1; 1547b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 1548b60f2a0bSfr41279 BIG_CHUNK_TYPE *r, *t, *a, *b; 15497c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 15507c478bd9Sstevel@tonic-gate int i, alen, blen, rsize, sign, diff; 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate if (aa == bb) { 15537c478bd9Sstevel@tonic-gate diff = 0; 15547c478bd9Sstevel@tonic-gate } else { 15557c478bd9Sstevel@tonic-gate diff = big_cmp_abs(aa, bb); 15567c478bd9Sstevel@tonic-gate if (diff < 0) { 15577c478bd9Sstevel@tonic-gate BIGNUM *tt; 15587c478bd9Sstevel@tonic-gate tt = aa; 15597c478bd9Sstevel@tonic-gate aa = bb; 15607c478bd9Sstevel@tonic-gate bb = tt; 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate } 15637c478bd9Sstevel@tonic-gate a = aa->value; 15647c478bd9Sstevel@tonic-gate b = bb->value; 15657c478bd9Sstevel@tonic-gate alen = aa->len; 15667c478bd9Sstevel@tonic-gate blen = bb->len; 1567b60f2a0bSfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 1568b60f2a0bSfr41279 alen--; 1569b60f2a0bSfr41279 } 15707c478bd9Sstevel@tonic-gate aa->len = alen; 1571b60f2a0bSfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 1572b60f2a0bSfr41279 blen--; 1573b60f2a0bSfr41279 } 15747c478bd9Sstevel@tonic-gate bb->len = blen; 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate rsize = alen + blen; 15778475e043SDan OpenSolaris Anderson ASSERT(rsize > 0); 15787c478bd9Sstevel@tonic-gate if (result->size < rsize) { 15797c478bd9Sstevel@tonic-gate err = big_extend(result, rsize); 1580b60f2a0bSfr41279 if (err != BIG_OK) { 15817c478bd9Sstevel@tonic-gate return (err); 1582b60f2a0bSfr41279 } 15837c478bd9Sstevel@tonic-gate /* aa or bb might be an alias to result */ 15847c478bd9Sstevel@tonic-gate a = aa->value; 15857c478bd9Sstevel@tonic-gate b = bb->value; 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate r = result->value; 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) { 15907c478bd9Sstevel@tonic-gate result->len = 1; 15917c478bd9Sstevel@tonic-gate result->sign = 1; 15927c478bd9Sstevel@tonic-gate r[0] = 0; 15937c478bd9Sstevel@tonic-gate return (BIG_OK); 15947c478bd9Sstevel@tonic-gate } 15957c478bd9Sstevel@tonic-gate sign = aa->sign * bb->sign; 15967c478bd9Sstevel@tonic-gate if ((alen == 1) && (a[0] == 1)) { 1597b60f2a0bSfr41279 for (i = 0; i < blen; i++) { 1598b60f2a0bSfr41279 r[i] = b[i]; 1599b60f2a0bSfr41279 } 16007c478bd9Sstevel@tonic-gate result->len = blen; 16017c478bd9Sstevel@tonic-gate result->sign = sign; 16027c478bd9Sstevel@tonic-gate return (BIG_OK); 16037c478bd9Sstevel@tonic-gate } 16047c478bd9Sstevel@tonic-gate if ((blen == 1) && (b[0] == 1)) { 1605b60f2a0bSfr41279 for (i = 0; i < alen; i++) { 1606b60f2a0bSfr41279 r[i] = a[i]; 1607b60f2a0bSfr41279 } 16087c478bd9Sstevel@tonic-gate result->len = alen; 16097c478bd9Sstevel@tonic-gate result->sign = sign; 16107c478bd9Sstevel@tonic-gate return (BIG_OK); 16117c478bd9Sstevel@tonic-gate } 16127c478bd9Sstevel@tonic-gate 1613b60f2a0bSfr41279 if ((err = big_init1(&tmp1, rsize, 1614b60f2a0bSfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 16157c478bd9Sstevel@tonic-gate return (err); 1616b60f2a0bSfr41279 } 16177c478bd9Sstevel@tonic-gate t = tmp1.value; 16187c478bd9Sstevel@tonic-gate 1619b60f2a0bSfr41279 for (i = 0; i < rsize; i++) { 1620b60f2a0bSfr41279 t[i] = 0; 1621b60f2a0bSfr41279 } 1622b60f2a0bSfr41279 1623b60f2a0bSfr41279 if (diff == 0 && alen > 2) { 16247c478bd9Sstevel@tonic-gate BIG_SQR_VEC(t, a, alen); 1625b60f2a0bSfr41279 } else if (blen > 0) { 16267c478bd9Sstevel@tonic-gate BIG_MUL_VEC(t, a, alen, b, blen); 1627b60f2a0bSfr41279 } 16287c478bd9Sstevel@tonic-gate 1629b60f2a0bSfr41279 if (t[rsize - 1] == 0) { 1630b60f2a0bSfr41279 tmp1.len = rsize - 1; 1631b60f2a0bSfr41279 } else { 1632b60f2a0bSfr41279 tmp1.len = rsize; 1633b60f2a0bSfr41279 } 16348475e043SDan OpenSolaris Anderson 16358475e043SDan OpenSolaris Anderson err = big_copy(result, &tmp1); 16368475e043SDan OpenSolaris Anderson 16377c478bd9Sstevel@tonic-gate result->sign = sign; 16387c478bd9Sstevel@tonic-gate 1639b60f2a0bSfr41279 big_finish(&tmp1); 16407c478bd9Sstevel@tonic-gate 16418475e043SDan OpenSolaris Anderson return (err); 16427c478bd9Sstevel@tonic-gate } 16437c478bd9Sstevel@tonic-gate 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate /* 1646*0a1ad920SDan OpenSolaris Anderson * big_mont_mul() 1647*0a1ad920SDan OpenSolaris Anderson * Montgomery multiplication. 1648*0a1ad920SDan OpenSolaris Anderson * 1649*0a1ad920SDan OpenSolaris Anderson * Caller must ensure that a < n, b < n, ret->size >= 2 * n->len + 1, 1650*0a1ad920SDan OpenSolaris Anderson * and that ret is not n. 16517c478bd9Sstevel@tonic-gate */ 16527c478bd9Sstevel@tonic-gate BIG_ERR_CODE 1653b60f2a0bSfr41279 big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, BIG_CHUNK_TYPE n0) 16547c478bd9Sstevel@tonic-gate { 16557c478bd9Sstevel@tonic-gate int i, j, nlen, needsubtract; 1656*0a1ad920SDan OpenSolaris Anderson BIG_CHUNK_TYPE *nn, *rr, *rrplusi; 1657b60f2a0bSfr41279 BIG_CHUNK_TYPE digit, c; 16587c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 1659*0a1ad920SDan OpenSolaris Anderson #ifdef __amd64 1660*0a1ad920SDan OpenSolaris Anderson #define BIG_CPU_UNKNOWN 0 1661*0a1ad920SDan OpenSolaris Anderson #define BIG_CPU_AMD 1 1662*0a1ad920SDan OpenSolaris Anderson #define BIG_CPU_INTEL 2 1663*0a1ad920SDan OpenSolaris Anderson static int big_cpu = BIG_CPU_UNKNOWN; 1664*0a1ad920SDan OpenSolaris Anderson BIG_CHUNK_TYPE carry[BIGTMPSIZE]; 1665*0a1ad920SDan OpenSolaris Anderson 1666*0a1ad920SDan OpenSolaris Anderson if (big_cpu == BIG_CPU_UNKNOWN) { 1667*0a1ad920SDan OpenSolaris Anderson big_cpu = 1 + bignum_on_intel(); 1668*0a1ad920SDan OpenSolaris Anderson } 1669*0a1ad920SDan OpenSolaris Anderson #endif /* __amd64 */ 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate nlen = n->len; 16727c478bd9Sstevel@tonic-gate nn = n->value; 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate rr = ret->value; 16757c478bd9Sstevel@tonic-gate 1676b60f2a0bSfr41279 if ((err = big_mul(ret, a, b)) != BIG_OK) { 16777c478bd9Sstevel@tonic-gate return (err); 1678b60f2a0bSfr41279 } 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate rr = ret->value; 1681b60f2a0bSfr41279 for (i = ret->len; i < 2 * nlen + 1; i++) { 1682b60f2a0bSfr41279 rr[i] = 0; 1683b60f2a0bSfr41279 } 16847c478bd9Sstevel@tonic-gate 1685*0a1ad920SDan OpenSolaris Anderson #ifdef __amd64 /* pipelining optimization for Intel 64, but not AMD64 */ 1686*0a1ad920SDan OpenSolaris Anderson if ((big_cpu == BIG_CPU_INTEL) && (nlen <= BIGTMPSIZE)) { 1687*0a1ad920SDan OpenSolaris Anderson /* 1688*0a1ad920SDan OpenSolaris Anderson * Perform the following in two for loops to reduce the 1689*0a1ad920SDan OpenSolaris Anderson * dependency between computing the carryover bits with 1690*0a1ad920SDan OpenSolaris Anderson * BIG_MUL_ADD_VEC() and adding them, thus improving pipelining. 1691*0a1ad920SDan OpenSolaris Anderson */ 1692*0a1ad920SDan OpenSolaris Anderson for (i = 0; i < nlen; i++) { 1693*0a1ad920SDan OpenSolaris Anderson rrplusi = rr + i; 1694*0a1ad920SDan OpenSolaris Anderson digit = *rrplusi * n0; 1695*0a1ad920SDan OpenSolaris Anderson carry[i] = BIG_MUL_ADD_VEC(rrplusi, nn, nlen, digit); 1696*0a1ad920SDan OpenSolaris Anderson } 1697*0a1ad920SDan OpenSolaris Anderson for (i = 0; i < nlen; i++) { 1698*0a1ad920SDan OpenSolaris Anderson j = i + nlen; 1699*0a1ad920SDan OpenSolaris Anderson rr[j] += carry[i]; 1700*0a1ad920SDan OpenSolaris Anderson while (rr[j] < carry[i]) { 1701*0a1ad920SDan OpenSolaris Anderson rr[++j] += 1; 1702*0a1ad920SDan OpenSolaris Anderson carry[i] = 1; 1703*0a1ad920SDan OpenSolaris Anderson } 1704*0a1ad920SDan OpenSolaris Anderson } 1705*0a1ad920SDan OpenSolaris Anderson } else 1706*0a1ad920SDan OpenSolaris Anderson #endif /* __amd64 */ 1707*0a1ad920SDan OpenSolaris Anderson { /* no pipelining optimization */ 1708*0a1ad920SDan OpenSolaris Anderson for (i = 0; i < nlen; i++) { 1709*0a1ad920SDan OpenSolaris Anderson rrplusi = rr + i; 1710*0a1ad920SDan OpenSolaris Anderson digit = *rrplusi * n0; 1711*0a1ad920SDan OpenSolaris Anderson c = BIG_MUL_ADD_VEC(rrplusi, nn, nlen, digit); 17127c478bd9Sstevel@tonic-gate j = i + nlen; 17137c478bd9Sstevel@tonic-gate rr[j] += c; 17147c478bd9Sstevel@tonic-gate while (rr[j] < c) { 1715*0a1ad920SDan OpenSolaris Anderson rr[++j] += 1; 17167c478bd9Sstevel@tonic-gate c = 1; 17177c478bd9Sstevel@tonic-gate } 17187c478bd9Sstevel@tonic-gate } 1719*0a1ad920SDan OpenSolaris Anderson } 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate needsubtract = 0; 17227c478bd9Sstevel@tonic-gate if ((rr[2 * nlen] != 0)) 17237c478bd9Sstevel@tonic-gate needsubtract = 1; 17247c478bd9Sstevel@tonic-gate else { 17257c478bd9Sstevel@tonic-gate for (i = 2 * nlen - 1; i >= nlen; i--) { 17267c478bd9Sstevel@tonic-gate if (rr[i] > nn[i - nlen]) { 17277c478bd9Sstevel@tonic-gate needsubtract = 1; 17287c478bd9Sstevel@tonic-gate break; 1729b60f2a0bSfr41279 } else if (rr[i] < nn[i - nlen]) { 1730b60f2a0bSfr41279 break; 1731b60f2a0bSfr41279 } 17327c478bd9Sstevel@tonic-gate } 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate if (needsubtract) 17357c478bd9Sstevel@tonic-gate big_sub_vec(rr, rr + nlen, nn, nlen); 17367c478bd9Sstevel@tonic-gate else { 1737b60f2a0bSfr41279 for (i = 0; i < nlen; i++) { 17387c478bd9Sstevel@tonic-gate rr[i] = rr[i + nlen]; 17397c478bd9Sstevel@tonic-gate } 1740b60f2a0bSfr41279 } 17418475e043SDan OpenSolaris Anderson 17428475e043SDan OpenSolaris Anderson /* Remove leading zeros, but keep at least 1 digit: */ 17438475e043SDan OpenSolaris Anderson for (i = nlen - 1; (i > 0) && (rr[i] == 0); i--) 1744b60f2a0bSfr41279 ; 17457c478bd9Sstevel@tonic-gate ret->len = i + 1; 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate return (BIG_OK); 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate 1750b60f2a0bSfr41279 1751b60f2a0bSfr41279 BIG_CHUNK_TYPE 1752b60f2a0bSfr41279 big_n0(BIG_CHUNK_TYPE n) 17537c478bd9Sstevel@tonic-gate { 17547c478bd9Sstevel@tonic-gate int i; 1755b60f2a0bSfr41279 BIG_CHUNK_TYPE result, tmp; 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate result = 0; 1758b60f2a0bSfr41279 tmp = BIG_CHUNK_ALLBITS; 1759b60f2a0bSfr41279 for (i = 0; i < BIG_CHUNK_SIZE; i++) { 17607c478bd9Sstevel@tonic-gate if ((tmp & 1) == 1) { 1761b60f2a0bSfr41279 result = (result >> 1) | BIG_CHUNK_HIGHBIT; 17627c478bd9Sstevel@tonic-gate tmp = tmp - n; 1763b60f2a0bSfr41279 } else { 1764b60f2a0bSfr41279 result = (result >> 1); 1765b60f2a0bSfr41279 } 17667c478bd9Sstevel@tonic-gate tmp = tmp >> 1; 17677c478bd9Sstevel@tonic-gate } 17687c478bd9Sstevel@tonic-gate 17697c478bd9Sstevel@tonic-gate return (result); 17707c478bd9Sstevel@tonic-gate } 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate int 17747c478bd9Sstevel@tonic-gate big_numbits(BIGNUM *n) 17757c478bd9Sstevel@tonic-gate { 17767c478bd9Sstevel@tonic-gate int i, j; 1777b60f2a0bSfr41279 BIG_CHUNK_TYPE t; 17787c478bd9Sstevel@tonic-gate 1779b60f2a0bSfr41279 for (i = n->len - 1; i > 0; i--) { 1780b60f2a0bSfr41279 if (n->value[i] != 0) { 1781b60f2a0bSfr41279 break; 1782b60f2a0bSfr41279 } 1783b60f2a0bSfr41279 } 17847c478bd9Sstevel@tonic-gate t = n->value[i]; 1785b60f2a0bSfr41279 for (j = BIG_CHUNK_SIZE; j > 0; j--) { 1786b60f2a0bSfr41279 if ((t & BIG_CHUNK_HIGHBIT) == 0) { 17877c478bd9Sstevel@tonic-gate t = t << 1; 1788b60f2a0bSfr41279 } else { 1789b60f2a0bSfr41279 return (BIG_CHUNK_SIZE * i + j); 1790b60f2a0bSfr41279 } 17917c478bd9Sstevel@tonic-gate } 17927c478bd9Sstevel@tonic-gate return (0); 17937c478bd9Sstevel@tonic-gate } 17947c478bd9Sstevel@tonic-gate 1795b60f2a0bSfr41279 17967c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */ 17977c478bd9Sstevel@tonic-gate BIG_ERR_CODE 17987c478bd9Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n) 17997c478bd9Sstevel@tonic-gate { 18007c478bd9Sstevel@tonic-gate BIGNUM rr; 1801b60f2a0bSfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 18027c478bd9Sstevel@tonic-gate int len, i; 18037c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate rr.malloced = 0; 18067c478bd9Sstevel@tonic-gate len = n->len; 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, 1809b60f2a0bSfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 18107c478bd9Sstevel@tonic-gate return (err); 18117c478bd9Sstevel@tonic-gate } 18127c478bd9Sstevel@tonic-gate 1813b60f2a0bSfr41279 for (i = 0; i < 2 * len; i++) { 1814b60f2a0bSfr41279 rr.value[i] = 0; 1815b60f2a0bSfr41279 } 1816b60f2a0bSfr41279 rr.value[2 * len] = 1; 1817b60f2a0bSfr41279 rr.len = 2 * len + 1; 1818b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 1819b60f2a0bSfr41279 goto ret; 1820b60f2a0bSfr41279 } 1821b60f2a0bSfr41279 err = big_copy(result, &rr); 1822b60f2a0bSfr41279 ret: 1823b60f2a0bSfr41279 big_finish(&rr); 1824b60f2a0bSfr41279 return (err); 1825b60f2a0bSfr41279 } 1826b60f2a0bSfr41279 1827b60f2a0bSfr41279 18287c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */ 18297c478bd9Sstevel@tonic-gate BIG_ERR_CODE 1830b60f2a0bSfr41279 big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, BIG_CHUNK_TYPE n0, 1831b60f2a0bSfr41279 BIGNUM *n_rr) 18327c478bd9Sstevel@tonic-gate { 18337c478bd9Sstevel@tonic-gate BIGNUM rr; 1834b60f2a0bSfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 18357c478bd9Sstevel@tonic-gate int len, i; 18367c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate rr.malloced = 0; 18397c478bd9Sstevel@tonic-gate len = n->len; 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue))) 1842b60f2a0bSfr41279 != BIG_OK) { 18437c478bd9Sstevel@tonic-gate return (err); 1844b60f2a0bSfr41279 } 18457c478bd9Sstevel@tonic-gate 18467c478bd9Sstevel@tonic-gate if (n_rr == NULL) { 1847b60f2a0bSfr41279 for (i = 0; i < 2 * len; i++) { 1848b60f2a0bSfr41279 rr.value[i] = 0; 1849b60f2a0bSfr41279 } 18507c478bd9Sstevel@tonic-gate rr.value[2 * len] = 1; 18517c478bd9Sstevel@tonic-gate rr.len = 2 * len + 1; 1852b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 18537c478bd9Sstevel@tonic-gate goto ret; 1854b60f2a0bSfr41279 } 18557c478bd9Sstevel@tonic-gate n_rr = &rr; 18567c478bd9Sstevel@tonic-gate } 18577c478bd9Sstevel@tonic-gate 1858b60f2a0bSfr41279 if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK) { 18597c478bd9Sstevel@tonic-gate goto ret; 1860b60f2a0bSfr41279 } 18617c478bd9Sstevel@tonic-gate err = big_copy(result, &rr); 1862b60f2a0bSfr41279 18637c478bd9Sstevel@tonic-gate ret: 1864b60f2a0bSfr41279 big_finish(&rr); 18657c478bd9Sstevel@tonic-gate return (err); 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate 1869b60f2a0bSfr41279 #ifdef USE_FLOATING_POINT 1870b60f2a0bSfr41279 #define big_modexp_ncp_float big_modexp_ncp_sw 1871b60f2a0bSfr41279 #else 1872b60f2a0bSfr41279 #define big_modexp_ncp_int big_modexp_ncp_sw 1873b60f2a0bSfr41279 #endif 1874b60f2a0bSfr41279 18757c478bd9Sstevel@tonic-gate #define MAX_EXP_BIT_GROUP_SIZE 6 18767c478bd9Sstevel@tonic-gate #define APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1)) 18777c478bd9Sstevel@tonic-gate 1878b60f2a0bSfr41279 /* ARGSUSED */ 18797c478bd9Sstevel@tonic-gate static BIG_ERR_CODE 1880b60f2a0bSfr41279 big_modexp_ncp_int(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 1881b60f2a0bSfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 1882b60f2a0bSfr41279 18837c478bd9Sstevel@tonic-gate { 1884b60f2a0bSfr41279 BIGNUM apowers[APOWERS_MAX_SIZE]; 1885b60f2a0bSfr41279 BIGNUM tmp1; 1886b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 1887b60f2a0bSfr41279 int i, j, k, l, m, p; 18888475e043SDan OpenSolaris Anderson uint32_t bit, bitind, bitcount, groupbits, apowerssize; 18898475e043SDan OpenSolaris Anderson uint32_t nbits; 18907c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate nbits = big_numbits(e); 18937c478bd9Sstevel@tonic-gate if (nbits < 50) { 18947c478bd9Sstevel@tonic-gate groupbits = 1; 18957c478bd9Sstevel@tonic-gate apowerssize = 1; 18967c478bd9Sstevel@tonic-gate } else { 18977c478bd9Sstevel@tonic-gate groupbits = MAX_EXP_BIT_GROUP_SIZE; 18987c478bd9Sstevel@tonic-gate apowerssize = 1 << (groupbits - 1); 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate 1901b60f2a0bSfr41279 1902b60f2a0bSfr41279 if ((err = big_init1(&tmp1, 2 * n->len + 1, 1903b60f2a0bSfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 19047c478bd9Sstevel@tonic-gate return (err); 19057c478bd9Sstevel@tonic-gate } 19067c478bd9Sstevel@tonic-gate 19078475e043SDan OpenSolaris Anderson /* clear the malloced bit to help cleanup */ 1908b60f2a0bSfr41279 for (i = 0; i < apowerssize; i++) { 1909b60f2a0bSfr41279 apowers[i].malloced = 0; 1910b60f2a0bSfr41279 } 19118475e043SDan OpenSolaris Anderson 1912b60f2a0bSfr41279 for (i = 0; i < apowerssize; i++) { 1913b60f2a0bSfr41279 if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) != 1914b60f2a0bSfr41279 BIG_OK) { 1915b60f2a0bSfr41279 goto ret; 1916b60f2a0bSfr41279 } 1917b60f2a0bSfr41279 } 19187c478bd9Sstevel@tonic-gate 1919b60f2a0bSfr41279 (void) big_copy(&(apowers[0]), ma); 1920b60f2a0bSfr41279 1921b60f2a0bSfr41279 if ((err = big_mont_mul(&tmp1, ma, ma, n, n0)) != BIG_OK) { 1922b60f2a0bSfr41279 goto ret; 1923b60f2a0bSfr41279 } 1924b60f2a0bSfr41279 (void) big_copy(ma, &tmp1); 1925b60f2a0bSfr41279 1926b60f2a0bSfr41279 for (i = 1; i < apowerssize; i++) { 1927b60f2a0bSfr41279 if ((err = big_mont_mul(&tmp1, ma, 1928b60f2a0bSfr41279 &(apowers[i - 1]), n, n0)) != BIG_OK) { 1929b60f2a0bSfr41279 goto ret; 1930b60f2a0bSfr41279 } 1931b60f2a0bSfr41279 (void) big_copy(&apowers[i], &tmp1); 1932b60f2a0bSfr41279 } 1933b60f2a0bSfr41279 1934b60f2a0bSfr41279 bitind = nbits % BIG_CHUNK_SIZE; 1935b60f2a0bSfr41279 k = 0; 1936b60f2a0bSfr41279 l = 0; 1937b60f2a0bSfr41279 p = 0; 1938b60f2a0bSfr41279 bitcount = 0; 1939b60f2a0bSfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 1940b60f2a0bSfr41279 for (j = bitind - 1; j >= 0; j--) { 1941b60f2a0bSfr41279 bit = (e->value[i] >> j) & 1; 1942b60f2a0bSfr41279 if ((bitcount == 0) && (bit == 0)) { 1943b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, 1944b60f2a0bSfr41279 tmp, tmp, n, n0)) != BIG_OK) { 1945b60f2a0bSfr41279 goto ret; 1946b60f2a0bSfr41279 } 19477c478bd9Sstevel@tonic-gate } else { 1948b60f2a0bSfr41279 bitcount++; 1949b60f2a0bSfr41279 p = p * 2 + bit; 1950b60f2a0bSfr41279 if (bit == 1) { 1951b60f2a0bSfr41279 k = k + l + 1; 1952b60f2a0bSfr41279 l = 0; 1953b60f2a0bSfr41279 } else { 1954b60f2a0bSfr41279 l++; 19557c478bd9Sstevel@tonic-gate } 1956b60f2a0bSfr41279 if (bitcount == groupbits) { 1957b60f2a0bSfr41279 for (m = 0; m < k; m++) { 1958b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, 1959b60f2a0bSfr41279 tmp, tmp, n, n0)) != 1960b60f2a0bSfr41279 BIG_OK) { 1961b60f2a0bSfr41279 goto ret; 1962b60f2a0bSfr41279 } 1963b60f2a0bSfr41279 } 1964b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, tmp, 1965b60f2a0bSfr41279 &(apowers[p >> (l + 1)]), 1966b60f2a0bSfr41279 n, n0)) != BIG_OK) { 1967b60f2a0bSfr41279 goto ret; 1968b60f2a0bSfr41279 } 1969b60f2a0bSfr41279 for (m = 0; m < l; m++) { 1970b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, 1971b60f2a0bSfr41279 tmp, tmp, n, n0)) != 1972b60f2a0bSfr41279 BIG_OK) { 1973b60f2a0bSfr41279 goto ret; 1974b60f2a0bSfr41279 } 1975b60f2a0bSfr41279 } 1976b60f2a0bSfr41279 k = 0; 1977b60f2a0bSfr41279 l = 0; 1978b60f2a0bSfr41279 p = 0; 1979b60f2a0bSfr41279 bitcount = 0; 1980b60f2a0bSfr41279 } 1981b60f2a0bSfr41279 } 1982b60f2a0bSfr41279 } 1983b60f2a0bSfr41279 bitind = BIG_CHUNK_SIZE; 1984b60f2a0bSfr41279 } 19857c478bd9Sstevel@tonic-gate 1986b60f2a0bSfr41279 for (m = 0; m < k; m++) { 1987b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, tmp, tmp, n, n0)) != BIG_OK) { 1988b60f2a0bSfr41279 goto ret; 1989b60f2a0bSfr41279 } 1990b60f2a0bSfr41279 } 1991b60f2a0bSfr41279 if (p != 0) { 1992b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, tmp, 1993b60f2a0bSfr41279 &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK) { 1994b60f2a0bSfr41279 goto ret; 1995b60f2a0bSfr41279 } 1996b60f2a0bSfr41279 } 1997b60f2a0bSfr41279 for (m = 0; m < l; m++) { 1998b60f2a0bSfr41279 if ((err = big_mont_mul(result, tmp, tmp, n, n0)) != BIG_OK) { 1999b60f2a0bSfr41279 goto ret; 2000b60f2a0bSfr41279 } 2001b60f2a0bSfr41279 } 20027c478bd9Sstevel@tonic-gate 2003b60f2a0bSfr41279 ret: 2004b60f2a0bSfr41279 for (i = apowerssize - 1; i >= 0; i--) { 2005b60f2a0bSfr41279 big_finish(&(apowers[i])); 2006b60f2a0bSfr41279 } 2007b60f2a0bSfr41279 big_finish(&tmp1); 2008b60f2a0bSfr41279 2009b60f2a0bSfr41279 return (err); 2010b60f2a0bSfr41279 } 2011b60f2a0bSfr41279 2012b60f2a0bSfr41279 2013b60f2a0bSfr41279 #ifdef USE_FLOATING_POINT 2014b60f2a0bSfr41279 2015b60f2a0bSfr41279 #ifdef _KERNEL 2016b60f2a0bSfr41279 2017b60f2a0bSfr41279 #include <sys/sysmacros.h> 2018b60f2a0bSfr41279 #include <sys/regset.h> 2019b60f2a0bSfr41279 #include <sys/fpu/fpusystm.h> 2020b60f2a0bSfr41279 2021b60f2a0bSfr41279 /* the alignment for block stores to save fp registers */ 2022b60f2a0bSfr41279 #define FPR_ALIGN (64) 2023b60f2a0bSfr41279 2024b60f2a0bSfr41279 extern void big_savefp(kfpu_t *); 2025b60f2a0bSfr41279 extern void big_restorefp(kfpu_t *); 2026b60f2a0bSfr41279 2027b60f2a0bSfr41279 #endif /* _KERNEL */ 2028b60f2a0bSfr41279 2029b60f2a0bSfr41279 /* 2030b60f2a0bSfr41279 * This version makes use of floating point for performance 2031b60f2a0bSfr41279 */ 2032b60f2a0bSfr41279 static BIG_ERR_CODE 2033b60f2a0bSfr41279 big_modexp_ncp_float(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 2034b60f2a0bSfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 2035b60f2a0bSfr41279 { 2036b60f2a0bSfr41279 20378475e043SDan OpenSolaris Anderson int i, j, k, l, m, p; 20388475e043SDan OpenSolaris Anderson uint32_t bit, bitind, bitcount, nlen; 2039b60f2a0bSfr41279 double dn0; 2040b60f2a0bSfr41279 double *dn, *dt, *d16r, *d32r; 2041b60f2a0bSfr41279 uint32_t *nint, *prod; 2042b60f2a0bSfr41279 double *apowers[APOWERS_MAX_SIZE]; 20438475e043SDan OpenSolaris Anderson uint32_t nbits, groupbits, apowerssize; 2044b60f2a0bSfr41279 BIG_ERR_CODE err = BIG_OK; 2045b60f2a0bSfr41279 2046b60f2a0bSfr41279 #ifdef _KERNEL 2047b60f2a0bSfr41279 uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN]; 2048b60f2a0bSfr41279 kfpu_t *fpu; 2049b60f2a0bSfr41279 2050b60f2a0bSfr41279 #ifdef DEBUG 2051b60f2a0bSfr41279 if (!fpu_exists) 2052b60f2a0bSfr41279 return (BIG_GENERAL_ERR); 2053b60f2a0bSfr41279 #endif 2054b60f2a0bSfr41279 2055b60f2a0bSfr41279 fpu = (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN); 2056b60f2a0bSfr41279 big_savefp(fpu); 2057b60f2a0bSfr41279 2058b60f2a0bSfr41279 #endif /* _KERNEL */ 2059b60f2a0bSfr41279 2060b60f2a0bSfr41279 nbits = big_numbits(e); 2061b60f2a0bSfr41279 if (nbits < 50) { 2062b60f2a0bSfr41279 groupbits = 1; 2063b60f2a0bSfr41279 apowerssize = 1; 2064b60f2a0bSfr41279 } else { 2065b60f2a0bSfr41279 groupbits = MAX_EXP_BIT_GROUP_SIZE; 2066b60f2a0bSfr41279 apowerssize = 1 << (groupbits - 1); 2067b60f2a0bSfr41279 } 2068b60f2a0bSfr41279 2069b60f2a0bSfr41279 nlen = (BIG_CHUNK_SIZE / 32) * n->len; 20707c478bd9Sstevel@tonic-gate dn0 = (double)(n0 & 0xffff); 20717c478bd9Sstevel@tonic-gate 20727c478bd9Sstevel@tonic-gate dn = dt = d16r = d32r = NULL; 20737c478bd9Sstevel@tonic-gate nint = prod = NULL; 20747c478bd9Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 20757c478bd9Sstevel@tonic-gate apowers[i] = NULL; 20767c478bd9Sstevel@tonic-gate } 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate if ((dn = big_malloc(nlen * sizeof (double))) == NULL) { 20797c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 20807c478bd9Sstevel@tonic-gate goto ret; 20817c478bd9Sstevel@tonic-gate } 20827c478bd9Sstevel@tonic-gate if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) { 20837c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 20847c478bd9Sstevel@tonic-gate goto ret; 20857c478bd9Sstevel@tonic-gate } 20867c478bd9Sstevel@tonic-gate if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) { 20877c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 20887c478bd9Sstevel@tonic-gate goto ret; 20897c478bd9Sstevel@tonic-gate } 20907c478bd9Sstevel@tonic-gate if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) { 20917c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 20927c478bd9Sstevel@tonic-gate goto ret; 20937c478bd9Sstevel@tonic-gate } 20947c478bd9Sstevel@tonic-gate if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) { 20957c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 20967c478bd9Sstevel@tonic-gate goto ret; 20977c478bd9Sstevel@tonic-gate } 20987c478bd9Sstevel@tonic-gate if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) { 20997c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 21007c478bd9Sstevel@tonic-gate goto ret; 21017c478bd9Sstevel@tonic-gate } 21027c478bd9Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 21037c478bd9Sstevel@tonic-gate if ((apowers[i] = big_malloc((2 * nlen + 1) * 21047c478bd9Sstevel@tonic-gate sizeof (double))) == NULL) { 21057c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 21067c478bd9Sstevel@tonic-gate goto ret; 21077c478bd9Sstevel@tonic-gate } 21087c478bd9Sstevel@tonic-gate } 21097c478bd9Sstevel@tonic-gate 2110b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 2111b60f2a0bSfr41279 for (i = 0; i < ma->len; i++) { 2112b60f2a0bSfr41279 nint[i] = ma->value[i]; 2113b60f2a0bSfr41279 } 2114b60f2a0bSfr41279 for (; i < nlen; i++) { 2115b60f2a0bSfr41279 nint[i] = 0; 2116b60f2a0bSfr41279 } 2117b60f2a0bSfr41279 #else 2118b60f2a0bSfr41279 for (i = 0; i < ma->len; i++) { 2119b60f2a0bSfr41279 nint[2 * i] = (uint32_t)(ma->value[i] & 0xffffffffULL); 2120b60f2a0bSfr41279 nint[2 * i + 1] = (uint32_t)(ma->value[i] >> 32); 2121b60f2a0bSfr41279 } 2122b60f2a0bSfr41279 for (i = ma->len * 2; i < nlen; i++) { 2123b60f2a0bSfr41279 nint[i] = 0; 2124b60f2a0bSfr41279 } 2125b60f2a0bSfr41279 #endif 21267c478bd9Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen); 21277c478bd9Sstevel@tonic-gate 2128b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 2129b60f2a0bSfr41279 for (i = 0; i < n->len; i++) { 2130b60f2a0bSfr41279 nint[i] = n->value[i]; 2131b60f2a0bSfr41279 } 2132b60f2a0bSfr41279 for (; i < nlen; i++) { 2133b60f2a0bSfr41279 nint[i] = 0; 2134b60f2a0bSfr41279 } 2135b60f2a0bSfr41279 #else 2136b60f2a0bSfr41279 for (i = 0; i < n->len; i++) { 2137b60f2a0bSfr41279 nint[2 * i] = (uint32_t)(n->value[i] & 0xffffffffULL); 2138b60f2a0bSfr41279 nint[2 * i + 1] = (uint32_t)(n->value[i] >> 32); 2139b60f2a0bSfr41279 } 2140b60f2a0bSfr41279 for (i = n->len * 2; i < nlen; i++) { 2141b60f2a0bSfr41279 nint[i] = 0; 2142b60f2a0bSfr41279 } 2143b60f2a0bSfr41279 #endif 21447c478bd9Sstevel@tonic-gate conv_i32_to_d32(dn, nint, nlen); 21457c478bd9Sstevel@tonic-gate 21467c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0); 21477c478bd9Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 21487c478bd9Sstevel@tonic-gate for (i = 1; i < apowerssize; i++) { 21497c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[i - 1], 21507c478bd9Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21517c478bd9Sstevel@tonic-gate conv_i32_to_d16(apowers[i], prod, nlen); 21527c478bd9Sstevel@tonic-gate } 21537c478bd9Sstevel@tonic-gate 2154b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 2155b60f2a0bSfr41279 for (i = 0; i < tmp->len; i++) { 2156b60f2a0bSfr41279 prod[i] = tmp->value[i]; 2157b60f2a0bSfr41279 } 2158b60f2a0bSfr41279 for (; i < nlen + 1; i++) { 2159b60f2a0bSfr41279 prod[i] = 0; 2160b60f2a0bSfr41279 } 2161b60f2a0bSfr41279 #else 2162b60f2a0bSfr41279 for (i = 0; i < tmp->len; i++) { 2163b60f2a0bSfr41279 prod[2 * i] = (uint32_t)(tmp->value[i] & 0xffffffffULL); 2164b60f2a0bSfr41279 prod[2 * i + 1] = (uint32_t)(tmp->value[i] >> 32); 2165b60f2a0bSfr41279 } 2166b60f2a0bSfr41279 for (i = tmp->len * 2; i < nlen + 1; i++) { 2167b60f2a0bSfr41279 prod[i] = 0; 2168b60f2a0bSfr41279 } 2169b60f2a0bSfr41279 #endif 21707c478bd9Sstevel@tonic-gate 2171b60f2a0bSfr41279 bitind = nbits % BIG_CHUNK_SIZE; 21727c478bd9Sstevel@tonic-gate k = 0; 21737c478bd9Sstevel@tonic-gate l = 0; 21747c478bd9Sstevel@tonic-gate p = 0; 21757c478bd9Sstevel@tonic-gate bitcount = 0; 2176b60f2a0bSfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 21777c478bd9Sstevel@tonic-gate for (j = bitind - 1; j >= 0; j--) { 21787c478bd9Sstevel@tonic-gate bit = (e->value[i] >> j) & 1; 21797c478bd9Sstevel@tonic-gate if ((bitcount == 0) && (bit == 0)) { 21807c478bd9Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, 21817c478bd9Sstevel@tonic-gate prod, nlen); 21827c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, 21837c478bd9Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21847c478bd9Sstevel@tonic-gate } else { 21857c478bd9Sstevel@tonic-gate bitcount++; 21867c478bd9Sstevel@tonic-gate p = p * 2 + bit; 21877c478bd9Sstevel@tonic-gate if (bit == 1) { 21887c478bd9Sstevel@tonic-gate k = k + l + 1; 21897c478bd9Sstevel@tonic-gate l = 0; 21907c478bd9Sstevel@tonic-gate } else { 21917c478bd9Sstevel@tonic-gate l++; 21927c478bd9Sstevel@tonic-gate } 21937c478bd9Sstevel@tonic-gate if (bitcount == groupbits) { 21947c478bd9Sstevel@tonic-gate for (m = 0; m < k; m++) { 2195b60f2a0bSfr41279 conv_i32_to_d32_and_d16(d32r, 2196b60f2a0bSfr41279 d16r, prod, nlen); 21977c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 21987c478bd9Sstevel@tonic-gate d16r, dt, dn, nint, 21997c478bd9Sstevel@tonic-gate nlen, dn0); 22007c478bd9Sstevel@tonic-gate } 22017c478bd9Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 22027c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 22037c478bd9Sstevel@tonic-gate apowers[p >> (l + 1)], 22047c478bd9Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 22057c478bd9Sstevel@tonic-gate for (m = 0; m < l; m++) { 2206b60f2a0bSfr41279 conv_i32_to_d32_and_d16(d32r, 2207b60f2a0bSfr41279 d16r, prod, nlen); 22087c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 22097c478bd9Sstevel@tonic-gate d16r, dt, dn, nint, 22107c478bd9Sstevel@tonic-gate nlen, dn0); 22117c478bd9Sstevel@tonic-gate } 22127c478bd9Sstevel@tonic-gate k = 0; 22137c478bd9Sstevel@tonic-gate l = 0; 22147c478bd9Sstevel@tonic-gate p = 0; 22157c478bd9Sstevel@tonic-gate bitcount = 0; 22167c478bd9Sstevel@tonic-gate } 22177c478bd9Sstevel@tonic-gate } 22187c478bd9Sstevel@tonic-gate } 2219b60f2a0bSfr41279 bitind = BIG_CHUNK_SIZE; 22207c478bd9Sstevel@tonic-gate } 22217c478bd9Sstevel@tonic-gate 22227c478bd9Sstevel@tonic-gate for (m = 0; m < k; m++) { 22237c478bd9Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 22247c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 22257c478bd9Sstevel@tonic-gate } 22267c478bd9Sstevel@tonic-gate if (p != 0) { 22277c478bd9Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 22287c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)], 22297c478bd9Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 22307c478bd9Sstevel@tonic-gate } 22317c478bd9Sstevel@tonic-gate for (m = 0; m < l; m++) { 22327c478bd9Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 22337c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 22347c478bd9Sstevel@tonic-gate } 22357c478bd9Sstevel@tonic-gate 2236b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 2237b60f2a0bSfr41279 for (i = 0; i < nlen; i++) { 2238b60f2a0bSfr41279 result->value[i] = prod[i]; 2239b60f2a0bSfr41279 } 2240b60f2a0bSfr41279 for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--) 2241b60f2a0bSfr41279 ; 2242b60f2a0bSfr41279 #else 2243b60f2a0bSfr41279 for (i = 0; i < nlen / 2; i++) { 2244b60f2a0bSfr41279 result->value[i] = (uint64_t)(prod[2 * i]) + 2245b60f2a0bSfr41279 (((uint64_t)(prod[2 * i + 1])) << 32); 2246b60f2a0bSfr41279 } 2247b60f2a0bSfr41279 for (i = nlen / 2 - 1; (i > 0) && (result->value[i] == 0); i--) 2248b60f2a0bSfr41279 ; 2249b60f2a0bSfr41279 #endif 2250b60f2a0bSfr41279 result->len = i + 1; 2251b60f2a0bSfr41279 22527c478bd9Sstevel@tonic-gate ret: 22537c478bd9Sstevel@tonic-gate for (i = apowerssize - 1; i >= 0; i--) { 22547c478bd9Sstevel@tonic-gate if (apowers[i] != NULL) 22557c478bd9Sstevel@tonic-gate big_free(apowers[i], (2 * nlen + 1) * sizeof (double)); 22567c478bd9Sstevel@tonic-gate } 2257b60f2a0bSfr41279 if (d32r != NULL) { 22587c478bd9Sstevel@tonic-gate big_free(d32r, nlen * sizeof (double)); 2259b60f2a0bSfr41279 } 2260b60f2a0bSfr41279 if (d16r != NULL) { 22617c478bd9Sstevel@tonic-gate big_free(d16r, (2 * nlen + 1) * sizeof (double)); 2262b60f2a0bSfr41279 } 2263b60f2a0bSfr41279 if (prod != NULL) { 22647c478bd9Sstevel@tonic-gate big_free(prod, (nlen + 1) * sizeof (uint32_t)); 2265b60f2a0bSfr41279 } 2266b60f2a0bSfr41279 if (nint != NULL) { 22677c478bd9Sstevel@tonic-gate big_free(nint, nlen * sizeof (uint32_t)); 2268b60f2a0bSfr41279 } 2269b60f2a0bSfr41279 if (dt != NULL) { 22707c478bd9Sstevel@tonic-gate big_free(dt, (4 * nlen + 2) * sizeof (double)); 2271b60f2a0bSfr41279 } 2272b60f2a0bSfr41279 if (dn != NULL) { 22737c478bd9Sstevel@tonic-gate big_free(dn, nlen * sizeof (double)); 22747c478bd9Sstevel@tonic-gate } 22757c478bd9Sstevel@tonic-gate 22767c478bd9Sstevel@tonic-gate #ifdef _KERNEL 2277b60f2a0bSfr41279 big_restorefp(fpu); 22787c478bd9Sstevel@tonic-gate #endif 22797c478bd9Sstevel@tonic-gate 22807c478bd9Sstevel@tonic-gate return (err); 22817c478bd9Sstevel@tonic-gate } 22827c478bd9Sstevel@tonic-gate 22837c478bd9Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */ 22847c478bd9Sstevel@tonic-gate 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate BIG_ERR_CODE 2287b60f2a0bSfr41279 big_modexp_ext(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr, 2288b60f2a0bSfr41279 big_modexp_ncp_info_t *info) 2289b60f2a0bSfr41279 { 2290b60f2a0bSfr41279 BIGNUM ma, tmp, rr; 2291b60f2a0bSfr41279 BIG_CHUNK_TYPE mavalue[BIGTMPSIZE]; 2292b60f2a0bSfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 2293b60f2a0bSfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 2294b60f2a0bSfr41279 BIG_ERR_CODE err; 2295b60f2a0bSfr41279 BIG_CHUNK_TYPE n0; 2296b60f2a0bSfr41279 2297b60f2a0bSfr41279 if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue))) != 2298b60f2a0bSfr41279 BIG_OK) { 2299b60f2a0bSfr41279 return (err); 2300b60f2a0bSfr41279 } 2301b60f2a0bSfr41279 ma.len = 1; 2302b60f2a0bSfr41279 ma.value[0] = 0; 2303b60f2a0bSfr41279 2304b60f2a0bSfr41279 if ((err = big_init1(&tmp, 2 * n->len + 1, 2305b60f2a0bSfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 2306b60f2a0bSfr41279 goto ret1; 2307b60f2a0bSfr41279 } 2308b60f2a0bSfr41279 23098475e043SDan OpenSolaris Anderson /* clear the malloced bit to help cleanup */ 2310b60f2a0bSfr41279 rr.malloced = 0; 23118475e043SDan OpenSolaris Anderson 2312b60f2a0bSfr41279 if (n_rr == NULL) { 2313b60f2a0bSfr41279 if ((err = big_init1(&rr, 2 * n->len + 1, 2314b60f2a0bSfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 2315b60f2a0bSfr41279 goto ret2; 2316b60f2a0bSfr41279 } 2317b60f2a0bSfr41279 if (big_mont_rr(&rr, n) != BIG_OK) { 2318b60f2a0bSfr41279 goto ret; 2319b60f2a0bSfr41279 } 2320b60f2a0bSfr41279 n_rr = &rr; 2321b60f2a0bSfr41279 } 2322b60f2a0bSfr41279 2323b60f2a0bSfr41279 n0 = big_n0(n->value[0]); 2324b60f2a0bSfr41279 2325b60f2a0bSfr41279 if (big_cmp_abs(a, n) > 0) { 2326b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK) { 2327b60f2a0bSfr41279 goto ret; 2328b60f2a0bSfr41279 } 2329b60f2a0bSfr41279 err = big_mont_conv(&ma, &ma, n, n0, n_rr); 2330b60f2a0bSfr41279 } else { 2331b60f2a0bSfr41279 err = big_mont_conv(&ma, a, n, n0, n_rr); 2332b60f2a0bSfr41279 } 2333b60f2a0bSfr41279 if (err != BIG_OK) { 2334b60f2a0bSfr41279 goto ret; 2335b60f2a0bSfr41279 } 2336b60f2a0bSfr41279 2337b60f2a0bSfr41279 tmp.len = 1; 2338b60f2a0bSfr41279 tmp.value[0] = 1; 2339b60f2a0bSfr41279 if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK) { 2340b60f2a0bSfr41279 goto ret; 2341b60f2a0bSfr41279 } 2342b60f2a0bSfr41279 2343b60f2a0bSfr41279 if ((info != NULL) && (info->func != NULL)) { 2344b60f2a0bSfr41279 err = (*(info->func))(&tmp, &ma, e, n, &tmp, n0, 2345b60f2a0bSfr41279 info->ncp, info->reqp); 2346b60f2a0bSfr41279 } else { 2347b60f2a0bSfr41279 err = big_modexp_ncp_sw(&tmp, &ma, e, n, &tmp, n0); 2348b60f2a0bSfr41279 } 2349b60f2a0bSfr41279 if (err != BIG_OK) { 2350b60f2a0bSfr41279 goto ret; 2351b60f2a0bSfr41279 } 2352b60f2a0bSfr41279 2353b60f2a0bSfr41279 ma.value[0] = 1; 2354b60f2a0bSfr41279 ma.len = 1; 2355b60f2a0bSfr41279 if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK) { 2356b60f2a0bSfr41279 goto ret; 2357b60f2a0bSfr41279 } 2358b60f2a0bSfr41279 err = big_copy(result, &tmp); 2359b60f2a0bSfr41279 2360b60f2a0bSfr41279 ret: 2361b60f2a0bSfr41279 if (rr.malloced) { 2362b60f2a0bSfr41279 big_finish(&rr); 2363b60f2a0bSfr41279 } 2364b60f2a0bSfr41279 ret2: 2365b60f2a0bSfr41279 big_finish(&tmp); 2366b60f2a0bSfr41279 ret1: 2367b60f2a0bSfr41279 big_finish(&ma); 2368b60f2a0bSfr41279 2369b60f2a0bSfr41279 return (err); 2370b60f2a0bSfr41279 } 2371b60f2a0bSfr41279 2372b60f2a0bSfr41279 BIG_ERR_CODE 2373b60f2a0bSfr41279 big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr) 2374b60f2a0bSfr41279 { 2375b60f2a0bSfr41279 return (big_modexp_ext(result, a, e, n, n_rr, NULL)); 2376b60f2a0bSfr41279 } 2377b60f2a0bSfr41279 2378b60f2a0bSfr41279 2379b60f2a0bSfr41279 BIG_ERR_CODE 2380b60f2a0bSfr41279 big_modexp_crt_ext(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 23817c478bd9Sstevel@tonic-gate BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 2382b60f2a0bSfr41279 BIGNUM *p_rr, BIGNUM *q_rr, big_modexp_ncp_info_t *info) 23837c478bd9Sstevel@tonic-gate { 23847c478bd9Sstevel@tonic-gate BIGNUM ap, aq, tmp; 23857c478bd9Sstevel@tonic-gate int alen, biglen, sign; 23867c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 23877c478bd9Sstevel@tonic-gate 2388b60f2a0bSfr41279 if (p->len > q->len) { 2389b60f2a0bSfr41279 biglen = p->len; 2390b60f2a0bSfr41279 } else { 2391b60f2a0bSfr41279 biglen = q->len; 2392b60f2a0bSfr41279 } 23937c478bd9Sstevel@tonic-gate 2394b60f2a0bSfr41279 if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK) { 23957c478bd9Sstevel@tonic-gate return (err); 2396b60f2a0bSfr41279 } 2397b60f2a0bSfr41279 if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK) { 23987c478bd9Sstevel@tonic-gate goto ret1; 2399b60f2a0bSfr41279 } 2400b60f2a0bSfr41279 if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK) { 24017c478bd9Sstevel@tonic-gate goto ret2; 2402b60f2a0bSfr41279 } 24037c478bd9Sstevel@tonic-gate 24047c478bd9Sstevel@tonic-gate /* 24057c478bd9Sstevel@tonic-gate * check whether a is too short - to avoid timing attacks 24067c478bd9Sstevel@tonic-gate */ 24077c478bd9Sstevel@tonic-gate alen = a->len; 24087c478bd9Sstevel@tonic-gate while ((alen > p->len) && (a->value[alen - 1] == 0)) { 24097c478bd9Sstevel@tonic-gate alen--; 24107c478bd9Sstevel@tonic-gate } 24117c478bd9Sstevel@tonic-gate if (alen < p->len + q->len) { 24127c478bd9Sstevel@tonic-gate /* 24137c478bd9Sstevel@tonic-gate * a is too short, add p*q to it before 24147c478bd9Sstevel@tonic-gate * taking it modulo p and q 24157c478bd9Sstevel@tonic-gate * this will also affect timing, but this difference 24167c478bd9Sstevel@tonic-gate * does not depend on p or q, only on a 24177c478bd9Sstevel@tonic-gate * (in "normal" operation, this path will never be 24187c478bd9Sstevel@tonic-gate * taken, so it is not a performance penalty 24197c478bd9Sstevel@tonic-gate */ 2420b60f2a0bSfr41279 if ((err = big_mul(&tmp, p, q)) != BIG_OK) { 24217c478bd9Sstevel@tonic-gate goto ret; 24227c478bd9Sstevel@tonic-gate } 2423b60f2a0bSfr41279 if ((err = big_add(&tmp, &tmp, a)) != BIG_OK) { 2424b60f2a0bSfr41279 goto ret; 2425b60f2a0bSfr41279 } 2426b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK) { 2427b60f2a0bSfr41279 goto ret; 2428b60f2a0bSfr41279 } 2429b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 2430b60f2a0bSfr41279 goto ret; 2431b60f2a0bSfr41279 } 2432b60f2a0bSfr41279 } else { 2433b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK) { 2434b60f2a0bSfr41279 goto ret; 2435b60f2a0bSfr41279 } 2436b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK) { 2437b60f2a0bSfr41279 goto ret; 2438b60f2a0bSfr41279 } 2439b60f2a0bSfr41279 } 24407c478bd9Sstevel@tonic-gate 2441b60f2a0bSfr41279 if ((err = big_modexp_ext(&ap, &ap, dmodpminus1, p, p_rr, info)) != 2442b60f2a0bSfr41279 BIG_OK) { 24437c478bd9Sstevel@tonic-gate goto ret; 2444b60f2a0bSfr41279 } 2445b60f2a0bSfr41279 if ((err = big_modexp_ext(&aq, &aq, dmodqminus1, q, q_rr, info)) != 2446b60f2a0bSfr41279 BIG_OK) { 24477c478bd9Sstevel@tonic-gate goto ret; 2448b60f2a0bSfr41279 } 2449b60f2a0bSfr41279 if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK) { 24507c478bd9Sstevel@tonic-gate goto ret; 2451b60f2a0bSfr41279 } 2452b60f2a0bSfr41279 if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK) { 24537c478bd9Sstevel@tonic-gate goto ret; 2454b60f2a0bSfr41279 } 24557c478bd9Sstevel@tonic-gate sign = tmp.sign; 24567c478bd9Sstevel@tonic-gate tmp.sign = 1; 2457b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 24587c478bd9Sstevel@tonic-gate goto ret; 2459b60f2a0bSfr41279 } 24607c478bd9Sstevel@tonic-gate if ((sign == -1) && (!big_is_zero(&aq))) { 24617c478bd9Sstevel@tonic-gate (void) big_sub_pos(&aq, q, &aq); 24627c478bd9Sstevel@tonic-gate } 2463b60f2a0bSfr41279 if ((err = big_mul(&tmp, &aq, p)) != BIG_OK) { 24647c478bd9Sstevel@tonic-gate goto ret; 2465b60f2a0bSfr41279 } 24667c478bd9Sstevel@tonic-gate err = big_add_abs(result, &ap, &tmp); 24677c478bd9Sstevel@tonic-gate 24687c478bd9Sstevel@tonic-gate ret: 24697c478bd9Sstevel@tonic-gate big_finish(&tmp); 24707c478bd9Sstevel@tonic-gate ret2: 24717c478bd9Sstevel@tonic-gate big_finish(&aq); 24727c478bd9Sstevel@tonic-gate ret1: 24737c478bd9Sstevel@tonic-gate big_finish(&ap); 24747c478bd9Sstevel@tonic-gate 24757c478bd9Sstevel@tonic-gate return (err); 24767c478bd9Sstevel@tonic-gate } 24777c478bd9Sstevel@tonic-gate 24787c478bd9Sstevel@tonic-gate 2479b60f2a0bSfr41279 BIG_ERR_CODE 2480b60f2a0bSfr41279 big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 2481b60f2a0bSfr41279 BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 2482b60f2a0bSfr41279 BIGNUM *p_rr, BIGNUM *q_rr) 2483b60f2a0bSfr41279 { 2484b60f2a0bSfr41279 return (big_modexp_crt_ext(result, a, dmodpminus1, dmodqminus1, 2485b60f2a0bSfr41279 p, q, pinvmodq, p_rr, q_rr, NULL)); 2486b60f2a0bSfr41279 } 24877c478bd9Sstevel@tonic-gate 24887c478bd9Sstevel@tonic-gate 2489b60f2a0bSfr41279 static BIG_CHUNK_TYPE onearr[1] = {(BIG_CHUNK_TYPE)1}; 2490b60f2a0bSfr41279 BIGNUM big_One = {1, 1, 1, 0, onearr}; 2491b60f2a0bSfr41279 2492b60f2a0bSfr41279 static BIG_CHUNK_TYPE twoarr[1] = {(BIG_CHUNK_TYPE)2}; 2493b60f2a0bSfr41279 BIGNUM big_Two = {1, 1, 1, 0, twoarr}; 2494b60f2a0bSfr41279 2495b60f2a0bSfr41279 static BIG_CHUNK_TYPE fourarr[1] = {(BIG_CHUNK_TYPE)4}; 2496b60f2a0bSfr41279 static BIGNUM big_Four = {1, 1, 1, 0, fourarr}; 2497b60f2a0bSfr41279 24987c478bd9Sstevel@tonic-gate 24997c478bd9Sstevel@tonic-gate BIG_ERR_CODE 25007c478bd9Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n) 25017c478bd9Sstevel@tonic-gate { 25027c478bd9Sstevel@tonic-gate BIGNUM *high, *low, *mid, *t; 25037c478bd9Sstevel@tonic-gate BIGNUM t1, t2, t3, prod; 2504b60f2a0bSfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 2505b60f2a0bSfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 2506b60f2a0bSfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 2507b60f2a0bSfr41279 BIG_CHUNK_TYPE prodvalue[BIGTMPSIZE]; 25088475e043SDan OpenSolaris Anderson int i, diff; 25098475e043SDan OpenSolaris Anderson uint32_t nbits, nrootbits, highbits; 25107c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 25117c478bd9Sstevel@tonic-gate 25127c478bd9Sstevel@tonic-gate nbits = big_numbits(n); 25137c478bd9Sstevel@tonic-gate 25147c478bd9Sstevel@tonic-gate if ((err = big_init1(&t1, n->len + 1, 25157c478bd9Sstevel@tonic-gate t1value, arraysize(t1value))) != BIG_OK) 25167c478bd9Sstevel@tonic-gate return (err); 25177c478bd9Sstevel@tonic-gate if ((err = big_init1(&t2, n->len + 1, 25187c478bd9Sstevel@tonic-gate t2value, arraysize(t2value))) != BIG_OK) 25197c478bd9Sstevel@tonic-gate goto ret1; 25207c478bd9Sstevel@tonic-gate if ((err = big_init1(&t3, n->len + 1, 25217c478bd9Sstevel@tonic-gate t3value, arraysize(t3value))) != BIG_OK) 25227c478bd9Sstevel@tonic-gate goto ret2; 25237c478bd9Sstevel@tonic-gate if ((err = big_init1(&prod, n->len + 1, 25247c478bd9Sstevel@tonic-gate prodvalue, arraysize(prodvalue))) != BIG_OK) 25257c478bd9Sstevel@tonic-gate goto ret3; 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate nrootbits = (nbits + 1) / 2; 2528b60f2a0bSfr41279 t1.len = t2.len = t3.len = (nrootbits - 1) / BIG_CHUNK_SIZE + 1; 25297c478bd9Sstevel@tonic-gate for (i = 0; i < t1.len; i++) { 25307c478bd9Sstevel@tonic-gate t1.value[i] = 0; 2531b60f2a0bSfr41279 t2.value[i] = BIG_CHUNK_ALLBITS; 25327c478bd9Sstevel@tonic-gate } 2533b60f2a0bSfr41279 highbits = nrootbits - BIG_CHUNK_SIZE * (t1.len - 1); 2534b60f2a0bSfr41279 if (highbits == BIG_CHUNK_SIZE) { 2535b60f2a0bSfr41279 t1.value[t1.len - 1] = BIG_CHUNK_HIGHBIT; 2536b60f2a0bSfr41279 t2.value[t2.len - 1] = BIG_CHUNK_ALLBITS; 25377c478bd9Sstevel@tonic-gate } else { 2538b60f2a0bSfr41279 t1.value[t1.len - 1] = (BIG_CHUNK_TYPE)1 << (highbits - 1); 25397c478bd9Sstevel@tonic-gate t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1; 25407c478bd9Sstevel@tonic-gate } 2541b60f2a0bSfr41279 25427c478bd9Sstevel@tonic-gate high = &t2; 25437c478bd9Sstevel@tonic-gate low = &t1; 25447c478bd9Sstevel@tonic-gate mid = &t3; 25457c478bd9Sstevel@tonic-gate 2546b60f2a0bSfr41279 if ((err = big_mul(&prod, high, high)) != BIG_OK) { 25477c478bd9Sstevel@tonic-gate goto ret; 2548b60f2a0bSfr41279 } 25497c478bd9Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 25507c478bd9Sstevel@tonic-gate if (diff <= 0) { 25517c478bd9Sstevel@tonic-gate err = big_copy(result, high); 25527c478bd9Sstevel@tonic-gate goto ret; 25537c478bd9Sstevel@tonic-gate } 25547c478bd9Sstevel@tonic-gate 25557c478bd9Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 2556b60f2a0bSfr41279 while (big_cmp_abs(&big_One, mid) != 0) { 25577c478bd9Sstevel@tonic-gate (void) big_add_abs(mid, high, low); 25587c478bd9Sstevel@tonic-gate (void) big_half_pos(mid, mid); 25597c478bd9Sstevel@tonic-gate if ((err = big_mul(&prod, mid, mid)) != BIG_OK) 25607c478bd9Sstevel@tonic-gate goto ret; 25617c478bd9Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 25627c478bd9Sstevel@tonic-gate if (diff > 0) { 25637c478bd9Sstevel@tonic-gate t = high; 25647c478bd9Sstevel@tonic-gate high = mid; 25657c478bd9Sstevel@tonic-gate mid = t; 25667c478bd9Sstevel@tonic-gate } else if (diff < 0) { 25677c478bd9Sstevel@tonic-gate t = low; 25687c478bd9Sstevel@tonic-gate low = mid; 25697c478bd9Sstevel@tonic-gate mid = t; 25707c478bd9Sstevel@tonic-gate } else { 25717c478bd9Sstevel@tonic-gate err = big_copy(result, low); 25727c478bd9Sstevel@tonic-gate goto ret; 25737c478bd9Sstevel@tonic-gate } 25747c478bd9Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 25757c478bd9Sstevel@tonic-gate } 25767c478bd9Sstevel@tonic-gate 25777c478bd9Sstevel@tonic-gate err = big_copy(result, low); 25787c478bd9Sstevel@tonic-gate ret: 25797c478bd9Sstevel@tonic-gate if (prod.malloced) big_finish(&prod); 25807c478bd9Sstevel@tonic-gate ret3: 25817c478bd9Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 25827c478bd9Sstevel@tonic-gate ret2: 25837c478bd9Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 25847c478bd9Sstevel@tonic-gate ret1: 25857c478bd9Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 25867c478bd9Sstevel@tonic-gate 25877c478bd9Sstevel@tonic-gate return (err); 25887c478bd9Sstevel@tonic-gate } 25897c478bd9Sstevel@tonic-gate 25907c478bd9Sstevel@tonic-gate 25917c478bd9Sstevel@tonic-gate BIG_ERR_CODE 25927c478bd9Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm) 25937c478bd9Sstevel@tonic-gate { 25947c478bd9Sstevel@tonic-gate BIGNUM *t, *tmp2, *m, *n; 25957c478bd9Sstevel@tonic-gate BIGNUM t1, t2, t3; 2596b60f2a0bSfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 2597b60f2a0bSfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 2598b60f2a0bSfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 25997c478bd9Sstevel@tonic-gate int len, err; 26007c478bd9Sstevel@tonic-gate 26017c478bd9Sstevel@tonic-gate if (big_is_zero(nn) || 26027c478bd9Sstevel@tonic-gate (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) { 26037c478bd9Sstevel@tonic-gate *jac = 0; 26047c478bd9Sstevel@tonic-gate return (BIG_OK); 26057c478bd9Sstevel@tonic-gate } 26067c478bd9Sstevel@tonic-gate 2607b60f2a0bSfr41279 if (nn->len > mm->len) { 2608b60f2a0bSfr41279 len = nn->len; 2609b60f2a0bSfr41279 } else { 2610b60f2a0bSfr41279 len = mm->len; 2611b60f2a0bSfr41279 } 26127c478bd9Sstevel@tonic-gate 26137c478bd9Sstevel@tonic-gate if ((err = big_init1(&t1, len, 2614b60f2a0bSfr41279 t1value, arraysize(t1value))) != BIG_OK) { 26157c478bd9Sstevel@tonic-gate return (err); 2616b60f2a0bSfr41279 } 26177c478bd9Sstevel@tonic-gate if ((err = big_init1(&t2, len, 2618b60f2a0bSfr41279 t2value, arraysize(t2value))) != BIG_OK) { 26197c478bd9Sstevel@tonic-gate goto ret1; 2620b60f2a0bSfr41279 } 26217c478bd9Sstevel@tonic-gate if ((err = big_init1(&t3, len, 2622b60f2a0bSfr41279 t3value, arraysize(t3value))) != BIG_OK) { 26237c478bd9Sstevel@tonic-gate goto ret2; 2624b60f2a0bSfr41279 } 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate n = &t1; 26277c478bd9Sstevel@tonic-gate m = &t2; 26287c478bd9Sstevel@tonic-gate tmp2 = &t3; 26297c478bd9Sstevel@tonic-gate 26307c478bd9Sstevel@tonic-gate (void) big_copy(n, nn); 26317c478bd9Sstevel@tonic-gate (void) big_copy(m, mm); 26327c478bd9Sstevel@tonic-gate 26337c478bd9Sstevel@tonic-gate *jac = 1; 2634b60f2a0bSfr41279 while (big_cmp_abs(&big_One, m) != 0) { 26357c478bd9Sstevel@tonic-gate if (big_is_zero(n)) { 26367c478bd9Sstevel@tonic-gate *jac = 0; 26377c478bd9Sstevel@tonic-gate goto ret; 26387c478bd9Sstevel@tonic-gate } 26397c478bd9Sstevel@tonic-gate if ((m->value[0] & 1) == 0) { 26407c478bd9Sstevel@tonic-gate if (((n->value[0] & 7) == 3) || 2641b60f2a0bSfr41279 ((n->value[0] & 7) == 5)) 2642b60f2a0bSfr41279 *jac = -*jac; 26437c478bd9Sstevel@tonic-gate (void) big_half_pos(m, m); 26447c478bd9Sstevel@tonic-gate } else if ((n->value[0] & 1) == 0) { 26457c478bd9Sstevel@tonic-gate if (((m->value[0] & 7) == 3) || 2646b60f2a0bSfr41279 ((m->value[0] & 7) == 5)) 2647b60f2a0bSfr41279 *jac = -*jac; 26487c478bd9Sstevel@tonic-gate (void) big_half_pos(n, n); 26497c478bd9Sstevel@tonic-gate } else { 26507c478bd9Sstevel@tonic-gate if (((m->value[0] & 3) == 3) && 26517c478bd9Sstevel@tonic-gate ((n->value[0] & 3) == 3)) { 26527c478bd9Sstevel@tonic-gate *jac = -*jac; 26537c478bd9Sstevel@tonic-gate } 2654b60f2a0bSfr41279 if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK) { 26557c478bd9Sstevel@tonic-gate goto ret; 2656b60f2a0bSfr41279 } 26577c478bd9Sstevel@tonic-gate t = tmp2; 26587c478bd9Sstevel@tonic-gate tmp2 = m; 26597c478bd9Sstevel@tonic-gate m = n; 26607c478bd9Sstevel@tonic-gate n = t; 26617c478bd9Sstevel@tonic-gate } 26627c478bd9Sstevel@tonic-gate } 26637c478bd9Sstevel@tonic-gate err = BIG_OK; 26647c478bd9Sstevel@tonic-gate 26657c478bd9Sstevel@tonic-gate ret: 26667c478bd9Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 26677c478bd9Sstevel@tonic-gate ret2: 26687c478bd9Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 26697c478bd9Sstevel@tonic-gate ret1: 26707c478bd9Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 26717c478bd9Sstevel@tonic-gate 26727c478bd9Sstevel@tonic-gate return (err); 26737c478bd9Sstevel@tonic-gate } 26747c478bd9Sstevel@tonic-gate 26757c478bd9Sstevel@tonic-gate 26767c478bd9Sstevel@tonic-gate BIG_ERR_CODE 26777c478bd9Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n) 26787c478bd9Sstevel@tonic-gate { 26798475e043SDan OpenSolaris Anderson int i; 26808475e043SDan OpenSolaris Anderson uint32_t m, w; 2681b60f2a0bSfr41279 BIG_CHUNK_TYPE bit; 26827c478bd9Sstevel@tonic-gate BIGNUM ki, tmp, tmp2; 2683b60f2a0bSfr41279 BIG_CHUNK_TYPE kivalue[BIGTMPSIZE]; 2684b60f2a0bSfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 2685b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 26867c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 26877c478bd9Sstevel@tonic-gate 2688b60f2a0bSfr41279 if (big_cmp_abs(k, &big_One) == 0) { 26897c478bd9Sstevel@tonic-gate (void) big_copy(Lk, p); 2690b60f2a0bSfr41279 (void) big_copy(Lkminus1, &big_Two); 26917c478bd9Sstevel@tonic-gate return (BIG_OK); 26927c478bd9Sstevel@tonic-gate } 26937c478bd9Sstevel@tonic-gate 26947c478bd9Sstevel@tonic-gate if ((err = big_init1(&ki, k->len + 1, 26957c478bd9Sstevel@tonic-gate kivalue, arraysize(kivalue))) != BIG_OK) 26967c478bd9Sstevel@tonic-gate return (err); 26977c478bd9Sstevel@tonic-gate 26987c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * n->len + 1, 26997c478bd9Sstevel@tonic-gate tmpvalue, arraysize(tmpvalue))) != BIG_OK) 27007c478bd9Sstevel@tonic-gate goto ret1; 27017c478bd9Sstevel@tonic-gate 27027c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp2, n->len, 27037c478bd9Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 27047c478bd9Sstevel@tonic-gate goto ret2; 27057c478bd9Sstevel@tonic-gate 27067c478bd9Sstevel@tonic-gate m = big_numbits(k); 2707b60f2a0bSfr41279 ki.len = (m - 1) / BIG_CHUNK_SIZE + 1; 2708b60f2a0bSfr41279 w = (m - 1) / BIG_CHUNK_SIZE; 2709b60f2a0bSfr41279 bit = (BIG_CHUNK_TYPE)1 << ((m - 1) % BIG_CHUNK_SIZE); 2710b60f2a0bSfr41279 for (i = 0; i < ki.len; i++) { 2711b60f2a0bSfr41279 ki.value[i] = 0; 2712b60f2a0bSfr41279 } 27137c478bd9Sstevel@tonic-gate ki.value[ki.len - 1] = bit; 2714b60f2a0bSfr41279 if (big_cmp_abs(k, &ki) != 0) { 27157c478bd9Sstevel@tonic-gate (void) big_double(&ki, &ki); 2716b60f2a0bSfr41279 } 27177c478bd9Sstevel@tonic-gate (void) big_sub_pos(&ki, &ki, k); 27187c478bd9Sstevel@tonic-gate 27197c478bd9Sstevel@tonic-gate (void) big_copy(Lk, p); 2720b60f2a0bSfr41279 (void) big_copy(Lkminus1, &big_Two); 27217c478bd9Sstevel@tonic-gate 27227c478bd9Sstevel@tonic-gate for (i = 0; i < m; i++) { 2723b60f2a0bSfr41279 if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK) { 27247c478bd9Sstevel@tonic-gate goto ret; 2725b60f2a0bSfr41279 } 27267c478bd9Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 27277c478bd9Sstevel@tonic-gate (void) big_sub_pos(&tmp, &tmp, p); 2728b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK) { 27297c478bd9Sstevel@tonic-gate goto ret; 2730b60f2a0bSfr41279 } 27317c478bd9Sstevel@tonic-gate if ((ki.value[w] & bit) != 0) { 27327c478bd9Sstevel@tonic-gate if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) != 2733b60f2a0bSfr41279 BIG_OK) { 27347c478bd9Sstevel@tonic-gate goto ret; 2735b60f2a0bSfr41279 } 27367c478bd9Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 2737b60f2a0bSfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Two); 27387c478bd9Sstevel@tonic-gate if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) != 2739b60f2a0bSfr41279 BIG_OK) { 27407c478bd9Sstevel@tonic-gate goto ret; 2741b60f2a0bSfr41279 } 27427c478bd9Sstevel@tonic-gate (void) big_copy(Lk, &tmp2); 27437c478bd9Sstevel@tonic-gate } else { 2744b60f2a0bSfr41279 if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK) { 27457c478bd9Sstevel@tonic-gate goto ret; 2746b60f2a0bSfr41279 } 27477c478bd9Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 2748b60f2a0bSfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Two); 2749b60f2a0bSfr41279 if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK) { 27507c478bd9Sstevel@tonic-gate goto ret; 2751b60f2a0bSfr41279 } 27527c478bd9Sstevel@tonic-gate (void) big_copy(Lkminus1, &tmp2); 27537c478bd9Sstevel@tonic-gate } 27547c478bd9Sstevel@tonic-gate bit = bit >> 1; 27557c478bd9Sstevel@tonic-gate if (bit == 0) { 2756b60f2a0bSfr41279 bit = BIG_CHUNK_HIGHBIT; 27577c478bd9Sstevel@tonic-gate w--; 27587c478bd9Sstevel@tonic-gate } 27597c478bd9Sstevel@tonic-gate } 27607c478bd9Sstevel@tonic-gate 27617c478bd9Sstevel@tonic-gate err = BIG_OK; 27627c478bd9Sstevel@tonic-gate 27637c478bd9Sstevel@tonic-gate ret: 27647c478bd9Sstevel@tonic-gate if (tmp2.malloced) big_finish(&tmp2); 27657c478bd9Sstevel@tonic-gate ret2: 27667c478bd9Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 27677c478bd9Sstevel@tonic-gate ret1: 27687c478bd9Sstevel@tonic-gate if (ki.malloced) big_finish(&ki); 27697c478bd9Sstevel@tonic-gate 27707c478bd9Sstevel@tonic-gate return (err); 27717c478bd9Sstevel@tonic-gate } 27727c478bd9Sstevel@tonic-gate 27737c478bd9Sstevel@tonic-gate 27747c478bd9Sstevel@tonic-gate BIG_ERR_CODE 2775b60f2a0bSfr41279 big_isprime_pos_ext(BIGNUM *n, big_modexp_ncp_info_t *info) 27767c478bd9Sstevel@tonic-gate { 27777c478bd9Sstevel@tonic-gate BIGNUM o, nminus1, tmp, Lkminus1, Lk; 2778b60f2a0bSfr41279 BIG_CHUNK_TYPE ovalue[BIGTMPSIZE]; 2779b60f2a0bSfr41279 BIG_CHUNK_TYPE nminus1value[BIGTMPSIZE]; 2780b60f2a0bSfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 2781b60f2a0bSfr41279 BIG_CHUNK_TYPE Lkminus1value[BIGTMPSIZE]; 2782b60f2a0bSfr41279 BIG_CHUNK_TYPE Lkvalue[BIGTMPSIZE]; 27837c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 27847c478bd9Sstevel@tonic-gate int e, i, jac; 27857c478bd9Sstevel@tonic-gate 2786b60f2a0bSfr41279 if (big_cmp_abs(n, &big_One) == 0) { 27877c478bd9Sstevel@tonic-gate return (BIG_FALSE); 2788b60f2a0bSfr41279 } 2789b60f2a0bSfr41279 if (big_cmp_abs(n, &big_Two) == 0) { 27907c478bd9Sstevel@tonic-gate return (BIG_TRUE); 2791b60f2a0bSfr41279 } 2792b60f2a0bSfr41279 if ((n->value[0] & 1) == 0) { 27937c478bd9Sstevel@tonic-gate return (BIG_FALSE); 2794b60f2a0bSfr41279 } 27957c478bd9Sstevel@tonic-gate 2796b60f2a0bSfr41279 if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) != 2797b60f2a0bSfr41279 BIG_OK) { 27987c478bd9Sstevel@tonic-gate return (err); 2799b60f2a0bSfr41279 } 28007c478bd9Sstevel@tonic-gate 28017c478bd9Sstevel@tonic-gate if ((err = big_init1(&nminus1, n->len, 2802b60f2a0bSfr41279 nminus1value, arraysize(nminus1value))) != BIG_OK) { 28037c478bd9Sstevel@tonic-gate goto ret1; 2804b60f2a0bSfr41279 } 28057c478bd9Sstevel@tonic-gate 28067c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * n->len, 2807b60f2a0bSfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 28087c478bd9Sstevel@tonic-gate goto ret2; 2809b60f2a0bSfr41279 } 28107c478bd9Sstevel@tonic-gate 28117c478bd9Sstevel@tonic-gate if ((err = big_init1(&Lkminus1, n->len, 2812b60f2a0bSfr41279 Lkminus1value, arraysize(Lkminus1value))) != BIG_OK) { 28137c478bd9Sstevel@tonic-gate goto ret3; 2814b60f2a0bSfr41279 } 28157c478bd9Sstevel@tonic-gate 28167c478bd9Sstevel@tonic-gate if ((err = big_init1(&Lk, n->len, 2817b60f2a0bSfr41279 Lkvalue, arraysize(Lkvalue))) != BIG_OK) { 28187c478bd9Sstevel@tonic-gate goto ret4; 2819b60f2a0bSfr41279 } 28207c478bd9Sstevel@tonic-gate 2821b60f2a0bSfr41279 (void) big_sub_pos(&o, n, &big_One); /* cannot fail */ 28227c478bd9Sstevel@tonic-gate (void) big_copy(&nminus1, &o); /* cannot fail */ 28237c478bd9Sstevel@tonic-gate e = 0; 28247c478bd9Sstevel@tonic-gate while ((o.value[0] & 1) == 0) { 28257c478bd9Sstevel@tonic-gate e++; 28267c478bd9Sstevel@tonic-gate (void) big_half_pos(&o, &o); /* cannot fail */ 28277c478bd9Sstevel@tonic-gate } 2828b60f2a0bSfr41279 if ((err = big_modexp_ext(&tmp, &big_Two, &o, n, NULL, info)) != 2829b60f2a0bSfr41279 BIG_OK) { 28307c478bd9Sstevel@tonic-gate goto ret; 2831b60f2a0bSfr41279 } 2832b60f2a0bSfr41279 28337c478bd9Sstevel@tonic-gate i = 0; 28347c478bd9Sstevel@tonic-gate while ((i < e) && 2835b60f2a0bSfr41279 (big_cmp_abs(&tmp, &big_One) != 0) && 28367c478bd9Sstevel@tonic-gate (big_cmp_abs(&tmp, &nminus1) != 0)) { 2837b60f2a0bSfr41279 if ((err = 2838b60f2a0bSfr41279 big_modexp_ext(&tmp, &tmp, &big_Two, n, NULL, info)) != 2839b60f2a0bSfr41279 BIG_OK) 28407c478bd9Sstevel@tonic-gate goto ret; 28417c478bd9Sstevel@tonic-gate i++; 28427c478bd9Sstevel@tonic-gate } 2843b60f2a0bSfr41279 28447c478bd9Sstevel@tonic-gate if (!((big_cmp_abs(&tmp, &nminus1) == 0) || 2845b60f2a0bSfr41279 ((i == 0) && (big_cmp_abs(&tmp, &big_One) == 0)))) { 28467c478bd9Sstevel@tonic-gate err = BIG_FALSE; 28477c478bd9Sstevel@tonic-gate goto ret; 28487c478bd9Sstevel@tonic-gate } 28497c478bd9Sstevel@tonic-gate 2850b60f2a0bSfr41279 if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK) { 28517c478bd9Sstevel@tonic-gate goto ret; 2852b60f2a0bSfr41279 } 2853b60f2a0bSfr41279 2854b60f2a0bSfr41279 if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK) { 28557c478bd9Sstevel@tonic-gate goto ret; 2856b60f2a0bSfr41279 } 28577c478bd9Sstevel@tonic-gate if (big_cmp_abs(&tmp, n) == 0) { 28587c478bd9Sstevel@tonic-gate err = BIG_FALSE; 28597c478bd9Sstevel@tonic-gate goto ret; 28607c478bd9Sstevel@tonic-gate } 28617c478bd9Sstevel@tonic-gate 2862b60f2a0bSfr41279 (void) big_copy(&o, &big_Two); 28637c478bd9Sstevel@tonic-gate do { 2864b60f2a0bSfr41279 (void) big_add_abs(&o, &o, &big_One); 2865b60f2a0bSfr41279 if ((err = big_mul(&tmp, &o, &o)) != BIG_OK) { 28667c478bd9Sstevel@tonic-gate goto ret; 2867b60f2a0bSfr41279 } 2868b60f2a0bSfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Four); 2869b60f2a0bSfr41279 if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK) { 28707c478bd9Sstevel@tonic-gate goto ret; 2871b60f2a0bSfr41279 } 28727c478bd9Sstevel@tonic-gate } while (jac != -1); 28737c478bd9Sstevel@tonic-gate 2874b60f2a0bSfr41279 (void) big_add_abs(&tmp, n, &big_One); 2875b60f2a0bSfr41279 if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK) { 28767c478bd9Sstevel@tonic-gate goto ret; 2877b60f2a0bSfr41279 } 2878b60f2a0bSfr41279 2879b60f2a0bSfr41279 if ((big_cmp_abs(&Lkminus1, &o) == 0) && 2880b60f2a0bSfr41279 (big_cmp_abs(&Lk, &big_Two) == 0)) { 28817c478bd9Sstevel@tonic-gate err = BIG_TRUE; 2882b60f2a0bSfr41279 } else { 2883b60f2a0bSfr41279 err = BIG_FALSE; 2884b60f2a0bSfr41279 } 28857c478bd9Sstevel@tonic-gate 28867c478bd9Sstevel@tonic-gate ret: 28877c478bd9Sstevel@tonic-gate if (Lk.malloced) big_finish(&Lk); 28887c478bd9Sstevel@tonic-gate ret4: 28897c478bd9Sstevel@tonic-gate if (Lkminus1.malloced) big_finish(&Lkminus1); 28907c478bd9Sstevel@tonic-gate ret3: 28917c478bd9Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 28927c478bd9Sstevel@tonic-gate ret2: 28937c478bd9Sstevel@tonic-gate if (nminus1.malloced) big_finish(&nminus1); 28947c478bd9Sstevel@tonic-gate ret1: 28957c478bd9Sstevel@tonic-gate if (o.malloced) big_finish(&o); 28967c478bd9Sstevel@tonic-gate 28977c478bd9Sstevel@tonic-gate return (err); 28987c478bd9Sstevel@tonic-gate } 28997c478bd9Sstevel@tonic-gate 29007c478bd9Sstevel@tonic-gate 2901b60f2a0bSfr41279 BIG_ERR_CODE 2902b60f2a0bSfr41279 big_isprime_pos(BIGNUM *n) 2903b60f2a0bSfr41279 { 2904b60f2a0bSfr41279 return (big_isprime_pos_ext(n, NULL)); 2905b60f2a0bSfr41279 } 2906b60f2a0bSfr41279 2907b60f2a0bSfr41279 29087c478bd9Sstevel@tonic-gate #define SIEVESIZE 1000 29097c478bd9Sstevel@tonic-gate 29107c478bd9Sstevel@tonic-gate 29117c478bd9Sstevel@tonic-gate BIG_ERR_CODE 2912b60f2a0bSfr41279 big_nextprime_pos_ext(BIGNUM *result, BIGNUM *n, big_modexp_ncp_info_t *info) 29137c478bd9Sstevel@tonic-gate { 29148475e043SDan OpenSolaris Anderson static const uint32_t smallprimes[] = { 29158475e043SDan OpenSolaris Anderson 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 29168475e043SDan OpenSolaris Anderson 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97 }; 29177c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 29187c478bd9Sstevel@tonic-gate int sieve[SIEVESIZE]; 29197c478bd9Sstevel@tonic-gate int i; 29207c478bd9Sstevel@tonic-gate uint32_t off, p; 29217c478bd9Sstevel@tonic-gate 2922b60f2a0bSfr41279 if ((err = big_copy(result, n)) != BIG_OK) { 29237c478bd9Sstevel@tonic-gate return (err); 2924b60f2a0bSfr41279 } 29257c478bd9Sstevel@tonic-gate result->value[0] |= 1; 2926f56c1286Srobinson /* CONSTCOND */ 29277c478bd9Sstevel@tonic-gate while (1) { 29287c478bd9Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0; 29297c478bd9Sstevel@tonic-gate for (i = 0; 2930b60f2a0bSfr41279 i < sizeof (smallprimes) / sizeof (smallprimes[0]); i++) { 29317c478bd9Sstevel@tonic-gate p = smallprimes[i]; 2932b60f2a0bSfr41279 off = big_modhalf_pos(result, p); 29337c478bd9Sstevel@tonic-gate off = p - off; 2934b60f2a0bSfr41279 if ((off % 2) == 1) { 2935b60f2a0bSfr41279 off = off + p; 2936b60f2a0bSfr41279 } 29377c478bd9Sstevel@tonic-gate off = off / 2; 29387c478bd9Sstevel@tonic-gate while (off < SIEVESIZE) { 29397c478bd9Sstevel@tonic-gate sieve[off] = 1; 29407c478bd9Sstevel@tonic-gate off = off + p; 29417c478bd9Sstevel@tonic-gate } 29427c478bd9Sstevel@tonic-gate } 29437c478bd9Sstevel@tonic-gate 29447c478bd9Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) { 29457c478bd9Sstevel@tonic-gate if (sieve[i] == 0) { 2946b60f2a0bSfr41279 err = big_isprime_pos_ext(result, info); 29477c478bd9Sstevel@tonic-gate if (err != BIG_FALSE) { 2948b60f2a0bSfr41279 if (err != BIG_TRUE) { 29497c478bd9Sstevel@tonic-gate return (err); 2950b60f2a0bSfr41279 } else { 2951b60f2a0bSfr41279 goto out; 2952b60f2a0bSfr41279 } 29537c478bd9Sstevel@tonic-gate } 29547c478bd9Sstevel@tonic-gate 29557c478bd9Sstevel@tonic-gate } 2956b60f2a0bSfr41279 if ((err = big_add_abs(result, result, &big_Two)) != 2957b60f2a0bSfr41279 BIG_OK) { 29587c478bd9Sstevel@tonic-gate return (err); 29597c478bd9Sstevel@tonic-gate } 29607c478bd9Sstevel@tonic-gate } 2961b60f2a0bSfr41279 } 2962b60f2a0bSfr41279 2963b60f2a0bSfr41279 out: 2964b60f2a0bSfr41279 return (BIG_OK); 2965b60f2a0bSfr41279 } 2966b60f2a0bSfr41279 2967b60f2a0bSfr41279 2968b60f2a0bSfr41279 BIG_ERR_CODE 2969b60f2a0bSfr41279 big_nextprime_pos(BIGNUM *result, BIGNUM *n) 2970b60f2a0bSfr41279 { 2971b60f2a0bSfr41279 return (big_nextprime_pos_ext(result, n, NULL)); 29727c478bd9Sstevel@tonic-gate } 29737c478bd9Sstevel@tonic-gate 29747c478bd9Sstevel@tonic-gate 29757c478bd9Sstevel@tonic-gate BIG_ERR_CODE 29767c478bd9Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n) 29777c478bd9Sstevel@tonic-gate { 29787c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 29797c478bd9Sstevel@tonic-gate 29807c478bd9Sstevel@tonic-gate 29817c478bd9Sstevel@tonic-gate if ((err = big_copy(result, n)) != BIG_OK) 29827c478bd9Sstevel@tonic-gate return (err); 29837c478bd9Sstevel@tonic-gate result->value[0] |= 1; 2984b60f2a0bSfr41279 while ((err = big_isprime_pos_ext(result, NULL)) != BIG_TRUE) { 29857c478bd9Sstevel@tonic-gate if (err != BIG_FALSE) 29867c478bd9Sstevel@tonic-gate return (err); 2987b60f2a0bSfr41279 if ((err = big_add_abs(result, result, &big_Two)) != BIG_OK) 29887c478bd9Sstevel@tonic-gate return (err); 29897c478bd9Sstevel@tonic-gate } 29907c478bd9Sstevel@tonic-gate return (BIG_OK); 29917c478bd9Sstevel@tonic-gate } 29927c478bd9Sstevel@tonic-gate 29937c478bd9Sstevel@tonic-gate 29947c478bd9Sstevel@tonic-gate /* 29957c478bd9Sstevel@tonic-gate * given m and e, computes the rest in the equation 29967c478bd9Sstevel@tonic-gate * gcd(m, e) = cm * m + ce * e 29977c478bd9Sstevel@tonic-gate */ 29987c478bd9Sstevel@tonic-gate BIG_ERR_CODE 29997c478bd9Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e) 30007c478bd9Sstevel@tonic-gate { 3001b60f2a0bSfr41279 BIGNUM *xi, *ri, *riminus1, *riminus2, *t; 3002b60f2a0bSfr41279 BIGNUM *vmi, *vei, *vmiminus1, *veiminus1; 30037c478bd9Sstevel@tonic-gate BIGNUM t1, t2, t3, t4, t5, t6, t7, t8, tmp; 3004b60f2a0bSfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 3005b60f2a0bSfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 3006b60f2a0bSfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 3007b60f2a0bSfr41279 BIG_CHUNK_TYPE t4value[BIGTMPSIZE]; 3008b60f2a0bSfr41279 BIG_CHUNK_TYPE t5value[BIGTMPSIZE]; 3009b60f2a0bSfr41279 BIG_CHUNK_TYPE t6value[BIGTMPSIZE]; 3010b60f2a0bSfr41279 BIG_CHUNK_TYPE t7value[BIGTMPSIZE]; 3011b60f2a0bSfr41279 BIG_CHUNK_TYPE t8value[BIGTMPSIZE]; 3012b60f2a0bSfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 30137c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 30147c478bd9Sstevel@tonic-gate int len; 30157c478bd9Sstevel@tonic-gate 3016b60f2a0bSfr41279 if (big_cmp_abs(m, e) >= 0) { 3017b60f2a0bSfr41279 len = m->len; 3018b60f2a0bSfr41279 } else { 3019b60f2a0bSfr41279 len = e->len; 3020b60f2a0bSfr41279 } 30217c478bd9Sstevel@tonic-gate 30227c478bd9Sstevel@tonic-gate if ((err = big_init1(&t1, len, 3023b60f2a0bSfr41279 t1value, arraysize(t1value))) != BIG_OK) { 30247c478bd9Sstevel@tonic-gate return (err); 3025b60f2a0bSfr41279 } 30267c478bd9Sstevel@tonic-gate if ((err = big_init1(&t2, len, 3027b60f2a0bSfr41279 t2value, arraysize(t2value))) != BIG_OK) { 30287c478bd9Sstevel@tonic-gate goto ret1; 3029b60f2a0bSfr41279 } 30307c478bd9Sstevel@tonic-gate if ((err = big_init1(&t3, len, 3031b60f2a0bSfr41279 t3value, arraysize(t3value))) != BIG_OK) { 30327c478bd9Sstevel@tonic-gate goto ret2; 3033b60f2a0bSfr41279 } 30347c478bd9Sstevel@tonic-gate if ((err = big_init1(&t4, len, 3035b60f2a0bSfr41279 t4value, arraysize(t3value))) != BIG_OK) { 30367c478bd9Sstevel@tonic-gate goto ret3; 3037b60f2a0bSfr41279 } 30387c478bd9Sstevel@tonic-gate if ((err = big_init1(&t5, len, 3039b60f2a0bSfr41279 t5value, arraysize(t5value))) != BIG_OK) { 30407c478bd9Sstevel@tonic-gate goto ret4; 3041b60f2a0bSfr41279 } 30427c478bd9Sstevel@tonic-gate if ((err = big_init1(&t6, len, 3043b60f2a0bSfr41279 t6value, arraysize(t6value))) != BIG_OK) { 30447c478bd9Sstevel@tonic-gate goto ret5; 3045b60f2a0bSfr41279 } 30467c478bd9Sstevel@tonic-gate if ((err = big_init1(&t7, len, 3047b60f2a0bSfr41279 t7value, arraysize(t7value))) != BIG_OK) { 30487c478bd9Sstevel@tonic-gate goto ret6; 3049b60f2a0bSfr41279 } 30507c478bd9Sstevel@tonic-gate if ((err = big_init1(&t8, len, 3051b60f2a0bSfr41279 t8value, arraysize(t8value))) != BIG_OK) { 30527c478bd9Sstevel@tonic-gate goto ret7; 3053b60f2a0bSfr41279 } 30547c478bd9Sstevel@tonic-gate 30557c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * len, 3056b60f2a0bSfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 30577c478bd9Sstevel@tonic-gate goto ret8; 3058b60f2a0bSfr41279 } 30597c478bd9Sstevel@tonic-gate 30607c478bd9Sstevel@tonic-gate ri = &t1; 30617c478bd9Sstevel@tonic-gate ri->value[0] = 1; 30627c478bd9Sstevel@tonic-gate ri->len = 1; 30637c478bd9Sstevel@tonic-gate xi = &t2; 30647c478bd9Sstevel@tonic-gate riminus1 = &t3; 30657c478bd9Sstevel@tonic-gate riminus2 = &t4; 30667c478bd9Sstevel@tonic-gate vmi = &t5; 30677c478bd9Sstevel@tonic-gate vei = &t6; 30687c478bd9Sstevel@tonic-gate vmiminus1 = &t7; 30697c478bd9Sstevel@tonic-gate veiminus1 = &t8; 30707c478bd9Sstevel@tonic-gate 3071b60f2a0bSfr41279 (void) big_copy(vmiminus1, &big_One); 3072b60f2a0bSfr41279 (void) big_copy(vmi, &big_One); 3073b60f2a0bSfr41279 (void) big_copy(veiminus1, &big_One); 3074b60f2a0bSfr41279 (void) big_copy(xi, &big_One); 30757c478bd9Sstevel@tonic-gate vei->len = 1; 30767c478bd9Sstevel@tonic-gate vei->value[0] = 0; 30777c478bd9Sstevel@tonic-gate 30787c478bd9Sstevel@tonic-gate (void) big_copy(riminus1, m); 30797c478bd9Sstevel@tonic-gate (void) big_copy(ri, e); 30807c478bd9Sstevel@tonic-gate 30817c478bd9Sstevel@tonic-gate while (!big_is_zero(ri)) { 30827c478bd9Sstevel@tonic-gate t = riminus2; 30837c478bd9Sstevel@tonic-gate riminus2 = riminus1; 30847c478bd9Sstevel@tonic-gate riminus1 = ri; 30857c478bd9Sstevel@tonic-gate ri = t; 3086b60f2a0bSfr41279 if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK) { 30877c478bd9Sstevel@tonic-gate goto ret; 3088b60f2a0bSfr41279 } 3089b60f2a0bSfr41279 if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK) { 30907c478bd9Sstevel@tonic-gate goto ret; 3091b60f2a0bSfr41279 } 30927c478bd9Sstevel@tonic-gate t = vmiminus1; 30937c478bd9Sstevel@tonic-gate vmiminus1 = vmi; 30947c478bd9Sstevel@tonic-gate vmi = t; 3095b60f2a0bSfr41279 if ((err = big_mul(&tmp, vei, xi)) != BIG_OK) { 30967c478bd9Sstevel@tonic-gate goto ret; 3097b60f2a0bSfr41279 } 3098b60f2a0bSfr41279 if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK) { 30997c478bd9Sstevel@tonic-gate goto ret; 3100b60f2a0bSfr41279 } 31017c478bd9Sstevel@tonic-gate t = veiminus1; 31027c478bd9Sstevel@tonic-gate veiminus1 = vei; 31037c478bd9Sstevel@tonic-gate vei = t; 3104b60f2a0bSfr41279 if ((err = big_div_pos(xi, ri, riminus2, riminus1)) != 3105b60f2a0bSfr41279 BIG_OK) { 31067c478bd9Sstevel@tonic-gate goto ret; 31077c478bd9Sstevel@tonic-gate } 3108b60f2a0bSfr41279 } 3109b60f2a0bSfr41279 if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK)) { 31107c478bd9Sstevel@tonic-gate goto ret; 3111b60f2a0bSfr41279 } 3112b60f2a0bSfr41279 if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK)) { 31137c478bd9Sstevel@tonic-gate goto ret; 3114b60f2a0bSfr41279 } 3115b60f2a0bSfr41279 if (ce != NULL) { 31167c478bd9Sstevel@tonic-gate err = big_copy(ce, vei); 3117b60f2a0bSfr41279 } 31187c478bd9Sstevel@tonic-gate ret: 31197c478bd9Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 31207c478bd9Sstevel@tonic-gate ret8: 31217c478bd9Sstevel@tonic-gate if (t8.malloced) big_finish(&t8); 31227c478bd9Sstevel@tonic-gate ret7: 31237c478bd9Sstevel@tonic-gate if (t7.malloced) big_finish(&t7); 31247c478bd9Sstevel@tonic-gate ret6: 31257c478bd9Sstevel@tonic-gate if (t6.malloced) big_finish(&t6); 31267c478bd9Sstevel@tonic-gate ret5: 31277c478bd9Sstevel@tonic-gate if (t5.malloced) big_finish(&t5); 31287c478bd9Sstevel@tonic-gate ret4: 31297c478bd9Sstevel@tonic-gate if (t4.malloced) big_finish(&t4); 31307c478bd9Sstevel@tonic-gate ret3: 31317c478bd9Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 31327c478bd9Sstevel@tonic-gate ret2: 31337c478bd9Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 31347c478bd9Sstevel@tonic-gate ret1: 31357c478bd9Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 31367c478bd9Sstevel@tonic-gate 31377c478bd9Sstevel@tonic-gate return (err); 31387c478bd9Sstevel@tonic-gate } 3139