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