1 /** 2 * Botan BigInt operations 3 * 4 * Copyright: 5 * (C) 1999-2010,2014 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 2006 Luca Piccarreta 8 * 9 * License: 10 * Botan is released under the Simplified BSD License (see LICENSE.md) 11 */ 12 module botan_math.mp_bigint; 13 14 import botan_math.mp_word; 15 16 /* 17 * The size of the word type, in bits 18 */ 19 const size_t MP_WORD_BITS = BOTAN_MP_WORD_BITS; 20 21 /** 22 * Two operand addition 23 * Params: 24 * x = the first operand (and output) 25 * x_size = size of x 26 * y = the second operand 27 * y_size = size of y (must be >= x_size) 28 */ 29 void bigint_add2(word* x, size_t x_size, in word* y, size_t y_size) 30 { 31 if (bigint_add2_nc(x, x_size, y, y_size)) 32 x[x_size] += 1; 33 } 34 35 /** 36 * Three operand addition 37 */ 38 void bigint_add3(word* z, in word* x, size_t x_size, 39 in word* y, size_t y_size) 40 { 41 z[(x_size > y_size ? x_size : y_size)] += bigint_add3_nc(z, x, x_size, y, y_size); 42 } 43 44 /** 45 * Two operand addition with carry out 46 */ 47 word bigint_add2_nc(word* x, size_t x_size, in word* y, size_t y_size) 48 { 49 word carry = 0; 50 51 assert(x_size >= y_size, "Expected sizes"); 52 53 const size_t blocks = y_size - (y_size % 8); 54 55 for (size_t i = 0; i != blocks; i += 8) 56 carry = word8_add2((x + i)[0 .. 8], (y + i)[0 .. 8], carry); 57 58 foreach (size_t i; blocks .. y_size) 59 x[i] = word_add(x[i], y[i], &carry); 60 61 foreach (size_t i; y_size .. x_size) 62 x[i] = word_add(x[i], 0, &carry); 63 64 return carry; 65 } 66 67 /** 68 * Three operand addition with carry out 69 */ 70 word bigint_add3_nc(word* z, in word* x, size_t x_size, in word* y, size_t y_size) 71 { 72 if (x_size < y_size) 73 { return bigint_add3_nc(z, y, y_size, x, x_size); } 74 75 word carry = 0; 76 77 const size_t blocks = y_size - (y_size % 8); 78 79 for (size_t i = 0; i != blocks; i += 8) 80 carry = word8_add3(*cast(word[8]*) (z + i), *cast(word[8]*) (x + i), *cast(word[8]*) (y + i), carry); 81 82 foreach (size_t i; blocks .. y_size) 83 z[i] = word_add(x[i], y[i], &carry); 84 85 foreach (size_t i; y_size .. x_size) 86 z[i] = word_add(x[i], 0, &carry); 87 88 return carry; 89 } 90 91 /** 92 * Two operand subtraction 93 */ 94 word bigint_sub2(word* x, size_t x_size, in word* y, size_t y_size) 95 { 96 word borrow = 0; 97 98 assert(x_size >= y_size, "Expected sizes"); 99 100 const size_t blocks = y_size - (y_size % 8); 101 102 for (size_t i = 0; i != blocks; i += 8) 103 borrow = word8_sub2(*cast(word[8]*) (x + i), *cast(word[8]*) (y + i), borrow); 104 105 foreach (size_t i; blocks .. y_size) 106 x[i] = word_sub(x[i], y[i], &borrow); 107 108 foreach (size_t i; y_size .. x_size) 109 x[i] = word_sub(x[i], 0, &borrow); 110 111 return borrow; 112 } 113 114 /** 115 * Two operand subtraction, x = y - x; assumes y >= x 116 */ 117 void bigint_sub2_rev(word* x, in word* y, size_t y_size) 118 { 119 word borrow = 0; 120 121 const size_t blocks = y_size - (y_size % 8); 122 123 for (size_t i = 0; i != blocks; i += 8) 124 borrow = word8_sub2_rev(*cast(word[8]*) (x + i), *cast(word[8]*) (y + i), borrow); 125 126 foreach (size_t i; blocks .. y_size) 127 x[i] = word_sub(y[i], x[i], &borrow); 128 129 assert(!borrow, "y must be greater than x"); 130 } 131 132 /** 133 * Three operand subtraction 134 */ 135 word bigint_sub3(word* z, in word* x, size_t x_size, in word* y, size_t y_size) 136 { 137 word borrow = 0; 138 139 assert(x_size >= y_size, "Expected sizes"); 140 141 const size_t blocks = y_size - (y_size % 8); 142 143 for (size_t i = 0; i != blocks; i += 8) 144 borrow = word8_sub3(*cast(word[8]*) (z + i), *cast(word[8]*) (x + i), *cast(word[8]*) (y + i), borrow); 145 146 foreach (size_t i; blocks .. y_size) 147 z[i] = word_sub(x[i], y[i], &borrow); 148 149 foreach (size_t i; y_size .. x_size) 150 z[i] = word_sub(x[i], 0, &borrow); 151 152 return borrow; 153 } 154 155 /* 156 * Shift Operations 157 */ 158 159 /* 160 * Single Operand Left Shift 161 */ 162 void bigint_shl1(word* x, size_t x_size, size_t word_shift, size_t bit_shift) 163 { 164 if (word_shift) 165 { 166 copyMem(x + word_shift, x, x_size); 167 clearMem(x, word_shift); 168 } 169 170 if (bit_shift) 171 { 172 word carry = 0; 173 foreach (size_t j; word_shift .. (x_size + word_shift + 1)) 174 { 175 word temp = x[j]; 176 x[j] = (temp << bit_shift) | carry; 177 carry = (temp >> (MP_WORD_BITS - bit_shift)); 178 } 179 } 180 } 181 182 /* 183 * Single Operand Right Shift 184 */ 185 void bigint_shr1(word* x, size_t x_size, size_t word_shift, size_t bit_shift) 186 { 187 if (x_size < word_shift) 188 { 189 clearMem(x, x_size); 190 return; 191 } 192 193 if (word_shift) 194 { 195 copyMem(x, x + word_shift, x_size - word_shift); 196 clearMem(x + x_size - word_shift, word_shift); 197 } 198 199 if (bit_shift) 200 { 201 word carry = 0; 202 203 size_t top = x_size - word_shift; 204 205 while (top >= 4) 206 { 207 word w = x[top-1]; 208 x[top-1] = (w >> bit_shift) | carry; 209 carry = (w << (MP_WORD_BITS - bit_shift)); 210 211 w = x[top-2]; 212 x[top-2] = (w >> bit_shift) | carry; 213 carry = (w << (MP_WORD_BITS - bit_shift)); 214 215 w = x[top-3]; 216 x[top-3] = (w >> bit_shift) | carry; 217 carry = (w << (MP_WORD_BITS - bit_shift)); 218 219 w = x[top-4]; 220 x[top-4] = (w >> bit_shift) | carry; 221 carry = (w << (MP_WORD_BITS - bit_shift)); 222 223 top -= 4; 224 } 225 226 while (top) 227 { 228 word w = x[top-1]; 229 x[top-1] = (w >> bit_shift) | carry; 230 carry = (w << (MP_WORD_BITS - bit_shift)); 231 232 top--; 233 } 234 } 235 } 236 237 /* 238 * Two Operand Left Shift 239 */ 240 void bigint_shl2(word* y, in word* x, size_t x_size, size_t word_shift, size_t bit_shift) 241 { 242 foreach (size_t j; 0 .. x_size) 243 y[j + word_shift] = x[j]; 244 if (bit_shift) 245 { 246 word carry = 0; 247 foreach (size_t j; word_shift .. (x_size + word_shift + 1)) 248 { 249 word w = y[j]; 250 y[j] = (w << bit_shift) | carry; 251 carry = (w >> (MP_WORD_BITS - bit_shift)); 252 } 253 } 254 } 255 256 /* 257 * Two Operand Right Shift 258 */ 259 void bigint_shr2(word* y, in word* x, size_t x_size, 260 size_t word_shift, size_t bit_shift) 261 { 262 if (x_size < word_shift) return; 263 264 foreach (size_t j; 0 .. (x_size - word_shift)) 265 y[j] = x[j + word_shift]; 266 if (bit_shift) 267 { 268 word carry = 0; 269 for (size_t j = x_size - word_shift; j > 0; --j) 270 { 271 word w = y[j-1]; 272 y[j-1] = (w >> bit_shift) | carry; 273 carry = (w << (MP_WORD_BITS - bit_shift)); 274 } 275 } 276 } 277 278 /* 279 * Simple O(N^2) Multiplication and Squaring 280 */ 281 void bigint_simple_mul(word* z, in word* x, size_t x_size, in word* y, size_t y_size) 282 { 283 const size_t x_size_8 = x_size - (x_size % 8); 284 285 clearMem(z, x_size + y_size); 286 287 foreach (size_t i; 0 .. y_size) 288 { 289 const word y_i = y[i]; 290 291 word carry = 0; 292 293 for (size_t j = 0; j != x_size_8; j += 8) 294 carry = word8_madd3(*cast(word[8]*) (z + i + j), *cast(word[8]*) (x + j), y_i, carry); 295 296 foreach (size_t j; x_size_8 .. x_size) 297 z[i+j] = word_madd3(x[j], y_i, z[i+j], &carry); 298 299 z[x_size+i] = carry; 300 } 301 } 302 303 /* 304 * Simple O(N^2) Squaring 305 * 306 * This is exactly the same algorithm as bigint_simple_mul, however 307 * because C/C++ compilers suck at alias analysis it is good to have 308 * the version where the compiler knows that x == y 309 * 310 * There is an O(n^1.5) squaring algorithm specified in Handbook of 311 * Applied Cryptography, chapter 14 312 * 313 */ 314 void bigint_simple_sqr(word* z, in word* x, size_t x_size) 315 { 316 const size_t x_size_8 = x_size - (x_size % 8); 317 318 clearMem(z, 2*x_size); 319 320 foreach (size_t i; 0 .. x_size) 321 { 322 const word x_i = x[i]; 323 word carry = 0; 324 325 for (size_t j = 0; j != x_size_8; j += 8) 326 carry = word8_madd3(*cast(word[8]*) (z + i + j), *cast(word[8]*) (x + j), x_i, carry); 327 328 foreach (size_t j; x_size_8 .. x_size) 329 z[i+j] = word_madd3(x[j], x_i, z[i+j], &carry); 330 331 z[x_size+i] = carry; 332 } 333 } 334 335 336 /* 337 * Linear Multiply 338 */ 339 /* 340 * Two Operand Linear Multiply 341 */ 342 void bigint_linmul2(word* x, size_t x_size, word y) 343 { 344 const size_t blocks = x_size - (x_size % 8); 345 346 word carry = 0; 347 348 for (size_t i = 0; i != blocks; i += 8) 349 carry = word8_linmul2(*cast(word[8]*) (x + i), y, carry); 350 351 foreach (size_t i; blocks .. x_size) { 352 x[i] = word_madd2(x[i], y, &carry); 353 } 354 x[x_size] = carry; 355 } 356 357 /* 358 * Three Operand Linear Multiply 359 */ 360 void bigint_linmul3(word* z, in word* x, size_t x_size, word y) 361 { 362 const size_t blocks = x_size - (x_size % 8); 363 364 word carry = 0; 365 366 for (size_t i = 0; i != blocks; i += 8) 367 carry = word8_linmul3(*cast(word[8]*) (z + i), *cast(word[8]*) (x + i), y, carry); 368 369 foreach (size_t i; blocks .. x_size) 370 z[i] = word_madd2(x[i], y, &carry); 371 372 z[x_size] = carry; 373 } 374 375 376 377 /** 378 * Compare x and y 379 */ 380 int bigint_cmp(in word* x, size_t x_size, 381 in word* y, size_t y_size) 382 { 383 if (x_size < y_size) { return (-bigint_cmp(y, y_size, x, x_size)); } 384 385 while (x_size > y_size) 386 { 387 if (x[x_size-1]) 388 return 1; 389 x_size--; 390 } 391 392 for (size_t i = x_size; i > 0; --i) 393 { 394 if (x[i-1] > y[i-1]) 395 return 1; 396 if (x[i-1] < y[i-1]) 397 return -1; 398 } 399 400 return 0; 401 } 402 403 /** 404 * Compute ((n1<<bits) + n0) / d 405 */ 406 word bigint_divop(word n1, word n0, word d) 407 { 408 word high = n1 % d, quotient = 0; 409 410 foreach (size_t i; 0 .. MP_WORD_BITS) 411 { 412 word high_top_bit = (high & MP_WORD_TOP_BIT); 413 414 high <<= 1; 415 high |= (n0 >> (MP_WORD_BITS-1-i)) & 1; 416 quotient <<= 1; 417 418 if (high_top_bit || high >= d) 419 { 420 high -= d; 421 quotient |= 1; 422 } 423 } 424 425 return quotient; 426 } 427 428 /** 429 * Compute ((n1<<bits) + n0) % d 430 */ 431 word bigint_modop(word n1, word n0, word d) 432 { 433 word z = bigint_divop(n1, n0, d); 434 word dummy = 0; 435 z = word_madd2(z, d, &dummy); 436 return (n0-z); 437 }