📄 biginteger.java
字号:
if (useMonty) { mQ = m.getMQuote(); // tmp = this * R mod m BigInteger tmp = this.shiftLeft(32 * m.magnitude.length).mod(m); zVal = tmp.magnitude; useMonty = (zVal.length <= m.magnitude.length); if (useMonty) { yAccum = new int[m.magnitude.length + 1]; if (zVal.length < m.magnitude.length) { int[] longZ = new int[m.magnitude.length]; System.arraycopy(zVal, 0, longZ, longZ.length - zVal.length, zVal.length); zVal = longZ; } } } if (!useMonty) { if (magnitude.length <= m.magnitude.length) { //zAccum = new int[m.magnitude.length * 2]; zVal = new int[m.magnitude.length]; System.arraycopy(magnitude, 0, zVal, zVal.length - magnitude.length, magnitude.length); } else { // // in normal practice we'll never see this... // BigInteger tmp = this.remainder(m); //zAccum = new int[m.magnitude.length * 2]; zVal = new int[m.magnitude.length]; System.arraycopy(tmp.magnitude, 0, zVal, zVal.length - tmp.magnitude.length, tmp.magnitude.length); } yAccum = new int[m.magnitude.length * 2]; } yVal = new int[m.magnitude.length]; // // from LSW to MSW // for (int i = 0; i < exponent.magnitude.length; i++) { int v = exponent.magnitude[i]; int bits = 0; if (i == 0) { while (v > 0) { v <<= 1; bits++; } // // first time in initialise y // System.arraycopy(zVal, 0, yVal, 0, zVal.length); v <<= 1; bits++; } while (v != 0) { if (useMonty) { // Montgomery square algo doesn't exist, and a normal // square followed by a Montgomery reduction proved to // be almost as heavy as a Montgomery mulitply. multiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ); } else { square(yAccum, yVal); remainder(yAccum, m.magnitude); System.arraycopy(yAccum, yAccum.length - yVal.length, yVal, 0, yVal.length); zero(yAccum); } bits++; if (v < 0) { if (useMonty) { multiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ); } else { multiply(yAccum, yVal, zVal); remainder(yAccum, m.magnitude); System.arraycopy(yAccum, yAccum.length - yVal.length, yVal, 0, yVal.length); zero(yAccum); } } v <<= 1; } while (bits < 32) { if (useMonty) { multiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ); } else { square(yAccum, yVal); remainder(yAccum, m.magnitude); System.arraycopy(yAccum, yAccum.length - yVal.length, yVal, 0, yVal.length); zero(yAccum); } bits++; } } if (useMonty) { // Return y * R^(-1) mod m by doing y * 1 * R^(-1) mod m zero(zVal); zVal[zVal.length - 1] = 1; multiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ); } return new BigInteger(1, yVal); } /** * return w with w = x * x - w is assumed to have enough space. */ private int[] square(int[] w, int[] x) { long u1, u2, c; if (w.length != 2 * x.length) { throw new IllegalArgumentException("no I don't think so..."); } for (int i = x.length - 1; i != 0; i--) { long v = (x[i] & IMASK); u1 = v * v; u2 = u1 >>> 32; u1 = u1 & IMASK; u1 += (w[2 * i + 1] & IMASK); w[2 * i + 1] = (int)u1; c = u2 + (u1 >> 32); for (int j = i - 1; j >= 0; j--) { u1 = (x[j] & IMASK) * v; u2 = u1 >>> 31; // multiply by 2! u1 = (u1 & 0x7fffffff) << 1; // multiply by 2! u1 += (w[i + j + 1] & IMASK) + c; w[i + j + 1] = (int)u1; c = u2 + (u1 >>> 32); } c += w[i] & IMASK; w[i] = (int)c; w[i - 1] = (int)(c >> 32); } u1 = (x[0] & IMASK); u1 = u1 * u1; u2 = u1 >>> 32; u1 = u1 & IMASK; u1 += (w[1] & IMASK); w[1] = (int)u1; w[0] = (int)(u2 + (u1 >> 32) + w[0]); return w; } /** * return x with x = y * z - x is assumed to have enough space. */ private int[] multiply(int[] x, int[] y, int[] z) { for (int i = z.length - 1; i >= 0; i--) { long a = z[i] & IMASK; long value = 0; for (int j = y.length - 1; j >= 0; j--) { value += a * (y[j] & IMASK) + (x[i + j + 1] & IMASK); x[i + j + 1] = (int)value; value >>>= 32; } x[i] = (int)value; } return x; } private long _extEuclid(long a, long b, long[] uOut) { long res; long u1 = 1; long u3 = a; long v1 = 0; long v3 = b; while (v3 > 0) { long q, tn; q = u3 / v3; tn = u1 - (v1 * q); u1 = v1; v1 = tn; tn = u3 - (v3 * q); u3 = v3; v3 = tn; } uOut[0] = u1; res = (u3 - (u1 * a)) / b; uOut[1] = res; return u3; } private long _modInverse(long v, long m) throws ArithmeticException { if (m < 0) { throw new ArithmeticException("Modulus must be positive"); } long[] x = new long[2]; long gcd = _extEuclid(v, m, x); if (gcd != 1) { throw new ArithmeticException("Numbers not relatively prime."); } if (x[0] < 0) { x[0] = x[0] + m; } return x[0]; } /** * Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size) */ private long getMQuote() { if (mQuote != -1L) { // allready calculated return mQuote; } if ((magnitude[magnitude.length - 1] & 1) == 0) { return -1L; // not for even numbers }/* byte[] bytes = {1, 0, 0, 0, 0}; BigInteger b = new BigInteger(1, bytes); // 2^32 mQuote = this.negate().mod(b).modInverse(b).longValue();*/ long v = (((~this.magnitude[this.magnitude.length - 1]) | 1) & 0xffffffffL); mQuote = _modInverse(v, 0x100000000L); return mQuote; } /** * Montgomery multiplication: a = x * y * R^(-1) mod m * <br> * Based algorithm 14.36 of Handbook of Applied Cryptography. * <br> * <li> m, x, y should have length n </li> * <li> a should have length (n + 1) </li> * <li> b = 2^32, R = b^n </li> * <br> * The result is put in x * <br> * NOTE: the indices of x, y, m, a different in HAC and in Java */ private void multiplyMonty(int[] a, int[] x, int[] y, int[] m, long mQuote) // mQuote = -m^(-1) mod b { int n = m.length; int nMinus1 = n - 1; long y_0 = y[n - 1] & IMASK; // 1. a = 0 (Notation: a = (a_{n} a_{n-1} ... a_{0})_{b} ) for (int i = 0; i <= n; i++) { a[i] = 0; } // 2. for i from 0 to (n - 1) do the following: for (int i = n; i > 0; i--) { long x_i = x[i - 1] & IMASK; // 2.1 u = ((a[0] + (x[i] * y[0]) * mQuote) mod b long u = ((((a[n] & IMASK) + ((x_i * y_0) & IMASK)) & IMASK) * mQuote) & IMASK; // 2.2 a = (a + x_i * y + u * m) / b long prod1 = x_i * y_0; long prod2 = u * (m[n - 1] & IMASK); long tmp = (a[n] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK); long carry = (prod1 >>> 32) + (prod2 >>> 32) + (tmp >>> 32); for (int j = nMinus1; j > 0; j--) { prod1 = x_i * (y[j - 1] & IMASK); prod2 = u * (m[j - 1] & IMASK); tmp = (a[j] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK) + (carry & IMASK); carry = (carry >>> 32) + (prod1 >>> 32) + (prod2 >>> 32) + (tmp >>> 32); a[j + 1] = (int)tmp; // division by b } carry += (a[0] & IMASK); a[1] = (int)carry; a[0] = (int)(carry >>> 32); } // 3. if x >= m the x = x - m if (compareTo(0, a, 0, m) >= 0) { subtract(0, a, 0, m); } // put the result in x System.arraycopy(a, 1, x, 0, n); } public BigInteger multiply(BigInteger val) { if (sign == 0 || val.sign == 0) return BigInteger.ZERO; int[] res = new int[magnitude.length + val.magnitude.length]; return new BigInteger(sign * val.sign, multiply(res, magnitude, val.magnitude)); } public BigInteger negate() { return new BigInteger( -sign, magnitude); } public BigInteger not() { return add(ONE).negate(); } public BigInteger pow(int exp) throws ArithmeticException { if (exp < 0) throw new ArithmeticException("Negative exponent"); if (sign == 0) return (exp == 0 ? BigInteger.ONE : this); BigInteger y, z; y = BigInteger.ONE; z = this; while (exp != 0) { if ((exp & 0x1) == 1) { y = y.multiply(z); } exp >>= 1; if (exp != 0) { z = z.multiply(z); } } return y; } private int remainder(int m) { long acc = 0; for (int pos = 0; pos < magnitude.length; ++pos) { acc = (acc << 32 | ((long)magnitude[pos] & 0xffffffffL)) % m; } return (int) acc; } /** * return x = x % y - done in place (y value preserved) */ private int[] remainder(int[] x, int[] y) { int xyCmp = compareTo(0, x, 0, y); if (xyCmp > 0) { int[] c; int shift = bitLength(0, x) - bitLength(0, y); if (shift > 1) { c = shiftLeft(y, shift - 1); } else { c = new int[x.length]; System.arraycopy(y, 0, c, c.length - y.length, y.length); } subtract(0, x, 0, c); int xStart = 0; int cStart = 0; for (; ; ) { int cmp = compareTo(xStart, x, cStart, c); while (cmp >= 0) { subtract(xStart, x, cStart, c); cmp = compareTo(xStart, x, cStart, c); } xyCmp = compareTo(xStart, x, 0, y); if (xyCmp > 0) { if (x[xStart] == 0) { xStart++; } shift = bitLength(cStart, c) - bitLength(xStart, x); if (shift == 0) { c = shiftRightOne(cStart, c); } else { c = shiftRight(cStart, c, shift); } if (c[cStart] == 0) { cStart++; } } else if (xyCmp == 0) { for (int i = xStart; i != x.length; i++) { x[i] = 0; } break; } else { break; } } } else if (xyCmp == 0) { for (int i = 0; i != x.length; i++) { x[i] = 0; } } return x; } public BigInteger remainder(BigInteger val) throws ArithmeticException { if (val.sign == 0) { throw new ArithmeticException("BigInteger: Divide by zero"); } if (sign == 0) { return BigInteger.ZERO; } int[] res = new int[this.magnitude.length]; System.arraycopy(this.magnitude, 0, res, 0, res.length); return new BigInteger(sign, remainder(res, val.magnitude)); } /** * do a left shift - this returns a new array. */ private int[] shiftLeft(int[] mag, int n) { int nInts = n >>> 5; int nBits = n & 0x1f; int magLen = mag.length; int newMag[] = null; if (nBits == 0) { newMag = new int[magLen + nInts]; System.arraycopy(mag, 0, newMag, 0, magLen); } else { int i = 0; int nBits2 = 32 - nBits; int highBits = mag[0] >>> nBits2; if (highBits != 0) { newMag = new int[magLen + nInts + 1]; newMag[i++] = highBits; } else { newMag = new int[magLen + nInts]; } int m = mag[0]; for (int j = 0; j < magLen - 1; j++) { int next = mag[j + 1]; newMag[i++] = (m << nBits) | (next >>> nBits2); m = next; } newMag[i] = mag[magLen - 1] << nBits; } return newMag; } public BigInteger shiftLeft(int n) { if (sign == 0 || magnitude.length == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -