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 5*b60f2a0bSfr41279 * Common Development and Distribution License (the "License"). 6*b60f2a0bSfr41279 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*b60f2a0bSfr41279 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #define big_div_pos_fast big_div_pos 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include "bignum.h" 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate /* 337c478bd9Sstevel@tonic-gate * Configuration guide 347c478bd9Sstevel@tonic-gate * ------------------- 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * There are 4 preprocessor symbols used to configure the bignum 377c478bd9Sstevel@tonic-gate * implementation. This file contains no logic to configure based on 387c478bd9Sstevel@tonic-gate * processor; we leave that to the Makefiles to specify. 397c478bd9Sstevel@tonic-gate * 407c478bd9Sstevel@tonic-gate * USE_FLOATING_POINT 417c478bd9Sstevel@tonic-gate * Meaning: There is support for a fast floating-point implementation of 427c478bd9Sstevel@tonic-gate * Montgomery multiply. 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * PSR_MUL 457c478bd9Sstevel@tonic-gate * Meaning: There are processor-specific versions of the low level 467c478bd9Sstevel@tonic-gate * functions to implement big_mul. Those functions are: big_mul_set_vec, 477c478bd9Sstevel@tonic-gate * big_mul_add_vec, big_mul_vec, and big_sqr_vec. PSR_MUL implies support 487c478bd9Sstevel@tonic-gate * for all 4 functions. You cannot pick and choose which subset of these 497c478bd9Sstevel@tonic-gate * functions to support; that would lead to a rat's nest of #ifdefs. 507c478bd9Sstevel@tonic-gate * 517c478bd9Sstevel@tonic-gate * HWCAP 527c478bd9Sstevel@tonic-gate * Meaning: Call multiply support functions through a function pointer. 537c478bd9Sstevel@tonic-gate * On x86, there are multiple implementations for differnt hardware 547c478bd9Sstevel@tonic-gate * capabilities, such as MMX, SSE2, etc. Tests are made at run-time, when 557c478bd9Sstevel@tonic-gate * a function is first used. So, the support functions are called through 567c478bd9Sstevel@tonic-gate * a function pointer. There is no need for that on Sparc, because there 577c478bd9Sstevel@tonic-gate * is only one implementation; support functions are called directly. 587c478bd9Sstevel@tonic-gate * Later, if there were some new VIS instruction, or something, and a 597c478bd9Sstevel@tonic-gate * run-time test were needed, rather than variant kernel modules and 607c478bd9Sstevel@tonic-gate * libraries, then HWCAP would be defined for Sparc, as well. 617c478bd9Sstevel@tonic-gate * 627c478bd9Sstevel@tonic-gate * UMUL64 637c478bd9Sstevel@tonic-gate * Meaning: It is safe to use generic C code that assumes the existence 647c478bd9Sstevel@tonic-gate * of a 32 x 32 --> 64 bit unsigned multiply. If this is not defined, 657c478bd9Sstevel@tonic-gate * then the generic code for big_mul_add_vec() must necessarily be very slow, 667c478bd9Sstevel@tonic-gate * because it must fall back to using 16 x 16 --> 32 bit multiplication. 677c478bd9Sstevel@tonic-gate * 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate #ifdef _KERNEL 72*b60f2a0bSfr41279 #include <sys/ddi.h> 73*b60f2a0bSfr41279 #include <sys/mdesc.h> 74*b60f2a0bSfr41279 #include <sys/crypto/common.h> 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate #include <sys/types.h> 777c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 787c478bd9Sstevel@tonic-gate #include <sys/param.h> 797c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate #define big_malloc(size) kmem_alloc(size, KM_NOSLEEP) 827c478bd9Sstevel@tonic-gate #define big_free(ptr, size) kmem_free(ptr, size) 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate void * 857c478bd9Sstevel@tonic-gate big_realloc(void *from, size_t oldsize, size_t newsize) 867c478bd9Sstevel@tonic-gate { 877c478bd9Sstevel@tonic-gate void *rv; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate rv = kmem_alloc(newsize, KM_NOSLEEP); 907c478bd9Sstevel@tonic-gate if (rv != NULL) 917c478bd9Sstevel@tonic-gate bcopy(from, rv, oldsize); 927c478bd9Sstevel@tonic-gate kmem_free(from, oldsize); 937c478bd9Sstevel@tonic-gate return (rv); 947c478bd9Sstevel@tonic-gate } 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate #else /* _KERNEL */ 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate #include <stdlib.h> 997c478bd9Sstevel@tonic-gate #include <stdio.h> 100*b60f2a0bSfr41279 #include <assert.h> 101*b60f2a0bSfr41279 #define ASSERT assert 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate #ifndef MALLOC_DEBUG 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate #define big_malloc(size) malloc(size) 1067c478bd9Sstevel@tonic-gate #define big_free(ptr, size) free(ptr) 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate #else 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate void 1117c478bd9Sstevel@tonic-gate big_free(void *ptr, size_t size) 1127c478bd9Sstevel@tonic-gate { 1137c478bd9Sstevel@tonic-gate printf("freed %d bytes at %p\n", size, ptr); 1147c478bd9Sstevel@tonic-gate free(ptr); 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate void * 1187c478bd9Sstevel@tonic-gate big_malloc(size_t size) 1197c478bd9Sstevel@tonic-gate { 1207c478bd9Sstevel@tonic-gate void *rv; 1217c478bd9Sstevel@tonic-gate rv = malloc(size); 1227c478bd9Sstevel@tonic-gate printf("malloced %d bytes, addr:%p\n", size, rv); 1237c478bd9Sstevel@tonic-gate return (rv); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate #endif /* MALLOC_DEBUG */ 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate #define big_realloc(x, y, z) realloc((x), (z)) 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate void 1307c478bd9Sstevel@tonic-gate printbignum(char *aname, BIGNUM *a) 1317c478bd9Sstevel@tonic-gate { 1327c478bd9Sstevel@tonic-gate int i; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate (void) printf("\n%s\n%d\n", aname, a->sign*a->len); 1357c478bd9Sstevel@tonic-gate for (i = a->len - 1; i >= 0; i--) { 136*b60f2a0bSfr41279 #ifdef BIGNUM_CHUNK_32 1377c478bd9Sstevel@tonic-gate (void) printf("%08x ", a->value[i]); 138*b60f2a0bSfr41279 if ((i % 8 == 0) && (i != 0)) { 1397c478bd9Sstevel@tonic-gate (void) printf("\n"); 1407c478bd9Sstevel@tonic-gate } 141*b60f2a0bSfr41279 #else 142*b60f2a0bSfr41279 (void) printf("%08x %08x ", (uint32_t)((a->value[i]) >> 32), 143*b60f2a0bSfr41279 (uint32_t)((a->value[i]) & 0xffffffff)); 144*b60f2a0bSfr41279 if ((i % 4 == 0) && (i != 0)) { 145*b60f2a0bSfr41279 (void) printf("\n"); 146*b60f2a0bSfr41279 } 147*b60f2a0bSfr41279 #endif 148*b60f2a0bSfr41279 } 1497c478bd9Sstevel@tonic-gate (void) printf("\n"); 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate 155*b60f2a0bSfr41279 /* size in BIG_CHUNK_SIZE-bit words */ 1567c478bd9Sstevel@tonic-gate BIG_ERR_CODE 1577c478bd9Sstevel@tonic-gate big_init(BIGNUM *number, int size) 1587c478bd9Sstevel@tonic-gate { 159*b60f2a0bSfr41279 number->value = big_malloc(sizeof (BIG_CHUNK_TYPE) * size); 1607c478bd9Sstevel@tonic-gate if (number->value == NULL) { 1617c478bd9Sstevel@tonic-gate return (BIG_NO_MEM); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate number->size = size; 1647c478bd9Sstevel@tonic-gate number->len = 0; 1657c478bd9Sstevel@tonic-gate number->sign = 1; 1667c478bd9Sstevel@tonic-gate number->malloced = 1; 1677c478bd9Sstevel@tonic-gate return (BIG_OK); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 170*b60f2a0bSfr41279 /* size in BIG_CHUNK_SIZE-bit words */ 1717c478bd9Sstevel@tonic-gate BIG_ERR_CODE 172*b60f2a0bSfr41279 big_init1(BIGNUM *number, int size, BIG_CHUNK_TYPE *buf, int bufsize) 1737c478bd9Sstevel@tonic-gate { 1747c478bd9Sstevel@tonic-gate if ((buf == NULL) || (size > bufsize)) { 175*b60f2a0bSfr41279 number->value = big_malloc(sizeof (BIG_CHUNK_TYPE) * size); 1767c478bd9Sstevel@tonic-gate if (number->value == NULL) { 1777c478bd9Sstevel@tonic-gate return (BIG_NO_MEM); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate number->size = size; 1807c478bd9Sstevel@tonic-gate number->malloced = 1; 1817c478bd9Sstevel@tonic-gate } else { 1827c478bd9Sstevel@tonic-gate number->value = buf; 1837c478bd9Sstevel@tonic-gate number->size = bufsize; 1847c478bd9Sstevel@tonic-gate number->malloced = 0; 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate number->len = 0; 1877c478bd9Sstevel@tonic-gate number->sign = 1; 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate return (BIG_OK); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate void 1937c478bd9Sstevel@tonic-gate big_finish(BIGNUM *number) 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate if (number->malloced == 1) { 196*b60f2a0bSfr41279 big_free(number->value, 197*b60f2a0bSfr41279 sizeof (BIG_CHUNK_TYPE) * number->size); 1987c478bd9Sstevel@tonic-gate number->malloced = 0; 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 202*b60f2a0bSfr41279 2037c478bd9Sstevel@tonic-gate /* 204*b60f2a0bSfr41279 * bn->size should be at least 205*b60f2a0bSfr41279 * (len + sizeof (BIG_CHUNK_TYPE) - 1) / sizeof (BIG_CHUNK_TYPE) bytes 2067c478bd9Sstevel@tonic-gate * converts from byte-big-endian format to bignum format (words in 2077c478bd9Sstevel@tonic-gate * little endian order, but bytes within the words big endian) 2087c478bd9Sstevel@tonic-gate */ 2097c478bd9Sstevel@tonic-gate void 2107c478bd9Sstevel@tonic-gate bytestring2bignum(BIGNUM *bn, uchar_t *kn, size_t len) 2117c478bd9Sstevel@tonic-gate { 2127c478bd9Sstevel@tonic-gate int i, j, offs; 213*b60f2a0bSfr41279 BIG_CHUNK_TYPE word; 2147c478bd9Sstevel@tonic-gate uchar_t *knwordp; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate #ifdef _LP64 217*b60f2a0bSfr41279 offs = (uint32_t)len % sizeof (BIG_CHUNK_TYPE); 218*b60f2a0bSfr41279 bn->len = (uint32_t)len / sizeof (BIG_CHUNK_TYPE); 219*b60f2a0bSfr41279 220*b60f2a0bSfr41279 for (i = 0; i < (uint32_t)len / sizeof (BIG_CHUNK_TYPE); i++) { 2217c478bd9Sstevel@tonic-gate #else /* !_LP64 */ 222*b60f2a0bSfr41279 offs = len % sizeof (BIG_CHUNK_TYPE); 223*b60f2a0bSfr41279 bn->len = len / sizeof (BIG_CHUNK_TYPE); 224*b60f2a0bSfr41279 for (i = 0; i < len / sizeof (BIG_CHUNK_TYPE); i++) { 2257c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 226*b60f2a0bSfr41279 knwordp = &(kn[len - sizeof (BIG_CHUNK_TYPE) * (i + 1)]); 2277c478bd9Sstevel@tonic-gate word = knwordp[0]; 228*b60f2a0bSfr41279 for (j = 1; j < sizeof (BIG_CHUNK_TYPE); j++) { 2297c478bd9Sstevel@tonic-gate word = (word << 8)+ knwordp[j]; 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate bn->value[i] = word; 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate if (offs > 0) { 2347c478bd9Sstevel@tonic-gate word = kn[0]; 2357c478bd9Sstevel@tonic-gate for (i = 1; i < offs; i++) word = (word << 8) + kn[i]; 2367c478bd9Sstevel@tonic-gate bn->value[bn->len++] = word; 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate while ((bn->len > 1) && (bn->value[bn->len-1] == 0)) { 2397c478bd9Sstevel@tonic-gate bn->len --; 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate /* 2447c478bd9Sstevel@tonic-gate * copies the least significant len bytes if 245*b60f2a0bSfr41279 * len < bn->len * sizeof (BIG_CHUNK_TYPE) 2467c478bd9Sstevel@tonic-gate * converts from bignum format to byte-big-endian format. 247*b60f2a0bSfr41279 * bignum format is words of type BIG_CHUNK_TYPE in little endian order. 2487c478bd9Sstevel@tonic-gate */ 2497c478bd9Sstevel@tonic-gate void 2507c478bd9Sstevel@tonic-gate bignum2bytestring(uchar_t *kn, BIGNUM *bn, size_t len) 2517c478bd9Sstevel@tonic-gate { 2527c478bd9Sstevel@tonic-gate int i, j, offs; 253*b60f2a0bSfr41279 BIG_CHUNK_TYPE word; 2547c478bd9Sstevel@tonic-gate 255*b60f2a0bSfr41279 if (len < sizeof (BIG_CHUNK_TYPE) * bn->len) { 2567c478bd9Sstevel@tonic-gate #ifdef _LP64 257*b60f2a0bSfr41279 for (i = 0; i < (uint32_t)len / sizeof (BIG_CHUNK_TYPE); i++) { 2587c478bd9Sstevel@tonic-gate #else /* !_LP64 */ 259*b60f2a0bSfr41279 for (i = 0; i < len / sizeof (BIG_CHUNK_TYPE); i++) { 2607c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 2617c478bd9Sstevel@tonic-gate word = bn->value[i]; 262*b60f2a0bSfr41279 for (j = 0; j < sizeof (BIG_CHUNK_TYPE); j++) { 263*b60f2a0bSfr41279 kn[len - sizeof (BIG_CHUNK_TYPE) * i - j - 1] = 2647c478bd9Sstevel@tonic-gate word & 0xff; 2657c478bd9Sstevel@tonic-gate word = word >> 8; 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate #ifdef _LP64 269*b60f2a0bSfr41279 offs = (uint32_t)len % sizeof (BIG_CHUNK_TYPE); 2707c478bd9Sstevel@tonic-gate #else /* !_LP64 */ 271*b60f2a0bSfr41279 offs = len % sizeof (BIG_CHUNK_TYPE); 2727c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 2737c478bd9Sstevel@tonic-gate if (offs > 0) { 274*b60f2a0bSfr41279 word = bn->value[len / sizeof (BIG_CHUNK_TYPE)]; 2757c478bd9Sstevel@tonic-gate #ifdef _LP64 276*b60f2a0bSfr41279 for (i = (uint32_t)len % sizeof (BIG_CHUNK_TYPE); 2777c478bd9Sstevel@tonic-gate i > 0; i --) { 2787c478bd9Sstevel@tonic-gate #else /* !_LP64 */ 279*b60f2a0bSfr41279 for (i = len % sizeof (BIG_CHUNK_TYPE); 280*b60f2a0bSfr41279 i > 0; i --) { 2817c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 2827c478bd9Sstevel@tonic-gate kn[i - 1] = word & 0xff; 2837c478bd9Sstevel@tonic-gate word = word >> 8; 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate } else { 2877c478bd9Sstevel@tonic-gate for (i = 0; i < bn->len; i++) { 2887c478bd9Sstevel@tonic-gate word = bn->value[i]; 289*b60f2a0bSfr41279 for (j = 0; j < sizeof (BIG_CHUNK_TYPE); j++) { 290*b60f2a0bSfr41279 kn[len - sizeof (BIG_CHUNK_TYPE) * i - j - 1] = 2917c478bd9Sstevel@tonic-gate word & 0xff; 2927c478bd9Sstevel@tonic-gate word = word >> 8; 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate #ifdef _LP64 296*b60f2a0bSfr41279 for (i = 0; 297*b60f2a0bSfr41279 i < (uint32_t)len - sizeof (BIG_CHUNK_TYPE) * bn->len; 2987c478bd9Sstevel@tonic-gate i++) { 2997c478bd9Sstevel@tonic-gate #else /* !_LP64 */ 300*b60f2a0bSfr41279 for (i = 0; i < len - sizeof (BIG_CHUNK_TYPE) * bn->len; i++) { 3017c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 3027c478bd9Sstevel@tonic-gate kn[i] = 0; 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate int 3097c478bd9Sstevel@tonic-gate big_bitlength(BIGNUM *a) 3107c478bd9Sstevel@tonic-gate { 311*b60f2a0bSfr41279 int l = 0, b = 0; 312*b60f2a0bSfr41279 BIG_CHUNK_TYPE c; 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate l = a->len - 1; 3157c478bd9Sstevel@tonic-gate while ((l > 0) && (a->value[l] == 0)) { 3167c478bd9Sstevel@tonic-gate l--; 3177c478bd9Sstevel@tonic-gate } 318*b60f2a0bSfr41279 b = sizeof (BIG_CHUNK_TYPE) * BITSINBYTE; 3197c478bd9Sstevel@tonic-gate c = a->value[l]; 320*b60f2a0bSfr41279 while ((b > 1) && ((c & BIG_CHUNK_HIGHBIT) == 0)) { 3217c478bd9Sstevel@tonic-gate c = c << 1; 3227c478bd9Sstevel@tonic-gate b--; 3237c478bd9Sstevel@tonic-gate } 324*b60f2a0bSfr41279 325*b60f2a0bSfr41279 return (l * sizeof (BIG_CHUNK_TYPE) * BITSINBYTE + b); 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate BIG_ERR_CODE 3307c478bd9Sstevel@tonic-gate big_copy(BIGNUM *dest, BIGNUM *src) 3317c478bd9Sstevel@tonic-gate { 332*b60f2a0bSfr41279 BIG_CHUNK_TYPE *newptr; 3337c478bd9Sstevel@tonic-gate int i, len; 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate len = src->len; 336*b60f2a0bSfr41279 while ((len > 1) && (src->value[len - 1] == 0)) { 3377c478bd9Sstevel@tonic-gate len--; 338*b60f2a0bSfr41279 } 3397c478bd9Sstevel@tonic-gate src->len = len; 3407c478bd9Sstevel@tonic-gate if (dest->size < len) { 3417c478bd9Sstevel@tonic-gate if (dest->malloced == 1) { 342*b60f2a0bSfr41279 newptr = (BIG_CHUNK_TYPE *)big_realloc(dest->value, 343*b60f2a0bSfr41279 sizeof (BIG_CHUNK_TYPE) * dest->size, 344*b60f2a0bSfr41279 sizeof (BIG_CHUNK_TYPE) * len); 3457c478bd9Sstevel@tonic-gate } else { 346*b60f2a0bSfr41279 newptr = (BIG_CHUNK_TYPE *) 347*b60f2a0bSfr41279 big_malloc(sizeof (BIG_CHUNK_TYPE) * len); 348*b60f2a0bSfr41279 if (newptr != NULL) { 349*b60f2a0bSfr41279 dest->malloced = 1; 3507c478bd9Sstevel@tonic-gate } 351*b60f2a0bSfr41279 } 352*b60f2a0bSfr41279 if (newptr == NULL) { 3537c478bd9Sstevel@tonic-gate return (BIG_NO_MEM); 354*b60f2a0bSfr41279 } 3557c478bd9Sstevel@tonic-gate dest->value = newptr; 3567c478bd9Sstevel@tonic-gate dest->size = len; 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate dest->len = len; 3597c478bd9Sstevel@tonic-gate dest->sign = src->sign; 360*b60f2a0bSfr41279 for (i = 0; i < len; i++) { 361*b60f2a0bSfr41279 dest->value[i] = src->value[i]; 362*b60f2a0bSfr41279 } 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate return (BIG_OK); 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate BIG_ERR_CODE 3697c478bd9Sstevel@tonic-gate big_extend(BIGNUM *number, int size) 3707c478bd9Sstevel@tonic-gate { 371*b60f2a0bSfr41279 BIG_CHUNK_TYPE *newptr; 3727c478bd9Sstevel@tonic-gate int i; 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate if (number->size >= size) 3757c478bd9Sstevel@tonic-gate return (BIG_OK); 3767c478bd9Sstevel@tonic-gate if (number->malloced) { 377*b60f2a0bSfr41279 number->value = big_realloc(number->value, 378*b60f2a0bSfr41279 sizeof (BIG_CHUNK_TYPE) * number->size, 379*b60f2a0bSfr41279 sizeof (BIG_CHUNK_TYPE) * size); 3807c478bd9Sstevel@tonic-gate } else { 381*b60f2a0bSfr41279 newptr = big_malloc(sizeof (BIG_CHUNK_TYPE) * size); 3827c478bd9Sstevel@tonic-gate if (newptr != NULL) { 3837c478bd9Sstevel@tonic-gate for (i = 0; i < number->size; i++) { 3847c478bd9Sstevel@tonic-gate newptr[i] = number->value[i]; 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate number->value = newptr; 3887c478bd9Sstevel@tonic-gate } 3897c478bd9Sstevel@tonic-gate 390*b60f2a0bSfr41279 if (number->value == NULL) { 3917c478bd9Sstevel@tonic-gate return (BIG_NO_MEM); 392*b60f2a0bSfr41279 } 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate number->size = size; 3957c478bd9Sstevel@tonic-gate number->malloced = 1; 3967c478bd9Sstevel@tonic-gate return (BIG_OK); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate 400*b60f2a0bSfr41279 /* returns 1 if n == 0 */ 4017c478bd9Sstevel@tonic-gate int 4027c478bd9Sstevel@tonic-gate big_is_zero(BIGNUM *n) 4037c478bd9Sstevel@tonic-gate { 4047c478bd9Sstevel@tonic-gate int i, result; 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate result = 1; 407*b60f2a0bSfr41279 for (i = 0; i < n->len; i++) { 408*b60f2a0bSfr41279 if (n->value[i] != 0) { 409*b60f2a0bSfr41279 result = 0; 410*b60f2a0bSfr41279 } 411*b60f2a0bSfr41279 } 4127c478bd9Sstevel@tonic-gate return (result); 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate BIG_ERR_CODE 4177c478bd9Sstevel@tonic-gate big_add_abs(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 4187c478bd9Sstevel@tonic-gate { 4197c478bd9Sstevel@tonic-gate int i, shorter, longer; 420*b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, ai; 421*b60f2a0bSfr41279 BIG_CHUNK_TYPE *r, *a, *b, *c; 4227c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 423*b60f2a0bSfr41279 BIGNUM *longerarg; 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate if (aa->len > bb->len) { 4267c478bd9Sstevel@tonic-gate shorter = bb->len; 4277c478bd9Sstevel@tonic-gate longer = aa->len; 428*b60f2a0bSfr41279 longerarg = aa; 4297c478bd9Sstevel@tonic-gate } else { 4307c478bd9Sstevel@tonic-gate shorter = aa->len; 4317c478bd9Sstevel@tonic-gate longer = bb->len; 432*b60f2a0bSfr41279 longerarg = bb; 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate if (result->size < longer + 1) { 4357c478bd9Sstevel@tonic-gate err = big_extend(result, longer + 1); 436*b60f2a0bSfr41279 if (err != BIG_OK) { 4377c478bd9Sstevel@tonic-gate return (err); 4387c478bd9Sstevel@tonic-gate } 439*b60f2a0bSfr41279 } 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate r = result->value; 4427c478bd9Sstevel@tonic-gate a = aa->value; 4437c478bd9Sstevel@tonic-gate b = bb->value; 444*b60f2a0bSfr41279 c = longerarg->value; 4457c478bd9Sstevel@tonic-gate cy = 0; 4467c478bd9Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 4477c478bd9Sstevel@tonic-gate ai = a[i]; 4487c478bd9Sstevel@tonic-gate r[i] = ai + b[i] + cy; 449*b60f2a0bSfr41279 if (r[i] > ai) { 450*b60f2a0bSfr41279 cy = 0; 451*b60f2a0bSfr41279 } else if (r[i] < ai) { 452*b60f2a0bSfr41279 cy = 1; 453*b60f2a0bSfr41279 } 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate for (; i < longer; i++) { 4567c478bd9Sstevel@tonic-gate ai = c[i]; 4577c478bd9Sstevel@tonic-gate r[i] = ai + cy; 458*b60f2a0bSfr41279 if (r[i] >= ai) { 459*b60f2a0bSfr41279 cy = 0; 460*b60f2a0bSfr41279 } 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate if (cy == 1) { 4637c478bd9Sstevel@tonic-gate r[i] = cy; 4647c478bd9Sstevel@tonic-gate result->len = longer + 1; 4657c478bd9Sstevel@tonic-gate } else { 4667c478bd9Sstevel@tonic-gate result->len = longer; 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate result->sign = 1; 4697c478bd9Sstevel@tonic-gate return (BIG_OK); 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate /* caller must make sure that result has at least len words allocated */ 4747c478bd9Sstevel@tonic-gate void 475*b60f2a0bSfr41279 big_sub_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, BIG_CHUNK_TYPE *b, int len) 4767c478bd9Sstevel@tonic-gate { 4777c478bd9Sstevel@tonic-gate int i; 478*b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, ai; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate cy = 1; 4817c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) { 4827c478bd9Sstevel@tonic-gate ai = a[i]; 4837c478bd9Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 484*b60f2a0bSfr41279 if (r[i] > ai) { 485*b60f2a0bSfr41279 cy = 0; 486*b60f2a0bSfr41279 } else if (r[i] < ai) { 487*b60f2a0bSfr41279 cy = 1; 488*b60f2a0bSfr41279 } 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate /* result=aa-bb it is assumed that aa>=bb */ 4947c478bd9Sstevel@tonic-gate BIG_ERR_CODE 4957c478bd9Sstevel@tonic-gate big_sub_pos(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 4967c478bd9Sstevel@tonic-gate { 4977c478bd9Sstevel@tonic-gate int i, shorter; 498*b60f2a0bSfr41279 BIG_CHUNK_TYPE cy = 1, ai; 499*b60f2a0bSfr41279 BIG_CHUNK_TYPE *r, *a, *b; 500*b60f2a0bSfr41279 BIG_ERR_CODE err = BIG_OK; 5017c478bd9Sstevel@tonic-gate 502*b60f2a0bSfr41279 if (aa->len > bb->len) { 503*b60f2a0bSfr41279 shorter = bb->len; 504*b60f2a0bSfr41279 } else { 505*b60f2a0bSfr41279 shorter = aa->len; 506*b60f2a0bSfr41279 } 5077c478bd9Sstevel@tonic-gate if (result->size < aa->len) { 5087c478bd9Sstevel@tonic-gate err = big_extend(result, aa->len); 509*b60f2a0bSfr41279 if (err != BIG_OK) { 5107c478bd9Sstevel@tonic-gate return (err); 5117c478bd9Sstevel@tonic-gate } 512*b60f2a0bSfr41279 } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate r = result->value; 5157c478bd9Sstevel@tonic-gate a = aa->value; 5167c478bd9Sstevel@tonic-gate b = bb->value; 5177c478bd9Sstevel@tonic-gate result->len = aa->len; 5187c478bd9Sstevel@tonic-gate cy = 1; 5197c478bd9Sstevel@tonic-gate for (i = 0; i < shorter; i++) { 5207c478bd9Sstevel@tonic-gate ai = a[i]; 5217c478bd9Sstevel@tonic-gate r[i] = ai + (~b[i]) + cy; 522*b60f2a0bSfr41279 if (r[i] > ai) { 523*b60f2a0bSfr41279 cy = 0; 524*b60f2a0bSfr41279 } else if (r[i] < ai) { 525*b60f2a0bSfr41279 cy = 1; 526*b60f2a0bSfr41279 } 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate for (; i < aa->len; i++) { 5297c478bd9Sstevel@tonic-gate ai = a[i]; 5307c478bd9Sstevel@tonic-gate r[i] = ai + (~0) + cy; 531*b60f2a0bSfr41279 if (r[i] < ai) { 532*b60f2a0bSfr41279 cy = 1; 533*b60f2a0bSfr41279 } 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate result->sign = 1; 536*b60f2a0bSfr41279 537*b60f2a0bSfr41279 if (cy == 0) { 5387c478bd9Sstevel@tonic-gate return (BIG_INVALID_ARGS); 539*b60f2a0bSfr41279 } else { 5407c478bd9Sstevel@tonic-gate return (BIG_OK); 5417c478bd9Sstevel@tonic-gate } 542*b60f2a0bSfr41279 } 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate /* returns -1 if |aa|<|bb|, 0 if |aa|==|bb| 1 if |aa|>|bb| */ 5467c478bd9Sstevel@tonic-gate int 5477c478bd9Sstevel@tonic-gate big_cmp_abs(BIGNUM *aa, BIGNUM *bb) 5487c478bd9Sstevel@tonic-gate { 5497c478bd9Sstevel@tonic-gate int i; 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate if (aa->len > bb->len) { 5527c478bd9Sstevel@tonic-gate for (i = aa->len - 1; i > bb->len - 1; i--) { 553*b60f2a0bSfr41279 if (aa->value[i] > 0) { 5547c478bd9Sstevel@tonic-gate return (1); 5557c478bd9Sstevel@tonic-gate } 556*b60f2a0bSfr41279 } 5577c478bd9Sstevel@tonic-gate } else if (aa->len < bb->len) { 5587c478bd9Sstevel@tonic-gate for (i = bb->len - 1; i > aa->len - 1; i--) { 559*b60f2a0bSfr41279 if (bb->value[i] > 0) { 5607c478bd9Sstevel@tonic-gate return (-1); 5617c478bd9Sstevel@tonic-gate } 562*b60f2a0bSfr41279 } 563*b60f2a0bSfr41279 } else { 564*b60f2a0bSfr41279 i = aa->len-1; 565*b60f2a0bSfr41279 } 5667c478bd9Sstevel@tonic-gate for (; i >= 0; i--) { 567*b60f2a0bSfr41279 if (aa->value[i] > bb->value[i]) { 5687c478bd9Sstevel@tonic-gate return (1); 569*b60f2a0bSfr41279 } else if (aa->value[i] < bb->value[i]) { 5707c478bd9Sstevel@tonic-gate return (-1); 5717c478bd9Sstevel@tonic-gate } 572*b60f2a0bSfr41279 } 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate return (0); 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate BIG_ERR_CODE 5797c478bd9Sstevel@tonic-gate big_sub(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 5807c478bd9Sstevel@tonic-gate { 5817c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate if ((bb->sign == -1) && (aa->sign == 1)) { 584*b60f2a0bSfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 5857c478bd9Sstevel@tonic-gate return (err); 586*b60f2a0bSfr41279 } 5877c478bd9Sstevel@tonic-gate result->sign = 1; 5887c478bd9Sstevel@tonic-gate } else if ((aa->sign == -1) && (bb->sign == 1)) { 589*b60f2a0bSfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 5907c478bd9Sstevel@tonic-gate return (err); 591*b60f2a0bSfr41279 } 5927c478bd9Sstevel@tonic-gate result->sign = -1; 5937c478bd9Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == 1)) { 5947c478bd9Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 595*b60f2a0bSfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 5967c478bd9Sstevel@tonic-gate return (err); 597*b60f2a0bSfr41279 } 5987c478bd9Sstevel@tonic-gate result->sign = 1; 5997c478bd9Sstevel@tonic-gate } else { 600*b60f2a0bSfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6017c478bd9Sstevel@tonic-gate return (err); 602*b60f2a0bSfr41279 } 6037c478bd9Sstevel@tonic-gate result->sign = -1; 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate } else { 6067c478bd9Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 607*b60f2a0bSfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6087c478bd9Sstevel@tonic-gate return (err); 609*b60f2a0bSfr41279 } 6107c478bd9Sstevel@tonic-gate result->sign = -1; 6117c478bd9Sstevel@tonic-gate } else { 612*b60f2a0bSfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6137c478bd9Sstevel@tonic-gate return (err); 614*b60f2a0bSfr41279 } 6157c478bd9Sstevel@tonic-gate result->sign = 1; 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate return (BIG_OK); 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate BIG_ERR_CODE 6237c478bd9Sstevel@tonic-gate big_add(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 6247c478bd9Sstevel@tonic-gate { 6257c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate if ((bb->sign == -1) && (aa->sign == -1)) { 628*b60f2a0bSfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6297c478bd9Sstevel@tonic-gate return (err); 630*b60f2a0bSfr41279 } 6317c478bd9Sstevel@tonic-gate result->sign = -1; 6327c478bd9Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == 1)) { 633*b60f2a0bSfr41279 if ((err = big_add_abs(result, aa, bb)) != BIG_OK) { 6347c478bd9Sstevel@tonic-gate return (err); 635*b60f2a0bSfr41279 } 6367c478bd9Sstevel@tonic-gate result->sign = 1; 6377c478bd9Sstevel@tonic-gate } else if ((aa->sign == 1) && (bb->sign == -1)) { 6387c478bd9Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 639*b60f2a0bSfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6407c478bd9Sstevel@tonic-gate return (err); 641*b60f2a0bSfr41279 } 6427c478bd9Sstevel@tonic-gate result->sign = 1; 6437c478bd9Sstevel@tonic-gate } else { 644*b60f2a0bSfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6457c478bd9Sstevel@tonic-gate return (err); 646*b60f2a0bSfr41279 } 6477c478bd9Sstevel@tonic-gate result->sign = -1; 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate } else { 6507c478bd9Sstevel@tonic-gate if (big_cmp_abs(aa, bb) >= 0) { 651*b60f2a0bSfr41279 if ((err = big_sub_pos(result, aa, bb)) != BIG_OK) { 6527c478bd9Sstevel@tonic-gate return (err); 653*b60f2a0bSfr41279 } 6547c478bd9Sstevel@tonic-gate result->sign = -1; 6557c478bd9Sstevel@tonic-gate } else { 656*b60f2a0bSfr41279 if ((err = big_sub_pos(result, bb, aa)) != BIG_OK) { 6577c478bd9Sstevel@tonic-gate return (err); 658*b60f2a0bSfr41279 } 6597c478bd9Sstevel@tonic-gate result->sign = 1; 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate return (BIG_OK); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate 666*b60f2a0bSfr41279 /* result = aa/2 */ 6677c478bd9Sstevel@tonic-gate BIG_ERR_CODE 6687c478bd9Sstevel@tonic-gate big_half_pos(BIGNUM *result, BIGNUM *aa) 6697c478bd9Sstevel@tonic-gate { 6707c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 6717c478bd9Sstevel@tonic-gate int i; 672*b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, cy1; 673*b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *r; 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate if (result->size < aa->len) { 6767c478bd9Sstevel@tonic-gate err = big_extend(result, aa->len); 677*b60f2a0bSfr41279 if (err != BIG_OK) { 6787c478bd9Sstevel@tonic-gate return (err); 6797c478bd9Sstevel@tonic-gate } 680*b60f2a0bSfr41279 } 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate result->len = aa->len; 6837c478bd9Sstevel@tonic-gate a = aa->value; 6847c478bd9Sstevel@tonic-gate r = result->value; 6857c478bd9Sstevel@tonic-gate cy = 0; 6867c478bd9Sstevel@tonic-gate for (i = aa->len - 1; i >= 0; i--) { 687*b60f2a0bSfr41279 cy1 = a[i] << (BIG_CHUNK_SIZE - 1); 6887c478bd9Sstevel@tonic-gate r[i] = (cy | (a[i] >> 1)); 6897c478bd9Sstevel@tonic-gate cy = cy1; 6907c478bd9Sstevel@tonic-gate } 691*b60f2a0bSfr41279 if (r[result->len - 1] == 0) { 692*b60f2a0bSfr41279 result->len--; 693*b60f2a0bSfr41279 } 694*b60f2a0bSfr41279 6957c478bd9Sstevel@tonic-gate return (BIG_OK); 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 698*b60f2a0bSfr41279 /* result = aa*2 */ 6997c478bd9Sstevel@tonic-gate BIG_ERR_CODE 7007c478bd9Sstevel@tonic-gate big_double(BIGNUM *result, BIGNUM *aa) 7017c478bd9Sstevel@tonic-gate { 7027c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 7037c478bd9Sstevel@tonic-gate int i, rsize; 704*b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, cy1; 705*b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *r; 7067c478bd9Sstevel@tonic-gate 707*b60f2a0bSfr41279 if ((aa->len > 0) && 708*b60f2a0bSfr41279 ((aa->value[aa->len - 1] & BIG_CHUNK_HIGHBIT) != 0)) { 7097c478bd9Sstevel@tonic-gate rsize = aa->len + 1; 710*b60f2a0bSfr41279 } else { 711*b60f2a0bSfr41279 rsize = aa->len; 712*b60f2a0bSfr41279 } 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate if (result->size < rsize) { 7157c478bd9Sstevel@tonic-gate err = big_extend(result, rsize); 7167c478bd9Sstevel@tonic-gate if (err != BIG_OK) 7177c478bd9Sstevel@tonic-gate return (err); 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate a = aa->value; 7217c478bd9Sstevel@tonic-gate r = result->value; 722*b60f2a0bSfr41279 if (rsize == aa->len + 1) { 723*b60f2a0bSfr41279 r[rsize - 1] = 1; 724*b60f2a0bSfr41279 } 7257c478bd9Sstevel@tonic-gate cy = 0; 7267c478bd9Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 727*b60f2a0bSfr41279 cy1 = a[i] >> (BIG_CHUNK_SIZE - 1); 7287c478bd9Sstevel@tonic-gate r[i] = (cy | (a[i] << 1)); 7297c478bd9Sstevel@tonic-gate cy = cy1; 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate result->len = rsize; 7327c478bd9Sstevel@tonic-gate return (BIG_OK); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 735*b60f2a0bSfr41279 736*b60f2a0bSfr41279 /* 737*b60f2a0bSfr41279 * returns aa mod b, aa must be nonneg, b must be a max 738*b60f2a0bSfr41279 * (BIG_CHUNK_SIZE / 2)-bit integer 739*b60f2a0bSfr41279 */ 740*b60f2a0bSfr41279 static uint32_t 741*b60f2a0bSfr41279 big_modhalf_pos(BIGNUM *aa, uint32_t b) 7427c478bd9Sstevel@tonic-gate { 7437c478bd9Sstevel@tonic-gate int i; 744*b60f2a0bSfr41279 BIG_CHUNK_TYPE rem; 7457c478bd9Sstevel@tonic-gate 746*b60f2a0bSfr41279 if (aa->len == 0) { 7477c478bd9Sstevel@tonic-gate return (0); 748*b60f2a0bSfr41279 } 7497c478bd9Sstevel@tonic-gate rem = aa->value[aa->len - 1] % b; 7507c478bd9Sstevel@tonic-gate for (i = aa->len - 2; i >= 0; i--) { 751*b60f2a0bSfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 752*b60f2a0bSfr41279 (aa->value[i] >> (BIG_CHUNK_SIZE / 2))) % b; 753*b60f2a0bSfr41279 rem = ((rem << (BIG_CHUNK_SIZE / 2)) | 754*b60f2a0bSfr41279 (aa->value[i] & BIG_CHUNK_LOWHALFBITS)) % b; 7557c478bd9Sstevel@tonic-gate } 756*b60f2a0bSfr41279 757*b60f2a0bSfr41279 return ((uint32_t)rem); 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate /* 762*b60f2a0bSfr41279 * result = aa - (2^BIG_CHUNK_SIZE)^lendiff * bb 7637c478bd9Sstevel@tonic-gate * result->size should be at least aa->len at entry 7647c478bd9Sstevel@tonic-gate * aa, bb, and result should be positive 7657c478bd9Sstevel@tonic-gate */ 7667c478bd9Sstevel@tonic-gate void 7677c478bd9Sstevel@tonic-gate big_sub_pos_high(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 7687c478bd9Sstevel@tonic-gate { 7697c478bd9Sstevel@tonic-gate int i, lendiff; 7707c478bd9Sstevel@tonic-gate BIGNUM res1, aa1; 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate lendiff = aa->len - bb->len; 7737c478bd9Sstevel@tonic-gate res1.size = result->size - lendiff; 7747c478bd9Sstevel@tonic-gate res1.malloced = 0; 7757c478bd9Sstevel@tonic-gate res1.value = result->value + lendiff; 7767c478bd9Sstevel@tonic-gate aa1.size = aa->size - lendiff; 7777c478bd9Sstevel@tonic-gate aa1.value = aa->value + lendiff; 7787c478bd9Sstevel@tonic-gate aa1.len = bb->len; 7797c478bd9Sstevel@tonic-gate aa1.sign = 1; 7807c478bd9Sstevel@tonic-gate (void) big_sub_pos(&res1, &aa1, bb); 7817c478bd9Sstevel@tonic-gate if (result->value != aa->value) { 7827c478bd9Sstevel@tonic-gate for (i = 0; i < lendiff; i++) { 7837c478bd9Sstevel@tonic-gate result->value[i] = aa->value[i]; 7847c478bd9Sstevel@tonic-gate } 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate result->len = aa->len; 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate /* 7917c478bd9Sstevel@tonic-gate * returns 1, 0, or -1 depending on whether |aa| > , ==, or < 792*b60f2a0bSfr41279 * (2^BIG_CHUNK_SIZE)^lendiff * |bb| 7937c478bd9Sstevel@tonic-gate * aa->len should be >= bb->len 7947c478bd9Sstevel@tonic-gate */ 7957c478bd9Sstevel@tonic-gate int 7967c478bd9Sstevel@tonic-gate big_cmp_abs_high(BIGNUM *aa, BIGNUM *bb) 7977c478bd9Sstevel@tonic-gate { 7987c478bd9Sstevel@tonic-gate int lendiff; 7997c478bd9Sstevel@tonic-gate BIGNUM aa1; 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate lendiff = aa->len - bb->len; 8027c478bd9Sstevel@tonic-gate aa1.len = bb->len; 8037c478bd9Sstevel@tonic-gate aa1.size = aa->size - lendiff; 8047c478bd9Sstevel@tonic-gate aa1.malloced = 0; 8057c478bd9Sstevel@tonic-gate aa1.value = aa->value + lendiff; 8067c478bd9Sstevel@tonic-gate return (big_cmp_abs(&aa1, bb)); 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate /* 811*b60f2a0bSfr41279 * result = aa * b where b is a max. (BIG_CHUNK_SIZE / 2)-bit positive integer. 8127c478bd9Sstevel@tonic-gate * result should have enough space allocated. 8137c478bd9Sstevel@tonic-gate */ 814*b60f2a0bSfr41279 static void 815*b60f2a0bSfr41279 big_mulhalf_low(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 8167c478bd9Sstevel@tonic-gate { 8177c478bd9Sstevel@tonic-gate int i; 818*b60f2a0bSfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy; 819*b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *r; 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate a = aa->value; 8227c478bd9Sstevel@tonic-gate r = result->value; 8237c478bd9Sstevel@tonic-gate cy = 0; 8247c478bd9Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 8257c478bd9Sstevel@tonic-gate ai = a[i]; 826*b60f2a0bSfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 827*b60f2a0bSfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 828*b60f2a0bSfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 829*b60f2a0bSfr41279 r[i] = (t1 & BIG_CHUNK_LOWHALFBITS) | 830*b60f2a0bSfr41279 (t2 << (BIG_CHUNK_SIZE / 2)); 831*b60f2a0bSfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate r[i] = cy; 8347c478bd9Sstevel@tonic-gate result->len = aa->len + 1; 8357c478bd9Sstevel@tonic-gate result->sign = aa->sign; 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate /* 840*b60f2a0bSfr41279 * result = aa * b * 2^(BIG_CHUNK_SIZE / 2) where b is a max. 841*b60f2a0bSfr41279 * (BIG_CHUNK_SIZE / 2)-bit positive integer. 8427c478bd9Sstevel@tonic-gate * result should have enough space allocated. 8437c478bd9Sstevel@tonic-gate */ 844*b60f2a0bSfr41279 static void 845*b60f2a0bSfr41279 big_mulhalf_high(BIGNUM *result, BIGNUM *aa, BIG_CHUNK_TYPE b) 8467c478bd9Sstevel@tonic-gate { 8477c478bd9Sstevel@tonic-gate int i; 848*b60f2a0bSfr41279 BIG_CHUNK_TYPE t1, t2, ai, cy, ri; 849*b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *r; 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate a = aa->value; 8527c478bd9Sstevel@tonic-gate r = result->value; 8537c478bd9Sstevel@tonic-gate cy = 0; 8547c478bd9Sstevel@tonic-gate ri = 0; 8557c478bd9Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 8567c478bd9Sstevel@tonic-gate ai = a[i]; 857*b60f2a0bSfr41279 t1 = (ai & BIG_CHUNK_LOWHALFBITS) * b + cy; 858*b60f2a0bSfr41279 t2 = (ai >> (BIG_CHUNK_SIZE / 2)) * b + 859*b60f2a0bSfr41279 (t1 >> (BIG_CHUNK_SIZE / 2)); 860*b60f2a0bSfr41279 r[i] = (t1 << (BIG_CHUNK_SIZE / 2)) + ri; 861*b60f2a0bSfr41279 ri = t2 & BIG_CHUNK_LOWHALFBITS; 862*b60f2a0bSfr41279 cy = t2 >> (BIG_CHUNK_SIZE / 2); 8637c478bd9Sstevel@tonic-gate } 864*b60f2a0bSfr41279 r[i] = (cy << (BIG_CHUNK_SIZE / 2)) + ri; 8657c478bd9Sstevel@tonic-gate result->len = aa->len + 1; 8667c478bd9Sstevel@tonic-gate result->sign = aa->sign; 8677c478bd9Sstevel@tonic-gate } 8687c478bd9Sstevel@tonic-gate 869*b60f2a0bSfr41279 8707c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 8717c478bd9Sstevel@tonic-gate void 8727c478bd9Sstevel@tonic-gate big_shiftleft(BIGNUM *result, BIGNUM *aa, int offs) 8737c478bd9Sstevel@tonic-gate { 8747c478bd9Sstevel@tonic-gate int i; 875*b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, ai; 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate if (offs == 0) { 8787c478bd9Sstevel@tonic-gate if (result != aa) { 8797c478bd9Sstevel@tonic-gate (void) big_copy(result, aa); 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate return; 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate cy = 0; 8847c478bd9Sstevel@tonic-gate for (i = 0; i < aa->len; i++) { 8857c478bd9Sstevel@tonic-gate ai = aa->value[i]; 8867c478bd9Sstevel@tonic-gate result->value[i] = (ai << offs) | cy; 887*b60f2a0bSfr41279 cy = ai >> (BIG_CHUNK_SIZE - offs); 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate if (cy != 0) { 8907c478bd9Sstevel@tonic-gate result->len = aa->len + 1; 8917c478bd9Sstevel@tonic-gate result->value[result->len - 1] = cy; 8927c478bd9Sstevel@tonic-gate } else { 8937c478bd9Sstevel@tonic-gate result->len = aa->len; 8947c478bd9Sstevel@tonic-gate } 8957c478bd9Sstevel@tonic-gate result->sign = aa->sign; 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 898*b60f2a0bSfr41279 8997c478bd9Sstevel@tonic-gate /* it is assumed that result->size is big enough */ 9007c478bd9Sstevel@tonic-gate void 9017c478bd9Sstevel@tonic-gate big_shiftright(BIGNUM *result, BIGNUM *aa, int offs) 9027c478bd9Sstevel@tonic-gate { 9037c478bd9Sstevel@tonic-gate int i; 904*b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, ai; 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate if (offs == 0) { 9077c478bd9Sstevel@tonic-gate if (result != aa) { 9087c478bd9Sstevel@tonic-gate (void) big_copy(result, aa); 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate return; 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate cy = aa->value[0] >> offs; 9137c478bd9Sstevel@tonic-gate for (i = 1; i < aa->len; i++) { 9147c478bd9Sstevel@tonic-gate ai = aa->value[i]; 915*b60f2a0bSfr41279 result->value[i-1] = (ai << (BIG_CHUNK_SIZE - offs)) | cy; 9167c478bd9Sstevel@tonic-gate cy = ai >> offs; 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate result->len = aa->len; 9197c478bd9Sstevel@tonic-gate result->value[result->len - 1] = cy; 9207c478bd9Sstevel@tonic-gate result->sign = aa->sign; 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate /* 9257c478bd9Sstevel@tonic-gate * result = aa/bb remainder = aa mod bb 9267c478bd9Sstevel@tonic-gate * it is assumed that aa and bb are positive 9277c478bd9Sstevel@tonic-gate */ 9287c478bd9Sstevel@tonic-gate BIG_ERR_CODE 9297c478bd9Sstevel@tonic-gate big_div_pos_fast(BIGNUM *result, BIGNUM *remainder, BIGNUM *aa, BIGNUM *bb) 9307c478bd9Sstevel@tonic-gate { 931*b60f2a0bSfr41279 BIG_ERR_CODE err = BIG_OK; 9327c478bd9Sstevel@tonic-gate int i, alen, blen, tlen, rlen, offs; 933*b60f2a0bSfr41279 BIG_CHUNK_TYPE higha, highb, coeff; 934*b60f2a0bSfr41279 BIG_CHUNK_TYPE *a, *b; 9357c478bd9Sstevel@tonic-gate BIGNUM bbhigh, bblow, tresult, tmp1, tmp2; 936*b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 937*b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 938*b60f2a0bSfr41279 BIG_CHUNK_TYPE tresultvalue[BIGTMPSIZE]; 939*b60f2a0bSfr41279 BIG_CHUNK_TYPE bblowvalue[BIGTMPSIZE]; 940*b60f2a0bSfr41279 BIG_CHUNK_TYPE bbhighvalue[BIGTMPSIZE]; 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate a = aa->value; 9437c478bd9Sstevel@tonic-gate b = bb->value; 9447c478bd9Sstevel@tonic-gate alen = aa->len; 9457c478bd9Sstevel@tonic-gate blen = bb->len; 946*b60f2a0bSfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 947*b60f2a0bSfr41279 alen = alen - 1; 948*b60f2a0bSfr41279 } 9497c478bd9Sstevel@tonic-gate aa->len = alen; 950*b60f2a0bSfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 951*b60f2a0bSfr41279 blen = blen - 1; 952*b60f2a0bSfr41279 } 9537c478bd9Sstevel@tonic-gate bb->len = blen; 954*b60f2a0bSfr41279 if ((blen == 1) && (b[0] == 0)) { 9557c478bd9Sstevel@tonic-gate return (BIG_DIV_BY_0); 956*b60f2a0bSfr41279 } 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate if (big_cmp_abs(aa, bb) < 0) { 9597c478bd9Sstevel@tonic-gate if ((remainder != NULL) && 960*b60f2a0bSfr41279 ((err = big_copy(remainder, aa)) != BIG_OK)) { 9617c478bd9Sstevel@tonic-gate return (err); 962*b60f2a0bSfr41279 } 9637c478bd9Sstevel@tonic-gate if (result != NULL) { 9647c478bd9Sstevel@tonic-gate result->len = 1; 9657c478bd9Sstevel@tonic-gate result->sign = 1; 9667c478bd9Sstevel@tonic-gate result->value[0] = 0; 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate return (BIG_OK); 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate if ((err = big_init1(&bblow, blen + 1, 9727c478bd9Sstevel@tonic-gate bblowvalue, arraysize(bblowvalue))) != BIG_OK) 9737c478bd9Sstevel@tonic-gate return (err); 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate if ((err = big_init1(&bbhigh, blen + 1, 9767c478bd9Sstevel@tonic-gate bbhighvalue, arraysize(bbhighvalue))) != BIG_OK) 9777c478bd9Sstevel@tonic-gate goto ret1; 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp1, alen + 2, 9807c478bd9Sstevel@tonic-gate tmp1value, arraysize(tmp1value))) != BIG_OK) 9817c478bd9Sstevel@tonic-gate goto ret2; 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp2, blen + 2, 9847c478bd9Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 9857c478bd9Sstevel@tonic-gate goto ret3; 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate if ((err = big_init1(&tresult, alen - blen + 2, 9887c478bd9Sstevel@tonic-gate tresultvalue, arraysize(tresultvalue))) != BIG_OK) 9897c478bd9Sstevel@tonic-gate goto ret4; 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate offs = 0; 992*b60f2a0bSfr41279 highb = b[blen - 1]; 993*b60f2a0bSfr41279 if (highb >= (BIG_CHUNK_HALF_HIGHBIT << 1)) { 994*b60f2a0bSfr41279 highb = highb >> (BIG_CHUNK_SIZE / 2); 995*b60f2a0bSfr41279 offs = (BIG_CHUNK_SIZE / 2); 9967c478bd9Sstevel@tonic-gate } 997*b60f2a0bSfr41279 while ((highb & BIG_CHUNK_HALF_HIGHBIT) == 0) { 998*b60f2a0bSfr41279 highb = highb << 1; 9997c478bd9Sstevel@tonic-gate offs++; 10007c478bd9Sstevel@tonic-gate } 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate big_shiftleft(&bblow, bb, offs); 1003*b60f2a0bSfr41279 1004*b60f2a0bSfr41279 if (offs <= (BIG_CHUNK_SIZE / 2 - 1)) { 1005*b60f2a0bSfr41279 big_shiftleft(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10067c478bd9Sstevel@tonic-gate } else { 1007*b60f2a0bSfr41279 big_shiftright(&bbhigh, &bblow, BIG_CHUNK_SIZE / 2); 10087c478bd9Sstevel@tonic-gate } 10097c478bd9Sstevel@tonic-gate if (bbhigh.value[bbhigh.len - 1] == 0) { 10107c478bd9Sstevel@tonic-gate bbhigh.len--; 10117c478bd9Sstevel@tonic-gate } else { 10127c478bd9Sstevel@tonic-gate bbhigh.value[bbhigh.len] = 0; 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate 1015*b60f2a0bSfr41279 highb = bblow.value[bblow.len - 1]; 1016*b60f2a0bSfr41279 10177c478bd9Sstevel@tonic-gate big_shiftleft(&tmp1, aa, offs); 10187c478bd9Sstevel@tonic-gate rlen = tmp1.len - bblow.len + 1; 10197c478bd9Sstevel@tonic-gate tresult.len = rlen; 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate tmp1.len++; 10227c478bd9Sstevel@tonic-gate tlen = tmp1.len; 10237c478bd9Sstevel@tonic-gate tmp1.value[tmp1.len - 1] = 0; 10247c478bd9Sstevel@tonic-gate for (i = 0; i < rlen; i++) { 1025*b60f2a0bSfr41279 higha = (tmp1.value[tlen - 1] << (BIG_CHUNK_SIZE / 2)) + 1026*b60f2a0bSfr41279 (tmp1.value[tlen - 2] >> (BIG_CHUNK_SIZE / 2)); 10277c478bd9Sstevel@tonic-gate coeff = higha / (highb + 1); 1028*b60f2a0bSfr41279 big_mulhalf_high(&tmp2, &bblow, coeff); 10297c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 10307c478bd9Sstevel@tonic-gate bbhigh.len++; 10317c478bd9Sstevel@tonic-gate while (tmp1.value[tlen - 1] > 0) { 10327c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 10337c478bd9Sstevel@tonic-gate coeff++; 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate bbhigh.len--; 10367c478bd9Sstevel@tonic-gate tlen--; 10377c478bd9Sstevel@tonic-gate tmp1.len--; 10387c478bd9Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bbhigh) >= 0) { 10397c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bbhigh); 10407c478bd9Sstevel@tonic-gate coeff++; 10417c478bd9Sstevel@tonic-gate } 1042*b60f2a0bSfr41279 tresult.value[rlen - i - 1] = coeff << (BIG_CHUNK_SIZE / 2); 10437c478bd9Sstevel@tonic-gate higha = tmp1.value[tlen - 1]; 10447c478bd9Sstevel@tonic-gate coeff = higha / (highb + 1); 1045*b60f2a0bSfr41279 big_mulhalf_low(&tmp2, &bblow, coeff); 10467c478bd9Sstevel@tonic-gate tmp2.len--; 10477c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &tmp2); 10487c478bd9Sstevel@tonic-gate while (big_cmp_abs_high(&tmp1, &bblow) >= 0) { 10497c478bd9Sstevel@tonic-gate big_sub_pos_high(&tmp1, &tmp1, &bblow); 10507c478bd9Sstevel@tonic-gate coeff++; 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate tresult.value[rlen - i - 1] = 10537c478bd9Sstevel@tonic-gate tresult.value[rlen - i - 1] + coeff; 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate big_shiftright(&tmp1, &tmp1, offs); 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate err = BIG_OK; 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate if ((remainder != NULL) && 10617c478bd9Sstevel@tonic-gate ((err = big_copy(remainder, &tmp1)) != BIG_OK)) 10627c478bd9Sstevel@tonic-gate goto ret; 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate if (result != NULL) 10657c478bd9Sstevel@tonic-gate err = big_copy(result, &tresult); 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate ret: 10687c478bd9Sstevel@tonic-gate big_finish(&tresult); 10697c478bd9Sstevel@tonic-gate ret4: 10707c478bd9Sstevel@tonic-gate big_finish(&tmp1); 10717c478bd9Sstevel@tonic-gate ret3: 10727c478bd9Sstevel@tonic-gate big_finish(&tmp2); 10737c478bd9Sstevel@tonic-gate ret2: 10747c478bd9Sstevel@tonic-gate big_finish(&bbhigh); 10757c478bd9Sstevel@tonic-gate ret1: 10767c478bd9Sstevel@tonic-gate big_finish(&bblow); 10777c478bd9Sstevel@tonic-gate return (err); 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate /* 10817c478bd9Sstevel@tonic-gate * If there is no processor-specific integer implementation of 10827c478bd9Sstevel@tonic-gate * the lower level multiply functions, then this code is provided 10837c478bd9Sstevel@tonic-gate * for big_mul_set_vec(), big_mul_add_vec(), big_mul_vec() and 10847c478bd9Sstevel@tonic-gate * big_sqr_vec(). 10857c478bd9Sstevel@tonic-gate * 10867c478bd9Sstevel@tonic-gate * There are two generic implementations. One that assumes that 10877c478bd9Sstevel@tonic-gate * there is hardware and C compiler support for a 32 x 32 --> 64 10887c478bd9Sstevel@tonic-gate * bit unsigned multiply, but otherwise is not specific to any 10897c478bd9Sstevel@tonic-gate * processor, platform, or ISA. 10907c478bd9Sstevel@tonic-gate * 10917c478bd9Sstevel@tonic-gate * The other makes very few assumptions about hardware capabilities. 10927c478bd9Sstevel@tonic-gate * It does not even assume that there is any implementation of a 10937c478bd9Sstevel@tonic-gate * 32 x 32 --> 64 bit multiply that is accessible to C code and 10947c478bd9Sstevel@tonic-gate * appropriate to use. It falls constructs 32 x 32 --> 64 bit 10957c478bd9Sstevel@tonic-gate * multiplies from 16 x 16 --> 32 bit multiplies. 10967c478bd9Sstevel@tonic-gate * 10977c478bd9Sstevel@tonic-gate */ 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate #if !defined(PSR_MUL) 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate #ifdef UMUL64 11027c478bd9Sstevel@tonic-gate 1103*b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 1104*b60f2a0bSfr41279 11057c478bd9Sstevel@tonic-gate #define UNROLL8 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_PREFETCH(R) \ 11087c478bd9Sstevel@tonic-gate p = pf * d; \ 11097c478bd9Sstevel@tonic-gate pf = (uint64_t)a[R+1]; \ 11107c478bd9Sstevel@tonic-gate t = p + cy; \ 11117c478bd9Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11127c478bd9Sstevel@tonic-gate cy = t >> 32 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate #define MUL_SET_VEC_ROUND_NOPREFETCH(R) \ 11157c478bd9Sstevel@tonic-gate p = pf * d; \ 11167c478bd9Sstevel@tonic-gate t = p + cy; \ 11177c478bd9Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11187c478bd9Sstevel@tonic-gate cy = t >> 32 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_PREFETCH(R) \ 11217c478bd9Sstevel@tonic-gate t = (uint64_t)r[R]; \ 11227c478bd9Sstevel@tonic-gate p = pf * d; \ 11237c478bd9Sstevel@tonic-gate pf = (uint64_t)a[R+1]; \ 11247c478bd9Sstevel@tonic-gate t = p + t + cy; \ 11257c478bd9Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11267c478bd9Sstevel@tonic-gate cy = t >> 32 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate #define MUL_ADD_VEC_ROUND_NOPREFETCH(R) \ 11297c478bd9Sstevel@tonic-gate t = (uint64_t)r[R]; \ 11307c478bd9Sstevel@tonic-gate p = pf * d; \ 11317c478bd9Sstevel@tonic-gate t = p + t + cy; \ 11327c478bd9Sstevel@tonic-gate r[R] = (uint32_t)t; \ 11337c478bd9Sstevel@tonic-gate cy = t >> 32 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate #ifdef UNROLL8 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate #define UNROLL 8 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate /* 11407c478bd9Sstevel@tonic-gate * r = a * b 11417c478bd9Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 11427c478bd9Sstevel@tonic-gate */ 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate uint32_t 11457c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 11467c478bd9Sstevel@tonic-gate { 11477c478bd9Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate if (len == 0) 11507c478bd9Sstevel@tonic-gate return (0); 11517c478bd9Sstevel@tonic-gate cy = 0; 11527c478bd9Sstevel@tonic-gate d = (uint64_t)b; 11537c478bd9Sstevel@tonic-gate pf = (uint64_t)a[0]; 11547c478bd9Sstevel@tonic-gate while (len > UNROLL) { 11557c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 11567c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 11577c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 11587c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 11597c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 11607c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 11617c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 11627c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(7); 11637c478bd9Sstevel@tonic-gate r += UNROLL; 11647c478bd9Sstevel@tonic-gate a += UNROLL; 11657c478bd9Sstevel@tonic-gate len -= UNROLL; 11667c478bd9Sstevel@tonic-gate } 11677c478bd9Sstevel@tonic-gate if (len == UNROLL) { 11687c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 11697c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(1); 11707c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(2); 11717c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(3); 11727c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(4); 11737c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(5); 11747c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(6); 11757c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(7); 11767c478bd9Sstevel@tonic-gate return ((uint32_t)cy); 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate while (len > 1) { 11797c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_PREFETCH(0); 11807c478bd9Sstevel@tonic-gate ++r; 11817c478bd9Sstevel@tonic-gate ++a; 11827c478bd9Sstevel@tonic-gate --len; 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate if (len > 0) { 11857c478bd9Sstevel@tonic-gate MUL_SET_VEC_ROUND_NOPREFETCH(0); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate return ((uint32_t)cy); 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate /* 11917c478bd9Sstevel@tonic-gate * r += a * b 11927c478bd9Sstevel@tonic-gate * where r and a are vectors; b is a single 32-bit digit 11937c478bd9Sstevel@tonic-gate */ 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate uint32_t 11967c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t b) 11977c478bd9Sstevel@tonic-gate { 11987c478bd9Sstevel@tonic-gate uint64_t d, pf, p, t, cy; 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate if (len == 0) 12017c478bd9Sstevel@tonic-gate return (0); 12027c478bd9Sstevel@tonic-gate cy = 0; 12037c478bd9Sstevel@tonic-gate d = (uint64_t)b; 12047c478bd9Sstevel@tonic-gate pf = (uint64_t)a[0]; 12057c478bd9Sstevel@tonic-gate while (len > 8) { 12067c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12077c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 12087c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 12097c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 12107c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 12117c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 12127c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 12137c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(7); 12147c478bd9Sstevel@tonic-gate r += 8; 12157c478bd9Sstevel@tonic-gate a += 8; 12167c478bd9Sstevel@tonic-gate len -= 8; 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate if (len == 8) { 12197c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12207c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(1); 12217c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(2); 12227c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(3); 12237c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(4); 12247c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(5); 12257c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(6); 12267c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(7); 12277c478bd9Sstevel@tonic-gate return ((uint32_t)cy); 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate while (len > 1) { 12307c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_PREFETCH(0); 12317c478bd9Sstevel@tonic-gate ++r; 12327c478bd9Sstevel@tonic-gate ++a; 12337c478bd9Sstevel@tonic-gate --len; 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate if (len > 0) { 12367c478bd9Sstevel@tonic-gate MUL_ADD_VEC_ROUND_NOPREFETCH(0); 12377c478bd9Sstevel@tonic-gate } 12387c478bd9Sstevel@tonic-gate return ((uint32_t)cy); 12397c478bd9Sstevel@tonic-gate } 12407c478bd9Sstevel@tonic-gate #endif /* UNROLL8 */ 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate void 12437c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 12447c478bd9Sstevel@tonic-gate { 12457c478bd9Sstevel@tonic-gate uint32_t *tr, *ta; 12467c478bd9Sstevel@tonic-gate int tlen, row, col; 12477c478bd9Sstevel@tonic-gate uint64_t p, s, t, t2, cy; 12487c478bd9Sstevel@tonic-gate uint32_t d; 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate tr = r + 1; 12517c478bd9Sstevel@tonic-gate ta = a; 12527c478bd9Sstevel@tonic-gate tlen = len - 1; 12537c478bd9Sstevel@tonic-gate tr[tlen] = big_mul_set_vec(tr, ta + 1, tlen, ta[0]); 12547c478bd9Sstevel@tonic-gate while (--tlen > 0) { 12557c478bd9Sstevel@tonic-gate tr += 2; 12567c478bd9Sstevel@tonic-gate ++ta; 12577c478bd9Sstevel@tonic-gate tr[tlen] = big_mul_add_vec(tr, ta + 1, tlen, ta[0]); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate s = (uint64_t)a[0]; 12607c478bd9Sstevel@tonic-gate s = s * s; 12617c478bd9Sstevel@tonic-gate r[0] = (uint32_t)s; 12627c478bd9Sstevel@tonic-gate cy = s >> 32; 12637c478bd9Sstevel@tonic-gate p = ((uint64_t)r[1] << 1) + cy; 12647c478bd9Sstevel@tonic-gate r[1] = (uint32_t)p; 12657c478bd9Sstevel@tonic-gate cy = p >> 32; 12667c478bd9Sstevel@tonic-gate row = 1; 12677c478bd9Sstevel@tonic-gate col = 2; 12687c478bd9Sstevel@tonic-gate while (row < len) { 12697c478bd9Sstevel@tonic-gate s = (uint64_t)a[row]; 12707c478bd9Sstevel@tonic-gate s = s * s; 12717c478bd9Sstevel@tonic-gate p = (uint64_t)r[col] << 1; 12727c478bd9Sstevel@tonic-gate t = p + s; 12737c478bd9Sstevel@tonic-gate d = (uint32_t)t; 12747c478bd9Sstevel@tonic-gate t2 = (uint64_t)d + cy; 12757c478bd9Sstevel@tonic-gate r[col] = (uint32_t)t2; 12767c478bd9Sstevel@tonic-gate cy = (t >> 32) + (t2 >> 32); 12777c478bd9Sstevel@tonic-gate if (row == len - 1) 12787c478bd9Sstevel@tonic-gate break; 12797c478bd9Sstevel@tonic-gate p = ((uint64_t)r[col+1] << 1) + cy; 12807c478bd9Sstevel@tonic-gate r[col+1] = (uint32_t)p; 12817c478bd9Sstevel@tonic-gate cy = p >> 32; 12827c478bd9Sstevel@tonic-gate ++row; 12837c478bd9Sstevel@tonic-gate col += 2; 12847c478bd9Sstevel@tonic-gate } 12857c478bd9Sstevel@tonic-gate r[col+1] = (uint32_t)cy; 12867c478bd9Sstevel@tonic-gate } 12877c478bd9Sstevel@tonic-gate 1288*b60f2a0bSfr41279 #else /* BIG_CHUNK_SIZE == 64 */ 1289*b60f2a0bSfr41279 1290*b60f2a0bSfr41279 /* 1291*b60f2a0bSfr41279 * r = r + a * digit, r and a are vectors of length len 1292*b60f2a0bSfr41279 * returns the carry digit 1293*b60f2a0bSfr41279 */ 1294*b60f2a0bSfr41279 BIG_CHUNK_TYPE 1295*b60f2a0bSfr41279 big_mul_add_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 1296*b60f2a0bSfr41279 BIG_CHUNK_TYPE digit) 1297*b60f2a0bSfr41279 { 1298*b60f2a0bSfr41279 BIG_CHUNK_TYPE cy, cy1, retcy, dlow, dhigh; 1299*b60f2a0bSfr41279 int i; 1300*b60f2a0bSfr41279 1301*b60f2a0bSfr41279 cy1 = 0; 1302*b60f2a0bSfr41279 dlow = digit & BIG_CHUNK_LOWHALFBITS; 1303*b60f2a0bSfr41279 dhigh = digit >> (BIG_CHUNK_SIZE / 2); 1304*b60f2a0bSfr41279 for (i = 0; i < len; i++) { 1305*b60f2a0bSfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 1306*b60f2a0bSfr41279 dlow * (a[i] & BIG_CHUNK_LOWHALFBITS) + 1307*b60f2a0bSfr41279 (r[i] & BIG_CHUNK_LOWHALFBITS); 1308*b60f2a0bSfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 1309*b60f2a0bSfr41279 dlow * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 1310*b60f2a0bSfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 1311*b60f2a0bSfr41279 r[i] = (cy & BIG_CHUNK_LOWHALFBITS) | 1312*b60f2a0bSfr41279 (cy1 << (BIG_CHUNK_SIZE / 2)); 1313*b60f2a0bSfr41279 } 1314*b60f2a0bSfr41279 retcy = cy1 >> (BIG_CHUNK_SIZE / 2); 1315*b60f2a0bSfr41279 1316*b60f2a0bSfr41279 cy1 = r[0] & BIG_CHUNK_LOWHALFBITS; 1317*b60f2a0bSfr41279 for (i = 0; i < len - 1; i++) { 1318*b60f2a0bSfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 1319*b60f2a0bSfr41279 dhigh * (a[i] & BIG_CHUNK_LOWHALFBITS) + 1320*b60f2a0bSfr41279 (r[i] >> (BIG_CHUNK_SIZE / 2)); 1321*b60f2a0bSfr41279 r[i] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 1322*b60f2a0bSfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 1323*b60f2a0bSfr41279 cy1 = (cy >> (BIG_CHUNK_SIZE / 2)) + 1324*b60f2a0bSfr41279 dhigh * (a[i] >> (BIG_CHUNK_SIZE / 2)) + 1325*b60f2a0bSfr41279 (r[i + 1] & BIG_CHUNK_LOWHALFBITS); 1326*b60f2a0bSfr41279 } 1327*b60f2a0bSfr41279 cy = (cy1 >> (BIG_CHUNK_SIZE / 2)) + 1328*b60f2a0bSfr41279 dhigh * (a[len - 1] & BIG_CHUNK_LOWHALFBITS) + 1329*b60f2a0bSfr41279 (r[len - 1] >> (BIG_CHUNK_SIZE / 2)); 1330*b60f2a0bSfr41279 r[len - 1] = (cy1 & BIG_CHUNK_LOWHALFBITS) | 1331*b60f2a0bSfr41279 (cy << (BIG_CHUNK_SIZE / 2)); 1332*b60f2a0bSfr41279 retcy = (cy >> (BIG_CHUNK_SIZE / 2)) + 1333*b60f2a0bSfr41279 dhigh * (a[len - 1] >> (BIG_CHUNK_SIZE / 2)) + retcy; 1334*b60f2a0bSfr41279 1335*b60f2a0bSfr41279 return (retcy); 1336*b60f2a0bSfr41279 } 1337*b60f2a0bSfr41279 1338*b60f2a0bSfr41279 1339*b60f2a0bSfr41279 /* 1340*b60f2a0bSfr41279 * r = a * digit, r and a are vectors of length len 1341*b60f2a0bSfr41279 * returns the carry digit 1342*b60f2a0bSfr41279 */ 1343*b60f2a0bSfr41279 BIG_CHUNK_TYPE 1344*b60f2a0bSfr41279 big_mul_set_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len, 1345*b60f2a0bSfr41279 BIG_CHUNK_TYPE digit) 1346*b60f2a0bSfr41279 { 1347*b60f2a0bSfr41279 int i; 1348*b60f2a0bSfr41279 1349*b60f2a0bSfr41279 ASSERT(r != a); 1350*b60f2a0bSfr41279 for (i = 0; i < len; i++) { 1351*b60f2a0bSfr41279 r[i] = 0; 1352*b60f2a0bSfr41279 } 1353*b60f2a0bSfr41279 return (big_mul_add_vec(r, a, len, digit)); 1354*b60f2a0bSfr41279 } 1355*b60f2a0bSfr41279 1356*b60f2a0bSfr41279 void 1357*b60f2a0bSfr41279 big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len) 1358*b60f2a0bSfr41279 { 1359*b60f2a0bSfr41279 int i; 1360*b60f2a0bSfr41279 1361*b60f2a0bSfr41279 ASSERT(r != a); 1362*b60f2a0bSfr41279 r[len] = big_mul_set_vec(r, a, len, a[0]); 1363*b60f2a0bSfr41279 for (i = 1; i < len; ++i) 1364*b60f2a0bSfr41279 r[len + i] = big_mul_add_vec(r+i, a, len, a[i]); 1365*b60f2a0bSfr41279 } 1366*b60f2a0bSfr41279 1367*b60f2a0bSfr41279 #endif /* BIG_CHUNK_SIZE == 32/64 */ 1368*b60f2a0bSfr41279 13697c478bd9Sstevel@tonic-gate #else /* ! UMUL64 */ 13707c478bd9Sstevel@tonic-gate 1371*b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE != 32) 1372*b60f2a0bSfr41279 #error Don't use 64-bit chunks without defining UMUL64 1373*b60f2a0bSfr41279 #endif 1374*b60f2a0bSfr41279 1375*b60f2a0bSfr41279 13767c478bd9Sstevel@tonic-gate /* 13777c478bd9Sstevel@tonic-gate * r = r + a * digit, r and a are vectors of length len 13787c478bd9Sstevel@tonic-gate * returns the carry digit 13797c478bd9Sstevel@tonic-gate */ 13807c478bd9Sstevel@tonic-gate uint32_t 13817c478bd9Sstevel@tonic-gate big_mul_add_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 13827c478bd9Sstevel@tonic-gate { 13837c478bd9Sstevel@tonic-gate uint32_t cy, cy1, retcy, dlow, dhigh; 13847c478bd9Sstevel@tonic-gate int i; 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate cy1 = 0; 13877c478bd9Sstevel@tonic-gate dlow = digit & 0xffff; 13887c478bd9Sstevel@tonic-gate dhigh = digit >> 16; 13897c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) { 13907c478bd9Sstevel@tonic-gate cy = (cy1 >> 16) + dlow * (a[i] & 0xffff) + (r[i] & 0xffff); 13917c478bd9Sstevel@tonic-gate cy1 = (cy >> 16) + dlow * (a[i]>>16) + (r[i] >> 16); 13927c478bd9Sstevel@tonic-gate r[i] = (cy & 0xffff) | (cy1 << 16); 13937c478bd9Sstevel@tonic-gate } 13947c478bd9Sstevel@tonic-gate retcy = cy1 >> 16; 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate cy1 = r[0] & 0xffff; 13977c478bd9Sstevel@tonic-gate for (i = 0; i < len - 1; i++) { 13987c478bd9Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[i] & 0xffff) + (r[i] >> 16); 13997c478bd9Sstevel@tonic-gate r[i] = (cy1 & 0xffff) | (cy << 16); 14007c478bd9Sstevel@tonic-gate cy1 = (cy >> 16) + dhigh * (a[i] >> 16) + (r[i + 1] & 0xffff); 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate cy = (cy1 >> 16) + dhigh * (a[len - 1] & 0xffff) + (r[len - 1] >> 16); 14037c478bd9Sstevel@tonic-gate r[len - 1] = (cy1 & 0xffff) | (cy << 16); 14047c478bd9Sstevel@tonic-gate retcy = (cy >> 16) + dhigh * (a[len - 1] >> 16) + retcy; 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate return (retcy); 14077c478bd9Sstevel@tonic-gate } 14087c478bd9Sstevel@tonic-gate 1409*b60f2a0bSfr41279 14107c478bd9Sstevel@tonic-gate /* 14117c478bd9Sstevel@tonic-gate * r = a * digit, r and a are vectors of length len 14127c478bd9Sstevel@tonic-gate * returns the carry digit 14137c478bd9Sstevel@tonic-gate */ 14147c478bd9Sstevel@tonic-gate uint32_t 14157c478bd9Sstevel@tonic-gate big_mul_set_vec(uint32_t *r, uint32_t *a, int len, uint32_t digit) 14167c478bd9Sstevel@tonic-gate { 1417*b60f2a0bSfr41279 int i; 1418*b60f2a0bSfr41279 1419*b60f2a0bSfr41279 ASSERT(r != a); 1420*b60f2a0bSfr41279 for (i = 0; i < len; i++) { 1421*b60f2a0bSfr41279 r[i] = 0; 1422*b60f2a0bSfr41279 } 1423*b60f2a0bSfr41279 14247c478bd9Sstevel@tonic-gate return (big_mul_add_vec(r, a, len, digit)); 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate void 14287c478bd9Sstevel@tonic-gate big_sqr_vec(uint32_t *r, uint32_t *a, int len) 14297c478bd9Sstevel@tonic-gate { 14307c478bd9Sstevel@tonic-gate int i; 14317c478bd9Sstevel@tonic-gate 1432*b60f2a0bSfr41279 ASSERT(r != a); 14337c478bd9Sstevel@tonic-gate r[len] = big_mul_set_vec(r, a, len, a[0]); 14347c478bd9Sstevel@tonic-gate for (i = 1; i < len; ++i) 14357c478bd9Sstevel@tonic-gate r[len + i] = big_mul_add_vec(r+i, a, len, a[i]); 14367c478bd9Sstevel@tonic-gate } 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate #endif /* UMUL64 */ 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate void 1441*b60f2a0bSfr41279 big_mul_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int alen, 1442*b60f2a0bSfr41279 BIG_CHUNK_TYPE *b, int blen) 14437c478bd9Sstevel@tonic-gate { 14447c478bd9Sstevel@tonic-gate int i; 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate r[alen] = big_mul_set_vec(r, a, alen, b[0]); 14477c478bd9Sstevel@tonic-gate for (i = 1; i < blen; ++i) 14487c478bd9Sstevel@tonic-gate r[alen + i] = big_mul_add_vec(r+i, a, alen, b[i]); 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate #endif /* ! PSR_MUL */ 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate /* 14567c478bd9Sstevel@tonic-gate * result = aa * bb result->value should be big enough to hold the result 14577c478bd9Sstevel@tonic-gate * 14587c478bd9Sstevel@tonic-gate * Implementation: Standard grammar school algorithm 14597c478bd9Sstevel@tonic-gate * 14607c478bd9Sstevel@tonic-gate */ 14617c478bd9Sstevel@tonic-gate BIG_ERR_CODE 14627c478bd9Sstevel@tonic-gate big_mul(BIGNUM *result, BIGNUM *aa, BIGNUM *bb) 14637c478bd9Sstevel@tonic-gate { 14647c478bd9Sstevel@tonic-gate BIGNUM tmp1; 1465*b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 1466*b60f2a0bSfr41279 BIG_CHUNK_TYPE *r, *t, *a, *b; 14677c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 14687c478bd9Sstevel@tonic-gate int i, alen, blen, rsize, sign, diff; 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate if (aa == bb) { 14717c478bd9Sstevel@tonic-gate diff = 0; 14727c478bd9Sstevel@tonic-gate } else { 14737c478bd9Sstevel@tonic-gate diff = big_cmp_abs(aa, bb); 14747c478bd9Sstevel@tonic-gate if (diff < 0) { 14757c478bd9Sstevel@tonic-gate BIGNUM *tt; 14767c478bd9Sstevel@tonic-gate tt = aa; 14777c478bd9Sstevel@tonic-gate aa = bb; 14787c478bd9Sstevel@tonic-gate bb = tt; 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate a = aa->value; 14827c478bd9Sstevel@tonic-gate b = bb->value; 14837c478bd9Sstevel@tonic-gate alen = aa->len; 14847c478bd9Sstevel@tonic-gate blen = bb->len; 1485*b60f2a0bSfr41279 while ((alen > 1) && (a[alen - 1] == 0)) { 1486*b60f2a0bSfr41279 alen--; 1487*b60f2a0bSfr41279 } 14887c478bd9Sstevel@tonic-gate aa->len = alen; 1489*b60f2a0bSfr41279 while ((blen > 1) && (b[blen - 1] == 0)) { 1490*b60f2a0bSfr41279 blen--; 1491*b60f2a0bSfr41279 } 14927c478bd9Sstevel@tonic-gate bb->len = blen; 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate rsize = alen + blen; 14957c478bd9Sstevel@tonic-gate if (result->size < rsize) { 14967c478bd9Sstevel@tonic-gate err = big_extend(result, rsize); 1497*b60f2a0bSfr41279 if (err != BIG_OK) { 14987c478bd9Sstevel@tonic-gate return (err); 1499*b60f2a0bSfr41279 } 15007c478bd9Sstevel@tonic-gate /* aa or bb might be an alias to result */ 15017c478bd9Sstevel@tonic-gate a = aa->value; 15027c478bd9Sstevel@tonic-gate b = bb->value; 15037c478bd9Sstevel@tonic-gate } 15047c478bd9Sstevel@tonic-gate r = result->value; 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate if (((alen == 1) && (a[0] == 0)) || ((blen == 1) && (b[0] == 0))) { 15077c478bd9Sstevel@tonic-gate result->len = 1; 15087c478bd9Sstevel@tonic-gate result->sign = 1; 15097c478bd9Sstevel@tonic-gate r[0] = 0; 15107c478bd9Sstevel@tonic-gate return (BIG_OK); 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate sign = aa->sign * bb->sign; 15137c478bd9Sstevel@tonic-gate if ((alen == 1) && (a[0] == 1)) { 1514*b60f2a0bSfr41279 for (i = 0; i < blen; i++) { 1515*b60f2a0bSfr41279 r[i] = b[i]; 1516*b60f2a0bSfr41279 } 15177c478bd9Sstevel@tonic-gate result->len = blen; 15187c478bd9Sstevel@tonic-gate result->sign = sign; 15197c478bd9Sstevel@tonic-gate return (BIG_OK); 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate if ((blen == 1) && (b[0] == 1)) { 1522*b60f2a0bSfr41279 for (i = 0; i < alen; i++) { 1523*b60f2a0bSfr41279 r[i] = a[i]; 1524*b60f2a0bSfr41279 } 15257c478bd9Sstevel@tonic-gate result->len = alen; 15267c478bd9Sstevel@tonic-gate result->sign = sign; 15277c478bd9Sstevel@tonic-gate return (BIG_OK); 15287c478bd9Sstevel@tonic-gate } 15297c478bd9Sstevel@tonic-gate 1530*b60f2a0bSfr41279 if ((err = big_init1(&tmp1, rsize, 1531*b60f2a0bSfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 15327c478bd9Sstevel@tonic-gate return (err); 1533*b60f2a0bSfr41279 } 1534*b60f2a0bSfr41279 (void) big_copy(&tmp1, aa); 15357c478bd9Sstevel@tonic-gate t = tmp1.value; 15367c478bd9Sstevel@tonic-gate 1537*b60f2a0bSfr41279 for (i = 0; i < rsize; i++) { 1538*b60f2a0bSfr41279 t[i] = 0; 1539*b60f2a0bSfr41279 } 1540*b60f2a0bSfr41279 1541*b60f2a0bSfr41279 if (diff == 0 && alen > 2) { 15427c478bd9Sstevel@tonic-gate BIG_SQR_VEC(t, a, alen); 1543*b60f2a0bSfr41279 } else if (blen > 0) { 15447c478bd9Sstevel@tonic-gate BIG_MUL_VEC(t, a, alen, b, blen); 1545*b60f2a0bSfr41279 } 15467c478bd9Sstevel@tonic-gate 1547*b60f2a0bSfr41279 if (t[rsize - 1] == 0) { 1548*b60f2a0bSfr41279 tmp1.len = rsize - 1; 1549*b60f2a0bSfr41279 } else { 1550*b60f2a0bSfr41279 tmp1.len = rsize; 1551*b60f2a0bSfr41279 } 1552*b60f2a0bSfr41279 if ((err = big_copy(result, &tmp1)) != BIG_OK) { 1553*b60f2a0bSfr41279 return (err); 1554*b60f2a0bSfr41279 } 15557c478bd9Sstevel@tonic-gate result->sign = sign; 15567c478bd9Sstevel@tonic-gate 1557*b60f2a0bSfr41279 big_finish(&tmp1); 15587c478bd9Sstevel@tonic-gate 15597c478bd9Sstevel@tonic-gate return (BIG_OK); 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate /* 15647c478bd9Sstevel@tonic-gate * caller must ensure that a < n, b < n and ret->size >= 2 * n->len + 1 15657c478bd9Sstevel@tonic-gate * and that ret is not n 15667c478bd9Sstevel@tonic-gate */ 15677c478bd9Sstevel@tonic-gate BIG_ERR_CODE 1568*b60f2a0bSfr41279 big_mont_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *n, BIG_CHUNK_TYPE n0) 15697c478bd9Sstevel@tonic-gate { 15707c478bd9Sstevel@tonic-gate int i, j, nlen, needsubtract; 1571*b60f2a0bSfr41279 BIG_CHUNK_TYPE *nn, *rr; 1572*b60f2a0bSfr41279 BIG_CHUNK_TYPE digit, c; 15737c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 15747c478bd9Sstevel@tonic-gate 15757c478bd9Sstevel@tonic-gate nlen = n->len; 15767c478bd9Sstevel@tonic-gate nn = n->value; 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate rr = ret->value; 15797c478bd9Sstevel@tonic-gate 1580*b60f2a0bSfr41279 if ((err = big_mul(ret, a, b)) != BIG_OK) { 15817c478bd9Sstevel@tonic-gate return (err); 1582*b60f2a0bSfr41279 } 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate rr = ret->value; 1585*b60f2a0bSfr41279 for (i = ret->len; i < 2 * nlen + 1; i++) { 1586*b60f2a0bSfr41279 rr[i] = 0; 1587*b60f2a0bSfr41279 } 15887c478bd9Sstevel@tonic-gate for (i = 0; i < nlen; i++) { 15897c478bd9Sstevel@tonic-gate digit = rr[i]; 15907c478bd9Sstevel@tonic-gate digit = digit * n0; 15917c478bd9Sstevel@tonic-gate 15927c478bd9Sstevel@tonic-gate c = BIG_MUL_ADD_VEC(rr + i, nn, nlen, digit); 15937c478bd9Sstevel@tonic-gate j = i + nlen; 15947c478bd9Sstevel@tonic-gate rr[j] += c; 15957c478bd9Sstevel@tonic-gate while (rr[j] < c) { 15967c478bd9Sstevel@tonic-gate rr[j + 1] += 1; 15977c478bd9Sstevel@tonic-gate j++; 15987c478bd9Sstevel@tonic-gate c = 1; 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate } 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate needsubtract = 0; 16037c478bd9Sstevel@tonic-gate if ((rr[2 * nlen] != 0)) 16047c478bd9Sstevel@tonic-gate needsubtract = 1; 16057c478bd9Sstevel@tonic-gate else { 16067c478bd9Sstevel@tonic-gate for (i = 2 * nlen - 1; i >= nlen; i--) { 16077c478bd9Sstevel@tonic-gate if (rr[i] > nn[i - nlen]) { 16087c478bd9Sstevel@tonic-gate needsubtract = 1; 16097c478bd9Sstevel@tonic-gate break; 1610*b60f2a0bSfr41279 } else if (rr[i] < nn[i - nlen]) { 1611*b60f2a0bSfr41279 break; 1612*b60f2a0bSfr41279 } 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate if (needsubtract) 16167c478bd9Sstevel@tonic-gate big_sub_vec(rr, rr + nlen, nn, nlen); 16177c478bd9Sstevel@tonic-gate else { 1618*b60f2a0bSfr41279 for (i = 0; i < nlen; i++) { 16197c478bd9Sstevel@tonic-gate rr[i] = rr[i + nlen]; 16207c478bd9Sstevel@tonic-gate } 1621*b60f2a0bSfr41279 } 1622*b60f2a0bSfr41279 for (i = nlen - 1; (i >= 0) && (rr[i] == 0); i--) 1623*b60f2a0bSfr41279 ; 16247c478bd9Sstevel@tonic-gate ret->len = i+1; 16257c478bd9Sstevel@tonic-gate 16267c478bd9Sstevel@tonic-gate return (BIG_OK); 16277c478bd9Sstevel@tonic-gate } 16287c478bd9Sstevel@tonic-gate 1629*b60f2a0bSfr41279 1630*b60f2a0bSfr41279 BIG_CHUNK_TYPE 1631*b60f2a0bSfr41279 big_n0(BIG_CHUNK_TYPE n) 16327c478bd9Sstevel@tonic-gate { 16337c478bd9Sstevel@tonic-gate int i; 1634*b60f2a0bSfr41279 BIG_CHUNK_TYPE result, tmp; 16357c478bd9Sstevel@tonic-gate 16367c478bd9Sstevel@tonic-gate result = 0; 1637*b60f2a0bSfr41279 tmp = BIG_CHUNK_ALLBITS; 1638*b60f2a0bSfr41279 for (i = 0; i < BIG_CHUNK_SIZE; i++) { 16397c478bd9Sstevel@tonic-gate if ((tmp & 1) == 1) { 1640*b60f2a0bSfr41279 result = (result >> 1) | BIG_CHUNK_HIGHBIT; 16417c478bd9Sstevel@tonic-gate tmp = tmp - n; 1642*b60f2a0bSfr41279 } else { 1643*b60f2a0bSfr41279 result = (result >> 1); 1644*b60f2a0bSfr41279 } 16457c478bd9Sstevel@tonic-gate tmp = tmp >> 1; 16467c478bd9Sstevel@tonic-gate } 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate return (result); 16497c478bd9Sstevel@tonic-gate } 16507c478bd9Sstevel@tonic-gate 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate int 16537c478bd9Sstevel@tonic-gate big_numbits(BIGNUM *n) 16547c478bd9Sstevel@tonic-gate { 16557c478bd9Sstevel@tonic-gate int i, j; 1656*b60f2a0bSfr41279 BIG_CHUNK_TYPE t; 16577c478bd9Sstevel@tonic-gate 1658*b60f2a0bSfr41279 for (i = n->len - 1; i > 0; i--) { 1659*b60f2a0bSfr41279 if (n->value[i] != 0) { 1660*b60f2a0bSfr41279 break; 1661*b60f2a0bSfr41279 } 1662*b60f2a0bSfr41279 } 16637c478bd9Sstevel@tonic-gate t = n->value[i]; 1664*b60f2a0bSfr41279 for (j = BIG_CHUNK_SIZE; j > 0; j--) { 1665*b60f2a0bSfr41279 if ((t & BIG_CHUNK_HIGHBIT) == 0) { 16667c478bd9Sstevel@tonic-gate t = t << 1; 1667*b60f2a0bSfr41279 } else { 1668*b60f2a0bSfr41279 return (BIG_CHUNK_SIZE * i + j); 1669*b60f2a0bSfr41279 } 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate return (0); 16727c478bd9Sstevel@tonic-gate } 16737c478bd9Sstevel@tonic-gate 1674*b60f2a0bSfr41279 16757c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */ 16767c478bd9Sstevel@tonic-gate BIG_ERR_CODE 16777c478bd9Sstevel@tonic-gate big_mont_rr(BIGNUM *result, BIGNUM *n) 16787c478bd9Sstevel@tonic-gate { 16797c478bd9Sstevel@tonic-gate BIGNUM rr; 1680*b60f2a0bSfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 16817c478bd9Sstevel@tonic-gate int len, i; 16827c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate rr.malloced = 0; 16857c478bd9Sstevel@tonic-gate len = n->len; 16867c478bd9Sstevel@tonic-gate 16877c478bd9Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, 1688*b60f2a0bSfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 16897c478bd9Sstevel@tonic-gate return (err); 16907c478bd9Sstevel@tonic-gate } 16917c478bd9Sstevel@tonic-gate 1692*b60f2a0bSfr41279 for (i = 0; i < 2 * len; i++) { 1693*b60f2a0bSfr41279 rr.value[i] = 0; 1694*b60f2a0bSfr41279 } 1695*b60f2a0bSfr41279 rr.value[2 * len] = 1; 1696*b60f2a0bSfr41279 rr.len = 2 * len + 1; 1697*b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 1698*b60f2a0bSfr41279 goto ret; 1699*b60f2a0bSfr41279 } 1700*b60f2a0bSfr41279 err = big_copy(result, &rr); 1701*b60f2a0bSfr41279 ret: 1702*b60f2a0bSfr41279 big_finish(&rr); 1703*b60f2a0bSfr41279 return (err); 1704*b60f2a0bSfr41279 } 1705*b60f2a0bSfr41279 1706*b60f2a0bSfr41279 17077c478bd9Sstevel@tonic-gate /* caller must make sure that a < n */ 17087c478bd9Sstevel@tonic-gate BIG_ERR_CODE 1709*b60f2a0bSfr41279 big_mont_conv(BIGNUM *result, BIGNUM *a, BIGNUM *n, BIG_CHUNK_TYPE n0, 1710*b60f2a0bSfr41279 BIGNUM *n_rr) 17117c478bd9Sstevel@tonic-gate { 17127c478bd9Sstevel@tonic-gate BIGNUM rr; 1713*b60f2a0bSfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 17147c478bd9Sstevel@tonic-gate int len, i; 17157c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate rr.malloced = 0; 17187c478bd9Sstevel@tonic-gate len = n->len; 17197c478bd9Sstevel@tonic-gate 17207c478bd9Sstevel@tonic-gate if ((err = big_init1(&rr, 2 * len + 1, rrvalue, arraysize(rrvalue))) 1721*b60f2a0bSfr41279 != BIG_OK) { 17227c478bd9Sstevel@tonic-gate return (err); 1723*b60f2a0bSfr41279 } 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate if (n_rr == NULL) { 1726*b60f2a0bSfr41279 for (i = 0; i < 2 * len; i++) { 1727*b60f2a0bSfr41279 rr.value[i] = 0; 1728*b60f2a0bSfr41279 } 17297c478bd9Sstevel@tonic-gate rr.value[2 * len] = 1; 17307c478bd9Sstevel@tonic-gate rr.len = 2 * len + 1; 1731*b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &rr, &rr, n)) != BIG_OK) { 17327c478bd9Sstevel@tonic-gate goto ret; 1733*b60f2a0bSfr41279 } 17347c478bd9Sstevel@tonic-gate n_rr = &rr; 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate 1737*b60f2a0bSfr41279 if ((err = big_mont_mul(&rr, n_rr, a, n, n0)) != BIG_OK) { 17387c478bd9Sstevel@tonic-gate goto ret; 1739*b60f2a0bSfr41279 } 17407c478bd9Sstevel@tonic-gate err = big_copy(result, &rr); 1741*b60f2a0bSfr41279 17427c478bd9Sstevel@tonic-gate ret: 1743*b60f2a0bSfr41279 big_finish(&rr); 17447c478bd9Sstevel@tonic-gate return (err); 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate 1748*b60f2a0bSfr41279 #ifdef USE_FLOATING_POINT 1749*b60f2a0bSfr41279 #define big_modexp_ncp_float big_modexp_ncp_sw 1750*b60f2a0bSfr41279 #else 1751*b60f2a0bSfr41279 #define big_modexp_ncp_int big_modexp_ncp_sw 1752*b60f2a0bSfr41279 #endif 1753*b60f2a0bSfr41279 17547c478bd9Sstevel@tonic-gate #define MAX_EXP_BIT_GROUP_SIZE 6 17557c478bd9Sstevel@tonic-gate #define APOWERS_MAX_SIZE (1 << (MAX_EXP_BIT_GROUP_SIZE - 1)) 17567c478bd9Sstevel@tonic-gate 1757*b60f2a0bSfr41279 /* ARGSUSED */ 17587c478bd9Sstevel@tonic-gate static BIG_ERR_CODE 1759*b60f2a0bSfr41279 big_modexp_ncp_int(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 1760*b60f2a0bSfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 1761*b60f2a0bSfr41279 17627c478bd9Sstevel@tonic-gate { 1763*b60f2a0bSfr41279 BIGNUM apowers[APOWERS_MAX_SIZE]; 1764*b60f2a0bSfr41279 BIGNUM tmp1; 1765*b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp1value[BIGTMPSIZE]; 1766*b60f2a0bSfr41279 int i, j, k, l, m, p; 1767*b60f2a0bSfr41279 int bit, bitind, bitcount, groupbits, apowerssize; 1768*b60f2a0bSfr41279 int nbits; 17697c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 17707c478bd9Sstevel@tonic-gate 17717c478bd9Sstevel@tonic-gate nbits = big_numbits(e); 17727c478bd9Sstevel@tonic-gate if (nbits < 50) { 17737c478bd9Sstevel@tonic-gate groupbits = 1; 17747c478bd9Sstevel@tonic-gate apowerssize = 1; 17757c478bd9Sstevel@tonic-gate } else { 17767c478bd9Sstevel@tonic-gate groupbits = MAX_EXP_BIT_GROUP_SIZE; 17777c478bd9Sstevel@tonic-gate apowerssize = 1 << (groupbits - 1); 17787c478bd9Sstevel@tonic-gate } 17797c478bd9Sstevel@tonic-gate 1780*b60f2a0bSfr41279 1781*b60f2a0bSfr41279 if ((err = big_init1(&tmp1, 2 * n->len + 1, 1782*b60f2a0bSfr41279 tmp1value, arraysize(tmp1value))) != BIG_OK) { 17837c478bd9Sstevel@tonic-gate return (err); 17847c478bd9Sstevel@tonic-gate } 17857c478bd9Sstevel@tonic-gate 1786*b60f2a0bSfr41279 /* set the malloced bit to help cleanup */ 1787*b60f2a0bSfr41279 for (i = 0; i < apowerssize; i++) { 1788*b60f2a0bSfr41279 apowers[i].malloced = 0; 1789*b60f2a0bSfr41279 } 1790*b60f2a0bSfr41279 for (i = 0; i < apowerssize; i++) { 1791*b60f2a0bSfr41279 if ((err = big_init1(&(apowers[i]), n->len, NULL, 0)) != 1792*b60f2a0bSfr41279 BIG_OK) { 1793*b60f2a0bSfr41279 goto ret; 1794*b60f2a0bSfr41279 } 1795*b60f2a0bSfr41279 } 17967c478bd9Sstevel@tonic-gate 1797*b60f2a0bSfr41279 (void) big_copy(&(apowers[0]), ma); 1798*b60f2a0bSfr41279 1799*b60f2a0bSfr41279 if ((err = big_mont_mul(&tmp1, ma, ma, n, n0)) != BIG_OK) { 1800*b60f2a0bSfr41279 goto ret; 1801*b60f2a0bSfr41279 } 1802*b60f2a0bSfr41279 (void) big_copy(ma, &tmp1); 1803*b60f2a0bSfr41279 1804*b60f2a0bSfr41279 for (i = 1; i < apowerssize; i++) { 1805*b60f2a0bSfr41279 if ((err = big_mont_mul(&tmp1, ma, 1806*b60f2a0bSfr41279 &(apowers[i-1]), n, n0)) != BIG_OK) { 1807*b60f2a0bSfr41279 goto ret; 1808*b60f2a0bSfr41279 } 1809*b60f2a0bSfr41279 (void) big_copy(&apowers[i], &tmp1); 1810*b60f2a0bSfr41279 } 1811*b60f2a0bSfr41279 1812*b60f2a0bSfr41279 bitind = nbits % BIG_CHUNK_SIZE; 1813*b60f2a0bSfr41279 k = 0; 1814*b60f2a0bSfr41279 l = 0; 1815*b60f2a0bSfr41279 p = 0; 1816*b60f2a0bSfr41279 bitcount = 0; 1817*b60f2a0bSfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 1818*b60f2a0bSfr41279 for (j = bitind - 1; j >= 0; j--) { 1819*b60f2a0bSfr41279 bit = (e->value[i] >> j) & 1; 1820*b60f2a0bSfr41279 if ((bitcount == 0) && (bit == 0)) { 1821*b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, 1822*b60f2a0bSfr41279 tmp, tmp, n, n0)) != BIG_OK) { 1823*b60f2a0bSfr41279 goto ret; 1824*b60f2a0bSfr41279 } 18257c478bd9Sstevel@tonic-gate } else { 1826*b60f2a0bSfr41279 bitcount++; 1827*b60f2a0bSfr41279 p = p * 2 + bit; 1828*b60f2a0bSfr41279 if (bit == 1) { 1829*b60f2a0bSfr41279 k = k + l + 1; 1830*b60f2a0bSfr41279 l = 0; 1831*b60f2a0bSfr41279 } else { 1832*b60f2a0bSfr41279 l++; 18337c478bd9Sstevel@tonic-gate } 1834*b60f2a0bSfr41279 if (bitcount == groupbits) { 1835*b60f2a0bSfr41279 for (m = 0; m < k; m++) { 1836*b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, 1837*b60f2a0bSfr41279 tmp, tmp, n, n0)) != 1838*b60f2a0bSfr41279 BIG_OK) { 1839*b60f2a0bSfr41279 goto ret; 1840*b60f2a0bSfr41279 } 1841*b60f2a0bSfr41279 } 1842*b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, tmp, 1843*b60f2a0bSfr41279 &(apowers[p >> (l + 1)]), 1844*b60f2a0bSfr41279 n, n0)) != BIG_OK) { 1845*b60f2a0bSfr41279 goto ret; 1846*b60f2a0bSfr41279 } 1847*b60f2a0bSfr41279 for (m = 0; m < l; m++) { 1848*b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, 1849*b60f2a0bSfr41279 tmp, tmp, n, n0)) != 1850*b60f2a0bSfr41279 BIG_OK) { 1851*b60f2a0bSfr41279 goto ret; 1852*b60f2a0bSfr41279 } 1853*b60f2a0bSfr41279 } 1854*b60f2a0bSfr41279 k = 0; 1855*b60f2a0bSfr41279 l = 0; 1856*b60f2a0bSfr41279 p = 0; 1857*b60f2a0bSfr41279 bitcount = 0; 1858*b60f2a0bSfr41279 } 1859*b60f2a0bSfr41279 } 1860*b60f2a0bSfr41279 } 1861*b60f2a0bSfr41279 bitind = BIG_CHUNK_SIZE; 1862*b60f2a0bSfr41279 } 18637c478bd9Sstevel@tonic-gate 1864*b60f2a0bSfr41279 for (m = 0; m < k; m++) { 1865*b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, tmp, tmp, n, n0)) != BIG_OK) { 1866*b60f2a0bSfr41279 goto ret; 1867*b60f2a0bSfr41279 } 1868*b60f2a0bSfr41279 } 1869*b60f2a0bSfr41279 if (p != 0) { 1870*b60f2a0bSfr41279 if ((err = big_mont_mul(tmp, tmp, 1871*b60f2a0bSfr41279 &(apowers[p >> (l + 1)]), n, n0)) != BIG_OK) { 1872*b60f2a0bSfr41279 goto ret; 1873*b60f2a0bSfr41279 } 1874*b60f2a0bSfr41279 } 1875*b60f2a0bSfr41279 for (m = 0; m < l; m++) { 1876*b60f2a0bSfr41279 if ((err = big_mont_mul(result, tmp, tmp, n, n0)) != BIG_OK) { 1877*b60f2a0bSfr41279 goto ret; 1878*b60f2a0bSfr41279 } 1879*b60f2a0bSfr41279 } 18807c478bd9Sstevel@tonic-gate 1881*b60f2a0bSfr41279 ret: 1882*b60f2a0bSfr41279 for (i = apowerssize - 1; i >= 0; i--) { 1883*b60f2a0bSfr41279 big_finish(&(apowers[i])); 1884*b60f2a0bSfr41279 } 1885*b60f2a0bSfr41279 big_finish(&tmp1); 1886*b60f2a0bSfr41279 1887*b60f2a0bSfr41279 return (err); 1888*b60f2a0bSfr41279 } 1889*b60f2a0bSfr41279 1890*b60f2a0bSfr41279 1891*b60f2a0bSfr41279 #ifdef USE_FLOATING_POINT 1892*b60f2a0bSfr41279 1893*b60f2a0bSfr41279 #ifdef _KERNEL 1894*b60f2a0bSfr41279 1895*b60f2a0bSfr41279 #include <sys/sysmacros.h> 1896*b60f2a0bSfr41279 #include <sys/regset.h> 1897*b60f2a0bSfr41279 #include <sys/fpu/fpusystm.h> 1898*b60f2a0bSfr41279 1899*b60f2a0bSfr41279 /* the alignment for block stores to save fp registers */ 1900*b60f2a0bSfr41279 #define FPR_ALIGN (64) 1901*b60f2a0bSfr41279 1902*b60f2a0bSfr41279 extern void big_savefp(kfpu_t *); 1903*b60f2a0bSfr41279 extern void big_restorefp(kfpu_t *); 1904*b60f2a0bSfr41279 1905*b60f2a0bSfr41279 #endif /* _KERNEL */ 1906*b60f2a0bSfr41279 1907*b60f2a0bSfr41279 /* 1908*b60f2a0bSfr41279 * This version makes use of floating point for performance 1909*b60f2a0bSfr41279 */ 1910*b60f2a0bSfr41279 static BIG_ERR_CODE 1911*b60f2a0bSfr41279 big_modexp_ncp_float(BIGNUM *result, BIGNUM *ma, BIGNUM *e, BIGNUM *n, 1912*b60f2a0bSfr41279 BIGNUM *tmp, BIG_CHUNK_TYPE n0) 1913*b60f2a0bSfr41279 { 1914*b60f2a0bSfr41279 1915*b60f2a0bSfr41279 int i, j, k, l, m, p, bit, bitind, bitcount, nlen; 1916*b60f2a0bSfr41279 double dn0; 1917*b60f2a0bSfr41279 double *dn, *dt, *d16r, *d32r; 1918*b60f2a0bSfr41279 uint32_t *nint, *prod; 1919*b60f2a0bSfr41279 double *apowers[APOWERS_MAX_SIZE]; 1920*b60f2a0bSfr41279 int nbits, groupbits, apowerssize; 1921*b60f2a0bSfr41279 BIG_ERR_CODE err = BIG_OK; 1922*b60f2a0bSfr41279 1923*b60f2a0bSfr41279 #ifdef _KERNEL 1924*b60f2a0bSfr41279 uint8_t fpua[sizeof (kfpu_t) + FPR_ALIGN]; 1925*b60f2a0bSfr41279 kfpu_t *fpu; 1926*b60f2a0bSfr41279 1927*b60f2a0bSfr41279 #ifdef DEBUG 1928*b60f2a0bSfr41279 if (!fpu_exists) 1929*b60f2a0bSfr41279 return (BIG_GENERAL_ERR); 1930*b60f2a0bSfr41279 #endif 1931*b60f2a0bSfr41279 1932*b60f2a0bSfr41279 fpu = (kfpu_t *)P2ROUNDUP((uintptr_t)fpua, FPR_ALIGN); 1933*b60f2a0bSfr41279 big_savefp(fpu); 1934*b60f2a0bSfr41279 1935*b60f2a0bSfr41279 #endif /* _KERNEL */ 1936*b60f2a0bSfr41279 1937*b60f2a0bSfr41279 nbits = big_numbits(e); 1938*b60f2a0bSfr41279 if (nbits < 50) { 1939*b60f2a0bSfr41279 groupbits = 1; 1940*b60f2a0bSfr41279 apowerssize = 1; 1941*b60f2a0bSfr41279 } else { 1942*b60f2a0bSfr41279 groupbits = MAX_EXP_BIT_GROUP_SIZE; 1943*b60f2a0bSfr41279 apowerssize = 1 << (groupbits - 1); 1944*b60f2a0bSfr41279 } 1945*b60f2a0bSfr41279 1946*b60f2a0bSfr41279 nlen = (BIG_CHUNK_SIZE / 32) * n->len; 19477c478bd9Sstevel@tonic-gate dn0 = (double)(n0 & 0xffff); 19487c478bd9Sstevel@tonic-gate 19497c478bd9Sstevel@tonic-gate dn = dt = d16r = d32r = NULL; 19507c478bd9Sstevel@tonic-gate nint = prod = NULL; 19517c478bd9Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 19527c478bd9Sstevel@tonic-gate apowers[i] = NULL; 19537c478bd9Sstevel@tonic-gate } 19547c478bd9Sstevel@tonic-gate 19557c478bd9Sstevel@tonic-gate if ((dn = big_malloc(nlen * sizeof (double))) == NULL) { 19567c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 19577c478bd9Sstevel@tonic-gate goto ret; 19587c478bd9Sstevel@tonic-gate } 19597c478bd9Sstevel@tonic-gate if ((dt = big_malloc((4 * nlen + 2) * sizeof (double))) == NULL) { 19607c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 19617c478bd9Sstevel@tonic-gate goto ret; 19627c478bd9Sstevel@tonic-gate } 19637c478bd9Sstevel@tonic-gate if ((nint = big_malloc(nlen * sizeof (uint32_t))) == NULL) { 19647c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 19657c478bd9Sstevel@tonic-gate goto ret; 19667c478bd9Sstevel@tonic-gate } 19677c478bd9Sstevel@tonic-gate if ((prod = big_malloc((nlen + 1) * sizeof (uint32_t))) == NULL) { 19687c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 19697c478bd9Sstevel@tonic-gate goto ret; 19707c478bd9Sstevel@tonic-gate } 19717c478bd9Sstevel@tonic-gate if ((d16r = big_malloc((2 * nlen + 1) * sizeof (double))) == NULL) { 19727c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 19737c478bd9Sstevel@tonic-gate goto ret; 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate if ((d32r = big_malloc(nlen * sizeof (double))) == NULL) { 19767c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 19777c478bd9Sstevel@tonic-gate goto ret; 19787c478bd9Sstevel@tonic-gate } 19797c478bd9Sstevel@tonic-gate for (i = 0; i < apowerssize; i++) { 19807c478bd9Sstevel@tonic-gate if ((apowers[i] = big_malloc((2 * nlen + 1) * 19817c478bd9Sstevel@tonic-gate sizeof (double))) == NULL) { 19827c478bd9Sstevel@tonic-gate err = BIG_NO_MEM; 19837c478bd9Sstevel@tonic-gate goto ret; 19847c478bd9Sstevel@tonic-gate } 19857c478bd9Sstevel@tonic-gate } 19867c478bd9Sstevel@tonic-gate 1987*b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 1988*b60f2a0bSfr41279 for (i = 0; i < ma->len; i++) { 1989*b60f2a0bSfr41279 nint[i] = ma->value[i]; 1990*b60f2a0bSfr41279 } 1991*b60f2a0bSfr41279 for (; i < nlen; i++) { 1992*b60f2a0bSfr41279 nint[i] = 0; 1993*b60f2a0bSfr41279 } 1994*b60f2a0bSfr41279 #else 1995*b60f2a0bSfr41279 for (i = 0; i < ma->len; i++) { 1996*b60f2a0bSfr41279 nint[2 * i] = (uint32_t)(ma->value[i] & 0xffffffffULL); 1997*b60f2a0bSfr41279 nint[2 * i + 1] = (uint32_t)(ma->value[i] >> 32); 1998*b60f2a0bSfr41279 } 1999*b60f2a0bSfr41279 for (i = ma->len * 2; i < nlen; i++) { 2000*b60f2a0bSfr41279 nint[i] = 0; 2001*b60f2a0bSfr41279 } 2002*b60f2a0bSfr41279 #endif 20037c478bd9Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, apowers[0], nint, nlen); 20047c478bd9Sstevel@tonic-gate 2005*b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 2006*b60f2a0bSfr41279 for (i = 0; i < n->len; i++) { 2007*b60f2a0bSfr41279 nint[i] = n->value[i]; 2008*b60f2a0bSfr41279 } 2009*b60f2a0bSfr41279 for (; i < nlen; i++) { 2010*b60f2a0bSfr41279 nint[i] = 0; 2011*b60f2a0bSfr41279 } 2012*b60f2a0bSfr41279 #else 2013*b60f2a0bSfr41279 for (i = 0; i < n->len; i++) { 2014*b60f2a0bSfr41279 nint[2 * i] = (uint32_t)(n->value[i] & 0xffffffffULL); 2015*b60f2a0bSfr41279 nint[2 * i + 1] = (uint32_t)(n->value[i] >> 32); 2016*b60f2a0bSfr41279 } 2017*b60f2a0bSfr41279 for (i = n->len * 2; i < nlen; i++) { 2018*b60f2a0bSfr41279 nint[i] = 0; 2019*b60f2a0bSfr41279 } 2020*b60f2a0bSfr41279 #endif 20217c478bd9Sstevel@tonic-gate conv_i32_to_d32(dn, nint, nlen); 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[0], dt, dn, nint, nlen, dn0); 20247c478bd9Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 20257c478bd9Sstevel@tonic-gate for (i = 1; i < apowerssize; i++) { 20267c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[i - 1], 20277c478bd9Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 20287c478bd9Sstevel@tonic-gate conv_i32_to_d16(apowers[i], prod, nlen); 20297c478bd9Sstevel@tonic-gate } 20307c478bd9Sstevel@tonic-gate 2031*b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 2032*b60f2a0bSfr41279 for (i = 0; i < tmp->len; i++) { 2033*b60f2a0bSfr41279 prod[i] = tmp->value[i]; 2034*b60f2a0bSfr41279 } 2035*b60f2a0bSfr41279 for (; i < nlen + 1; i++) { 2036*b60f2a0bSfr41279 prod[i] = 0; 2037*b60f2a0bSfr41279 } 2038*b60f2a0bSfr41279 #else 2039*b60f2a0bSfr41279 for (i = 0; i < tmp->len; i++) { 2040*b60f2a0bSfr41279 prod[2 * i] = (uint32_t)(tmp->value[i] & 0xffffffffULL); 2041*b60f2a0bSfr41279 prod[2 * i + 1] = (uint32_t)(tmp->value[i] >> 32); 2042*b60f2a0bSfr41279 } 2043*b60f2a0bSfr41279 for (i = tmp->len * 2; i < nlen + 1; i++) { 2044*b60f2a0bSfr41279 prod[i] = 0; 2045*b60f2a0bSfr41279 } 2046*b60f2a0bSfr41279 #endif 20477c478bd9Sstevel@tonic-gate 2048*b60f2a0bSfr41279 bitind = nbits % BIG_CHUNK_SIZE; 20497c478bd9Sstevel@tonic-gate k = 0; 20507c478bd9Sstevel@tonic-gate l = 0; 20517c478bd9Sstevel@tonic-gate p = 0; 20527c478bd9Sstevel@tonic-gate bitcount = 0; 2053*b60f2a0bSfr41279 for (i = nbits / BIG_CHUNK_SIZE; i >= 0; i--) { 20547c478bd9Sstevel@tonic-gate for (j = bitind - 1; j >= 0; j--) { 20557c478bd9Sstevel@tonic-gate bit = (e->value[i] >> j) & 1; 20567c478bd9Sstevel@tonic-gate if ((bitcount == 0) && (bit == 0)) { 20577c478bd9Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, 20587c478bd9Sstevel@tonic-gate prod, nlen); 20597c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, 20607c478bd9Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 20617c478bd9Sstevel@tonic-gate } else { 20627c478bd9Sstevel@tonic-gate bitcount++; 20637c478bd9Sstevel@tonic-gate p = p * 2 + bit; 20647c478bd9Sstevel@tonic-gate if (bit == 1) { 20657c478bd9Sstevel@tonic-gate k = k + l + 1; 20667c478bd9Sstevel@tonic-gate l = 0; 20677c478bd9Sstevel@tonic-gate } else { 20687c478bd9Sstevel@tonic-gate l++; 20697c478bd9Sstevel@tonic-gate } 20707c478bd9Sstevel@tonic-gate if (bitcount == groupbits) { 20717c478bd9Sstevel@tonic-gate for (m = 0; m < k; m++) { 2072*b60f2a0bSfr41279 conv_i32_to_d32_and_d16(d32r, 2073*b60f2a0bSfr41279 d16r, prod, nlen); 20747c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 20757c478bd9Sstevel@tonic-gate d16r, dt, dn, nint, 20767c478bd9Sstevel@tonic-gate nlen, dn0); 20777c478bd9Sstevel@tonic-gate } 20787c478bd9Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 20797c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 20807c478bd9Sstevel@tonic-gate apowers[p >> (l+1)], 20817c478bd9Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 20827c478bd9Sstevel@tonic-gate for (m = 0; m < l; m++) { 2083*b60f2a0bSfr41279 conv_i32_to_d32_and_d16(d32r, 2084*b60f2a0bSfr41279 d16r, prod, nlen); 20857c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, 20867c478bd9Sstevel@tonic-gate d16r, dt, dn, nint, 20877c478bd9Sstevel@tonic-gate nlen, dn0); 20887c478bd9Sstevel@tonic-gate } 20897c478bd9Sstevel@tonic-gate k = 0; 20907c478bd9Sstevel@tonic-gate l = 0; 20917c478bd9Sstevel@tonic-gate p = 0; 20927c478bd9Sstevel@tonic-gate bitcount = 0; 20937c478bd9Sstevel@tonic-gate } 20947c478bd9Sstevel@tonic-gate } 20957c478bd9Sstevel@tonic-gate } 2096*b60f2a0bSfr41279 bitind = BIG_CHUNK_SIZE; 20977c478bd9Sstevel@tonic-gate } 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate for (m = 0; m < k; m++) { 21007c478bd9Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 21017c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 21027c478bd9Sstevel@tonic-gate } 21037c478bd9Sstevel@tonic-gate if (p != 0) { 21047c478bd9Sstevel@tonic-gate conv_i32_to_d32(d32r, prod, nlen); 21057c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, apowers[p >> (l + 1)], 21067c478bd9Sstevel@tonic-gate dt, dn, nint, nlen, dn0); 21077c478bd9Sstevel@tonic-gate } 21087c478bd9Sstevel@tonic-gate for (m = 0; m < l; m++) { 21097c478bd9Sstevel@tonic-gate conv_i32_to_d32_and_d16(d32r, d16r, prod, nlen); 21107c478bd9Sstevel@tonic-gate mont_mulf_noconv(prod, d32r, d16r, dt, dn, nint, nlen, dn0); 21117c478bd9Sstevel@tonic-gate } 21127c478bd9Sstevel@tonic-gate 2113*b60f2a0bSfr41279 #if (BIG_CHUNK_SIZE == 32) 2114*b60f2a0bSfr41279 for (i = 0; i < nlen; i++) { 2115*b60f2a0bSfr41279 result->value[i] = prod[i]; 2116*b60f2a0bSfr41279 } 2117*b60f2a0bSfr41279 for (i = nlen - 1; (i > 0) && (prod[i] == 0); i--) 2118*b60f2a0bSfr41279 ; 2119*b60f2a0bSfr41279 #else 2120*b60f2a0bSfr41279 for (i = 0; i < nlen / 2; i++) { 2121*b60f2a0bSfr41279 result->value[i] = (uint64_t)(prod[2 * i]) + 2122*b60f2a0bSfr41279 (((uint64_t)(prod[2 * i + 1])) << 32); 2123*b60f2a0bSfr41279 } 2124*b60f2a0bSfr41279 for (i = nlen / 2 - 1; (i > 0) && (result->value[i] == 0); i--) 2125*b60f2a0bSfr41279 ; 2126*b60f2a0bSfr41279 #endif 2127*b60f2a0bSfr41279 result->len = i + 1; 2128*b60f2a0bSfr41279 21297c478bd9Sstevel@tonic-gate ret: 21307c478bd9Sstevel@tonic-gate for (i = apowerssize - 1; i >= 0; i--) { 21317c478bd9Sstevel@tonic-gate if (apowers[i] != NULL) 21327c478bd9Sstevel@tonic-gate big_free(apowers[i], (2 * nlen + 1) * sizeof (double)); 21337c478bd9Sstevel@tonic-gate } 2134*b60f2a0bSfr41279 if (d32r != NULL) { 21357c478bd9Sstevel@tonic-gate big_free(d32r, nlen * sizeof (double)); 2136*b60f2a0bSfr41279 } 2137*b60f2a0bSfr41279 if (d16r != NULL) { 21387c478bd9Sstevel@tonic-gate big_free(d16r, (2 * nlen + 1) * sizeof (double)); 2139*b60f2a0bSfr41279 } 2140*b60f2a0bSfr41279 if (prod != NULL) { 21417c478bd9Sstevel@tonic-gate big_free(prod, (nlen + 1) * sizeof (uint32_t)); 2142*b60f2a0bSfr41279 } 2143*b60f2a0bSfr41279 if (nint != NULL) { 21447c478bd9Sstevel@tonic-gate big_free(nint, nlen * sizeof (uint32_t)); 2145*b60f2a0bSfr41279 } 2146*b60f2a0bSfr41279 if (dt != NULL) { 21477c478bd9Sstevel@tonic-gate big_free(dt, (4 * nlen + 2) * sizeof (double)); 2148*b60f2a0bSfr41279 } 2149*b60f2a0bSfr41279 if (dn != NULL) { 21507c478bd9Sstevel@tonic-gate big_free(dn, nlen * sizeof (double)); 21517c478bd9Sstevel@tonic-gate } 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate #ifdef _KERNEL 2154*b60f2a0bSfr41279 big_restorefp(fpu); 21557c478bd9Sstevel@tonic-gate #endif 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate return (err); 21587c478bd9Sstevel@tonic-gate } 21597c478bd9Sstevel@tonic-gate 21607c478bd9Sstevel@tonic-gate #endif /* USE_FLOATING_POINT */ 21617c478bd9Sstevel@tonic-gate 21627c478bd9Sstevel@tonic-gate 21637c478bd9Sstevel@tonic-gate BIG_ERR_CODE 2164*b60f2a0bSfr41279 big_modexp_ext(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr, 2165*b60f2a0bSfr41279 big_modexp_ncp_info_t *info) 2166*b60f2a0bSfr41279 { 2167*b60f2a0bSfr41279 BIGNUM ma, tmp, rr; 2168*b60f2a0bSfr41279 BIG_CHUNK_TYPE mavalue[BIGTMPSIZE]; 2169*b60f2a0bSfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 2170*b60f2a0bSfr41279 BIG_CHUNK_TYPE rrvalue[BIGTMPSIZE]; 2171*b60f2a0bSfr41279 BIG_ERR_CODE err; 2172*b60f2a0bSfr41279 BIG_CHUNK_TYPE n0; 2173*b60f2a0bSfr41279 2174*b60f2a0bSfr41279 if ((err = big_init1(&ma, n->len, mavalue, arraysize(mavalue))) != 2175*b60f2a0bSfr41279 BIG_OK) { 2176*b60f2a0bSfr41279 return (err); 2177*b60f2a0bSfr41279 } 2178*b60f2a0bSfr41279 ma.len = 1; 2179*b60f2a0bSfr41279 ma.value[0] = 0; 2180*b60f2a0bSfr41279 2181*b60f2a0bSfr41279 if ((err = big_init1(&tmp, 2 * n->len + 1, 2182*b60f2a0bSfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 2183*b60f2a0bSfr41279 goto ret1; 2184*b60f2a0bSfr41279 } 2185*b60f2a0bSfr41279 2186*b60f2a0bSfr41279 /* set the malloced bit to help cleanup */ 2187*b60f2a0bSfr41279 rr.malloced = 0; 2188*b60f2a0bSfr41279 if (n_rr == NULL) { 2189*b60f2a0bSfr41279 if ((err = big_init1(&rr, 2 * n->len + 1, 2190*b60f2a0bSfr41279 rrvalue, arraysize(rrvalue))) != BIG_OK) { 2191*b60f2a0bSfr41279 goto ret2; 2192*b60f2a0bSfr41279 } 2193*b60f2a0bSfr41279 if (big_mont_rr(&rr, n) != BIG_OK) { 2194*b60f2a0bSfr41279 goto ret; 2195*b60f2a0bSfr41279 } 2196*b60f2a0bSfr41279 n_rr = &rr; 2197*b60f2a0bSfr41279 } 2198*b60f2a0bSfr41279 2199*b60f2a0bSfr41279 n0 = big_n0(n->value[0]); 2200*b60f2a0bSfr41279 2201*b60f2a0bSfr41279 if (big_cmp_abs(a, n) > 0) { 2202*b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &ma, a, n)) != BIG_OK) { 2203*b60f2a0bSfr41279 goto ret; 2204*b60f2a0bSfr41279 } 2205*b60f2a0bSfr41279 err = big_mont_conv(&ma, &ma, n, n0, n_rr); 2206*b60f2a0bSfr41279 } else { 2207*b60f2a0bSfr41279 err = big_mont_conv(&ma, a, n, n0, n_rr); 2208*b60f2a0bSfr41279 } 2209*b60f2a0bSfr41279 if (err != BIG_OK) { 2210*b60f2a0bSfr41279 goto ret; 2211*b60f2a0bSfr41279 } 2212*b60f2a0bSfr41279 2213*b60f2a0bSfr41279 tmp.len = 1; 2214*b60f2a0bSfr41279 tmp.value[0] = 1; 2215*b60f2a0bSfr41279 if ((err = big_mont_conv(&tmp, &tmp, n, n0, n_rr)) != BIG_OK) { 2216*b60f2a0bSfr41279 goto ret; 2217*b60f2a0bSfr41279 } 2218*b60f2a0bSfr41279 2219*b60f2a0bSfr41279 if ((info != NULL) && (info->func != NULL)) { 2220*b60f2a0bSfr41279 err = (*(info->func))(&tmp, &ma, e, n, &tmp, n0, 2221*b60f2a0bSfr41279 info->ncp, info->reqp); 2222*b60f2a0bSfr41279 } else { 2223*b60f2a0bSfr41279 err = big_modexp_ncp_sw(&tmp, &ma, e, n, &tmp, n0); 2224*b60f2a0bSfr41279 } 2225*b60f2a0bSfr41279 if (err != BIG_OK) { 2226*b60f2a0bSfr41279 goto ret; 2227*b60f2a0bSfr41279 } 2228*b60f2a0bSfr41279 2229*b60f2a0bSfr41279 ma.value[0] = 1; 2230*b60f2a0bSfr41279 ma.len = 1; 2231*b60f2a0bSfr41279 if ((err = big_mont_mul(&tmp, &tmp, &ma, n, n0)) != BIG_OK) { 2232*b60f2a0bSfr41279 goto ret; 2233*b60f2a0bSfr41279 } 2234*b60f2a0bSfr41279 err = big_copy(result, &tmp); 2235*b60f2a0bSfr41279 2236*b60f2a0bSfr41279 ret: 2237*b60f2a0bSfr41279 if (rr.malloced) { 2238*b60f2a0bSfr41279 big_finish(&rr); 2239*b60f2a0bSfr41279 } 2240*b60f2a0bSfr41279 ret2: 2241*b60f2a0bSfr41279 big_finish(&tmp); 2242*b60f2a0bSfr41279 ret1: 2243*b60f2a0bSfr41279 big_finish(&ma); 2244*b60f2a0bSfr41279 2245*b60f2a0bSfr41279 return (err); 2246*b60f2a0bSfr41279 } 2247*b60f2a0bSfr41279 2248*b60f2a0bSfr41279 BIG_ERR_CODE 2249*b60f2a0bSfr41279 big_modexp(BIGNUM *result, BIGNUM *a, BIGNUM *e, BIGNUM *n, BIGNUM *n_rr) 2250*b60f2a0bSfr41279 { 2251*b60f2a0bSfr41279 return (big_modexp_ext(result, a, e, n, n_rr, NULL)); 2252*b60f2a0bSfr41279 } 2253*b60f2a0bSfr41279 2254*b60f2a0bSfr41279 2255*b60f2a0bSfr41279 BIG_ERR_CODE 2256*b60f2a0bSfr41279 big_modexp_crt_ext(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 22577c478bd9Sstevel@tonic-gate BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 2258*b60f2a0bSfr41279 BIGNUM *p_rr, BIGNUM *q_rr, big_modexp_ncp_info_t *info) 22597c478bd9Sstevel@tonic-gate { 22607c478bd9Sstevel@tonic-gate BIGNUM ap, aq, tmp; 22617c478bd9Sstevel@tonic-gate int alen, biglen, sign; 22627c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 22637c478bd9Sstevel@tonic-gate 2264*b60f2a0bSfr41279 if (p->len > q->len) { 2265*b60f2a0bSfr41279 biglen = p->len; 2266*b60f2a0bSfr41279 } else { 2267*b60f2a0bSfr41279 biglen = q->len; 2268*b60f2a0bSfr41279 } 22697c478bd9Sstevel@tonic-gate 2270*b60f2a0bSfr41279 if ((err = big_init1(&ap, p->len, NULL, 0)) != BIG_OK) { 22717c478bd9Sstevel@tonic-gate return (err); 2272*b60f2a0bSfr41279 } 2273*b60f2a0bSfr41279 if ((err = big_init1(&aq, q->len, NULL, 0)) != BIG_OK) { 22747c478bd9Sstevel@tonic-gate goto ret1; 2275*b60f2a0bSfr41279 } 2276*b60f2a0bSfr41279 if ((err = big_init1(&tmp, biglen + q->len + 1, NULL, 0)) != BIG_OK) { 22777c478bd9Sstevel@tonic-gate goto ret2; 2278*b60f2a0bSfr41279 } 22797c478bd9Sstevel@tonic-gate 22807c478bd9Sstevel@tonic-gate /* 22817c478bd9Sstevel@tonic-gate * check whether a is too short - to avoid timing attacks 22827c478bd9Sstevel@tonic-gate */ 22837c478bd9Sstevel@tonic-gate alen = a->len; 22847c478bd9Sstevel@tonic-gate while ((alen > p->len) && (a->value[alen - 1] == 0)) { 22857c478bd9Sstevel@tonic-gate alen--; 22867c478bd9Sstevel@tonic-gate } 22877c478bd9Sstevel@tonic-gate if (alen < p->len + q->len) { 22887c478bd9Sstevel@tonic-gate /* 22897c478bd9Sstevel@tonic-gate * a is too short, add p*q to it before 22907c478bd9Sstevel@tonic-gate * taking it modulo p and q 22917c478bd9Sstevel@tonic-gate * this will also affect timing, but this difference 22927c478bd9Sstevel@tonic-gate * does not depend on p or q, only on a 22937c478bd9Sstevel@tonic-gate * (in "normal" operation, this path will never be 22947c478bd9Sstevel@tonic-gate * taken, so it is not a performance penalty 22957c478bd9Sstevel@tonic-gate */ 2296*b60f2a0bSfr41279 if ((err = big_mul(&tmp, p, q)) != BIG_OK) { 22977c478bd9Sstevel@tonic-gate goto ret; 22987c478bd9Sstevel@tonic-gate } 2299*b60f2a0bSfr41279 if ((err = big_add(&tmp, &tmp, a)) != BIG_OK) { 2300*b60f2a0bSfr41279 goto ret; 2301*b60f2a0bSfr41279 } 2302*b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &ap, &tmp, p)) != BIG_OK) { 2303*b60f2a0bSfr41279 goto ret; 2304*b60f2a0bSfr41279 } 2305*b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 2306*b60f2a0bSfr41279 goto ret; 2307*b60f2a0bSfr41279 } 2308*b60f2a0bSfr41279 } else { 2309*b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &ap, a, p)) != BIG_OK) { 2310*b60f2a0bSfr41279 goto ret; 2311*b60f2a0bSfr41279 } 2312*b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &aq, a, q)) != BIG_OK) { 2313*b60f2a0bSfr41279 goto ret; 2314*b60f2a0bSfr41279 } 2315*b60f2a0bSfr41279 } 23167c478bd9Sstevel@tonic-gate 2317*b60f2a0bSfr41279 if ((err = big_modexp_ext(&ap, &ap, dmodpminus1, p, p_rr, info)) != 2318*b60f2a0bSfr41279 BIG_OK) { 23197c478bd9Sstevel@tonic-gate goto ret; 2320*b60f2a0bSfr41279 } 2321*b60f2a0bSfr41279 if ((err = big_modexp_ext(&aq, &aq, dmodqminus1, q, q_rr, info)) != 2322*b60f2a0bSfr41279 BIG_OK) { 23237c478bd9Sstevel@tonic-gate goto ret; 2324*b60f2a0bSfr41279 } 2325*b60f2a0bSfr41279 if ((err = big_sub(&tmp, &aq, &ap)) != BIG_OK) { 23267c478bd9Sstevel@tonic-gate goto ret; 2327*b60f2a0bSfr41279 } 2328*b60f2a0bSfr41279 if ((err = big_mul(&tmp, &tmp, pinvmodq)) != BIG_OK) { 23297c478bd9Sstevel@tonic-gate goto ret; 2330*b60f2a0bSfr41279 } 23317c478bd9Sstevel@tonic-gate sign = tmp.sign; 23327c478bd9Sstevel@tonic-gate tmp.sign = 1; 2333*b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &aq, &tmp, q)) != BIG_OK) { 23347c478bd9Sstevel@tonic-gate goto ret; 2335*b60f2a0bSfr41279 } 23367c478bd9Sstevel@tonic-gate if ((sign == -1) && (!big_is_zero(&aq))) { 23377c478bd9Sstevel@tonic-gate (void) big_sub_pos(&aq, q, &aq); 23387c478bd9Sstevel@tonic-gate } 2339*b60f2a0bSfr41279 if ((err = big_mul(&tmp, &aq, p)) != BIG_OK) { 23407c478bd9Sstevel@tonic-gate goto ret; 2341*b60f2a0bSfr41279 } 23427c478bd9Sstevel@tonic-gate err = big_add_abs(result, &ap, &tmp); 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate ret: 23457c478bd9Sstevel@tonic-gate big_finish(&tmp); 23467c478bd9Sstevel@tonic-gate ret2: 23477c478bd9Sstevel@tonic-gate big_finish(&aq); 23487c478bd9Sstevel@tonic-gate ret1: 23497c478bd9Sstevel@tonic-gate big_finish(&ap); 23507c478bd9Sstevel@tonic-gate 23517c478bd9Sstevel@tonic-gate return (err); 23527c478bd9Sstevel@tonic-gate } 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate 2355*b60f2a0bSfr41279 BIG_ERR_CODE 2356*b60f2a0bSfr41279 big_modexp_crt(BIGNUM *result, BIGNUM *a, BIGNUM *dmodpminus1, 2357*b60f2a0bSfr41279 BIGNUM *dmodqminus1, BIGNUM *p, BIGNUM *q, BIGNUM *pinvmodq, 2358*b60f2a0bSfr41279 BIGNUM *p_rr, BIGNUM *q_rr) 2359*b60f2a0bSfr41279 { 2360*b60f2a0bSfr41279 return (big_modexp_crt_ext(result, a, dmodpminus1, dmodqminus1, 2361*b60f2a0bSfr41279 p, q, pinvmodq, p_rr, q_rr, NULL)); 2362*b60f2a0bSfr41279 } 23637c478bd9Sstevel@tonic-gate 23647c478bd9Sstevel@tonic-gate 2365*b60f2a0bSfr41279 static BIG_CHUNK_TYPE onearr[1] = {(BIG_CHUNK_TYPE)1}; 2366*b60f2a0bSfr41279 BIGNUM big_One = {1, 1, 1, 0, onearr}; 2367*b60f2a0bSfr41279 2368*b60f2a0bSfr41279 static BIG_CHUNK_TYPE twoarr[1] = {(BIG_CHUNK_TYPE)2}; 2369*b60f2a0bSfr41279 BIGNUM big_Two = {1, 1, 1, 0, twoarr}; 2370*b60f2a0bSfr41279 2371*b60f2a0bSfr41279 static BIG_CHUNK_TYPE fourarr[1] = {(BIG_CHUNK_TYPE)4}; 2372*b60f2a0bSfr41279 static BIGNUM big_Four = {1, 1, 1, 0, fourarr}; 2373*b60f2a0bSfr41279 23747c478bd9Sstevel@tonic-gate 23757c478bd9Sstevel@tonic-gate BIG_ERR_CODE 23767c478bd9Sstevel@tonic-gate big_sqrt_pos(BIGNUM *result, BIGNUM *n) 23777c478bd9Sstevel@tonic-gate { 23787c478bd9Sstevel@tonic-gate BIGNUM *high, *low, *mid, *t; 23797c478bd9Sstevel@tonic-gate BIGNUM t1, t2, t3, prod; 2380*b60f2a0bSfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 2381*b60f2a0bSfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 2382*b60f2a0bSfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 2383*b60f2a0bSfr41279 BIG_CHUNK_TYPE prodvalue[BIGTMPSIZE]; 23847c478bd9Sstevel@tonic-gate int i, nbits, diff, nrootbits, highbits; 23857c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 23867c478bd9Sstevel@tonic-gate 23877c478bd9Sstevel@tonic-gate nbits = big_numbits(n); 23887c478bd9Sstevel@tonic-gate 23897c478bd9Sstevel@tonic-gate if ((err = big_init1(&t1, n->len + 1, 23907c478bd9Sstevel@tonic-gate t1value, arraysize(t1value))) != BIG_OK) 23917c478bd9Sstevel@tonic-gate return (err); 23927c478bd9Sstevel@tonic-gate if ((err = big_init1(&t2, n->len + 1, 23937c478bd9Sstevel@tonic-gate t2value, arraysize(t2value))) != BIG_OK) 23947c478bd9Sstevel@tonic-gate goto ret1; 23957c478bd9Sstevel@tonic-gate if ((err = big_init1(&t3, n->len + 1, 23967c478bd9Sstevel@tonic-gate t3value, arraysize(t3value))) != BIG_OK) 23977c478bd9Sstevel@tonic-gate goto ret2; 23987c478bd9Sstevel@tonic-gate if ((err = big_init1(&prod, n->len + 1, 23997c478bd9Sstevel@tonic-gate prodvalue, arraysize(prodvalue))) != BIG_OK) 24007c478bd9Sstevel@tonic-gate goto ret3; 24017c478bd9Sstevel@tonic-gate 24027c478bd9Sstevel@tonic-gate nrootbits = (nbits + 1) / 2; 2403*b60f2a0bSfr41279 t1.len = t2.len = t3.len = (nrootbits - 1) / BIG_CHUNK_SIZE + 1; 24047c478bd9Sstevel@tonic-gate for (i = 0; i < t1.len; i++) { 24057c478bd9Sstevel@tonic-gate t1.value[i] = 0; 2406*b60f2a0bSfr41279 t2.value[i] = BIG_CHUNK_ALLBITS; 24077c478bd9Sstevel@tonic-gate } 2408*b60f2a0bSfr41279 highbits = nrootbits - BIG_CHUNK_SIZE * (t1.len - 1); 2409*b60f2a0bSfr41279 if (highbits == BIG_CHUNK_SIZE) { 2410*b60f2a0bSfr41279 t1.value[t1.len - 1] = BIG_CHUNK_HIGHBIT; 2411*b60f2a0bSfr41279 t2.value[t2.len - 1] = BIG_CHUNK_ALLBITS; 24127c478bd9Sstevel@tonic-gate } else { 2413*b60f2a0bSfr41279 t1.value[t1.len - 1] = (BIG_CHUNK_TYPE)1 << (highbits - 1); 24147c478bd9Sstevel@tonic-gate t2.value[t2.len - 1] = 2 * t1.value[t1.len - 1] - 1; 24157c478bd9Sstevel@tonic-gate } 2416*b60f2a0bSfr41279 24177c478bd9Sstevel@tonic-gate high = &t2; 24187c478bd9Sstevel@tonic-gate low = &t1; 24197c478bd9Sstevel@tonic-gate mid = &t3; 24207c478bd9Sstevel@tonic-gate 2421*b60f2a0bSfr41279 if ((err = big_mul(&prod, high, high)) != BIG_OK) { 24227c478bd9Sstevel@tonic-gate goto ret; 2423*b60f2a0bSfr41279 } 24247c478bd9Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 24257c478bd9Sstevel@tonic-gate if (diff <= 0) { 24267c478bd9Sstevel@tonic-gate err = big_copy(result, high); 24277c478bd9Sstevel@tonic-gate goto ret; 24287c478bd9Sstevel@tonic-gate } 24297c478bd9Sstevel@tonic-gate 24307c478bd9Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 2431*b60f2a0bSfr41279 while (big_cmp_abs(&big_One, mid) != 0) { 24327c478bd9Sstevel@tonic-gate (void) big_add_abs(mid, high, low); 24337c478bd9Sstevel@tonic-gate (void) big_half_pos(mid, mid); 24347c478bd9Sstevel@tonic-gate if ((err = big_mul(&prod, mid, mid)) != BIG_OK) 24357c478bd9Sstevel@tonic-gate goto ret; 24367c478bd9Sstevel@tonic-gate diff = big_cmp_abs(&prod, n); 24377c478bd9Sstevel@tonic-gate if (diff > 0) { 24387c478bd9Sstevel@tonic-gate t = high; 24397c478bd9Sstevel@tonic-gate high = mid; 24407c478bd9Sstevel@tonic-gate mid = t; 24417c478bd9Sstevel@tonic-gate } else if (diff < 0) { 24427c478bd9Sstevel@tonic-gate t = low; 24437c478bd9Sstevel@tonic-gate low = mid; 24447c478bd9Sstevel@tonic-gate mid = t; 24457c478bd9Sstevel@tonic-gate } else { 24467c478bd9Sstevel@tonic-gate err = big_copy(result, low); 24477c478bd9Sstevel@tonic-gate goto ret; 24487c478bd9Sstevel@tonic-gate } 24497c478bd9Sstevel@tonic-gate (void) big_sub_pos(mid, high, low); 24507c478bd9Sstevel@tonic-gate } 24517c478bd9Sstevel@tonic-gate 24527c478bd9Sstevel@tonic-gate err = big_copy(result, low); 24537c478bd9Sstevel@tonic-gate ret: 24547c478bd9Sstevel@tonic-gate if (prod.malloced) big_finish(&prod); 24557c478bd9Sstevel@tonic-gate ret3: 24567c478bd9Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 24577c478bd9Sstevel@tonic-gate ret2: 24587c478bd9Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 24597c478bd9Sstevel@tonic-gate ret1: 24607c478bd9Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 24617c478bd9Sstevel@tonic-gate 24627c478bd9Sstevel@tonic-gate return (err); 24637c478bd9Sstevel@tonic-gate } 24647c478bd9Sstevel@tonic-gate 24657c478bd9Sstevel@tonic-gate 24667c478bd9Sstevel@tonic-gate BIG_ERR_CODE 24677c478bd9Sstevel@tonic-gate big_Jacobi_pos(int *jac, BIGNUM *nn, BIGNUM *mm) 24687c478bd9Sstevel@tonic-gate { 24697c478bd9Sstevel@tonic-gate BIGNUM *t, *tmp2, *m, *n; 24707c478bd9Sstevel@tonic-gate BIGNUM t1, t2, t3; 2471*b60f2a0bSfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 2472*b60f2a0bSfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 2473*b60f2a0bSfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 24747c478bd9Sstevel@tonic-gate int len, err; 24757c478bd9Sstevel@tonic-gate 24767c478bd9Sstevel@tonic-gate if (big_is_zero(nn) || 24777c478bd9Sstevel@tonic-gate (((nn->value[0] & 1) | (mm->value[0] & 1)) == 0)) { 24787c478bd9Sstevel@tonic-gate *jac = 0; 24797c478bd9Sstevel@tonic-gate return (BIG_OK); 24807c478bd9Sstevel@tonic-gate } 24817c478bd9Sstevel@tonic-gate 2482*b60f2a0bSfr41279 if (nn->len > mm->len) { 2483*b60f2a0bSfr41279 len = nn->len; 2484*b60f2a0bSfr41279 } else { 2485*b60f2a0bSfr41279 len = mm->len; 2486*b60f2a0bSfr41279 } 24877c478bd9Sstevel@tonic-gate 24887c478bd9Sstevel@tonic-gate if ((err = big_init1(&t1, len, 2489*b60f2a0bSfr41279 t1value, arraysize(t1value))) != BIG_OK) { 24907c478bd9Sstevel@tonic-gate return (err); 2491*b60f2a0bSfr41279 } 24927c478bd9Sstevel@tonic-gate if ((err = big_init1(&t2, len, 2493*b60f2a0bSfr41279 t2value, arraysize(t2value))) != BIG_OK) { 24947c478bd9Sstevel@tonic-gate goto ret1; 2495*b60f2a0bSfr41279 } 24967c478bd9Sstevel@tonic-gate if ((err = big_init1(&t3, len, 2497*b60f2a0bSfr41279 t3value, arraysize(t3value))) != BIG_OK) { 24987c478bd9Sstevel@tonic-gate goto ret2; 2499*b60f2a0bSfr41279 } 25007c478bd9Sstevel@tonic-gate 25017c478bd9Sstevel@tonic-gate n = &t1; 25027c478bd9Sstevel@tonic-gate m = &t2; 25037c478bd9Sstevel@tonic-gate tmp2 = &t3; 25047c478bd9Sstevel@tonic-gate 25057c478bd9Sstevel@tonic-gate (void) big_copy(n, nn); 25067c478bd9Sstevel@tonic-gate (void) big_copy(m, mm); 25077c478bd9Sstevel@tonic-gate 25087c478bd9Sstevel@tonic-gate *jac = 1; 2509*b60f2a0bSfr41279 while (big_cmp_abs(&big_One, m) != 0) { 25107c478bd9Sstevel@tonic-gate if (big_is_zero(n)) { 25117c478bd9Sstevel@tonic-gate *jac = 0; 25127c478bd9Sstevel@tonic-gate goto ret; 25137c478bd9Sstevel@tonic-gate } 25147c478bd9Sstevel@tonic-gate if ((m->value[0] & 1) == 0) { 25157c478bd9Sstevel@tonic-gate if (((n->value[0] & 7) == 3) || 2516*b60f2a0bSfr41279 ((n->value[0] & 7) == 5)) 2517*b60f2a0bSfr41279 *jac = -*jac; 25187c478bd9Sstevel@tonic-gate (void) big_half_pos(m, m); 25197c478bd9Sstevel@tonic-gate } else if ((n->value[0] & 1) == 0) { 25207c478bd9Sstevel@tonic-gate if (((m->value[0] & 7) == 3) || 2521*b60f2a0bSfr41279 ((m->value[0] & 7) == 5)) 2522*b60f2a0bSfr41279 *jac = -*jac; 25237c478bd9Sstevel@tonic-gate (void) big_half_pos(n, n); 25247c478bd9Sstevel@tonic-gate } else { 25257c478bd9Sstevel@tonic-gate if (((m->value[0] & 3) == 3) && 25267c478bd9Sstevel@tonic-gate ((n->value[0] & 3) == 3)) { 25277c478bd9Sstevel@tonic-gate *jac = -*jac; 25287c478bd9Sstevel@tonic-gate } 2529*b60f2a0bSfr41279 if ((err = big_div_pos(NULL, tmp2, m, n)) != BIG_OK) { 25307c478bd9Sstevel@tonic-gate goto ret; 2531*b60f2a0bSfr41279 } 25327c478bd9Sstevel@tonic-gate t = tmp2; 25337c478bd9Sstevel@tonic-gate tmp2 = m; 25347c478bd9Sstevel@tonic-gate m = n; 25357c478bd9Sstevel@tonic-gate n = t; 25367c478bd9Sstevel@tonic-gate } 25377c478bd9Sstevel@tonic-gate } 25387c478bd9Sstevel@tonic-gate err = BIG_OK; 25397c478bd9Sstevel@tonic-gate 25407c478bd9Sstevel@tonic-gate ret: 25417c478bd9Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 25427c478bd9Sstevel@tonic-gate ret2: 25437c478bd9Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 25447c478bd9Sstevel@tonic-gate ret1: 25457c478bd9Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 25467c478bd9Sstevel@tonic-gate 25477c478bd9Sstevel@tonic-gate return (err); 25487c478bd9Sstevel@tonic-gate } 25497c478bd9Sstevel@tonic-gate 25507c478bd9Sstevel@tonic-gate 25517c478bd9Sstevel@tonic-gate BIG_ERR_CODE 25527c478bd9Sstevel@tonic-gate big_Lucas(BIGNUM *Lkminus1, BIGNUM *Lk, BIGNUM *p, BIGNUM *k, BIGNUM *n) 25537c478bd9Sstevel@tonic-gate { 25547c478bd9Sstevel@tonic-gate int m, w, i; 2555*b60f2a0bSfr41279 BIG_CHUNK_TYPE bit; 25567c478bd9Sstevel@tonic-gate BIGNUM ki, tmp, tmp2; 2557*b60f2a0bSfr41279 BIG_CHUNK_TYPE kivalue[BIGTMPSIZE]; 2558*b60f2a0bSfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 2559*b60f2a0bSfr41279 BIG_CHUNK_TYPE tmp2value[BIGTMPSIZE]; 25607c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 25617c478bd9Sstevel@tonic-gate 2562*b60f2a0bSfr41279 if (big_cmp_abs(k, &big_One) == 0) { 25637c478bd9Sstevel@tonic-gate (void) big_copy(Lk, p); 2564*b60f2a0bSfr41279 (void) big_copy(Lkminus1, &big_Two); 25657c478bd9Sstevel@tonic-gate return (BIG_OK); 25667c478bd9Sstevel@tonic-gate } 25677c478bd9Sstevel@tonic-gate 25687c478bd9Sstevel@tonic-gate if ((err = big_init1(&ki, k->len + 1, 25697c478bd9Sstevel@tonic-gate kivalue, arraysize(kivalue))) != BIG_OK) 25707c478bd9Sstevel@tonic-gate return (err); 25717c478bd9Sstevel@tonic-gate 25727c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * n->len +1, 25737c478bd9Sstevel@tonic-gate tmpvalue, arraysize(tmpvalue))) != BIG_OK) 25747c478bd9Sstevel@tonic-gate goto ret1; 25757c478bd9Sstevel@tonic-gate 25767c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp2, n->len, 25777c478bd9Sstevel@tonic-gate tmp2value, arraysize(tmp2value))) != BIG_OK) 25787c478bd9Sstevel@tonic-gate goto ret2; 25797c478bd9Sstevel@tonic-gate 25807c478bd9Sstevel@tonic-gate m = big_numbits(k); 2581*b60f2a0bSfr41279 ki.len = (m - 1) / BIG_CHUNK_SIZE + 1; 2582*b60f2a0bSfr41279 w = (m - 1) / BIG_CHUNK_SIZE; 2583*b60f2a0bSfr41279 bit = (BIG_CHUNK_TYPE)1 << ((m - 1) % BIG_CHUNK_SIZE); 2584*b60f2a0bSfr41279 for (i = 0; i < ki.len; i++) { 2585*b60f2a0bSfr41279 ki.value[i] = 0; 2586*b60f2a0bSfr41279 } 25877c478bd9Sstevel@tonic-gate ki.value[ki.len - 1] = bit; 2588*b60f2a0bSfr41279 if (big_cmp_abs(k, &ki) != 0) { 25897c478bd9Sstevel@tonic-gate (void) big_double(&ki, &ki); 2590*b60f2a0bSfr41279 } 25917c478bd9Sstevel@tonic-gate (void) big_sub_pos(&ki, &ki, k); 25927c478bd9Sstevel@tonic-gate 25937c478bd9Sstevel@tonic-gate (void) big_copy(Lk, p); 2594*b60f2a0bSfr41279 (void) big_copy(Lkminus1, &big_Two); 25957c478bd9Sstevel@tonic-gate 25967c478bd9Sstevel@tonic-gate for (i = 0; i < m; i++) { 2597*b60f2a0bSfr41279 if ((err = big_mul(&tmp, Lk, Lkminus1)) != BIG_OK) { 25987c478bd9Sstevel@tonic-gate goto ret; 2599*b60f2a0bSfr41279 } 26007c478bd9Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 26017c478bd9Sstevel@tonic-gate (void) big_sub_pos(&tmp, &tmp, p); 2602*b60f2a0bSfr41279 if ((err = big_div_pos(NULL, &tmp2, &tmp, n)) != BIG_OK) { 26037c478bd9Sstevel@tonic-gate goto ret; 2604*b60f2a0bSfr41279 } 26057c478bd9Sstevel@tonic-gate if ((ki.value[w] & bit) != 0) { 26067c478bd9Sstevel@tonic-gate if ((err = big_mul(&tmp, Lkminus1, Lkminus1)) != 2607*b60f2a0bSfr41279 BIG_OK) { 26087c478bd9Sstevel@tonic-gate goto ret; 2609*b60f2a0bSfr41279 } 26107c478bd9Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 2611*b60f2a0bSfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Two); 26127c478bd9Sstevel@tonic-gate if ((err = big_div_pos(NULL, Lkminus1, &tmp, n)) != 2613*b60f2a0bSfr41279 BIG_OK) { 26147c478bd9Sstevel@tonic-gate goto ret; 2615*b60f2a0bSfr41279 } 26167c478bd9Sstevel@tonic-gate (void) big_copy(Lk, &tmp2); 26177c478bd9Sstevel@tonic-gate } else { 2618*b60f2a0bSfr41279 if ((err = big_mul(&tmp, Lk, Lk)) != BIG_OK) { 26197c478bd9Sstevel@tonic-gate goto ret; 2620*b60f2a0bSfr41279 } 26217c478bd9Sstevel@tonic-gate (void) big_add_abs(&tmp, &tmp, n); 2622*b60f2a0bSfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Two); 2623*b60f2a0bSfr41279 if ((err = big_div_pos(NULL, Lk, &tmp, n)) != BIG_OK) { 26247c478bd9Sstevel@tonic-gate goto ret; 2625*b60f2a0bSfr41279 } 26267c478bd9Sstevel@tonic-gate (void) big_copy(Lkminus1, &tmp2); 26277c478bd9Sstevel@tonic-gate } 26287c478bd9Sstevel@tonic-gate bit = bit >> 1; 26297c478bd9Sstevel@tonic-gate if (bit == 0) { 2630*b60f2a0bSfr41279 bit = BIG_CHUNK_HIGHBIT; 26317c478bd9Sstevel@tonic-gate w--; 26327c478bd9Sstevel@tonic-gate } 26337c478bd9Sstevel@tonic-gate } 26347c478bd9Sstevel@tonic-gate 26357c478bd9Sstevel@tonic-gate err = BIG_OK; 26367c478bd9Sstevel@tonic-gate 26377c478bd9Sstevel@tonic-gate ret: 26387c478bd9Sstevel@tonic-gate if (tmp2.malloced) big_finish(&tmp2); 26397c478bd9Sstevel@tonic-gate ret2: 26407c478bd9Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 26417c478bd9Sstevel@tonic-gate ret1: 26427c478bd9Sstevel@tonic-gate if (ki.malloced) big_finish(&ki); 26437c478bd9Sstevel@tonic-gate 26447c478bd9Sstevel@tonic-gate return (err); 26457c478bd9Sstevel@tonic-gate } 26467c478bd9Sstevel@tonic-gate 26477c478bd9Sstevel@tonic-gate 26487c478bd9Sstevel@tonic-gate BIG_ERR_CODE 2649*b60f2a0bSfr41279 big_isprime_pos_ext(BIGNUM *n, big_modexp_ncp_info_t *info) 26507c478bd9Sstevel@tonic-gate { 26517c478bd9Sstevel@tonic-gate BIGNUM o, nminus1, tmp, Lkminus1, Lk; 2652*b60f2a0bSfr41279 BIG_CHUNK_TYPE ovalue[BIGTMPSIZE]; 2653*b60f2a0bSfr41279 BIG_CHUNK_TYPE nminus1value[BIGTMPSIZE]; 2654*b60f2a0bSfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 2655*b60f2a0bSfr41279 BIG_CHUNK_TYPE Lkminus1value[BIGTMPSIZE]; 2656*b60f2a0bSfr41279 BIG_CHUNK_TYPE Lkvalue[BIGTMPSIZE]; 26577c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 26587c478bd9Sstevel@tonic-gate int e, i, jac; 26597c478bd9Sstevel@tonic-gate 2660*b60f2a0bSfr41279 if (big_cmp_abs(n, &big_One) == 0) { 26617c478bd9Sstevel@tonic-gate return (BIG_FALSE); 2662*b60f2a0bSfr41279 } 2663*b60f2a0bSfr41279 if (big_cmp_abs(n, &big_Two) == 0) { 26647c478bd9Sstevel@tonic-gate return (BIG_TRUE); 2665*b60f2a0bSfr41279 } 2666*b60f2a0bSfr41279 if ((n->value[0] & 1) == 0) { 26677c478bd9Sstevel@tonic-gate return (BIG_FALSE); 2668*b60f2a0bSfr41279 } 26697c478bd9Sstevel@tonic-gate 2670*b60f2a0bSfr41279 if ((err = big_init1(&o, n->len, ovalue, arraysize(ovalue))) != 2671*b60f2a0bSfr41279 BIG_OK) { 26727c478bd9Sstevel@tonic-gate return (err); 2673*b60f2a0bSfr41279 } 26747c478bd9Sstevel@tonic-gate 26757c478bd9Sstevel@tonic-gate if ((err = big_init1(&nminus1, n->len, 2676*b60f2a0bSfr41279 nminus1value, arraysize(nminus1value))) != BIG_OK) { 26777c478bd9Sstevel@tonic-gate goto ret1; 2678*b60f2a0bSfr41279 } 26797c478bd9Sstevel@tonic-gate 26807c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * n->len, 2681*b60f2a0bSfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 26827c478bd9Sstevel@tonic-gate goto ret2; 2683*b60f2a0bSfr41279 } 26847c478bd9Sstevel@tonic-gate 26857c478bd9Sstevel@tonic-gate if ((err = big_init1(&Lkminus1, n->len, 2686*b60f2a0bSfr41279 Lkminus1value, arraysize(Lkminus1value))) != BIG_OK) { 26877c478bd9Sstevel@tonic-gate goto ret3; 2688*b60f2a0bSfr41279 } 26897c478bd9Sstevel@tonic-gate 26907c478bd9Sstevel@tonic-gate if ((err = big_init1(&Lk, n->len, 2691*b60f2a0bSfr41279 Lkvalue, arraysize(Lkvalue))) != BIG_OK) { 26927c478bd9Sstevel@tonic-gate goto ret4; 2693*b60f2a0bSfr41279 } 26947c478bd9Sstevel@tonic-gate 2695*b60f2a0bSfr41279 (void) big_sub_pos(&o, n, &big_One); /* cannot fail */ 26967c478bd9Sstevel@tonic-gate (void) big_copy(&nminus1, &o); /* cannot fail */ 26977c478bd9Sstevel@tonic-gate e = 0; 26987c478bd9Sstevel@tonic-gate while ((o.value[0] & 1) == 0) { 26997c478bd9Sstevel@tonic-gate e++; 27007c478bd9Sstevel@tonic-gate (void) big_half_pos(&o, &o); /* cannot fail */ 27017c478bd9Sstevel@tonic-gate } 2702*b60f2a0bSfr41279 if ((err = big_modexp_ext(&tmp, &big_Two, &o, n, NULL, info)) != 2703*b60f2a0bSfr41279 BIG_OK) { 27047c478bd9Sstevel@tonic-gate goto ret; 2705*b60f2a0bSfr41279 } 2706*b60f2a0bSfr41279 27077c478bd9Sstevel@tonic-gate i = 0; 27087c478bd9Sstevel@tonic-gate while ((i < e) && 2709*b60f2a0bSfr41279 (big_cmp_abs(&tmp, &big_One) != 0) && 27107c478bd9Sstevel@tonic-gate (big_cmp_abs(&tmp, &nminus1) != 0)) { 2711*b60f2a0bSfr41279 if ((err = 2712*b60f2a0bSfr41279 big_modexp_ext(&tmp, &tmp, &big_Two, n, NULL, info)) != 2713*b60f2a0bSfr41279 BIG_OK) 27147c478bd9Sstevel@tonic-gate goto ret; 27157c478bd9Sstevel@tonic-gate i++; 27167c478bd9Sstevel@tonic-gate } 2717*b60f2a0bSfr41279 27187c478bd9Sstevel@tonic-gate if (!((big_cmp_abs(&tmp, &nminus1) == 0) || 2719*b60f2a0bSfr41279 ((i == 0) && (big_cmp_abs(&tmp, &big_One) == 0)))) { 27207c478bd9Sstevel@tonic-gate err = BIG_FALSE; 27217c478bd9Sstevel@tonic-gate goto ret; 27227c478bd9Sstevel@tonic-gate } 27237c478bd9Sstevel@tonic-gate 2724*b60f2a0bSfr41279 if ((err = big_sqrt_pos(&tmp, n)) != BIG_OK) { 27257c478bd9Sstevel@tonic-gate goto ret; 2726*b60f2a0bSfr41279 } 2727*b60f2a0bSfr41279 2728*b60f2a0bSfr41279 if ((err = big_mul(&tmp, &tmp, &tmp)) != BIG_OK) { 27297c478bd9Sstevel@tonic-gate goto ret; 2730*b60f2a0bSfr41279 } 27317c478bd9Sstevel@tonic-gate if (big_cmp_abs(&tmp, n) == 0) { 27327c478bd9Sstevel@tonic-gate err = BIG_FALSE; 27337c478bd9Sstevel@tonic-gate goto ret; 27347c478bd9Sstevel@tonic-gate } 27357c478bd9Sstevel@tonic-gate 2736*b60f2a0bSfr41279 (void) big_copy(&o, &big_Two); 27377c478bd9Sstevel@tonic-gate do { 2738*b60f2a0bSfr41279 (void) big_add_abs(&o, &o, &big_One); 2739*b60f2a0bSfr41279 if ((err = big_mul(&tmp, &o, &o)) != BIG_OK) { 27407c478bd9Sstevel@tonic-gate goto ret; 2741*b60f2a0bSfr41279 } 2742*b60f2a0bSfr41279 (void) big_sub_pos(&tmp, &tmp, &big_Four); 2743*b60f2a0bSfr41279 if ((err = big_Jacobi_pos(&jac, &tmp, n)) != BIG_OK) { 27447c478bd9Sstevel@tonic-gate goto ret; 2745*b60f2a0bSfr41279 } 27467c478bd9Sstevel@tonic-gate } while (jac != -1); 27477c478bd9Sstevel@tonic-gate 2748*b60f2a0bSfr41279 (void) big_add_abs(&tmp, n, &big_One); 2749*b60f2a0bSfr41279 if ((err = big_Lucas(&Lkminus1, &Lk, &o, &tmp, n)) != BIG_OK) { 27507c478bd9Sstevel@tonic-gate goto ret; 2751*b60f2a0bSfr41279 } 2752*b60f2a0bSfr41279 2753*b60f2a0bSfr41279 if ((big_cmp_abs(&Lkminus1, &o) == 0) && 2754*b60f2a0bSfr41279 (big_cmp_abs(&Lk, &big_Two) == 0)) { 27557c478bd9Sstevel@tonic-gate err = BIG_TRUE; 2756*b60f2a0bSfr41279 } else { 2757*b60f2a0bSfr41279 err = BIG_FALSE; 2758*b60f2a0bSfr41279 } 27597c478bd9Sstevel@tonic-gate 27607c478bd9Sstevel@tonic-gate ret: 27617c478bd9Sstevel@tonic-gate if (Lk.malloced) big_finish(&Lk); 27627c478bd9Sstevel@tonic-gate ret4: 27637c478bd9Sstevel@tonic-gate if (Lkminus1.malloced) big_finish(&Lkminus1); 27647c478bd9Sstevel@tonic-gate ret3: 27657c478bd9Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 27667c478bd9Sstevel@tonic-gate ret2: 27677c478bd9Sstevel@tonic-gate if (nminus1.malloced) big_finish(&nminus1); 27687c478bd9Sstevel@tonic-gate ret1: 27697c478bd9Sstevel@tonic-gate if (o.malloced) big_finish(&o); 27707c478bd9Sstevel@tonic-gate 27717c478bd9Sstevel@tonic-gate return (err); 27727c478bd9Sstevel@tonic-gate } 27737c478bd9Sstevel@tonic-gate 27747c478bd9Sstevel@tonic-gate 2775*b60f2a0bSfr41279 BIG_ERR_CODE 2776*b60f2a0bSfr41279 big_isprime_pos(BIGNUM *n) 2777*b60f2a0bSfr41279 { 2778*b60f2a0bSfr41279 return (big_isprime_pos_ext(n, NULL)); 2779*b60f2a0bSfr41279 } 2780*b60f2a0bSfr41279 2781*b60f2a0bSfr41279 27827c478bd9Sstevel@tonic-gate #define SIEVESIZE 1000 27837c478bd9Sstevel@tonic-gate 27847c478bd9Sstevel@tonic-gate uint32_t smallprimes[] = 27857c478bd9Sstevel@tonic-gate { 27867c478bd9Sstevel@tonic-gate 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 27877c478bd9Sstevel@tonic-gate 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97 27887c478bd9Sstevel@tonic-gate }; 27897c478bd9Sstevel@tonic-gate 27907c478bd9Sstevel@tonic-gate 27917c478bd9Sstevel@tonic-gate BIG_ERR_CODE 2792*b60f2a0bSfr41279 big_nextprime_pos_ext(BIGNUM *result, BIGNUM *n, big_modexp_ncp_info_t *info) 27937c478bd9Sstevel@tonic-gate { 27947c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 27957c478bd9Sstevel@tonic-gate int sieve[SIEVESIZE]; 27967c478bd9Sstevel@tonic-gate int i; 27977c478bd9Sstevel@tonic-gate uint32_t off, p; 27987c478bd9Sstevel@tonic-gate 2799*b60f2a0bSfr41279 if ((err = big_copy(result, n)) != BIG_OK) { 28007c478bd9Sstevel@tonic-gate return (err); 2801*b60f2a0bSfr41279 } 28027c478bd9Sstevel@tonic-gate result->value[0] |= 1; 2803f56c1286Srobinson /* CONSTCOND */ 28047c478bd9Sstevel@tonic-gate while (1) { 28057c478bd9Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) sieve[i] = 0; 28067c478bd9Sstevel@tonic-gate for (i = 0; 2807*b60f2a0bSfr41279 i < sizeof (smallprimes) / sizeof (smallprimes[0]); i++) { 28087c478bd9Sstevel@tonic-gate p = smallprimes[i]; 2809*b60f2a0bSfr41279 off = big_modhalf_pos(result, p); 28107c478bd9Sstevel@tonic-gate off = p - off; 2811*b60f2a0bSfr41279 if ((off % 2) == 1) { 2812*b60f2a0bSfr41279 off = off + p; 2813*b60f2a0bSfr41279 } 28147c478bd9Sstevel@tonic-gate off = off / 2; 28157c478bd9Sstevel@tonic-gate while (off < SIEVESIZE) { 28167c478bd9Sstevel@tonic-gate sieve[off] = 1; 28177c478bd9Sstevel@tonic-gate off = off + p; 28187c478bd9Sstevel@tonic-gate } 28197c478bd9Sstevel@tonic-gate } 28207c478bd9Sstevel@tonic-gate 28217c478bd9Sstevel@tonic-gate for (i = 0; i < SIEVESIZE; i++) { 28227c478bd9Sstevel@tonic-gate if (sieve[i] == 0) { 2823*b60f2a0bSfr41279 err = big_isprime_pos_ext(result, info); 28247c478bd9Sstevel@tonic-gate if (err != BIG_FALSE) { 2825*b60f2a0bSfr41279 if (err != BIG_TRUE) { 28267c478bd9Sstevel@tonic-gate return (err); 2827*b60f2a0bSfr41279 } else { 2828*b60f2a0bSfr41279 goto out; 2829*b60f2a0bSfr41279 } 28307c478bd9Sstevel@tonic-gate } 28317c478bd9Sstevel@tonic-gate 28327c478bd9Sstevel@tonic-gate } 2833*b60f2a0bSfr41279 if ((err = big_add_abs(result, result, &big_Two)) != 2834*b60f2a0bSfr41279 BIG_OK) { 28357c478bd9Sstevel@tonic-gate return (err); 28367c478bd9Sstevel@tonic-gate } 28377c478bd9Sstevel@tonic-gate } 2838*b60f2a0bSfr41279 } 2839*b60f2a0bSfr41279 2840*b60f2a0bSfr41279 out: 2841*b60f2a0bSfr41279 return (BIG_OK); 2842*b60f2a0bSfr41279 } 2843*b60f2a0bSfr41279 2844*b60f2a0bSfr41279 2845*b60f2a0bSfr41279 BIG_ERR_CODE 2846*b60f2a0bSfr41279 big_nextprime_pos(BIGNUM *result, BIGNUM *n) 2847*b60f2a0bSfr41279 { 2848*b60f2a0bSfr41279 return (big_nextprime_pos_ext(result, n, NULL)); 28497c478bd9Sstevel@tonic-gate } 28507c478bd9Sstevel@tonic-gate 28517c478bd9Sstevel@tonic-gate 28527c478bd9Sstevel@tonic-gate BIG_ERR_CODE 28537c478bd9Sstevel@tonic-gate big_nextprime_pos_slow(BIGNUM *result, BIGNUM *n) 28547c478bd9Sstevel@tonic-gate { 28557c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 28567c478bd9Sstevel@tonic-gate 28577c478bd9Sstevel@tonic-gate 28587c478bd9Sstevel@tonic-gate if ((err = big_copy(result, n)) != BIG_OK) 28597c478bd9Sstevel@tonic-gate return (err); 28607c478bd9Sstevel@tonic-gate result->value[0] |= 1; 2861*b60f2a0bSfr41279 while ((err = big_isprime_pos_ext(result, NULL)) != BIG_TRUE) { 28627c478bd9Sstevel@tonic-gate if (err != BIG_FALSE) 28637c478bd9Sstevel@tonic-gate return (err); 2864*b60f2a0bSfr41279 if ((err = big_add_abs(result, result, &big_Two)) != BIG_OK) 28657c478bd9Sstevel@tonic-gate return (err); 28667c478bd9Sstevel@tonic-gate } 28677c478bd9Sstevel@tonic-gate return (BIG_OK); 28687c478bd9Sstevel@tonic-gate } 28697c478bd9Sstevel@tonic-gate 28707c478bd9Sstevel@tonic-gate 28717c478bd9Sstevel@tonic-gate /* 28727c478bd9Sstevel@tonic-gate * given m and e, computes the rest in the equation 28737c478bd9Sstevel@tonic-gate * gcd(m, e) = cm * m + ce * e 28747c478bd9Sstevel@tonic-gate */ 28757c478bd9Sstevel@tonic-gate BIG_ERR_CODE 28767c478bd9Sstevel@tonic-gate big_ext_gcd_pos(BIGNUM *gcd, BIGNUM *cm, BIGNUM *ce, BIGNUM *m, BIGNUM *e) 28777c478bd9Sstevel@tonic-gate { 2878*b60f2a0bSfr41279 BIGNUM *xi, *ri, *riminus1, *riminus2, *t; 2879*b60f2a0bSfr41279 BIGNUM *vmi, *vei, *vmiminus1, *veiminus1; 28807c478bd9Sstevel@tonic-gate BIGNUM t1, t2, t3, t4, t5, t6, t7, t8, tmp; 2881*b60f2a0bSfr41279 BIG_CHUNK_TYPE t1value[BIGTMPSIZE]; 2882*b60f2a0bSfr41279 BIG_CHUNK_TYPE t2value[BIGTMPSIZE]; 2883*b60f2a0bSfr41279 BIG_CHUNK_TYPE t3value[BIGTMPSIZE]; 2884*b60f2a0bSfr41279 BIG_CHUNK_TYPE t4value[BIGTMPSIZE]; 2885*b60f2a0bSfr41279 BIG_CHUNK_TYPE t5value[BIGTMPSIZE]; 2886*b60f2a0bSfr41279 BIG_CHUNK_TYPE t6value[BIGTMPSIZE]; 2887*b60f2a0bSfr41279 BIG_CHUNK_TYPE t7value[BIGTMPSIZE]; 2888*b60f2a0bSfr41279 BIG_CHUNK_TYPE t8value[BIGTMPSIZE]; 2889*b60f2a0bSfr41279 BIG_CHUNK_TYPE tmpvalue[BIGTMPSIZE]; 28907c478bd9Sstevel@tonic-gate BIG_ERR_CODE err; 28917c478bd9Sstevel@tonic-gate int len; 28927c478bd9Sstevel@tonic-gate 2893*b60f2a0bSfr41279 if (big_cmp_abs(m, e) >= 0) { 2894*b60f2a0bSfr41279 len = m->len; 2895*b60f2a0bSfr41279 } else { 2896*b60f2a0bSfr41279 len = e->len; 2897*b60f2a0bSfr41279 } 28987c478bd9Sstevel@tonic-gate 28997c478bd9Sstevel@tonic-gate if ((err = big_init1(&t1, len, 2900*b60f2a0bSfr41279 t1value, arraysize(t1value))) != BIG_OK) { 29017c478bd9Sstevel@tonic-gate return (err); 2902*b60f2a0bSfr41279 } 29037c478bd9Sstevel@tonic-gate if ((err = big_init1(&t2, len, 2904*b60f2a0bSfr41279 t2value, arraysize(t2value))) != BIG_OK) { 29057c478bd9Sstevel@tonic-gate goto ret1; 2906*b60f2a0bSfr41279 } 29077c478bd9Sstevel@tonic-gate if ((err = big_init1(&t3, len, 2908*b60f2a0bSfr41279 t3value, arraysize(t3value))) != BIG_OK) { 29097c478bd9Sstevel@tonic-gate goto ret2; 2910*b60f2a0bSfr41279 } 29117c478bd9Sstevel@tonic-gate if ((err = big_init1(&t4, len, 2912*b60f2a0bSfr41279 t4value, arraysize(t3value))) != BIG_OK) { 29137c478bd9Sstevel@tonic-gate goto ret3; 2914*b60f2a0bSfr41279 } 29157c478bd9Sstevel@tonic-gate if ((err = big_init1(&t5, len, 2916*b60f2a0bSfr41279 t5value, arraysize(t5value))) != BIG_OK) { 29177c478bd9Sstevel@tonic-gate goto ret4; 2918*b60f2a0bSfr41279 } 29197c478bd9Sstevel@tonic-gate if ((err = big_init1(&t6, len, 2920*b60f2a0bSfr41279 t6value, arraysize(t6value))) != BIG_OK) { 29217c478bd9Sstevel@tonic-gate goto ret5; 2922*b60f2a0bSfr41279 } 29237c478bd9Sstevel@tonic-gate if ((err = big_init1(&t7, len, 2924*b60f2a0bSfr41279 t7value, arraysize(t7value))) != BIG_OK) { 29257c478bd9Sstevel@tonic-gate goto ret6; 2926*b60f2a0bSfr41279 } 29277c478bd9Sstevel@tonic-gate if ((err = big_init1(&t8, len, 2928*b60f2a0bSfr41279 t8value, arraysize(t8value))) != BIG_OK) { 29297c478bd9Sstevel@tonic-gate goto ret7; 2930*b60f2a0bSfr41279 } 29317c478bd9Sstevel@tonic-gate 29327c478bd9Sstevel@tonic-gate if ((err = big_init1(&tmp, 2 * len, 2933*b60f2a0bSfr41279 tmpvalue, arraysize(tmpvalue))) != BIG_OK) { 29347c478bd9Sstevel@tonic-gate goto ret8; 2935*b60f2a0bSfr41279 } 29367c478bd9Sstevel@tonic-gate 29377c478bd9Sstevel@tonic-gate ri = &t1; 29387c478bd9Sstevel@tonic-gate ri->value[0] = 1; 29397c478bd9Sstevel@tonic-gate ri->len = 1; 29407c478bd9Sstevel@tonic-gate xi = &t2; 29417c478bd9Sstevel@tonic-gate riminus1 = &t3; 29427c478bd9Sstevel@tonic-gate riminus2 = &t4; 29437c478bd9Sstevel@tonic-gate vmi = &t5; 29447c478bd9Sstevel@tonic-gate vei = &t6; 29457c478bd9Sstevel@tonic-gate vmiminus1 = &t7; 29467c478bd9Sstevel@tonic-gate veiminus1 = &t8; 29477c478bd9Sstevel@tonic-gate 2948*b60f2a0bSfr41279 (void) big_copy(vmiminus1, &big_One); 2949*b60f2a0bSfr41279 (void) big_copy(vmi, &big_One); 2950*b60f2a0bSfr41279 (void) big_copy(veiminus1, &big_One); 2951*b60f2a0bSfr41279 (void) big_copy(xi, &big_One); 29527c478bd9Sstevel@tonic-gate vei->len = 1; 29537c478bd9Sstevel@tonic-gate vei->value[0] = 0; 29547c478bd9Sstevel@tonic-gate 29557c478bd9Sstevel@tonic-gate (void) big_copy(riminus1, m); 29567c478bd9Sstevel@tonic-gate (void) big_copy(ri, e); 29577c478bd9Sstevel@tonic-gate 29587c478bd9Sstevel@tonic-gate while (!big_is_zero(ri)) { 29597c478bd9Sstevel@tonic-gate t = riminus2; 29607c478bd9Sstevel@tonic-gate riminus2 = riminus1; 29617c478bd9Sstevel@tonic-gate riminus1 = ri; 29627c478bd9Sstevel@tonic-gate ri = t; 2963*b60f2a0bSfr41279 if ((err = big_mul(&tmp, vmi, xi)) != BIG_OK) { 29647c478bd9Sstevel@tonic-gate goto ret; 2965*b60f2a0bSfr41279 } 2966*b60f2a0bSfr41279 if ((err = big_sub(vmiminus1, vmiminus1, &tmp)) != BIG_OK) { 29677c478bd9Sstevel@tonic-gate goto ret; 2968*b60f2a0bSfr41279 } 29697c478bd9Sstevel@tonic-gate t = vmiminus1; 29707c478bd9Sstevel@tonic-gate vmiminus1 = vmi; 29717c478bd9Sstevel@tonic-gate vmi = t; 2972*b60f2a0bSfr41279 if ((err = big_mul(&tmp, vei, xi)) != BIG_OK) { 29737c478bd9Sstevel@tonic-gate goto ret; 2974*b60f2a0bSfr41279 } 2975*b60f2a0bSfr41279 if ((err = big_sub(veiminus1, veiminus1, &tmp)) != BIG_OK) { 29767c478bd9Sstevel@tonic-gate goto ret; 2977*b60f2a0bSfr41279 } 29787c478bd9Sstevel@tonic-gate t = veiminus1; 29797c478bd9Sstevel@tonic-gate veiminus1 = vei; 29807c478bd9Sstevel@tonic-gate vei = t; 2981*b60f2a0bSfr41279 if ((err = big_div_pos(xi, ri, riminus2, riminus1)) != 2982*b60f2a0bSfr41279 BIG_OK) { 29837c478bd9Sstevel@tonic-gate goto ret; 29847c478bd9Sstevel@tonic-gate } 2985*b60f2a0bSfr41279 } 2986*b60f2a0bSfr41279 if ((gcd != NULL) && ((err = big_copy(gcd, riminus1)) != BIG_OK)) { 29877c478bd9Sstevel@tonic-gate goto ret; 2988*b60f2a0bSfr41279 } 2989*b60f2a0bSfr41279 if ((cm != NULL) && ((err = big_copy(cm, vmi)) != BIG_OK)) { 29907c478bd9Sstevel@tonic-gate goto ret; 2991*b60f2a0bSfr41279 } 2992*b60f2a0bSfr41279 if (ce != NULL) { 29937c478bd9Sstevel@tonic-gate err = big_copy(ce, vei); 2994*b60f2a0bSfr41279 } 29957c478bd9Sstevel@tonic-gate ret: 29967c478bd9Sstevel@tonic-gate if (tmp.malloced) big_finish(&tmp); 29977c478bd9Sstevel@tonic-gate ret8: 29987c478bd9Sstevel@tonic-gate if (t8.malloced) big_finish(&t8); 29997c478bd9Sstevel@tonic-gate ret7: 30007c478bd9Sstevel@tonic-gate if (t7.malloced) big_finish(&t7); 30017c478bd9Sstevel@tonic-gate ret6: 30027c478bd9Sstevel@tonic-gate if (t6.malloced) big_finish(&t6); 30037c478bd9Sstevel@tonic-gate ret5: 30047c478bd9Sstevel@tonic-gate if (t5.malloced) big_finish(&t5); 30057c478bd9Sstevel@tonic-gate ret4: 30067c478bd9Sstevel@tonic-gate if (t4.malloced) big_finish(&t4); 30077c478bd9Sstevel@tonic-gate ret3: 30087c478bd9Sstevel@tonic-gate if (t3.malloced) big_finish(&t3); 30097c478bd9Sstevel@tonic-gate ret2: 30107c478bd9Sstevel@tonic-gate if (t2.malloced) big_finish(&t2); 30117c478bd9Sstevel@tonic-gate ret1: 30127c478bd9Sstevel@tonic-gate if (t1.malloced) big_finish(&t1); 30137c478bd9Sstevel@tonic-gate 30147c478bd9Sstevel@tonic-gate return (err); 30157c478bd9Sstevel@tonic-gate } 3016