|
|
1.1 ! root 1: /* NN.C - natural numbers routines ! 2: */ ! 3: ! 4: /* Copyright (C) 1991-2 RSA Laboratories, a division of RSA Data ! 5: Security, Inc. All rights reserved. ! 6: */ ! 7: ! 8: /* ! 9: * CHANGES MADE TO THIS FILE UNDER RSAREF license clause 1(c): ! 10: * ! 11: * For the MIT PGP 2.6 distribution, this file was modified to permit ! 12: * replacement of the NN_ModExp routine by an equivalent routine ! 13: * contained in the PGP 2.6 sources. To enable this change, an #ifdef ! 14: * was added to this file (search for #ifndef USEMPILIB ! 15: * below). RSAREF *must* be compiled with USEMPILIB defined for this ! 16: * change to occur. ! 17: * ! 18: * Change made May 21, 1994. ! 19: */ ! 20: ! 21: #include "global.h" ! 22: #include "rsaref.h" ! 23: #include "nn.h" ! 24: #include "digit.h" ! 25: ! 26: static NN_DIGIT NN_LShift PROTO_LIST ! 27: ((NN_DIGIT *, NN_DIGIT *, unsigned int, unsigned int)); ! 28: static NN_DIGIT NN_RShift PROTO_LIST ! 29: ((NN_DIGIT *, NN_DIGIT *, unsigned int, unsigned int)); ! 30: static void NN_Div PROTO_LIST ! 31: ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int, NN_DIGIT *, ! 32: unsigned int)); ! 33: ! 34: static NN_DIGIT NN_AddDigitMult PROTO_LIST ! 35: ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT, NN_DIGIT *, unsigned int)); ! 36: static NN_DIGIT NN_SubDigitMult PROTO_LIST ! 37: ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT, NN_DIGIT *, unsigned int)); ! 38: ! 39: static unsigned int NN_DigitBits PROTO_LIST ((NN_DIGIT)); ! 40: ! 41: /* Decodes character string b into a, where character string is ordered ! 42: from most to least significant. ! 43: ! 44: Length: a[digits], b[len]. ! 45: Assumes b[i] = 0 for i < len - digits * NN_DIGIT_LEN. (Otherwise most ! 46: significant bytes are truncated.) ! 47: */ ! 48: void NN_Decode (a, digits, b, len) ! 49: NN_DIGIT *a; ! 50: unsigned char *b; ! 51: unsigned int digits, len; ! 52: { ! 53: NN_DIGIT t; ! 54: int j; ! 55: unsigned int i, u; ! 56: ! 57: for (i = 0, j = len - 1; j >= 0; i++) { ! 58: t = 0; ! 59: for (u = 0; j >= 0 && u < NN_DIGIT_BITS; j--, u += 8) ! 60: t |= ((NN_DIGIT)b[j]) << u; ! 61: a[i] = t; ! 62: } ! 63: ! 64: for (; i < digits; i++) ! 65: a[i] = 0; ! 66: } ! 67: ! 68: /* Encodes b into character string a, where character string is ordered ! 69: from most to least significant. ! 70: ! 71: Lengths: a[len], b[digits]. ! 72: Assumes NN_Bits (b, digits) <= 8 * len. (Otherwise most significant ! 73: digits are truncated.) ! 74: */ ! 75: void NN_Encode (a, len, b, digits) ! 76: NN_DIGIT *b; ! 77: unsigned char *a; ! 78: unsigned int digits, len; ! 79: { ! 80: NN_DIGIT t; ! 81: int j; ! 82: unsigned int i, u; ! 83: ! 84: for (i = 0, j = len - 1; i < digits; i++) { ! 85: t = b[i]; ! 86: for (u = 0; j >= 0 && u < NN_DIGIT_BITS; j--, u += 8) ! 87: a[j] = (unsigned char)(t >> u); ! 88: } ! 89: ! 90: for (; j >= 0; j--) ! 91: a[j] = 0; ! 92: } ! 93: ! 94: /* Assigns a = 0. ! 95: ! 96: Lengths: a[digits], b[digits]. ! 97: */ ! 98: void NN_Assign (a, b, digits) ! 99: NN_DIGIT *a, *b; ! 100: unsigned int digits; ! 101: { ! 102: unsigned int i; ! 103: ! 104: for (i = 0; i < digits; i++) ! 105: a[i] = b[i]; ! 106: } ! 107: ! 108: /* Assigns a = 0. ! 109: ! 110: Lengths: a[digits]. ! 111: */ ! 112: void NN_AssignZero (a, digits) ! 113: NN_DIGIT *a; ! 114: unsigned int digits; ! 115: { ! 116: unsigned int i; ! 117: ! 118: for (i = 0; i < digits; i++) ! 119: a[i] = 0; ! 120: } ! 121: ! 122: /* Assigns a = 2^b. ! 123: ! 124: Lengths: a[digits]. ! 125: Requires b < digits * NN_DIGIT_BITS. ! 126: */ ! 127: void NN_Assign2Exp (a, b, digits) ! 128: NN_DIGIT *a; ! 129: unsigned int b, digits; ! 130: { ! 131: NN_AssignZero (a, digits); ! 132: ! 133: if (b >= digits * NN_DIGIT_BITS) ! 134: return; ! 135: ! 136: a[b / NN_DIGIT_BITS] = (NN_DIGIT)1 << (b % NN_DIGIT_BITS); ! 137: } ! 138: ! 139: /* Computes a = b + c. Returns carry. ! 140: ! 141: Lengths: a[digits], b[digits], c[digits]. ! 142: */ ! 143: NN_DIGIT NN_Add (a, b, c, digits) ! 144: NN_DIGIT *a, *b, *c; ! 145: unsigned int digits; ! 146: { ! 147: NN_DIGIT ai, carry; ! 148: unsigned int i; ! 149: ! 150: carry = 0; ! 151: ! 152: for (i = 0; i < digits; i++) { ! 153: if ((ai = b[i] + carry) < carry) ! 154: ai = c[i]; ! 155: else if ((ai += c[i]) < c[i]) ! 156: carry = 1; ! 157: else ! 158: carry = 0; ! 159: a[i] = ai; ! 160: } ! 161: ! 162: return (carry); ! 163: } ! 164: ! 165: /* Computes a = b - c. Returns borrow. ! 166: ! 167: Lengths: a[digits], b[digits], c[digits]. ! 168: */ ! 169: NN_DIGIT NN_Sub (a, b, c, digits) ! 170: NN_DIGIT *a, *b, *c; ! 171: unsigned int digits; ! 172: { ! 173: NN_DIGIT ai, borrow; ! 174: unsigned int i; ! 175: ! 176: borrow = 0; ! 177: ! 178: for (i = 0; i < digits; i++) { ! 179: if ((ai = b[i] - borrow) > (MAX_NN_DIGIT - borrow)) ! 180: ai = MAX_NN_DIGIT - c[i]; ! 181: else if ((ai -= c[i]) > (MAX_NN_DIGIT - c[i])) ! 182: borrow = 1; ! 183: else ! 184: borrow = 0; ! 185: a[i] = ai; ! 186: } ! 187: ! 188: return (borrow); ! 189: } ! 190: ! 191: /* Computes a = b * c. ! 192: ! 193: Lengths: a[2*digits], b[digits], c[digits]. ! 194: Assumes digits < MAX_NN_DIGITS. ! 195: */ ! 196: void NN_Mult (a, b, c, digits) ! 197: NN_DIGIT *a, *b, *c; ! 198: unsigned int digits; ! 199: { ! 200: NN_DIGIT t[2*MAX_NN_DIGITS]; ! 201: unsigned int bDigits, cDigits, i; ! 202: ! 203: NN_AssignZero (t, 2 * digits); ! 204: ! 205: bDigits = NN_Digits (b, digits); ! 206: cDigits = NN_Digits (c, digits); ! 207: ! 208: for (i = 0; i < bDigits; i++) ! 209: t[i+cDigits] += NN_AddDigitMult (&t[i], &t[i], b[i], c, cDigits); ! 210: ! 211: NN_Assign (a, t, 2 * digits); ! 212: ! 213: /* Zeroize potentially sensitive information. ! 214: */ ! 215: R_memset ((POINTER)t, 0, sizeof (t)); ! 216: } ! 217: ! 218: /* Computes a = b mod c. ! 219: ! 220: Lengths: a[cDigits], b[bDigits], c[cDigits]. ! 221: Assumes c > 0, bDigits < 2 * MAX_NN_DIGITS, cDigits < MAX_NN_DIGITS. ! 222: */ ! 223: void NN_Mod (a, b, bDigits, c, cDigits) ! 224: NN_DIGIT *a, *b, *c; ! 225: unsigned int bDigits, cDigits; ! 226: { ! 227: NN_DIGIT t[2 * MAX_NN_DIGITS]; ! 228: ! 229: NN_Div (t, a, b, bDigits, c, cDigits); ! 230: ! 231: /* Zeroize potentially sensitive information. ! 232: */ ! 233: R_memset ((POINTER)t, 0, sizeof (t)); ! 234: } ! 235: ! 236: /* Computes a = b * c mod d. ! 237: ! 238: Lengths: a[digits], b[digits], c[digits], d[digits]. ! 239: Assumes d > 0, digits < MAX_NN_DIGITS. ! 240: */ ! 241: void NN_ModMult (a, b, c, d, digits) ! 242: NN_DIGIT *a, *b, *c, *d; ! 243: unsigned int digits; ! 244: { ! 245: NN_DIGIT t[2*MAX_NN_DIGITS]; ! 246: ! 247: NN_Mult (t, b, c, digits); ! 248: NN_Mod (a, t, 2 * digits, d, digits); ! 249: ! 250: /* Zeroize potentially sensitive information. ! 251: */ ! 252: R_memset ((POINTER)t, 0, sizeof (t)); ! 253: } ! 254: ! 255: ! 256: /* ! 257: * PGP 2.6's mpilib contains a faster modular exponentiation routine, ! 258: * mp_modexp. If USEMPILIB is defined, NN_ModExp is replaced in the ! 259: * PGP 2.6 sources with a stub call to mp_modexp. If USEMPILIB is ! 260: * not defined, we'll get a pure (albeit slower) RSAREF ! 261: * implementation. ! 262: * ! 263: * The RSAREF license, clause 1(c), permits "...modify[ing] the ! 264: * Program in any manner for porting or performance improvement ! 265: * purposes..." ! 266: */ ! 267: #ifndef USEMPILIB ! 268: /* Computes a = b^c mod d. ! 269: ! 270: Lengths: a[dDigits], b[dDigits], c[cDigits], d[dDigits]. ! 271: Assumes b < d, d > 0, cDigits > 0, dDigits > 0, ! 272: dDigits < MAX_NN_DIGITS. ! 273: */ ! 274: void NN_ModExp (a, b, c, cDigits, d, dDigits) ! 275: NN_DIGIT *a, *b, *c, *d; ! 276: unsigned int cDigits, dDigits; ! 277: { ! 278: NN_DIGIT bPower[3][MAX_NN_DIGITS], ci, t[MAX_NN_DIGITS]; ! 279: int i; ! 280: unsigned int ciBits, j, s; ! 281: ! 282: /* Store b, b^2 mod d, and b^3 mod d. ! 283: */ ! 284: NN_Assign (bPower[0], b, dDigits); ! 285: NN_ModMult (bPower[1], bPower[0], b, d, dDigits); ! 286: NN_ModMult (bPower[2], bPower[1], b, d, dDigits); ! 287: ! 288: NN_ASSIGN_DIGIT (t, 1, dDigits); ! 289: ! 290: cDigits = NN_Digits (c, cDigits); ! 291: for (i = cDigits - 1; i >= 0; i--) { ! 292: ci = c[i]; ! 293: ciBits = NN_DIGIT_BITS; ! 294: ! 295: /* Scan past leading zero bits of most significant digit. ! 296: */ ! 297: if (i == (int)(cDigits - 1)) { ! 298: while (! DIGIT_2MSB (ci)) { ! 299: ci <<= 2; ! 300: ciBits -= 2; ! 301: } ! 302: } ! 303: ! 304: for (j = 0; j < ciBits; j += 2, ci <<= 2) { ! 305: /* Compute t = t^4 * b^s mod d, where s = two MSB's of d. ! 306: */ ! 307: NN_ModMult (t, t, t, d, dDigits); ! 308: NN_ModMult (t, t, t, d, dDigits); ! 309: if (s = DIGIT_2MSB (ci)) ! 310: NN_ModMult (t, t, bPower[s-1], d, dDigits); ! 311: } ! 312: } ! 313: ! 314: NN_Assign (a, t, dDigits); ! 315: ! 316: /* Zeroize potentially sensitive information. ! 317: */ ! 318: R_memset ((POINTER)bPower, 0, sizeof (bPower)); ! 319: R_memset ((POINTER)t, 0, sizeof (t)); ! 320: } ! 321: #endif ! 322: ! 323: /* Compute a = 1/b mod c, assuming inverse exists. ! 324: ! 325: Lengths: a[digits], b[digits], c[digits]. ! 326: Assumes gcd (b, c) = 1, digits < MAX_NN_DIGITS. ! 327: */ ! 328: void NN_ModInv (a, b, c, digits) ! 329: NN_DIGIT *a, *b, *c; ! 330: unsigned int digits; ! 331: { ! 332: NN_DIGIT q[MAX_NN_DIGITS], t1[MAX_NN_DIGITS], t3[MAX_NN_DIGITS], ! 333: u1[MAX_NN_DIGITS], u3[MAX_NN_DIGITS], v1[MAX_NN_DIGITS], ! 334: v3[MAX_NN_DIGITS], w[2*MAX_NN_DIGITS]; ! 335: int u1Sign; ! 336: ! 337: /* Apply extended Euclidean algorithm, modified to avoid negative ! 338: numbers. ! 339: */ ! 340: NN_ASSIGN_DIGIT (u1, 1, digits); ! 341: NN_AssignZero (v1, digits); ! 342: NN_Assign (u3, b, digits); ! 343: NN_Assign (v3, c, digits); ! 344: u1Sign = 1; ! 345: ! 346: while (! NN_Zero (v3, digits)) { ! 347: NN_Div (q, t3, u3, digits, v3, digits); ! 348: NN_Mult (w, q, v1, digits); ! 349: NN_Add (t1, u1, w, digits); ! 350: NN_Assign (u1, v1, digits); ! 351: NN_Assign (v1, t1, digits); ! 352: NN_Assign (u3, v3, digits); ! 353: NN_Assign (v3, t3, digits); ! 354: u1Sign = -u1Sign; ! 355: } ! 356: ! 357: /* Negate result if sign is negative. ! 358: */ ! 359: if (u1Sign < 0) ! 360: NN_Sub (a, c, u1, digits); ! 361: else ! 362: NN_Assign (a, u1, digits); ! 363: ! 364: /* Zeroize potentially sensitive information. ! 365: */ ! 366: R_memset ((POINTER)q, 0, sizeof (q)); ! 367: R_memset ((POINTER)t1, 0, sizeof (t1)); ! 368: R_memset ((POINTER)t3, 0, sizeof (t3)); ! 369: R_memset ((POINTER)u1, 0, sizeof (u1)); ! 370: R_memset ((POINTER)u3, 0, sizeof (u3)); ! 371: R_memset ((POINTER)v1, 0, sizeof (v1)); ! 372: R_memset ((POINTER)v3, 0, sizeof (v3)); ! 373: R_memset ((POINTER)w, 0, sizeof (w)); ! 374: } ! 375: ! 376: /* Computes a = gcd(b, c). ! 377: ! 378: Lengths: a[digits], b[digits], c[digits]. ! 379: Assumes b > c, digits < MAX_NN_DIGITS. ! 380: */ ! 381: void NN_Gcd (a, b, c, digits) ! 382: NN_DIGIT *a, *b, *c; ! 383: unsigned int digits; ! 384: { ! 385: NN_DIGIT t[MAX_NN_DIGITS], u[MAX_NN_DIGITS], v[MAX_NN_DIGITS]; ! 386: ! 387: NN_Assign (u, b, digits); ! 388: NN_Assign (v, c, digits); ! 389: ! 390: while (! NN_Zero (v, digits)) { ! 391: NN_Mod (t, u, digits, v, digits); ! 392: NN_Assign (u, v, digits); ! 393: NN_Assign (v, t, digits); ! 394: } ! 395: ! 396: NN_Assign (a, u, digits); ! 397: ! 398: /* Zeroize potentially sensitive information. ! 399: */ ! 400: R_memset ((POINTER)t, 0, sizeof (t)); ! 401: R_memset ((POINTER)u, 0, sizeof (u)); ! 402: R_memset ((POINTER)v, 0, sizeof (v)); ! 403: } ! 404: ! 405: /* Returns sign of a - b. ! 406: ! 407: Lengths: a[digits], b[digits]. ! 408: */ ! 409: int NN_Cmp (a, b, digits) ! 410: NN_DIGIT *a, *b; ! 411: unsigned int digits; ! 412: { ! 413: int i; ! 414: ! 415: for (i = digits - 1; i >= 0; i--) { ! 416: if (a[i] > b[i]) ! 417: return (1); ! 418: if (a[i] < b[i]) ! 419: return (-1); ! 420: } ! 421: ! 422: return (0); ! 423: } ! 424: ! 425: /* Returns nonzero iff a is zero. ! 426: ! 427: Lengths: a[digits]. ! 428: */ ! 429: int NN_Zero (a, digits) ! 430: NN_DIGIT *a; ! 431: unsigned int digits; ! 432: { ! 433: unsigned int i; ! 434: ! 435: for (i = 0; i < digits; i++) ! 436: if (a[i]) ! 437: return (0); ! 438: ! 439: return (1); ! 440: } ! 441: ! 442: /* Returns the significant length of a in bits. ! 443: ! 444: Lengths: a[digits]. ! 445: */ ! 446: unsigned int NN_Bits (a, digits) ! 447: NN_DIGIT *a; ! 448: unsigned int digits; ! 449: { ! 450: if ((digits = NN_Digits (a, digits)) == 0) ! 451: return (0); ! 452: ! 453: return ((digits - 1) * NN_DIGIT_BITS + NN_DigitBits (a[digits-1])); ! 454: } ! 455: ! 456: /* Returns the significant length of a in digits. ! 457: ! 458: Lengths: a[digits]. ! 459: */ ! 460: unsigned int NN_Digits (a, digits) ! 461: NN_DIGIT *a; ! 462: unsigned int digits; ! 463: { ! 464: int i; ! 465: ! 466: for (i = digits - 1; i >= 0; i--) ! 467: if (a[i]) ! 468: break; ! 469: ! 470: return (i + 1); ! 471: } ! 472: ! 473: /* Computes a = b * 2^c (i.e., shifts left c bits), returning carry. ! 474: ! 475: Lengths: a[digits], b[digits]. ! 476: Requires c < NN_DIGIT_BITS. ! 477: */ ! 478: static NN_DIGIT NN_LShift (a, b, c, digits) ! 479: NN_DIGIT *a, *b; ! 480: unsigned int c, digits; ! 481: { ! 482: NN_DIGIT bi, carry; ! 483: unsigned int i, t; ! 484: ! 485: if (c >= NN_DIGIT_BITS) ! 486: return (0); ! 487: ! 488: t = NN_DIGIT_BITS - c; ! 489: ! 490: carry = 0; ! 491: ! 492: for (i = 0; i < digits; i++) { ! 493: bi = b[i]; ! 494: a[i] = (bi << c) | carry; ! 495: carry = c ? (bi >> t) : 0; ! 496: } ! 497: ! 498: return (carry); ! 499: } ! 500: ! 501: /* Computes a = c div 2^c (i.e., shifts right c bits), returning carry. ! 502: ! 503: Lengths: a[digits], b[digits]. ! 504: Requires: c < NN_DIGIT_BITS. ! 505: */ ! 506: static NN_DIGIT NN_RShift (a, b, c, digits) ! 507: NN_DIGIT *a, *b; ! 508: unsigned int c, digits; ! 509: { ! 510: NN_DIGIT bi, carry; ! 511: int i; ! 512: unsigned int t; ! 513: ! 514: if (c >= NN_DIGIT_BITS) ! 515: return (0); ! 516: ! 517: t = NN_DIGIT_BITS - c; ! 518: ! 519: carry = 0; ! 520: ! 521: for (i = digits - 1; i >= 0; i--) { ! 522: bi = b[i]; ! 523: a[i] = (bi >> c) | carry; ! 524: carry = c ? (bi << t) : 0; ! 525: } ! 526: ! 527: return (carry); ! 528: } ! 529: ! 530: /* Computes a = c div d and b = c mod d. ! 531: ! 532: Lengths: a[cDigits], b[dDigits], c[cDigits], d[dDigits]. ! 533: Assumes d > 0, cDigits < 2 * MAX_NN_DIGITS, ! 534: dDigits < MAX_NN_DIGITS. ! 535: */ ! 536: static void NN_Div (a, b, c, cDigits, d, dDigits) ! 537: NN_DIGIT *a, *b, *c, *d; ! 538: unsigned int cDigits, dDigits; ! 539: { ! 540: NN_DIGIT ai, cc[2*MAX_NN_DIGITS+1], dd[MAX_NN_DIGITS], t; ! 541: int i; ! 542: unsigned int ddDigits, shift; ! 543: ! 544: ddDigits = NN_Digits (d, dDigits); ! 545: if (ddDigits == 0) ! 546: return; ! 547: ! 548: /* Normalize operands. ! 549: */ ! 550: shift = NN_DIGIT_BITS - NN_DigitBits (d[ddDigits-1]); ! 551: NN_AssignZero (cc, ddDigits); ! 552: cc[cDigits] = NN_LShift (cc, c, shift, cDigits); ! 553: NN_LShift (dd, d, shift, ddDigits); ! 554: t = dd[ddDigits-1]; ! 555: ! 556: NN_AssignZero (a, cDigits); ! 557: ! 558: for (i = cDigits-ddDigits; i >= 0; i--) { ! 559: /* Underestimate quotient digit and subtract. ! 560: */ ! 561: if (t == MAX_NN_DIGIT) ! 562: ai = cc[i+dDigits]; ! 563: else ! 564: NN_DigitDiv (&ai, &cc[i+ddDigits-1], t + 1); ! 565: cc[i+ddDigits] -= NN_SubDigitMult (&cc[i], &cc[i], ai, dd, ddDigits); ! 566: ! 567: /* Correct estimate. ! 568: */ ! 569: while (cc[i+ddDigits] || (NN_Cmp (&cc[i], dd, ddDigits) >= 0)) { ! 570: ai++; ! 571: cc[i+ddDigits] -= NN_Sub (&cc[i], &cc[i], dd, ddDigits); ! 572: } ! 573: ! 574: a[i] = ai; ! 575: } ! 576: ! 577: /* Restore result. ! 578: */ ! 579: NN_AssignZero (b, dDigits); ! 580: NN_RShift (b, cc, shift, ddDigits); ! 581: ! 582: /* Zeroize potentially sensitive information. ! 583: */ ! 584: R_memset ((POINTER)cc, 0, sizeof (cc)); ! 585: R_memset ((POINTER)dd, 0, sizeof (dd)); ! 586: } ! 587: ! 588: /* Computes a = b + c*d, where c is a digit. Returns carry. ! 589: ! 590: Lengths: a[digits], b[digits], d[digits]. ! 591: */ ! 592: static NN_DIGIT NN_AddDigitMult (a, b, c, d, digits) ! 593: NN_DIGIT *a, *b, c, *d; ! 594: unsigned int digits; ! 595: { ! 596: NN_DIGIT carry, t[2]; ! 597: unsigned int i; ! 598: ! 599: if (c == 0) ! 600: return (0); ! 601: ! 602: carry = 0; ! 603: for (i = 0; i < digits; i++) { ! 604: NN_DigitMult (t, c, d[i]); ! 605: if ((a[i] = b[i] + carry) < carry) ! 606: carry = 1; ! 607: else ! 608: carry = 0; ! 609: if ((a[i] += t[0]) < t[0]) ! 610: carry++; ! 611: carry += t[1]; ! 612: } ! 613: ! 614: return (carry); ! 615: } ! 616: ! 617: /* Computes a = b - c*d, where c is a digit. Returns borrow. ! 618: ! 619: Lengths: a[digits], b[digits], d[digits]. ! 620: */ ! 621: static NN_DIGIT NN_SubDigitMult (a, b, c, d, digits) ! 622: NN_DIGIT *a, *b, c, *d; ! 623: unsigned int digits; ! 624: { ! 625: NN_DIGIT borrow, t[2]; ! 626: unsigned int i; ! 627: ! 628: if (c == 0) ! 629: return (0); ! 630: ! 631: borrow = 0; ! 632: for (i = 0; i < digits; i++) { ! 633: NN_DigitMult (t, c, d[i]); ! 634: if ((a[i] = b[i] - borrow) > (MAX_NN_DIGIT - borrow)) ! 635: borrow = 1; ! 636: else ! 637: borrow = 0; ! 638: if ((a[i] -= t[0]) > (MAX_NN_DIGIT - t[0])) ! 639: borrow++; ! 640: borrow += t[1]; ! 641: } ! 642: ! 643: return (borrow); ! 644: } ! 645: ! 646: /* Returns the significant length of a in bits, where a is a digit. ! 647: */ ! 648: static unsigned int NN_DigitBits (a) ! 649: NN_DIGIT a; ! 650: { ! 651: unsigned int i; ! 652: ! 653: for (i = 0; i < NN_DIGIT_BITS; i++, a >>= 1) ! 654: if (a == 0) ! 655: break; ! 656: ! 657: return (i); ! 658: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.