📄 biginteger.java
字号:
* after a suitable number of squarings have passed (e.g. a pattern * of "100" in the buffer requires that we multiply by n^1 immediately; * a pattern of "110" calls for multiplying by n^3 after one more * squaring), clear the buffer, and continue. * * When we start, there is one more optimization: the result buffer * is implcitly one, so squaring it or multiplying by it can be * optimized away. Further, if we start with a pattern like "100" * in the lookahead window, rather than placing n into the buffer * and then starting to square it, we have already computed n^2 * to compute the odd-powers table, so we can place that into * the buffer and save a squaring. * * This means that if you have a k-bit window, to compute n^z, * where z is the high k bits of the exponent, 1/2 of the time * it requires no squarings. 1/4 of the time, it requires 1 * squaring, ... 1/2^(k-1) of the time, it reqires k-2 squarings. * And the remaining 1/2^(k-1) of the time, the top k bits are a * 1 followed by k-1 0 bits, so it again only requires k-2 * squarings, not k-1. The average of these is 1. Add that * to the one squaring we have to do to compute the table, * and you'll see that a k-bit window saves k-2 squarings * as well as reducing the multiplies. (It actually doesn't * hurt in the case k = 1, either.) */ // Special case for exponent of one if (y.equals(ONE)) return this; // Special case for base of zero if (signum==0) return ZERO; int[] base = (int[])mag.clone(); int[] exp = y.mag; int[] mod = z.mag; int modLen = mod.length; // Select an appropriate window size int wbits = 0; int ebits = bitLength(exp, exp.length); while (ebits > bnExpModThreshTable[wbits]) wbits++; // Calculate appropriate table size int tblmask = 1 << wbits; // Allocate table for precomputed odd powers of base in Montgomery form int[][] table = new int[tblmask][]; for (int i=0; i<tblmask; i++) table[i] = new int[modLen]; // Compute the modular inverse int inv = -MutableBigInteger.inverseMod32(mod[modLen-1]); // Convert base to Montgomery form int[] a = leftShift(base, base.length, modLen << 5); MutableBigInteger q = new MutableBigInteger(), r = new MutableBigInteger(), a2 = new MutableBigInteger(a), b2 = new MutableBigInteger(mod); a2.divide(b2, q, r); table[0] = r.toIntArray(); // Pad table[0] with leading zeros so its length is at least modLen if (table[0].length < modLen) { int offset = modLen - table[0].length; int[] t2 = new int[modLen]; for (int i=0; i<table[0].length; i++) t2[i+offset] = table[0][i]; table[0] = t2; } // Set b to the square of the base int[] b = squareToLen(table[0], modLen, null); b = montReduce(b, mod, modLen, inv); // Set t to high half of b int[] t = new int[modLen]; for(int i=0; i<modLen; i++) t[i] = b[i]; // Fill in the table with odd powers of the base for (int i=1; i<tblmask; i++) { int[] prod = multiplyToLen(t, modLen, table[i-1], modLen, null); table[i] = montReduce(prod, mod, modLen, inv); } // Pre load the window that slides over the exponent int bitpos = 1 << ((ebits-1) & (32-1)); int buf = 0; int elen = exp.length; int eIndex = 0; for (int i = 0; i <= wbits; i++) { buf = (buf << 1) | (((exp[eIndex] & bitpos) != 0)?1:0); bitpos >>>= 1; if (bitpos == 0) { eIndex++; bitpos = 1 << (32-1); elen--; } } int multpos = ebits; // The first iteration, which is hoisted out of the main loop ebits--; boolean isone = true; multpos = ebits - wbits; while ((buf & 1) == 0) { buf >>>= 1; multpos++; } int[] mult = table[buf >>> 1]; buf = 0; if (multpos == ebits) isone = false; // The main loop while(true) { ebits--; // Advance the window buf <<= 1; if (elen != 0) { buf |= ((exp[eIndex] & bitpos) != 0) ? 1 : 0; bitpos >>>= 1; if (bitpos == 0) { eIndex++; bitpos = 1 << (32-1); elen--; } } // Examine the window for pending multiplies if ((buf & tblmask) != 0) { multpos = ebits - wbits; while ((buf & 1) == 0) { buf >>>= 1; multpos++; } mult = table[buf >>> 1]; buf = 0; } // Perform multiply if (ebits == multpos) { if (isone) { b = (int[])mult.clone(); isone = false; } else { t = b; a = multiplyToLen(t, modLen, mult, modLen, a); a = montReduce(a, mod, modLen, inv); t = a; a = b; b = t; } } // Check if done if (ebits == 0) break; // Square the input if (!isone) { t = b; a = squareToLen(t, modLen, a); a = montReduce(a, mod, modLen, inv); t = a; a = b; b = t; } } // Convert result out of Montgomery form and return int[] t2 = new int[2*modLen]; for(int i=0; i<modLen; i++) t2[i+modLen] = b[i]; b = montReduce(t2, mod, modLen, inv); t2 = new int[modLen]; for(int i=0; i<modLen; i++) t2[i] = b[i]; return new BigInteger(1, t2); } /** * Montgomery reduce n, modulo mod. This reduces modulo mod and divides * by 2^(32*mlen). Adapted from Colin Plumb's C library. */ private static int[] montReduce(int[] n, int[] mod, int mlen, int inv) { int c=0; int len = mlen; int offset=0; do { int nEnd = n[n.length-1-offset]; int carry = mulAdd(n, mod, offset, mlen, inv * nEnd); c += addOne(n, offset, mlen, carry); offset++; } while(--len > 0); while(c>0) c += subN(n, mod, mlen); while (intArrayCmpToLen(n, mod, mlen) >= 0) subN(n, mod, mlen); return n; } /* * Returns -1, 0 or +1 as big-endian unsigned int array arg1 is less than, * equal to, or greater than arg2 up to length len. */ private static int intArrayCmpToLen(int[] arg1, int[] arg2, int len) { for (int i=0; i<len; i++) { long b1 = arg1[i] & LONG_MASK; long b2 = arg2[i] & LONG_MASK; if (b1 < b2) return -1; if (b1 > b2) return 1; } return 0; } /** * Subtracts two numbers of same length, returning borrow. */ private static int subN(int[] a, int[] b, int len) { long sum = 0; while(--len >= 0) { sum = (a[len] & LONG_MASK) - (b[len] & LONG_MASK) + (sum >> 32); a[len] = (int)sum; } return (int)(sum >> 32); } /** * Multiply an array by one word k and add to result, return the carry */ static int mulAdd(int[] out, int[] in, int offset, int len, int k) { long kLong = k & LONG_MASK; long carry = 0; offset = out.length-offset - 1; for (int j=len-1; j >= 0; j--) { long product = (in[j] & LONG_MASK) * kLong + (out[offset] & LONG_MASK) + carry; out[offset--] = (int)product; carry = product >>> 32; } return (int)carry; } /** * Add one word to the number a mlen words into a. Return the resulting * carry. */ static int addOne(int[] a, int offset, int mlen, int carry) { offset = a.length-1-mlen-offset; long t = (a[offset] & LONG_MASK) + (carry & LONG_MASK); a[offset] = (int)t; if ((t >>> 32) == 0) return 0; while (--mlen >= 0) { if (--offset < 0) { // Carry out of number return 1; } else { a[offset]++; if (a[offset] != 0) return 0; } } return 1; } /** * Returns a BigInteger whose value is (this ** exponent) mod (2**p) */ private BigInteger modPow2(BigInteger exponent, int p) { /* * Perform exponentiation using repeated squaring trick, chopping off * high order bits as indicated by modulus. */ BigInteger result = valueOf(1); BigInteger baseToPow2 = this.mod2(p); int expOffset = 0; int limit = exponent.bitLength(); if (this.testBit(0)) limit = (p-1) < limit ? (p-1) : limit; while (expOffset < limit) { if (exponent.testBit(expOffset)) result = result.multiply(baseToPow2).mod2(p); expOffset++; if (expOffset < limit) baseToPow2 = baseToPow2.square().mod2(p); } return result; } /** * Returns a BigInteger whose value is this mod(2**p). * Assumes that this BigInteger >= 0 and p > 0. */ private BigInteger mod2(int p) { if (bitLength() <= p) return this; // Copy remaining ints of mag int numInts = (p+31)/32; int[] mag = new int[numInts]; for (int i=0; i<numInts; i++) mag[i] = this.mag[i + (this.mag.length - numInts)]; // Mask out any excess bits int excessBits = (numInts << 5) - p; mag[0] &= (1L << (32-excessBits)) - 1; return (mag[0]==0 ? new BigInteger(1, mag) : new BigInteger(mag, 1)); } /** * Returns a BigInteger whose value is <tt>(this<sup>-1</sup> mod m)</tt>. * * @param m the modulus. * @return <tt>this<sup>-1</sup> mod m</tt>. * @throws ArithmeticException <tt> m <= 0</tt>, or this BigInteger * has no multiplicative inverse mod m (that is, this BigInteger * is not <i>relatively prime</i> to m). */ public BigInteger modInverse(BigInteger m) { if (m.signum != 1) throw new ArithmeticException("BigInteger: modulus not positive"); if (m.equals(ONE)) return ZERO; // Calculate (this mod m) BigInteger modVal = this; if (signum < 0 || (intArrayCmp(mag, m.mag) >= 0)) modVal = this.mod(m); if (modVal.equals(ONE)) return ONE; MutableBigInteger a = new MutableBigInteger(modVal); MutableBigInteger b = new MutableBigInteger(m); MutableBigInteger result = a.mutableModInverse(b); return new BigInteger(result, 1); } // Shift Operations /** * Returns a BigInteger whose value is <tt>(this << n)</tt>. * The shift distance, <tt>n</tt>, may be negative, in which case * this method performs a right shift. * (Computes <tt>floor(this * 2<sup>n</sup>)</tt>.) * * @param n shift distance, in bits. * @return <tt>this << n</tt> * @see #shiftRight
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -