1 /* 2 * Copyright (C) 2017 - This file is part of libecc project 3 * 4 * Authors: 5 * Ryad BENADJILA <ryadbenadjila@gmail.com> 6 * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr> 7 * Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr> 8 * 9 * Contributors: 10 * Nicolas VIVET <nicolas.vivet@ssi.gouv.fr> 11 * Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr> 12 * 13 * This software is licensed under a dual BSD and GPL v2 license. 14 * See LICENSE file at the root folder of the project. 15 */ 16 #include <libecc/nn/nn_mul_public.h> 17 #include <libecc/nn/nn_logical.h> 18 #include <libecc/nn/nn_add.h> 19 #include <libecc/nn/nn.h> 20 /* Use internal API header */ 21 #include "nn_div.h" 22 23 /* 24 * Some helper functions to perform operations on an arbitrary part 25 * of a multiprecision number. 26 * This is exactly the same code as for operations on the least significant 27 * part of a multiprecision number except for the starting point in the 28 * array representing it. 29 * Done in *constant time*. 30 * 31 * Operations producing an output are in place. 32 */ 33 34 /* 35 * Compare all the bits of in2 with the same number of bits in in1 starting at 36 * 'shift' position in in1. in1 must be long enough for that purpose, i.e. 37 * in1->wlen >= (in2->wlen + shift). The comparison value is provided in 38 * 'cmp' parameter. The function returns 0 on success, -1 on error. 39 * 40 * The function is an internal helper; it expects initialized nn in1 and 41 * in2: it does not verify that. 42 */ 43 ATTRIBUTE_WARN_UNUSED_RET static int _nn_cmp_shift(nn_src_t in1, nn_src_t in2, u8 shift, int *cmp) 44 { 45 int ret, mask, tmp; 46 u8 i; 47 48 MUST_HAVE((in1->wlen >= (in2->wlen + shift)), ret, err); 49 MUST_HAVE((cmp != NULL), ret, err); 50 51 tmp = 0; 52 for (i = in2->wlen; i > 0; i--) { 53 mask = (!(tmp & 0x1)); 54 tmp += ((in1->val[shift + i - 1] > in2->val[i - 1]) & mask); 55 tmp -= ((in1->val[shift + i - 1] < in2->val[i - 1]) & mask); 56 } 57 (*cmp) = tmp; 58 ret = 0; 59 60 err: 61 return ret; 62 } 63 64 /* 65 * Conditionally subtract a shifted version of in from out, i.e.: 66 * - if cnd == 1, out <- out - (in << shift) 67 * - if cnd == 0, out <- out 68 * The function returns 0 on success, -1 on error. On success, 'borrow' 69 * provides the possible borrow resulting from the subtraction. 'borrow' 70 * is not meaningful on error. 71 * 72 * The function is an internal helper; it expects initialized nn out and 73 * in: it does not verify that. 74 */ 75 ATTRIBUTE_WARN_UNUSED_RET static int _nn_cnd_sub_shift(int cnd, nn_t out, nn_src_t in, 76 u8 shift, word_t *borrow) 77 { 78 word_t tmp, borrow1, borrow2, _borrow = WORD(0); 79 word_t mask = WORD_MASK_IFNOTZERO(cnd); 80 int ret; 81 u8 i; 82 83 MUST_HAVE((out->wlen >= (in->wlen + shift)), ret, err); 84 MUST_HAVE((borrow != NULL), ret, err); 85 86 /* 87 * Perform subtraction one word at a time, 88 * propagating the borrow. 89 */ 90 for (i = 0; i < in->wlen; i++) { 91 tmp = (word_t)(out->val[shift + i] - (in->val[i] & mask)); 92 borrow1 = (word_t)(tmp > out->val[shift + i]); 93 out->val[shift + i] = (word_t)(tmp - _borrow); 94 borrow2 = (word_t)(out->val[shift + i] > tmp); 95 /* There is at most one borrow going out. */ 96 _borrow = (word_t)(borrow1 | borrow2); 97 } 98 99 (*borrow) = _borrow; 100 ret = 0; 101 102 err: 103 return ret; 104 } 105 106 /* 107 * Subtract a shifted version of 'in' multiplied by 'w' from 'out' and return 108 * borrow. The function returns 0 on success, -1 on error. 'borrow' is 109 * meaningful only on success. 110 * 111 * The function is an internal helper; it expects initialized nn out and 112 * in: it does not verify that. 113 */ 114 ATTRIBUTE_WARN_UNUSED_RET static int _nn_submul_word_shift(nn_t out, nn_src_t in, word_t w, u8 shift, 115 word_t *borrow) 116 { 117 word_t _borrow = WORD(0), prod_high, prod_low, tmp; 118 int ret; 119 u8 i; 120 121 MUST_HAVE((out->wlen >= (in->wlen + shift)), ret, err); 122 MUST_HAVE((borrow != NULL), ret, err); 123 124 for (i = 0; i < in->wlen; i++) { 125 /* 126 * Compute the result of the multiplication of 127 * two words. 128 */ 129 WORD_MUL(prod_high, prod_low, in->val[i], w); 130 131 /* 132 * And add previous borrow. 133 */ 134 prod_low = (word_t)(prod_low + _borrow); 135 prod_high = (word_t)(prod_high + (prod_low < _borrow)); 136 137 /* 138 * Subtract computed word at current position in result. 139 */ 140 tmp = (word_t)(out->val[shift + i] - prod_low); 141 _borrow = (word_t)(prod_high + (tmp > out->val[shift + i])); 142 out->val[shift + i] = tmp; 143 } 144 145 (*borrow) = _borrow; 146 ret = 0; 147 148 err: 149 return ret; 150 } 151 152 /* 153 * Compute quotient 'q' and remainder 'r' of Euclidean division of 'a' by 'b' 154 * (i.e. q and r such that a = b*q + r). 'q' and 'r' are not normalized on 155 * return. * Computation are performed in *constant time*, only depending on 156 * the lengths of 'a' and 'b', but not on the values of 'a' and 'b'. 157 * 158 * This uses the above function to perform arithmetic on arbitrary parts 159 * of multiprecision numbers. 160 * 161 * The algorithm used is schoolbook division: 162 * + the quotient is computed word by word, 163 * + a small division of the MSW is performed to obtain an 164 * approximation of the MSW of the quotient, 165 * + the approximation is corrected to obtain the correct 166 * multiprecision MSW of the quotient, 167 * + the corresponding product is subtracted from the dividend, 168 * + the same procedure is used for the following word of the quotient. 169 * 170 * It is assumed that: 171 * + b is normalized: the MSB of its MSW is 1, 172 * + the most significant part of a is smaller than b, 173 * + a precomputed reciprocal 174 * v = floor(B^3/(d+1)) - B 175 * where d is the MSW of the (normalized) divisor 176 * is given to perform the small 3-by-2 division. 177 * + using this reciprocal, the approximated quotient is always 178 * too small and at most one multiprecision correction is needed. 179 * 180 * It returns 0 on sucess, -1 on error. 181 * 182 * CAUTION: 183 * 184 * - The function is expected to be used ONLY by the generic version 185 * nn_divrem_normalized() defined later in the file. 186 * - All parameters must have been initialized. Unlike exported/public 187 * functions, this internal helper does not verify that nn parameters 188 * have been initialized. Again, this is expected from the caller 189 * (nn_divrem_normalized()). 190 * - The function does not support aliasing of 'b' or 'q'. See 191 * _nn_divrem_normalized_aliased() for such a wrapper. 192 * 193 */ 194 ATTRIBUTE_WARN_UNUSED_RET static int _nn_divrem_normalized(nn_t q, nn_t r, 195 nn_src_t a, nn_src_t b, word_t v) 196 { 197 word_t borrow, qstar, qh, ql, rh, rl; /* for 3-by-2 div. */ 198 int _small, cmp, ret; 199 u8 i; 200 201 MUST_HAVE(!(b->wlen <= 0), ret, err); 202 MUST_HAVE(!(a->wlen <= b->wlen), ret, err); 203 MUST_HAVE(!(!((b->val[b->wlen - 1] >> (WORD_BITS - 1)) == WORD(1))), ret, err); 204 MUST_HAVE(!_nn_cmp_shift(a, b, (u8)(a->wlen - b->wlen), &cmp) && (cmp < 0), ret, err); 205 206 /* Handle trivial aliasing for a and r */ 207 if (r != a) { 208 ret = nn_set_wlen(r, a->wlen); EG(ret, err); 209 ret = nn_copy(r, a); EG(ret, err); 210 } 211 212 ret = nn_set_wlen(q, (u8)(r->wlen - b->wlen)); EG(ret, err); 213 214 /* 215 * Compute subsequent words of the quotient one by one. 216 * Perform approximate 3-by-2 division using the precomputed 217 * reciprocal and correct afterward. 218 */ 219 for (i = r->wlen; i > b->wlen; i--) { 220 u8 shift = (u8)(i - b->wlen - 1); 221 222 /* 223 * Perform 3-by-2 approximate division: 224 * <qstar, qh, ql> = <rh, rl> * (v + B) 225 * We are only interested in qstar. 226 */ 227 rh = r->val[i - 1]; 228 rl = r->val[i - 2]; 229 /* Perform 2-by-1 multiplication. */ 230 WORD_MUL(qh, ql, rl, v); 231 WORD_MUL(qstar, ql, rh, v); 232 /* And propagate carries. */ 233 qh = (word_t)(qh + ql); 234 qstar = (word_t)(qstar + (qh < ql)); 235 qh = (word_t)(qh + rl); 236 rh = (word_t)(rh + (qh < rl)); 237 qstar = (word_t)(qstar + rh); 238 239 /* 240 * Compute approximate quotient times divisor 241 * and subtract it from remainder: 242 * r = r - (b*qstar << B^shift) 243 */ 244 ret = _nn_submul_word_shift(r, b, qstar, shift, &borrow); EG(ret, err); 245 246 /* Check the approximate quotient was indeed not too large. */ 247 MUST_HAVE(!(r->val[i - 1] < borrow), ret, err); 248 r->val[i - 1] = (word_t)(r->val[i - 1] - borrow); 249 250 /* 251 * Check whether the approximate quotient was too small or not. 252 * At most one multiprecision correction is needed. 253 */ 254 ret = _nn_cmp_shift(r, b, shift, &cmp); EG(ret, err); 255 _small = ((!!(r->val[i - 1])) | (cmp >= 0)); 256 /* Perform conditional multiprecision correction. */ 257 ret = _nn_cnd_sub_shift(_small, r, b, shift, &borrow); EG(ret, err); 258 MUST_HAVE(!(r->val[i - 1] != borrow), ret, err); 259 r->val[i - 1] = (word_t)(r->val[i - 1] - borrow); 260 /* 261 * Adjust the quotient if it was too small and set it in the 262 * multiprecision array. 263 */ 264 qstar = (word_t)(qstar + (word_t)_small); 265 q->val[shift] = qstar; 266 /* 267 * Check that the MSW of remainder was cancelled out and that 268 * we could not increase the quotient anymore. 269 */ 270 MUST_HAVE(!(r->val[r->wlen - 1] != WORD(0)), ret, err); 271 272 ret = _nn_cmp_shift(r, b, shift, &cmp); EG(ret, err); 273 MUST_HAVE(!(cmp >= 0), ret, err); 274 275 ret = nn_set_wlen(r, (u8)(r->wlen - 1)); EG(ret, err); 276 } 277 278 err: 279 return ret; 280 } 281 282 /* 283 * Compute quotient 'q' and remainder 'r' of Euclidean division of 'a' by 'b' 284 * (i.e. q and r such that a = b*q + r). 'q' and 'r' are not normalized. 285 * Compared to _nn_divrem_normalized(), this internal version 286 * explicitly handle the case where 'b' and 'r' point to the same nn (i.e. 'r' 287 * result is stored in 'b' on success), hence the removal of 'r' parameter from 288 * function prototype compared to _nn_divrem_normalized(). 289 * 290 * The computation is performed in *constant time*, see documentation of 291 * _nn_divrem_normalized(). 292 * 293 * Assume that 'b' is normalized (the MSB of its MSW is set), that 'v' is the 294 * reciprocal of the MSW of 'b' and that the high part of 'a' is smaller than 295 * 'b'. 296 * 297 * The function returns 0 on success, -1 on error. 298 * 299 * CAUTION: 300 * 301 * - The function is expected to be used ONLY by the generic version 302 * nn_divrem_normalized() defined later in the file. 303 * - All parameters must have been initialized. Unlike exported/public 304 * functions, this internal helper does not verify that nn parameters 305 * have been initialized. Again, this is expected from the caller 306 * (nn_divrem_normalized()). 307 * - The function does not support aliasing of 'a' or 'q'. 308 * 309 */ 310 ATTRIBUTE_WARN_UNUSED_RET static int _nn_divrem_normalized_aliased(nn_t q, nn_src_t a, nn_t b, word_t v) 311 { 312 int ret; 313 nn r; 314 r.magic = WORD(0); 315 316 ret = nn_init(&r, 0); EG(ret, err); 317 ret = _nn_divrem_normalized(q, &r, a, b, v); EG(ret, err); 318 ret = nn_copy(b, &r); EG(ret, err); 319 320 err: 321 nn_uninit(&r); 322 return ret; 323 } 324 325 /* 326 * Compute quotient and remainder of Euclidean division, and do not normalize 327 * them. Done in *constant time*, see documentation of _nn_divrem_normalized(). 328 * 329 * Assume that 'b' is normalized (the MSB of its MSW is set), that 'v' is the 330 * reciprocal of the MSW of 'b' and that the high part of 'a' is smaller than 331 * 'b'. 332 * 333 * Aliasing is supported for 'r' only (with 'b'), i.e. 'r' and 'b' can point 334 * to the same nn. 335 * 336 * The function returns 0 on success, -1 on error. 337 */ 338 int nn_divrem_normalized(nn_t q, nn_t r, nn_src_t a, nn_src_t b, word_t v) 339 { 340 int ret; 341 342 ret = nn_check_initialized(a); EG(ret, err); 343 ret = nn_check_initialized(q); EG(ret, err); 344 ret = nn_check_initialized(r); EG(ret, err); 345 346 /* Unsupported aliasings */ 347 MUST_HAVE((q != r) && (q != a) && (q != b), ret, err); 348 349 if (r == b) { 350 ret = _nn_divrem_normalized_aliased(q, a, r, v); 351 } else { 352 ret = nn_check_initialized(b); EG(ret, err); 353 ret = _nn_divrem_normalized(q, r, a, b, v); 354 } 355 356 err: 357 return ret; 358 } 359 360 /* 361 * Compute remainder only and do not normalize it. 362 * Constant time, see documentation of _nn_divrem_normalized. 363 * 364 * Support aliasing of inputs and outputs. 365 * 366 * The function returns 0 on success, -1 on error. 367 */ 368 int nn_mod_normalized(nn_t r, nn_src_t a, nn_src_t b, word_t v) 369 { 370 int ret; 371 nn q; 372 q.magic = WORD(0); 373 374 ret = nn_init(&q, 0); EG(ret, err); 375 ret = nn_divrem_normalized(&q, r, a, b, v); 376 377 err: 378 nn_uninit(&q); 379 return ret; 380 } 381 382 /* 383 * Compute quotient and remainder of Euclidean division, 384 * and do not normalize them. 385 * Done in *constant time*, 386 * only depending on the lengths of 'a' and 'b' and the value of 'cnt', 387 * but not on the values of 'a' and 'b'. 388 * 389 * Assume that b has been normalized by a 'cnt' bit shift, 390 * that v is the reciprocal of the MSW of 'b', 391 * but a is not shifted yet. 392 * Useful when multiple multiplication by the same b are performed, 393 * e.g. at the fp level. 394 * 395 * All outputs MUST have been initialized. The function does not support 396 * aliasing of 'b' or 'q'. It returns 0 on success, -1 on error. 397 * 398 * CAUTION: 399 * 400 * - The function is expected to be used ONLY by the generic version 401 * nn_divrem_normalized() defined later in the file. 402 * - All parameters must have been initialized. Unlike exported/public 403 * functions, this internal helper does not verify that 404 * have been initialized. Again, this is expected from the caller 405 * (nn_divrem_unshifted()). 406 * - The function does not support aliasing. See 407 * _nn_divrem_unshifted_aliased() for such a wrapper. 408 */ 409 ATTRIBUTE_WARN_UNUSED_RET static int _nn_divrem_unshifted(nn_t q, nn_t r, nn_src_t a, nn_src_t b_norm, 410 word_t v, bitcnt_t cnt) 411 { 412 nn a_shift; 413 u8 new_wlen, b_wlen; 414 int larger, ret, cmp; 415 word_t borrow; 416 a_shift.magic = WORD(0); 417 418 /* Avoid overflow */ 419 MUST_HAVE(((a->wlen + BIT_LEN_WORDS(cnt)) < NN_MAX_WORD_LEN), ret, err); 420 421 /* We now know that new_wlen will fit in an u8 */ 422 new_wlen = (u8)(a->wlen + (u8)BIT_LEN_WORDS(cnt)); 423 424 b_wlen = b_norm->wlen; 425 if (new_wlen < b_wlen) { /* trivial case */ 426 ret = nn_copy(r, a); EG(ret, err); 427 ret = nn_zero(q); 428 goto err; 429 } 430 431 /* Shift a. */ 432 ret = nn_init(&a_shift, (u16)(new_wlen * WORD_BYTES)); EG(ret, err); 433 ret = nn_set_wlen(&a_shift, new_wlen); EG(ret, err); 434 ret = nn_lshift_fixedlen(&a_shift, a, cnt); EG(ret, err); 435 ret = nn_set_wlen(r, new_wlen); EG(ret, err); 436 437 if (new_wlen == b_wlen) { 438 /* Ensure that a is smaller than b. */ 439 ret = nn_cmp(&a_shift, b_norm, &cmp); EG(ret, err); 440 larger = (cmp >= 0); 441 ret = nn_cnd_sub(larger, r, &a_shift, b_norm); EG(ret, err); 442 MUST_HAVE(((!nn_cmp(r, b_norm, &cmp)) && (cmp < 0)), ret, err); 443 444 /* Set MSW of quotient. */ 445 ret = nn_set_wlen(q, (u8)(new_wlen - b_wlen + 1)); EG(ret, err); 446 q->val[new_wlen - b_wlen] = (word_t) larger; 447 /* And we are done as the quotient is 0 or 1. */ 448 } else if (new_wlen > b_wlen) { 449 /* Ensure that most significant part of a is smaller than b. */ 450 ret = _nn_cmp_shift(&a_shift, b_norm, (u8)(new_wlen - b_wlen), &cmp); EG(ret, err); 451 larger = (cmp >= 0); 452 ret = _nn_cnd_sub_shift(larger, &a_shift, b_norm, (u8)(new_wlen - b_wlen), &borrow); EG(ret, err); 453 MUST_HAVE(((!_nn_cmp_shift(&a_shift, b_norm, (u8)(new_wlen - b_wlen), &cmp)) && (cmp < 0)), ret, err); 454 455 /* 456 * Perform division with MSP of a smaller than b. This ensures 457 * that the quotient is of length a_len - b_len. 458 */ 459 ret = nn_divrem_normalized(q, r, &a_shift, b_norm, v); EG(ret, err); 460 461 /* Set MSW of quotient. */ 462 ret = nn_set_wlen(q, (u8)(new_wlen - b_wlen + 1)); EG(ret, err); 463 q->val[new_wlen - b_wlen] = (word_t) larger; 464 } /* else a is smaller than b... treated above. */ 465 466 ret = nn_rshift_fixedlen(r, r, cnt); EG(ret, err); 467 ret = nn_set_wlen(r, b_wlen); 468 469 err: 470 nn_uninit(&a_shift); 471 472 return ret; 473 } 474 475 /* 476 * Same as previous but handling aliasing of 'r' with 'b_norm', i.e. on success, 477 * result 'r' is passed through 'b_norm'. 478 * 479 * CAUTION: 480 * 481 * - The function is expected to be used ONLY by the generic version 482 * nn_divrem_normalized() defined later in the file. 483 * - All parameter must have been initialized. Unlike exported/public 484 * functions, this internal helper does not verify that nn parameters 485 * have been initialized. Again, this is expected from the caller 486 * (nn_divrem_unshifted()). 487 */ 488 ATTRIBUTE_WARN_UNUSED_RET static int _nn_divrem_unshifted_aliased(nn_t q, nn_src_t a, nn_t b_norm, 489 word_t v, bitcnt_t cnt) 490 { 491 int ret; 492 nn r; 493 r.magic = WORD(0); 494 495 ret = nn_init(&r, 0); EG(ret, err); 496 ret = _nn_divrem_unshifted(q, &r, a, b_norm, v, cnt); EG(ret, err); 497 ret = nn_copy(b_norm, &r); EG(ret, err); 498 499 err: 500 nn_uninit(&r); 501 return ret; 502 } 503 504 /* 505 * Compute quotient and remainder and do not normalize them. 506 * Constant time, see documentation of _nn_divrem_unshifted(). 507 * 508 * Alias-supporting version of _nn_divrem_unshifted for 'r' only. 509 * 510 * The function returns 0 on success, -1 on error. 511 */ 512 int nn_divrem_unshifted(nn_t q, nn_t r, nn_src_t a, nn_src_t b, 513 word_t v, bitcnt_t cnt) 514 { 515 int ret; 516 517 ret = nn_check_initialized(a); EG(ret, err); 518 ret = nn_check_initialized(q); EG(ret, err); 519 ret = nn_check_initialized(r); EG(ret, err); 520 521 /* Unsupported aliasings */ 522 MUST_HAVE((q != r) && (q != a) && (q != b), ret, err); 523 524 if (r == b) { 525 ret = _nn_divrem_unshifted_aliased(q, a, r, v, cnt); 526 } else { 527 ret = nn_check_initialized(b); EG(ret, err); 528 ret = _nn_divrem_unshifted(q, r, a, b, v, cnt); 529 } 530 531 err: 532 return ret; 533 } 534 535 /* 536 * Compute remainder only and do not normalize it. 537 * Constant time, see documentation of _nn_divrem_unshifted. 538 * 539 * Aliasing of inputs and outputs is possible. 540 * 541 * The function returns 0 on success, -1 on error. 542 */ 543 int nn_mod_unshifted(nn_t r, nn_src_t a, nn_src_t b, word_t v, bitcnt_t cnt) 544 { 545 nn q; 546 int ret; 547 q.magic = WORD(0); 548 549 ret = nn_init(&q, 0); EG(ret, err); 550 ret = nn_divrem_unshifted(&q, r, a, b, v, cnt); 551 552 err: 553 nn_uninit(&q); 554 555 return ret; 556 } 557 558 /* 559 * Helper functions for arithmetic in 2-by-1 division 560 * used in the reciprocal computation. 561 * 562 * These are variations of the nn multiprecision functions 563 * acting on arrays of fixed length, in place, 564 * and returning carry/borrow. 565 * 566 * Done in constant time. 567 */ 568 569 /* 570 * Comparison of two limbs numbers. Internal helper. 571 * Checks left to the caller 572 */ 573 ATTRIBUTE_WARN_UNUSED_RET static int _wcmp_22(word_t a[2], word_t b[2]) 574 { 575 int mask, ret = 0; 576 ret += (a[1] > b[1]); 577 ret -= (a[1] < b[1]); 578 mask = !(ret & 0x1); 579 ret += ((a[0] > b[0]) & mask); 580 ret -= ((a[0] < b[0]) & mask); 581 return ret; 582 } 583 584 /* 585 * Addition of two limbs numbers with carry returned. Internal helper. 586 * Checks left to the caller. 587 */ 588 ATTRIBUTE_WARN_UNUSED_RET static word_t _wadd_22(word_t a[2], word_t b[2]) 589 { 590 word_t carry; 591 a[0] = (word_t)(a[0] + b[0]); 592 carry = (word_t)(a[0] < b[0]); 593 a[1] = (word_t)(a[1] + carry); 594 carry = (word_t)(a[1] < carry); 595 a[1] = (word_t)(a[1] + b[1]); 596 carry = (word_t)(carry | (a[1] < b[1])); 597 return carry; 598 } 599 600 /* 601 * Subtraction of two limbs numbers with borrow returned. Internal helper. 602 * Checks left to the caller. 603 */ 604 ATTRIBUTE_WARN_UNUSED_RET static word_t _wsub_22(word_t a[2], word_t b[2]) 605 { 606 word_t borrow, tmp; 607 tmp = (word_t)(a[0] - b[0]); 608 borrow = (word_t)(tmp > a[0]); 609 a[0] = tmp; 610 tmp = (word_t)(a[1] - borrow); 611 borrow = (word_t)(tmp > a[1]); 612 a[1] = (word_t)(tmp - b[1]); 613 borrow = (word_t)(borrow | (a[1] > tmp)); 614 return borrow; 615 } 616 617 /* 618 * Helper macros for conditional subtraction in 2-by-1 division 619 * used in the reciprocal computation. 620 * 621 * Done in constant time. 622 */ 623 624 /* Conditional subtraction of a one limb number from a two limbs number. */ 625 #define WORD_CND_SUB_21(cnd, ah, al, b) do { \ 626 word_t tmp, mask; \ 627 mask = WORD_MASK_IFNOTZERO((cnd)); \ 628 tmp = (word_t)((al) - ((b) & mask)); \ 629 (ah) = (word_t)((ah) - (tmp > (al))); \ 630 (al) = tmp; \ 631 } while (0) 632 /* Conditional subtraction of a two limbs number from a two limbs number. */ 633 #define WORD_CND_SUB_22(cnd, ah, al, bh, bl) do { \ 634 word_t tmp, mask; \ 635 mask = WORD_MASK_IFNOTZERO((cnd)); \ 636 tmp = (word_t)((al) - ((bl) & mask)); \ 637 (ah) = (word_t)((ah) - (tmp > (al))); \ 638 (al) = tmp; \ 639 (ah) = (word_t)((ah) - ((bh) & mask)); \ 640 } while (0) 641 642 /* 643 * divide two words by a normalized word using schoolbook division on half 644 * words. This is only used below in the reciprocal computation. No checks 645 * are performed on inputs. This is expected to be done by the caller. 646 * 647 * Returns 0 on success, -1 on error. 648 */ 649 ATTRIBUTE_WARN_UNUSED_RET static int _word_divrem(word_t *q, word_t *r, word_t ah, word_t al, word_t b) 650 { 651 word_t bh, bl, qh, ql, rm, rhl[2], phl[2]; 652 int larger, ret; 653 u8 j; 654 655 MUST_HAVE((WRSHIFT((b), (WORD_BITS - 1)) == WORD(1)), ret, err); 656 bh = WRSHIFT((b), HWORD_BITS); 657 bl = WLSHIFT((b), HWORD_BITS); 658 rhl[1] = ah; 659 rhl[0] = al; 660 661 /* 662 * Compute high part of the quotient. We know from 663 * MUST_HAVE() check above that bh (a word_t) is not 0 664 */ 665 666 KNOWN_FACT(bh != 0, ret, err); 667 qh = (rhl[1] / bh); 668 qh = WORD_MIN(qh, HWORD_MASK); 669 WORD_MUL(phl[1], phl[0], qh, (b)); 670 phl[1] = (WLSHIFT(phl[1], HWORD_BITS) | 671 WRSHIFT(phl[0], HWORD_BITS)); 672 phl[0] = WLSHIFT(phl[0], HWORD_BITS); 673 674 for (j = 0; j < 2; j++) { 675 larger = (_wcmp_22(phl, rhl) > 0); 676 qh = (word_t)(qh - (word_t)larger); 677 WORD_CND_SUB_22(larger, phl[1], phl[0], bh, bl); 678 } 679 680 ret = (_wcmp_22(phl, rhl) > 0); 681 MUST_HAVE(!(ret), ret, err); 682 IGNORE_RET_VAL(_wsub_22(rhl, phl)); 683 MUST_HAVE((WRSHIFT(rhl[1], HWORD_BITS) == 0), ret, err); 684 685 /* Compute low part of the quotient. */ 686 rm = (WLSHIFT(rhl[1], HWORD_BITS) | 687 WRSHIFT(rhl[0], HWORD_BITS)); 688 ql = (rm / bh); 689 ql = WORD_MIN(ql, HWORD_MASK); 690 WORD_MUL(phl[1], phl[0], ql, (b)); 691 692 for (j = 0; j < 2; j++) { 693 larger = (_wcmp_22(phl, rhl) > 0); 694 ql = (word_t) (ql - (word_t)larger); 695 WORD_CND_SUB_21(larger, phl[1], phl[0], (b)); 696 } 697 698 ret = _wcmp_22(phl, rhl) > 0; 699 MUST_HAVE(!(ret), ret, err); 700 IGNORE_RET_VAL(_wsub_22(rhl, phl)); 701 /* Set outputs. */ 702 MUST_HAVE((rhl[1] == WORD(0)), ret, err); 703 MUST_HAVE(!(rhl[0] >= (b)), ret, err); 704 (*q) = (WLSHIFT(qh, HWORD_BITS) | ql); 705 (*r) = rhl[0]; 706 MUST_HAVE(!((word_t) ((*q)*(b) + (*r)) != (al)), ret, err); 707 ret = 0; 708 709 err: 710 return ret; 711 } 712 713 /* 714 * Compute the reciprocal of d as 715 * floor(B^3/(d+1)) - B 716 * which is used to perform approximate small division using a multiplication. 717 * 718 * No attempt was made to make it constant time. Indeed, such values are usually 719 * precomputed in contexts where constant time is wanted, e.g. in the fp layer. 720 * 721 * Returns 0 on success, -1 on error. 722 */ 723 int wreciprocal(word_t dh, word_t dl, word_t *reciprocal) 724 { 725 word_t q, carry, r[2], t[2]; 726 int ret; 727 728 MUST_HAVE((reciprocal != NULL), ret, err); 729 730 if (((word_t)(dh + WORD(1)) == WORD(0)) && 731 ((word_t)(dl + WORD(1)) == WORD(0))) { 732 (*reciprocal) = WORD(0); 733 ret = 0; 734 goto err; 735 } 736 737 if ((word_t)(dh + WORD(1)) == WORD(0)) { 738 q = (word_t)(~dh); 739 r[1] = (word_t)(~dl); 740 } else { 741 t[1] = (word_t)(~dh); 742 t[0] = (word_t)(~dl); 743 ret = _word_divrem(&q, r+1, t[1], t[0], 744 (word_t)(dh + WORD(1))); EG(ret, err); 745 } 746 747 if ((word_t)(dl + WORD(1)) == WORD(0)) { 748 (*reciprocal) = q; 749 ret = 0; 750 goto err; 751 } 752 753 r[0] = WORD(0); 754 755 WORD_MUL(t[1], t[0], q, (word_t)~dl); 756 carry = _wadd_22(r, t); 757 758 t[0] = (word_t)(dl + WORD(1)); 759 t[1] = dh; 760 while (carry || (_wcmp_22(r, t) >= 0)) { 761 q++; 762 carry = (word_t)(carry - _wsub_22(r, t)); 763 } 764 765 (*reciprocal) = q; 766 ret = 0; 767 768 err: 769 return ret; 770 } 771 772 /* 773 * Given an odd number p, compute division coefficients p_normalized, 774 * p_shift and p_reciprocal so that: 775 * - p_shift = p_rounded_bitlen - bitsizeof(p), where 776 * o p_rounded_bitlen = BIT_LEN_WORDS(p) (i.e. bit length of 777 * minimum number of words required to store p) and 778 * o p_bitlen is the real bit size of p 779 * - p_normalized = p << p_shift 780 * - p_reciprocal = B^3 / ((p_normalized >> (pbitlen - 2*WORDSIZE)) + 1) - B 781 * with B = 2^WORDSIZE 782 * 783 * These coefficients are useful for the optimized shifted variants of NN 784 * division and modular functions. Because we have two word_t outputs 785 * (p_shift and p_reciprocal), these are passed through word_t pointers. 786 * Aliasing of outputs with the input is possible since p_in is copied in 787 * local p at the beginning of the function. 788 * 789 * The function does not support aliasing. 790 * 791 * The function returns 0 on success, -1 on error. 792 */ 793 int nn_compute_div_coefs(nn_t p_normalized, word_t *p_shift, 794 word_t *p_reciprocal, nn_src_t p_in) 795 { 796 bitcnt_t p_rounded_bitlen, p_bitlen; 797 nn p, tmp_nn; 798 int ret; 799 p.magic = tmp_nn.magic = WORD(0); 800 801 ret = nn_check_initialized(p_in); EG(ret, err); 802 803 MUST_HAVE((p_shift != NULL), ret, err); 804 MUST_HAVE((p_reciprocal != NULL), ret, err); 805 806 /* Unsupported aliasing */ 807 MUST_HAVE((p_normalized != p_in), ret, err); 808 809 ret = nn_init(&p, 0); EG(ret, err); 810 ret = nn_copy(&p, p_in); EG(ret, err); 811 812 /* 813 * In order for our reciprocal division routines to work, it is expected 814 * that the bit length (including leading zeroes) of input prime 815 * p is >= 2 * wlen where wlen is the number of bits of a word size. 816 */ 817 if (p.wlen < 2) { 818 ret = nn_set_wlen(&p, 2); EG(ret, err); 819 } 820 821 ret = nn_init(p_normalized, 0); EG(ret, err); 822 ret = nn_init(&tmp_nn, 0); EG(ret, err); 823 824 /* p_rounded_bitlen = bitlen of p rounded to word size */ 825 p_rounded_bitlen = (bitcnt_t)(WORD_BITS * p.wlen); 826 827 /* p_shift */ 828 ret = nn_bitlen(&p, &p_bitlen); EG(ret, err); 829 (*p_shift) = (word_t)(p_rounded_bitlen - p_bitlen); 830 831 /* p_normalized = p << pshift */ 832 ret = nn_lshift(p_normalized, &p, (bitcnt_t)(*p_shift)); EG(ret, err); 833 834 /* Sanity check to protect the p_reciprocal computation */ 835 MUST_HAVE((p_rounded_bitlen >= (2 * WORDSIZE)), ret, err); 836 837 /* 838 * p_reciprocal = B^3 / ((p_normalized >> (p_rounded_bitlen - 2 * wlen)) + 1) - B 839 * where B = 2^wlen where wlen = word size in bits. We use our NN 840 * helper to compute it. 841 */ 842 ret = nn_rshift(&tmp_nn, p_normalized, (bitcnt_t)(p_rounded_bitlen - (2 * WORDSIZE))); EG(ret, err); 843 ret = wreciprocal(tmp_nn.val[1], tmp_nn.val[0], p_reciprocal); 844 845 err: 846 nn_uninit(&p); 847 nn_uninit(&tmp_nn); 848 849 return ret; 850 } 851 852 /* 853 * Compute quotient remainder of Euclidean division. 854 * 855 * This function is a wrapper to normalize the divisor, i.e. shift it so that 856 * the MSB of its MSW is set, and precompute the reciprocal of this MSW to be 857 * used to perform small divisions using multiplications during the long 858 * schoolbook division. It uses the helper functions/macros above. 859 * 860 * This is NOT constant time with regards to the word length of a and b, 861 * but also the actual bitlength of b as we need to normalize b at the 862 * bit level. 863 * Moreover the precomputation of the reciprocal is not constant time at all. 864 * 865 * r need not be initialized, the function does it for the the caller. 866 * 867 * This function does not support aliasing. This is an internal helper, which 868 * expects caller to check parameters. 869 * 870 * It returns 0 on sucess, -1 on error. 871 */ 872 ATTRIBUTE_WARN_UNUSED_RET static int _nn_divrem(nn_t q, nn_t r, nn_src_t a, nn_src_t b) 873 { 874 nn b_large, b_normalized; 875 bitcnt_t cnt; 876 word_t v; 877 nn_src_t ptr = b; 878 int ret, iszero; 879 b_large.magic = b_normalized.magic = WORD(0); 880 881 ret = nn_init(r, 0); EG(ret, err); 882 ret = nn_init(q, 0); EG(ret, err); 883 ret = nn_init(&b_large, 0); EG(ret, err); 884 885 MUST_HAVE(!nn_iszero(b, &iszero) && !iszero, ret, err); 886 887 if (b->wlen == 1) { 888 ret = nn_copy(&b_large, b); EG(ret, err); 889 890 /* Expand our big number with zeroes */ 891 ret = nn_set_wlen(&b_large, 2); EG(ret, err); 892 893 /* 894 * This cast could seem inappropriate, but we are 895 * sure here that we won't touch ptr since it is only 896 * given as a const parameter to sub functions. 897 */ 898 ptr = (nn_src_t) &b_large; 899 } 900 901 /* After this, we only handle >= 2 words big numbers */ 902 MUST_HAVE(!(ptr->wlen < 2), ret, err); 903 904 ret = nn_init(&b_normalized, (u16)((ptr->wlen) * WORD_BYTES)); EG(ret, err); 905 ret = nn_clz(ptr, &cnt); EG(ret, err); 906 ret = nn_lshift_fixedlen(&b_normalized, ptr, cnt); EG(ret, err); 907 ret = wreciprocal(b_normalized.val[ptr->wlen - 1], 908 b_normalized.val[ptr->wlen - 2], 909 &v); /* Not constant time. */ EG(ret, err); 910 911 ret = _nn_divrem_unshifted(q, r, a, &b_normalized, v, cnt); 912 913 err: 914 nn_uninit(&b_normalized); 915 nn_uninit(&b_large); 916 917 return ret; 918 } 919 920 /* 921 * Returns 0 on succes, -1 on error. Internal helper. Checks on params 922 * expected from the caller. 923 */ 924 ATTRIBUTE_WARN_UNUSED_RET static int __nn_divrem_notrim_alias(nn_t q, nn_t r, nn_src_t a, nn_src_t b) 925 { 926 nn a_cpy, b_cpy; 927 int ret; 928 a_cpy.magic = b_cpy.magic = WORD(0); 929 930 ret = nn_init(&a_cpy, 0); EG(ret, err); 931 ret = nn_init(&b_cpy, 0); EG(ret, err); 932 ret = nn_copy(&a_cpy, a); EG(ret, err); 933 ret = nn_copy(&b_cpy, b); EG(ret, err); 934 ret = _nn_divrem(q, r, &a_cpy, &b_cpy); 935 936 err: 937 nn_uninit(&b_cpy); 938 nn_uninit(&a_cpy); 939 940 return ret; 941 } 942 943 944 945 /* 946 * Compute quotient and remainder and normalize them. 947 * Not constant time, see documentation of _nn_divrem. 948 * 949 * Aliased version of _nn_divrem. Returns 0 on success, 950 * -1 on error. 951 */ 952 int nn_divrem_notrim(nn_t q, nn_t r, nn_src_t a, nn_src_t b) 953 { 954 int ret; 955 956 /* _nn_divrem initializes q and r */ 957 ret = nn_check_initialized(a); EG(ret, err); 958 ret = nn_check_initialized(b); EG(ret, err); 959 MUST_HAVE(((q != NULL) && (r != NULL)), ret, err); 960 961 /* 962 * Handle aliasing whenever any of the inputs is 963 * used as an output. 964 */ 965 if ((a == q) || (a == r) || (b == q) || (b == r)) { 966 ret = __nn_divrem_notrim_alias(q, r, a, b); 967 } else { 968 ret = _nn_divrem(q, r, a, b); 969 } 970 971 err: 972 return ret; 973 } 974 975 /* 976 * Compute quotient and remainder and normalize them. 977 * Not constant time, see documentation of _nn_divrem(). 978 * Returns 0 on success, -1 on error. 979 * 980 * Aliasing is supported. 981 */ 982 int nn_divrem(nn_t q, nn_t r, nn_src_t a, nn_src_t b) 983 { 984 int ret; 985 986 ret = nn_divrem_notrim(q, r, a, b); EG(ret, err); 987 988 /* Normalize (trim) the quotient and rest to avoid size overflow */ 989 ret = nn_normalize(q); EG(ret, err); 990 ret = nn_normalize(r); 991 992 err: 993 return ret; 994 } 995 996 /* 997 * Compute remainder only and do not normalize it. Not constant time, see 998 * documentation of _nn_divrem(). Returns 0 on success, -1 on error. 999 * 1000 * Aliasing is supported. 1001 */ 1002 int nn_mod_notrim(nn_t r, nn_src_t a, nn_src_t b) 1003 { 1004 int ret; 1005 nn q; 1006 q.magic = WORD(0); 1007 1008 /* nn_divrem() will init q. */ 1009 ret = nn_divrem_notrim(&q, r, a, b); 1010 1011 nn_uninit(&q); 1012 1013 return ret; 1014 } 1015 1016 /* 1017 * Compute remainder only and normalize it. Not constant time, see 1018 * documentation of _nn_divrem(). r is initialized by the function. 1019 * Returns 0 on success, -1 on error. 1020 * 1021 * Aliasing is supported. 1022 */ 1023 int nn_mod(nn_t r, nn_src_t a, nn_src_t b) 1024 { 1025 int ret; 1026 nn q; 1027 q.magic = WORD(0); 1028 1029 /* nn_divrem will init q. */ 1030 ret = nn_divrem(&q, r, a, b); 1031 1032 nn_uninit(&q); 1033 1034 return ret; 1035 } 1036 1037 /* 1038 * Below follow gcd and xgcd non constant time functions for the user ease. 1039 */ 1040 1041 /* 1042 * Unaliased version of xgcd, and we suppose that a >= b. Badly non-constant 1043 * time per the algorithm used. The function returns 0 on success, -1 on 1044 * error. internal helper: expect caller to check parameters. 1045 */ 1046 ATTRIBUTE_WARN_UNUSED_RET static int _nn_xgcd(nn_t g, nn_t u, nn_t v, nn_src_t a, nn_src_t b, 1047 int *sign) 1048 { 1049 nn_t c, d, q, r, u1, v1, u2, v2; 1050 nn scratch[8]; 1051 int ret, swap, iszero; 1052 u8 i; 1053 1054 for (i = 0; i < 8; i++){ 1055 scratch[i].magic = WORD(0); 1056 } 1057 1058 /* 1059 * Maintain: 1060 * |u1 v1| |c| = |a| 1061 * |u2 v2| |d| |b| 1062 * u1, v1, u2, v2 >= 0 1063 * c >= d 1064 * 1065 * Initially: 1066 * |1 0 | |a| = |a| 1067 * |0 1 | |b| |b| 1068 * 1069 * At each iteration: 1070 * c >= d 1071 * c = q*d + r 1072 * |u1 v1| = |q*u1+v1 u1| 1073 * |u2 v2| |q*u2+v2 u2| 1074 * 1075 * Finally, after i steps: 1076 * |u1 v1| |g| = |a| 1077 * |u2 v2| |0| = |b| 1078 * 1079 * Inverting the matrix: 1080 * |g| = (-1)^i | v2 -v1| |a| 1081 * |0| |-u2 u1| |b| 1082 */ 1083 1084 /* 1085 * Initialization. 1086 */ 1087 ret = nn_init(g, 0); EG(ret, err); 1088 ret = nn_init(u, 0); EG(ret, err); 1089 ret = nn_init(v, 0); EG(ret, err); 1090 ret = nn_iszero(b, &iszero); EG(ret, err); 1091 if (iszero) { 1092 /* gcd(0, a) = a, and 1*a + 0*b = a */ 1093 ret = nn_copy(g, a); EG(ret, err); 1094 ret = nn_one(u); EG(ret, err); 1095 ret = nn_zero(v); EG(ret, err); 1096 (*sign) = 1; 1097 goto err; 1098 } 1099 1100 for (i = 0; i < 8; i++){ 1101 ret = nn_init(&scratch[i], 0); EG(ret, err); 1102 } 1103 1104 u1 = &(scratch[0]); 1105 v1 = &(scratch[1]); 1106 u2 = &(scratch[2]); 1107 v2 = &(scratch[3]); 1108 ret = nn_one(u1); EG(ret, err); 1109 ret = nn_zero(v1); EG(ret, err); 1110 ret = nn_zero(u2); EG(ret, err); 1111 ret = nn_one(v2); EG(ret, err); 1112 c = &(scratch[4]); 1113 d = &(scratch[5]); 1114 ret = nn_copy(c, a); EG(ret, err); /* Copy could be skipped. */ 1115 ret = nn_copy(d, b); EG(ret, err); /* Copy could be skipped. */ 1116 q = &(scratch[6]); 1117 r = &(scratch[7]); 1118 swap = 0; 1119 1120 /* 1121 * Loop. 1122 */ 1123 ret = nn_iszero(d, &iszero); EG(ret, err); 1124 while (!iszero) { 1125 ret = nn_divrem(q, r, c, d); EG(ret, err); 1126 ret = nn_normalize(q); EG(ret, err); 1127 ret = nn_normalize(r); EG(ret, err); 1128 ret = nn_copy(c, r); EG(ret, err); 1129 ret = nn_mul(r, q, u1); EG(ret, err); 1130 ret = nn_normalize(r); EG(ret, err); 1131 ret = nn_add(v1, v1, r); EG(ret, err); 1132 ret = nn_mul(r, q, u2); EG(ret, err); 1133 ret = nn_normalize(r); EG(ret, err); 1134 ret = nn_add(v2, v2, r); EG(ret, err); 1135 ret = nn_normalize(v1); EG(ret, err); 1136 ret = nn_normalize(v2); EG(ret, err); 1137 swap = 1; 1138 ret = nn_iszero(c, &iszero); EG(ret, err); 1139 if (iszero) { 1140 break; 1141 } 1142 ret = nn_divrem(q, r, d, c); EG(ret, err); 1143 ret = nn_normalize(q); EG(ret, err); 1144 ret = nn_normalize(r); EG(ret, err); 1145 ret = nn_copy(d, r); EG(ret, err); 1146 ret = nn_mul(r, q, v1); EG(ret, err); 1147 ret = nn_normalize(r); EG(ret, err); 1148 ret = nn_add(u1, u1, r); EG(ret, err); 1149 ret = nn_mul(r, q, v2); EG(ret, err); 1150 ret = nn_normalize(r); EG(ret, err); 1151 ret = nn_add(u2, u2, r); EG(ret, err); 1152 ret = nn_normalize(u1); EG(ret, err); 1153 ret = nn_normalize(u2); EG(ret, err); 1154 swap = 0; 1155 1156 /* refresh loop condition */ 1157 ret = nn_iszero(d, &iszero); EG(ret, err); 1158 } 1159 1160 /* Copies could be skipped. */ 1161 if (swap) { 1162 ret = nn_copy(g, d); EG(ret, err); 1163 ret = nn_copy(u, u2); EG(ret, err); 1164 ret = nn_copy(v, u1); EG(ret, err); 1165 } else { 1166 ret = nn_copy(g, c); EG(ret, err); 1167 ret = nn_copy(u, v2); EG(ret, err); 1168 ret = nn_copy(v, v1); EG(ret, err); 1169 } 1170 1171 /* swap = -1 means u <= 0; = 1 means v <= 0 */ 1172 (*sign) = swap ? -1 : 1; 1173 ret = 0; 1174 1175 err: 1176 /* 1177 * We uninit scratch elements in all cases, i.e. whether or not 1178 * we return an error or not. 1179 */ 1180 for (i = 0; i < 8; i++){ 1181 nn_uninit(&scratch[i]); 1182 } 1183 /* Unitialize output in case of error */ 1184 if (ret){ 1185 nn_uninit(v); 1186 nn_uninit(u); 1187 nn_uninit(g); 1188 } 1189 1190 return ret; 1191 } 1192 1193 /* 1194 * Aliased version of xgcd, and no assumption on a and b. Not constant time at 1195 * all. returns 0 on success, -1 on error. XXX document 'sign' 1196 * 1197 * Aliasing is supported. 1198 */ 1199 int nn_xgcd(nn_t g, nn_t u, nn_t v, nn_src_t a, nn_src_t b, int *sign) 1200 { 1201 /* Handle aliasing 1202 * Note: in order to properly handle aliasing, we accept to lose 1203 * some "space" on the stack with copies. 1204 */ 1205 nn a_cpy, b_cpy; 1206 nn_src_t a_, b_; 1207 int ret, cmp, _sign; 1208 a_cpy.magic = b_cpy.magic = WORD(0); 1209 1210 /* The internal _nn_xgcd function initializes g, u and v */ 1211 ret = nn_check_initialized(a); EG(ret, err); 1212 ret = nn_check_initialized(b); EG(ret, err); 1213 MUST_HAVE((sign != NULL), ret, err); 1214 1215 ret = nn_init(&b_cpy, 0); EG(ret, err); 1216 1217 /* Aliasing of a */ 1218 if ((g == a) || (u == a) || (v == a)){ 1219 ret = nn_copy(&a_cpy, a); EG(ret, err); 1220 a_ = &a_cpy; 1221 } else { 1222 a_ = a; 1223 } 1224 /* Aliasing of b */ 1225 if ((g == b) || (u == b) || (v == b)) { 1226 ret = nn_copy(&b_cpy, b); EG(ret, err); 1227 b_ = &b_cpy; 1228 } else { 1229 b_ = b; 1230 } 1231 1232 ret = nn_cmp(a_, b_, &cmp); EG(ret, err); 1233 if (cmp < 0) { 1234 /* If a < b, swap the inputs */ 1235 ret = _nn_xgcd(g, v, u, b_, a_, &_sign); EG(ret, err); 1236 (*sign) = -(_sign); 1237 } else { 1238 ret = _nn_xgcd(g, u, v, a_, b_, &_sign); EG(ret, err); 1239 (*sign) = _sign; 1240 } 1241 1242 err: 1243 nn_uninit(&b_cpy); 1244 nn_uninit(&a_cpy); 1245 1246 return ret; 1247 } 1248 1249 /* 1250 * Compute g = gcd(a, b). Internally use the xgcd and drop u and v. 1251 * Not constant time at all. Returns 0 on success, -1 on error. 1252 * XXX document 'sign'. 1253 * 1254 * Aliasing is supported. 1255 */ 1256 int nn_gcd(nn_t g, nn_src_t a, nn_src_t b, int *sign) 1257 { 1258 nn u, v; 1259 int ret; 1260 u.magic = v.magic = WORD(0); 1261 1262 /* nn_xgcd will initialize g, u and v and 1263 * check if a and b are indeed initialized. 1264 */ 1265 ret = nn_xgcd(g, &u, &v, a, b, sign); 1266 1267 nn_uninit(&u); 1268 nn_uninit(&v); 1269 1270 return ret; 1271 } 1272