/* * This file is part of "MidpSSH". * * This file was adapted from Bouncy Castle JCE (www.bouncycastle.org) for * MidpSSH by Karl von Randow */ package org.bbssh.ssh.v2; import java.util.Stack; import net.rim.device.api.crypto.RandomSource; public class BigInteger { private int sign; // -1 means -ve; +1 means +ve; 0 means 0; private int[] magnitude; // array of ints with [0] being the most // significant private int nBits = -1; // cache bitCount() value private int nBitLength = -1; // cache bitLength() value private static final long IMASK = 0xffffffffL; private long mQuote = -1L; // -m^(-1) mod b, b = 2^32 (see Montgomery mult.) private BigInteger() { } // private BigInteger2(int nWords) { // sign = 1; // magnitude = new int[nWords]; // } private BigInteger(int signum, int[] mag) { sign = signum; if (mag.length > 0) { int i = 0; while (i < mag.length && mag[i] == 0) { i++; } if (i == 0) { magnitude = mag; } else { // strip leading 0 bytes int[] newMag = new int[mag.length - i]; System.arraycopy(mag, i, newMag, 0, newMag.length); magnitude = newMag; if (newMag.length == 0) sign = 0; } } else { magnitude = mag; sign = 0; } } public BigInteger(String sval) throws NumberFormatException { this(sval, 10); } public BigInteger(String sval, int rdx) throws NumberFormatException { if (sval.length() == 0) { throw new NumberFormatException("Zero length BigInteger"); } if (rdx < Character.MIN_RADIX || rdx > Character.MAX_RADIX) { throw new NumberFormatException("Radix out of range"); } int index = 0; sign = 1; if (sval.charAt(0) == '-') { if (sval.length() == 1) { throw new NumberFormatException("Zero length BigInteger"); } sign = -1; index = 1; } // strip leading zeros from the string value while (index < sval.length() && Character.digit(sval.charAt(index), rdx) == 0) { index++; } if (index >= sval.length()) { // zero value - we're done sign = 0; magnitude = new int[0]; return; } // //// // could we work out the max number of ints required to store // sval.length digits in the given base, then allocate that // storage in one hit?, then generate the magnitude in one hit too? // //// BigInteger b = BigInteger.ZERO; BigInteger r = valueOf(rdx); while (index < sval.length()) { // (optimise this by taking chunks of digits instead?) b = b.multiply(r).add(valueOf(Character.digit(sval.charAt(index), rdx))); index++; } magnitude = b.magnitude; return; } public BigInteger(byte[] bval) throws NumberFormatException { if (bval.length == 0) { throw new NumberFormatException("Zero length BigInteger"); } sign = 1; if (bval[0] < 0) { int iBval; sign = -1; // strip leading sign bytes for (iBval = 0; iBval < bval.length && bval[iBval] == -1; iBval++) ; magnitude = new int[(bval.length - iBval) / 2 + 1]; // copy bytes to magnitude // invert bytes then add one to find magnitude of value } else { // strip leading zero bytes and return magnitude bytes magnitude = makeMagnitude(bval); } } private int[] makeMagnitude(byte[] bval) { int i; int[] mag; int firstSignificant; // strip leading zeros for (firstSignificant = 0; firstSignificant < bval.length && bval[firstSignificant] == 0; firstSignificant++) ; if (firstSignificant >= bval.length) { return new int[0]; } int nInts = (bval.length - firstSignificant + 3) / 4; int bCount = (bval.length - firstSignificant) % 4; if (bCount == 0) bCount = 4; mag = new int[nInts]; int v = 0; int magnitudeIndex = 0; for (i = firstSignificant; i < bval.length; i++) { v <<= 8; v |= bval[i] & 0xff; bCount--; if (bCount <= 0) { mag[magnitudeIndex] = v; magnitudeIndex++; bCount = 4; v = 0; } } if (magnitudeIndex < mag.length) { mag[magnitudeIndex] = v; } return mag; } public BigInteger(int sign, byte[] mag) throws NumberFormatException { if (sign < -1 || sign > 1) { throw new NumberFormatException("Invalid sign value"); } if (sign == 0) { this.sign = 1; // changed from 0 to 1 this.magnitude = new int[0]; return; } // copy bytes this.magnitude = makeMagnitude(mag); this.sign = sign; } public BigInteger(int numBits) throws IllegalArgumentException { if (numBits < 0) { throw new IllegalArgumentException("numBits must be non-negative"); } int nBytes = (numBits + 7) / 8; byte[] b = new byte[nBytes]; if (nBytes > 0) { RandomSource.getBytes(b); // strip off any excess bits in the MSB b[0] &= rndMask[8 * nBytes - numBits]; } this.magnitude = makeMagnitude(b); this.sign = 1; this.nBits = -1; this.nBitLength = -1; } private static final byte[] rndMask = { (byte) 255, 127, 63, 31, 15, 7, 3, 1 }; public BigInteger(int bitLength, int certainty) throws ArithmeticException { int nBytes = (bitLength + 7) / 8; byte[] b = new byte[nBytes]; do { if (nBytes > 0) { RandomSource.getBytes(b); // strip off any excess bits in the MSB b[0] &= rndMask[8 * nBytes - bitLength]; } this.magnitude = makeMagnitude(b); this.sign = 1; this.nBits = -1; this.nBitLength = -1; this.mQuote = -1L; if (certainty > 0 && bitLength > 2) { this.magnitude[this.magnitude.length - 1] |= 1; } } while (this.bitLength() != bitLength || !this.isProbablePrime(certainty)); } public BigInteger abs() { return (sign >= 0) ? this : this.negate(); } /** * return a = a + b - b preserved. */ private int[] add(int[] a, int[] b) { int tI = a.length - 1; int vI = b.length - 1; long m = 0; while (vI >= 0) { m += (((long) a[tI]) & IMASK) + (((long) b[vI--]) & IMASK); a[tI--] = (int) m; m >>>= 32; } while (tI >= 0 && m != 0) { m += (((long) a[tI]) & IMASK); a[tI--] = (int) m; m >>>= 32; } return a; } public BigInteger add(BigInteger val) throws ArithmeticException { if (val.sign == 0 || val.magnitude.length == 0) return this; if (this.sign == 0 || this.magnitude.length == 0) return val; if (val.sign < 0) { if (this.sign > 0) return this.subtract(val.negate()); } else { if (this.sign < 0) return val.subtract(this.negate()); } // both BigIntegers are either +ve or -ve; set the sign later int[] mag, op; if (this.magnitude.length < val.magnitude.length) { mag = new int[val.magnitude.length + 1]; System.arraycopy(val.magnitude, 0, mag, 1, val.magnitude.length); op = this.magnitude; } else { mag = new int[this.magnitude.length + 1]; System.arraycopy(this.magnitude, 0, mag, 1, this.magnitude.length); op = val.magnitude; } return new BigInteger(this.sign, add(mag, op)); } public int bitCount() { if (nBits == -1) { nBits = 0; for (int i = 0; i < magnitude.length; i++) { nBits += bitCounts[magnitude[i] & 0xff]; nBits += bitCounts[(magnitude[i] >> 8) & 0xff]; nBits += bitCounts[(magnitude[i] >> 16) & 0xff]; nBits += bitCounts[(magnitude[i] >> 24) & 0xff]; } } return nBits; } private final static byte[] bitCounts = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 }; private int bitLength(int indx, int[] mag) { int bitLength; if (mag.length == 0) { return 0; } else { while (indx != mag.length && mag[indx] == 0) { indx++; } if (indx == mag.length) { return 0; } // bit length for everything after the first int bitLength = 32 * ((mag.length - indx) - 1); // and determine bitlength of first int bitLength += bitLen(mag[indx]); if (sign < 0) { // Check if magnitude is a power of two boolean pow2 = ((bitCounts[mag[indx] & 0xff]) + (bitCounts[(mag[indx] >> 8) & 0xff]) + (bitCounts[(mag[indx] >> 16) & 0xff]) + (bitCounts[(mag[indx] >> 24) & 0xff])) == 1; for (int i = indx + 1; i < mag.length && pow2; i++) { pow2 = (mag[i] == 0); } bitLength -= (pow2 ? 1 : 0); } } return bitLength; } public int bitLength() { if (nBitLength == -1) { if (sign == 0) { nBitLength = 0; } else { nBitLength = bitLength(0, magnitude); } } return nBitLength; } // // bitLen(val) is the number of bits in val. // static int bitLen(int w) { // Binary search - decision tree (5 tests, rarely 6) return (w < 1 << 15 ? (w < 1 << 7 ? (w < 1 << 3 ? (w < 1 << 1 ? (w < 1 << 0 ? (w < 0 ? 32 : 0) : 1) : (w < 1 << 2 ? 2 : 3)) : (w < 1 << 5 ? (w < 1 << 4 ? 4 : 5) : (w < 1 << 6 ? 6 : 7))) : (w < 1 << 11 ? (w < 1 << 9 ? (w < 1 << 8 ? 8 : 9) : (w < 1 << 10 ? 10 : 11)) : (w < 1 << 13 ? (w < 1 << 12 ? 12 : 13) : (w < 1 << 14 ? 14 : 15)))) : (w < 1 << 23 ? (w < 1 << 19 ? (w < 1 << 17 ? (w < 1 << 16 ? 16 : 17) : (w < 1 << 18 ? 18 : 19)) : (w < 1 << 21 ? (w < 1 << 20 ? 20 : 21) : (w < 1 << 22 ? 22 : 23))) : (w < 1 << 27 ? (w < 1 << 25 ? (w < 1 << 24 ? 24 : 25) : (w < 1 << 26 ? 26 : 27)) : (w < 1 << 29 ? (w < 1 << 28 ? 28 : 29) : (w < 1 << 30 ? 30 : 31))))); } // private final static byte[] bitLengths = { 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, // 4, // 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, // 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 8, 8, 8 }; public int compareTo(Object o) { return compareTo((BigInteger) o); } /** * unsigned comparison on two arrays - note the arrays may start with * leading zeros. */ private int compareTo(int xIndx, int[] x, int yIndx, int[] y) { while (xIndx != x.length && x[xIndx] == 0) { xIndx++; } while (yIndx != y.length && y[yIndx] == 0) { yIndx++; } if ((x.length - xIndx) < (y.length - yIndx)) { return -1; } if ((x.length - xIndx) > (y.length - yIndx)) { return 1; } // lengths of magnitudes the same, test the magnitude values while (xIndx < x.length) { long v1 = (long) (x[xIndx++]) & IMASK; long v2 = (long) (y[yIndx++]) & IMASK; if (v1 < v2) { return -1; } if (v1 > v2) { return 1; } } return 0; } public int compareTo(BigInteger val) { if (sign < val.sign) return -1; if (sign > val.sign) return 1; return compareTo(0, magnitude, 0, val.magnitude); } /** * return z = x / y - done in place (z value preserved, x contains the * remainder) */ private int[] divide(int[] x, int[] y) { int xyCmp = compareTo(0, x, 0, y); int[] count; if (xyCmp > 0) { int[] c; int shift = bitLength(0, x) - bitLength(0, y); if (shift > 1) { c = shiftLeft(y, shift - 1); count = shiftLeft(ONE.magnitude, shift - 1); if (shift % 32 == 0) { // Special case where the shift is the size of an int. int countSpecial[] = new int[shift / 32 + 1]; System.arraycopy(count, 0, countSpecial, 1, countSpecial.length - 1); countSpecial[0] = 0; count = countSpecial; } } else { c = new int[x.length]; count = new int[1]; System.arraycopy(y, 0, c, c.length - y.length, y.length); count[0] = 1; } int[] iCount = new int[count.length]; subtract(0, x, 0, c); System.arraycopy(count, 0, iCount, 0, count.length); int xStart = 0; int cStart = 0; int iCountStart = 0; for (;;) { int cmp = compareTo(xStart, x, cStart, c); while (cmp >= 0) { subtract(xStart, x, cStart, c); add(count, iCount); 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); iCount = shiftRightOne(iCountStart, iCount); } else { c = shiftRight(cStart, c, shift); iCount = shiftRight(iCountStart, iCount, shift); } if (c[cStart] == 0) { cStart++; } if (iCount[iCountStart] == 0) { iCountStart++; } } else if (xyCmp == 0) { add(count, ONE.magnitude); for (int i = xStart; i != x.length; i++) { x[i] = 0; } break; } else { break; } } } else if (xyCmp == 0) { count = new int[1]; count[0] = 1; } else { count = new int[1]; count[0] = 0; } return count; } public BigInteger divide(BigInteger val) throws ArithmeticException { if (val.sign == 0) { throw new ArithmeticException("Divide by zero"); } if (sign == 0) { return BigInteger.ZERO; } if (val.compareTo(BigInteger.ONE) == 0) { return this; } int[] mag = new int[this.magnitude.length]; System.arraycopy(this.magnitude, 0, mag, 0, mag.length); return new BigInteger(this.sign * val.sign, divide(mag, val.magnitude)); } public BigInteger[] divideAndRemainder(BigInteger val) throws ArithmeticException { if (val.sign == 0) { throw new ArithmeticException("Divide by zero"); } BigInteger biggies[] = new BigInteger[2]; if (sign == 0) { biggies[0] = biggies[1] = BigInteger.ZERO; return biggies; } if (val.compareTo(BigInteger.ONE) == 0) { biggies[0] = this; biggies[1] = BigInteger.ZERO; return biggies; } int[] remainder = new int[this.magnitude.length]; System.arraycopy(this.magnitude, 0, remainder, 0, remainder.length); int[] quotient = divide(remainder, val.magnitude); biggies[0] = new BigInteger(this.sign * val.sign, quotient); biggies[1] = new BigInteger(this.sign, remainder); return biggies; } public boolean equals(Object val) { if (val == this) return true; if (!(val instanceof BigInteger)) return false; BigInteger biggie = (BigInteger) val; if (biggie.sign != sign || biggie.magnitude.length != magnitude.length) return false; for (int i = 0; i < magnitude.length; i++) { if (biggie.magnitude[i] != magnitude[i]) return false; } return true; } public BigInteger gcd(BigInteger val) { if (val.sign == 0) return this.abs(); else if (sign == 0) return val.abs(); BigInteger r; BigInteger u = this; BigInteger v = val; while (v.sign != 0) { r = u.mod(v); u = v; v = r; } return u; } public int hashCode() { return 0; } public int intValue() { if (magnitude.length == 0) { return 0; } if (sign < 0) { return -magnitude[magnitude.length - 1]; } else { return magnitude[magnitude.length - 1]; } } /** * return whether or not a BigInteger2 is probably prime with a probability * of 1 - (1/2)**certainty. * <p> * From Knuth Vol 2, pg 395. */ public boolean isProbablePrime(int certainty) { if (certainty == 0) { return true; } BigInteger n = this.abs(); if (n.equals(TWO)) { return true; } if (n.equals(ONE) || !n.testBit(0)) { return false; } if ((certainty & 0x1) == 1) { certainty = certainty / 2 + 1; } else { certainty /= 2; } // // let n = 1 + 2^kq // BigInteger q = n.subtract(ONE); int k = q.getLowestSetBit(); q = q.shiftRight(k); for (int i = 0; i <= certainty; i++) { BigInteger x; do { x = new BigInteger(n.bitLength()); } while (x.compareTo(ONE) <= 0 || x.compareTo(n) >= 0); int j = 0; BigInteger y = x.modPow(q, n); while (!((j == 0 && y.equals(ONE)) || y.equals(n.subtract(ONE)))) { if (j > 0 && y.equals(ONE)) { return false; } if (++j == k) { return false; } y = y.modPow(TWO, n); } } return true; } public long longValue() { long val = 0; if (magnitude.length == 0) { return 0; } if (magnitude.length > 1) { val = ((long) magnitude[magnitude.length - 2] << 32) | (magnitude[magnitude.length - 1] & IMASK); } else { val = (magnitude[magnitude.length - 1] & IMASK); } if (sign < 0) { return -val; } else { return val; } } public BigInteger max(BigInteger val) { return (compareTo(val) > 0) ? this : val; } public BigInteger min(BigInteger val) { return (compareTo(val) < 0) ? this : val; } public BigInteger mod(BigInteger m) throws ArithmeticException { if (m.sign <= 0) { throw new ArithmeticException("BigInteger: modulus is not positive"); } BigInteger biggie = this.remainder(m); return (biggie.sign >= 0 ? biggie : biggie.add(m)); } public BigInteger modInverse(BigInteger m) throws ArithmeticException { if (m.sign != 1) { throw new ArithmeticException("Modulus must be positive"); } BigInteger x = new BigInteger(); BigInteger y = new BigInteger(); BigInteger gcd = BigInteger.extEuclid(this, m, x, y); if (!gcd.equals(BigInteger.ONE)) { throw new ArithmeticException("Numbers not relatively prime."); } if (x.compareTo(BigInteger.ZERO) < 0) { x = x.add(m); } return x; } /** * Calculate the numbers u1, u2, and u3 such that: * * u1 * a + u2 * b = u3 * * where u3 is the greatest common divider of a and b. a and b using the * extended Euclid algorithm (refer p. 323 of The Art of Computer * Programming vol 2, 2nd ed). This also seems to have the side effect of * calculating some form of multiplicative inverse. * * @param a * First number to calculate gcd for * @param b * Second number to calculate gcd for * @param u1Out * the return object for the u1 value * @param u2Out * the return object for the u2 value * @return The greatest common divisor of a and b */ private static BigInteger extEuclid(BigInteger a, BigInteger b, BigInteger u1Out, BigInteger u2Out) { BigInteger res; BigInteger u1 = BigInteger.ONE; BigInteger u3 = a; BigInteger v1 = BigInteger.ZERO; BigInteger v3 = b; while (v3.compareTo(BigInteger.ZERO) > 0) { BigInteger q; BigInteger tn; q = u3.divide(v3); tn = u1.subtract(v1.multiply(q)); u1 = v1; v1 = tn; tn = u3.subtract(v3.multiply(q)); u3 = v3; v3 = tn; } u1Out.sign = u1.sign; u1Out.magnitude = u1.magnitude; res = u3.subtract(u1.multiply(a)).divide(b); u2Out.sign = res.sign; u2Out.magnitude = res.magnitude; return u3; } /** * zero out the array x */ private void zero(int[] x) { for (int i = 0; i != x.length; i++) { x[i] = 0; } } public BigInteger modPow(BigInteger exponent, BigInteger m) throws ArithmeticException { // @todo if we need to keep this in the end, reference // http://developer.classpath.org/doc/java/math/BigInteger-source.html // there's a much more efficient way posible... int[] zVal = null; int[] yAccum = null; int[] yVal; // Montgomery exponentiation is only possible if the modulus is odd, // but AFAIK, this is always the case for crypto algo's boolean useMonty = ((m.magnitude[m.magnitude.length - 1] & 1) == 1); long mQ = 0; 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[] foo = new int[m.magnitude.length]; System.arraycopy(zVal, 0, foo, foo.length - zVal.length, zVal.length); zVal = foo; } } } 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; } /** * 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(); 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 */ public 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 for (int i = 0; i < n; i++) { x[i] = a[i + 1]; } } 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 pow(int exp) throws ArithmeticException { if (exp < 0) throw new ArithmeticException("Negative exponent"); if (sign == 0) return (exp == 0 ? BigInteger.ONE : this); BigInteger y; BigInteger 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; } /** * 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]; for (int i = 0; i < magLen; i++) { newMag[i] = mag[i]; } } 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) { return ZERO; } if (n == 0) { return this; } if (n < 0) { return shiftRight(-n); } return new BigInteger(sign, shiftLeft(magnitude, n)); } /** * do a right shift - this does it in place. */ private int[] shiftRight(int start, int[] mag, int n) { int nInts = (n >>> 5) + start; int nBits = n & 0x1f; int magLen = mag.length; if (nInts != start) { int delta = (nInts - start); for (int i = magLen - 1; i >= nInts; i--) { mag[i] = mag[i - delta]; } for (int i = nInts - 1; i >= start; i--) { mag[i] = 0; } } if (nBits != 0) { int nBits2 = 32 - nBits; int m = mag[magLen - 1]; for (int i = magLen - 1; i >= nInts + 1; i--) { int next = mag[i - 1]; mag[i] = (m >>> nBits) | (next << nBits2); m = next; } mag[nInts] >>>= nBits; } return mag; } /** * do a right shift by one - this does it in place. */ private int[] shiftRightOne(int start, int[] mag) { int magLen = mag.length; int m = mag[magLen - 1]; for (int i = magLen - 1; i >= start + 1; i--) { int next = mag[i - 1]; mag[i] = (m >>> 1) | (next << 31); m = next; } mag[start] >>>= 1; return mag; } public BigInteger shiftRight(int n) { if (n == 0) { return this; } if (n < 0) { return shiftLeft(-n); } if (n >= bitLength()) { return (this.sign < 0 ? valueOf(-1) : BigInteger.ZERO); } int[] res = new int[this.magnitude.length]; System.arraycopy(this.magnitude, 0, res, 0, res.length); return new BigInteger(this.sign, shiftRight(0, res, n)); } public int signum() { return sign; } /** * returns x = x - y - we assume x is >= y */ private int[] subtract(int xStart, int[] x, int yStart, int[] y) { int iT = x.length - 1; int iV = y.length - 1; long m; int borrow = 0; do { m = (((long) x[iT]) & IMASK) - (((long) y[iV--]) & IMASK) + borrow; x[iT--] = (int) m; if (m < 0) { borrow = -1; } else { borrow = 0; } } while (iV >= yStart); while (iT >= xStart) { m = (((long) x[iT]) & IMASK) + borrow; x[iT--] = (int) m; if (m < 0) { borrow = -1; } else { break; } } return x; } public BigInteger subtract(BigInteger val) { if (val.sign == 0 || val.magnitude.length == 0) { return this; } if (sign == 0 || magnitude.length == 0) { return val.negate(); } if (val.sign < 0) { if (this.sign > 0) return this.add(val.negate()); } else { if (this.sign < 0) return this.add(val.negate()); } BigInteger bigun; BigInteger littlun; int compare = compareTo(val); if (compare == 0) { return ZERO; } if (compare < 0) { bigun = val; littlun = this; } else { bigun = this; littlun = val; } int res[] = new int[bigun.magnitude.length]; System.arraycopy(bigun.magnitude, 0, res, 0, res.length); return new BigInteger(this.sign * compare, subtract(0, res, 0, littlun.magnitude)); } public byte[] toByteArray() { int bitLength = bitLength(); byte[] bytes = new byte[bitLength / 8 + 1]; int bytesCopied = 4; int mag = 0; int ofs = magnitude.length - 1; int carry = 1; long lMag; for (int i = bytes.length - 1; i >= 0; i--) { if (bytesCopied == 4 && ofs >= 0) { if (sign < 0) { // we are dealing with a +ve number and we want a -ve one, // so // invert the magnitude ints and add 1 (propagating the // carry) // to make a 2's complement -ve number lMag = ~magnitude[ofs--] & IMASK; lMag += carry; if ((lMag & ~IMASK) != 0) carry = 1; else carry = 0; mag = (int) (lMag & IMASK); } else { mag = magnitude[ofs--]; } bytesCopied = 1; } else { mag >>>= 8; bytesCopied++; } bytes[i] = (byte) mag; } return bytes; } public String toString() { return toString(10); } public String toString(int rdx) { if (magnitude == null) { return "null"; } else if (sign == 0) { return "0"; } String s = ""; String h; if (rdx == 16) { for (int i = 0; i < magnitude.length; i++) { h = "0000000" + Integer.toHexString(magnitude[i]); h = h.substring(h.length() - 8); s = s + h; } } else { // This is algorithm 1a from chapter 4.4 in Seminumerical // Algorithms, slow but it works Stack S = new Stack(); BigInteger base = new BigInteger(Integer.toString(rdx, rdx), rdx); // The sign is handled separatly. // Notice however that for this to work, radix 16 _MUST_ be a // special case, // unless we want to enter a recursion well. In their infinite // wisdom, why did not // the Sun engineers made a c'tor for BigIntegers taking a // BigInteger2 as parameter? // (Answer: Becuase Sun's BigIntger is clonable, something // bouncycastle's isn't.) BigInteger u = new BigInteger(this.abs().toString(16), 16); BigInteger b; // For speed, maye these test should look directly a // u.magnitude.length? while (!u.equals(BigInteger.ZERO)) { b = u.mod(base); if (b.equals(BigInteger.ZERO)) S.push("0"); else S.push(Integer.toString(b.magnitude[0], rdx)); u = u.divide(base); } // Then pop the stack while (!S.empty()) s = s + S.pop(); } // Strip leading zeros. while (s.length() > 1 && s.charAt(0) == '0') s = s.substring(1); if (s.length() == 0) s = "0"; else if (sign == -1) s = "-" + s; return s; } public static final BigInteger ZERO = new BigInteger(0, new byte[0]); public static final BigInteger ONE = valueOf(1); public static final BigInteger TWO = valueOf(2); public static BigInteger valueOf(long val) { if (val == 0) { return BigInteger.ZERO; } // store val into a byte array byte[] b = new byte[8]; for (int i = 0; i < 8; i++) { b[7 - i] = (byte) val; val >>= 8; } return new BigInteger(b); } // private int max(int a, int b) { // if (a < b) // return b; // return a; // } public int getLowestSetBit() { if (this.equals(ZERO)) { return -1; } int w = magnitude.length - 1; while (w >= 0) { if (magnitude[w] != 0) { break; } w--; } int b = 31; while (b > 0) { if ((magnitude[w] << b) == 0x80000000) { break; } b--; } return (((magnitude.length - 1) - w) * 32 + (31 - b)); } public boolean testBit(int n) throws ArithmeticException { if (n < 0) { throw new ArithmeticException("Bit position must not be negative"); } if ((n / 32) >= magnitude.length) { return sign < 0; } return ((magnitude[(magnitude.length - 1) - n / 32] >> (n % 32)) & 1) > 0; } }