1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This file contains bignum implementation code that 31 * is specific to AMD64, but which is still more appropriate 32 * to write in C, rather than assembly language. 33 * bignum_amd64_asm.s does all the assembly language code 34 * for AMD64 specific bignum support. The assembly language 35 * source file has pure code, no data. Let the C compiler 36 * generate what is needed to handle the variations in 37 * data representation and addressing, for example, 38 * statically linked vs PIC. 39 */ 40 41 #include "bignum.h" 42 43 /* 44 * The bignum interface deals only with arrays of 32-bit "digits". 45 * The 64-bit bignum functions are internal implementation details. 46 * If a bignum happens to be aligned on a 64-bit boundary 47 * and its length is even, then the pure 64-bit implementation 48 * can be used. 49 */ 50 51 #define ISALIGNED64(p) (((uintptr_t)(p) & 7) == 0) 52 #define ISBIGNUM64(p, len) (ISALIGNED64(p) && (((len) & 1) == 0)) 53 54 #if defined(__lint) 55 56 extern uint64_t *P64(uint32_t *addr); 57 58 #else /* lint */ 59 60 #define P64(addr) ((uint64_t *)addr) 61 62 #endif /* lint */ 63 64 extern uint64_t big_mul_set_vec64(uint64_t *, uint64_t *, int, uint64_t); 65 extern uint64_t big_mul_add_vec64(uint64_t *, uint64_t *, int, uint64_t); 66 extern void big_mul_vec64(uint64_t *, uint64_t *, int, uint64_t *, int); 67 extern void big_sqr_vec64(uint64_t *, uint64_t *, int); 68 69 extern uint32_t big_mul_set_vec32(uint32_t *, uint32_t *, int, uint32_t); 70 extern uint32_t big_mul_add_vec32(uint32_t *, uint32_t *, int, uint32_t); 71 extern void big_mul_vec32(uint32_t *, uint32_t *, int, uint32_t *, int); 72 extern void big_sqr_vec32(uint32_t *, uint32_t *, int); 73 74 uint32_t big_mul_set_vec(uint32_t *, uint32_t *, int, uint32_t); 75 uint32_t big_mul_add_vec(uint32_t *, uint32_t *, int, uint32_t); 76 void big_mul_vec(uint32_t *, uint32_t *, int, uint32_t *, int); 77 void big_sqr_vec(uint32_t *, uint32_t *, int); 78 79 80 void 81 big_mul_vec(uint32_t *r, uint32_t *a, int alen, uint32_t *b, int blen) 82 { 83 if (!ISALIGNED64(r) || !ISBIGNUM64(a, alen) || !ISBIGNUM64(b, blen)) { 84 big_mul_vec32(r, a, alen, b, blen); 85 return; 86 } 87 88 big_mul_vec64(P64(r), P64(a), alen / 2, P64(b), blen / 2); 89 } 90 91 void 92 big_sqr_vec(uint32_t *r, uint32_t *a, int alen) 93 { 94 if (!ISALIGNED64(r) || !ISBIGNUM64(a, alen)) { 95 big_mul_vec32(r, a, alen, a, alen); 96 return; 97 } 98 big_sqr_vec64(P64(r), P64(a), alen / 2); 99 } 100 101 /* 102 * It is OK to cast the 64-bit carry to 32 bit. 103 * There will be no loss, because although we are multiplying the vector, a, 104 * by a uint64_t, its value cannot exceedthat of a uint32_t. 105 */ 106 107 uint32_t 108 big_mul_set_vec(uint32_t *r, uint32_t *a, int alen, uint32_t digit) 109 { 110 if (!ISALIGNED64(r) || !ISBIGNUM64(a, alen)) 111 return (big_mul_set_vec32(r, a, alen, digit)); 112 113 return (big_mul_set_vec64(P64(r), P64(a), alen / 2, digit)); 114 } 115 uint32_t 116 big_mul_add_vec(uint32_t *r, uint32_t *a, int alen, uint32_t digit) 117 { 118 if (!ISALIGNED64(r) || !ISBIGNUM64(a, alen)) 119 return (big_mul_add_vec32(r, a, alen, digit)); 120 121 return (big_mul_add_vec64(P64(r), P64(a), alen / 2, digit)); 122 } 123 124 125 void 126 big_mul_vec64(uint64_t *r, uint64_t *a, int alen, uint64_t *b, int blen) 127 { 128 int i; 129 130 r[alen] = big_mul_set_vec64(r, a, alen, b[0]); 131 for (i = 1; i < blen; ++i) 132 r[alen + i] = big_mul_add_vec64(r+i, a, alen, b[i]); 133 } 134 135 void 136 big_mul_vec32(uint32_t *r, uint32_t *a, int alen, uint32_t *b, int blen) 137 { 138 int i; 139 140 r[alen] = big_mul_set_vec32(r, a, alen, b[0]); 141 for (i = 1; i < blen; ++i) 142 r[alen + i] = big_mul_add_vec32(r+i, a, alen, b[i]); 143 } 144 145 void 146 big_sqr_vec32(uint32_t *r, uint32_t *a, int alen) 147 { 148 big_mul_vec32(r, a, alen, a, alen); 149 } 150 151 152 uint32_t 153 big_mul_set_vec32(uint32_t *r, uint32_t *a, int alen, uint32_t digit) 154 { 155 uint64_t p, d, cy; 156 157 d = (uint64_t)digit; 158 cy = 0; 159 while (alen != 0) { 160 p = (uint64_t)a[0] * d + cy; 161 r[0] = (uint32_t)p; 162 cy = p >> 32; 163 ++r; 164 ++a; 165 --alen; 166 } 167 return ((uint32_t)cy); 168 } 169 170 uint32_t 171 big_mul_add_vec32(uint32_t *r, uint32_t *a, int alen, uint32_t digit) 172 { 173 uint64_t p, d, cy; 174 175 d = (uint64_t)digit; 176 cy = 0; 177 while (alen != 0) { 178 p = r[0] + (uint64_t)a[0] * d + cy; 179 r[0] = (uint32_t)p; 180 cy = p >> 32; 181 ++r; 182 ++a; 183 --alen; 184 } 185 return ((uint32_t)cy); 186 } 187