< prev index next >
src/java.base/share/classes/java/math/BigInteger.java
Print this page
rev 12150 : 8046943: Leverage CPU Instructions for GHASH and RSA
Summary: Add montgomeryMultiply intrinsics
Reviewed-by: kvn
@@ -260,10 +260,19 @@
* the number are larger than this value, {@code multiply(this)} will
* return {@code square()}.
*/
private static final int MULTIPLY_SQUARE_THRESHOLD = 20;
+ /**
+ * The threshold for using an intrinsic version of
+ * implMontgomeryXXX to perform Montgomery multiplication. If the
+ * number of ints in the number is less than this value we do not
+ * use the intrinsic.
+ */
+ private static final int MONTGOMERY_INTRINSIC_THRESHOLD = 512;
+
+
// Constructors
/**
* Translates a byte sub-array containing the two's-complement binary
* representation of a BigInteger into a BigInteger. The sub-array is
@@ -1637,11 +1646,11 @@
/**
* Multiplies int arrays x and y to the specified lengths and places
* the result into z. There will be no leading zeros in the resultant array.
*/
- private int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
+ private static int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
int xstart = xlen - 1;
int ystart = ylen - 1;
if (z == null || z.length < (xlen+ ylen))
z = new int[xlen+ylen];
@@ -2599,10 +2608,79 @@
}
return (invertResult ? result.modInverse(m) : result);
}
+ // Montgomery multiplication. These are wrappers for
+ // implMontgomeryXX routines which are expected to be replaced by
+ // virtual machine intrinsics. We don't use the intrinsics for
+ // very large operands: MONTGOMERY_INTRINSIC_THRESHOLD should be
+ // larger than any reasonable crypto key.
+ private static int[] montgomeryMultiply(int[] a, int[] b, int[] n, int len, long inv,
+ int[] product) {
+ implMontgomeryMultiplyChecks(a, b, n, len, product);
+ if (len > MONTGOMERY_INTRINSIC_THRESHOLD) {
+ // Very long argument: do not use an intrinsic
+ product = multiplyToLen(a, len, b, len, product);
+ return montReduce(product, n, len, (int)inv);
+ } else {
+ return implMontgomeryMultiply(a, b, n, len, inv, materialize(product, len));
+ }
+ }
+ private static int[] montgomerySquare(int[] a, int[] n, int len, long inv,
+ int[] product) {
+ implMontgomeryMultiplyChecks(a, a, n, len, product);
+ if (len > MONTGOMERY_INTRINSIC_THRESHOLD) {
+ // Very long argument: do not use an intrinsic
+ product = squareToLen(a, len, product);
+ return montReduce(product, n, len, (int)inv);
+ } else {
+ return implMontgomerySquare(a, n, len, inv, materialize(product, len));
+ }
+ }
+
+ // Range-check everything.
+ private static void implMontgomeryMultiplyChecks
+ (int[] a, int[] b, int[] n, int len, int[] product) throws RuntimeException {
+ if (len < 1) {
+ throw new IllegalArgumentException("invalid input length: " + len);
+ }
+
+ if (len < 1) {
+ throw new IllegalArgumentException("invalid input length: " + len);
+ }
+
+ if (len > a.length ||
+ len > b.length ||
+ len > n.length ||
+ (product != null && len > product.length)) {
+ throw new IllegalArgumentException("input array length out of bound: " + len);
+ }
+ }
+
+ // Make sure that the int array z (which is expected to contain
+ // the result of a Montgomery multiplication) is present and
+ // sufficiently large.
+ private static int[] materialize(int[] z, int len) {
+ if (z == null || z.length < len)
+ z = new int[len];
+ return z;
+ }
+
+ // These methods are intended to be be replaced by virtual machine
+ // intrinsics.
+ private static int[] implMontgomeryMultiply(int[] a, int[] b, int[] n, int len,
+ long inv, int[] product) {
+ product = multiplyToLen(a, len, b, len, product);
+ return montReduce(product, n, len, (int)inv);
+ }
+ private static int[] implMontgomerySquare(int[] a, int[] n, int len,
+ long inv, int[] product) {
+ product = squareToLen(a, len, product);
+ return montReduce(product, n, len, (int)inv);
+ }
+
static int[] bnExpModThreshTable = {7, 25, 81, 241, 673, 1793,
Integer.MAX_VALUE}; // Sentinel
/**
* Returns a BigInteger whose value is x to the power of y mod z.
@@ -2677,10 +2755,21 @@
int[] base = mag.clone();
int[] exp = y.mag;
int[] mod = z.mag;
int modLen = mod.length;
+ // Make modLen even. It is conventional to use a cryptographic
+ // modulus that is 512, 768, 1024, or 2048 bits, so this code
+ // will not normally be executed. However, it is necessary for
+ // the correct functioning of the HotSpot intrinsics.
+ if ((modLen & 1) != 0) {
+ int[] x = new int[modLen + 1];
+ System.arraycopy(mod, 0, x, 1, modLen);
+ mod = x;
+ modLen++;
+ }
+
// Select an appropriate window size
int wbits = 0;
int ebits = bitLength(exp, exp.length);
// if exponent is 65537 (0x10001), use minimum window size
if ((ebits != 17) || (exp[0] != 65537)) {
@@ -2695,43 +2784,44 @@
// 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]);
+ // Compute the modular inverse of the least significant 64-bit
+ // digit of the modulus
+ long n0 = (mod[modLen-1] & LONG_MASK) + ((mod[modLen-2] & LONG_MASK) << 32);
+ long inv = -MutableBigInteger.inverseMod64(n0);
// Convert base to Montgomery form
int[] a = leftShift(base, base.length, modLen << 5);
MutableBigInteger q = new MutableBigInteger(),
a2 = new MutableBigInteger(a),
b2 = new MutableBigInteger(mod);
+ b2.normalize(); // MutableBigInteger.divide() assumes that its
+ // divisor is in normal form.
MutableBigInteger r= a2.divide(b2, q);
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];
+ System.arraycopy(table[0], 0, t2, offset, table[0].length);
table[0] = t2;
}
// Set b to the square of the base
- int[] b = squareToLen(table[0], modLen, null);
- b = montReduce(b, mod, modLen, inv);
+ int[] b = montgomerySquare(table[0], mod, modLen, inv, null);
// Set t to high half of b
int[] t = Arrays.copyOf(b, modLen);
// 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);
+ table[i] = montgomeryMultiply(t, table[i-1], mod, modLen, inv, null);
}
// Pre load the window that slides over the exponent
int bitpos = 1 << ((ebits-1) & (32-1));
@@ -2798,12 +2888,11 @@
if (isone) {
b = mult.clone();
isone = false;
} else {
t = b;
- a = multiplyToLen(t, modLen, mult, modLen, a);
- a = montReduce(a, mod, modLen, inv);
+ a = montgomeryMultiply(t, mult, mod, modLen, inv, a);
t = a; a = b; b = t;
}
}
// Check if done
@@ -2811,21 +2900,20 @@
break;
// Square the input
if (!isone) {
t = b;
- a = squareToLen(t, modLen, a);
- a = montReduce(a, mod, modLen, inv);
+ a = montgomerySquare(t, mod, modLen, inv, a);
t = a; a = b; b = t;
}
}
// Convert result out of Montgomery form and return
int[] t2 = new int[2*modLen];
System.arraycopy(b, 0, t2, modLen, modLen);
- b = montReduce(t2, mod, modLen, inv);
+ b = montReduce(t2, mod, modLen, (int)inv);
t2 = Arrays.copyOf(b, modLen);
return new BigInteger(1, t2);
}
< prev index next >