1 //
   2 // Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
   3 // Copyright (c) 2015, Red Hat Inc. All rights reserved.
   4 // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5 //
   6 // This code is free software; you can redistribute it and/or modify it
   7 // under the terms of the GNU General Public License version 2 only, as
   8 // published by the Free Software Foundation.
   9 //
  10 // This code is distributed in the hope that it will be useful, but WITHOUT
  11 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13 // version 2 for more details (a copy is included in the LICENSE file that
  14 // accompanied this code).
  15 //
  16 // You should have received a copy of the GNU General Public License version
  17 // 2 along with this work; if not, write to the Free Software Foundation,
  18 // Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19 //
  20 // Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21 // or visit www.oracle.com if you need additional information or have any
  22 // questions.
  23 //
  24 //
  25 
  26 import java.lang.invoke.MethodHandle;
  27 import java.lang.invoke.MethodHandles;
  28 import java.lang.invoke.MethodType;
  29 import java.lang.reflect.Constructor;
  30 import java.lang.reflect.Field;
  31 import java.lang.reflect.Method;
  32 import java.math.BigInteger;
  33 import java.util.Arrays;
  34 import java.util.Random;
  35 
  36 /**
  37  * @test
  38  * @bug 8130150
  39  * @library /testlibrary
  40  * @summary Verify that the Montgomery multiply intrinsic works and correctly checks its arguments.
  41  */
  42 
  43 public class MontgomeryMultiplyTest {
  44 
  45     static final MethodHandles.Lookup lookup = MethodHandles.lookup();
  46 
  47     static final MethodHandle montgomeryMultiplyHandle, montgomerySquareHandle;
  48     static final MethodHandle bigIntegerConstructorHandle;
  49     static final Field bigIntegerMagField;
  50 
  51     static {
  52        // Use reflection to gain access to the methods we want to test.
  53         try {
  54             Method m = BigInteger.class.getDeclaredMethod("montgomeryMultiply",
  55                 /*a*/int[].class, /*b*/int[].class, /*n*/int[].class, /*len*/int.class,
  56                 /*inv*/long.class, /*product*/int[].class);
  57             m.setAccessible(true);
  58             montgomeryMultiplyHandle = lookup.unreflect(m);
  59 
  60             m = BigInteger.class.getDeclaredMethod("montgomerySquare",
  61                 /*a*/int[].class, /*n*/int[].class, /*len*/int.class,
  62                 /*inv*/long.class, /*product*/int[].class);
  63             m.setAccessible(true);
  64             montgomerySquareHandle = lookup.unreflect(m);
  65 
  66             Constructor c
  67                 = BigInteger.class.getDeclaredConstructor(int.class, int[].class);
  68             c.setAccessible(true);
  69             bigIntegerConstructorHandle = lookup.unreflectConstructor(c);
  70 
  71             bigIntegerMagField = BigInteger.class.getDeclaredField("mag");
  72             bigIntegerMagField.setAccessible(true);
  73 
  74         } catch (Throwable ex) {
  75             throw new RuntimeException(ex);
  76         }
  77     }
  78 
  79     // Invoke either the BigInteger.montgomeryMultiply or
  80     // BigInteger.montgomerySquare intrinsics.
  81     int[] montgomeryMultiply(int[] a, int[] b, int[] n, int len, long inv,
  82                              int[] product) throws Throwable {
  83         int[] result =
  84             (a == b) ? (int[]) montgomerySquareHandle.invokeExact(a, n, len, inv, product)
  85                      : (int[]) montgomeryMultiplyHandle.invokeExact(a, b, n, len, inv, product);
  86         return Arrays.copyOf(result, len);
  87     }
  88 
  89     // Invoke the private constructor BigInteger(int[]).
  90     BigInteger newBigInteger(int[] val) throws Throwable {
  91         return (BigInteger) bigIntegerConstructorHandle.invokeExact(1, val);
  92     }
  93 
  94     // Get the private field BigInteger.mag
  95     int[] mag(BigInteger n) {
  96         try {
  97             return (int[]) bigIntegerMagField.get(n);
  98         } catch (Exception ex) {
  99             throw new RuntimeException(ex);
 100         }
 101     }
 102 
 103     // Montgomery multiplication
 104     // Calculate a * b * r^-1 mod n)
 105     //
 106     // R is a power of the word size
 107     // N' = R^-1 mod N
 108     //
 109     // T := ab
 110     // m := (T mod R)N' mod R [so 0 <= m < R]
 111     // t := (T + mN)/R
 112     // if t >= N then return t - N else return t
 113     //
 114     BigInteger montgomeryMultiply(BigInteger a, BigInteger b, BigInteger N,
 115             int len, BigInteger n_prime)
 116             throws Throwable {
 117         BigInteger T = a.multiply(b);
 118         BigInteger R = BigInteger.ONE.shiftLeft(len*32);
 119         BigInteger mask = R.subtract(BigInteger.ONE);
 120         BigInteger m = (T.and(mask)).multiply(n_prime);
 121         m = m.and(mask); // i.e. m.mod(R)
 122         T = T.add(m.multiply(N));
 123         T = T.shiftRight(len*32); // i.e. T.divide(R)
 124         if (T.compareTo(N) > 0) {
 125             T = T.subtract(N);
 126         }
 127         return T;
 128     }
 129 
 130     BigInteger montgomeryMultiply(int[] a_words, int[] b_words, int[] n_words,
 131             int len, BigInteger inv)
 132             throws Throwable {
 133         BigInteger t = montgomeryMultiply(
 134                 newBigInteger(a_words),
 135                 newBigInteger(b_words),
 136                 newBigInteger(n_words),
 137                 len, inv);
 138         return t;
 139     }
 140 
 141     // Check that the Montgomery multiply intrinsic returns the same
 142     // result as the longhand calculation.
 143     void check(int[] a_words, int[] b_words, int[] n_words, int len, BigInteger inv)
 144             throws Throwable {
 145         BigInteger n = newBigInteger(n_words);
 146         BigInteger slow = montgomeryMultiply(a_words, b_words, n_words, len, inv);
 147         BigInteger fast
 148             = newBigInteger(montgomeryMultiply
 149                             (a_words, b_words, n_words, len, inv.longValue(), null));
 150         // The intrinsic may not return the same value as the longhand
 151         // calculation but they must have the same residue mod N.
 152         if (!slow.mod(n).equals(fast.mod(n))) {
 153             throw new RuntimeException();
 154         }
 155     }
 156 
 157     Random rnd = new Random(0);
 158 
 159     int[] random_val(int len) {
 160         int[] val = new int[len];
 161         for (int i = 0; i < len; i++)
 162             val[i] = rnd.nextInt();
 163         return val;
 164     }
 165 
 166     // Test the Montgomery multiply intrinsic with a bunch of random
 167     // values of varying lengths.  Do this for long enough that the
 168     // caller of the intrinsic is C2-compiled.
 169     void testResultValues() throws Throwable {
 170         for (int j = 10; j > 0; j--) {
 171             // Construct a random prime whose length in words is even
 172             int lenInBits = (rnd.nextInt(32)+1)*64 + rnd.nextInt(32) + 32;
 173             int lenInInts = (lenInBits + 31)/32;
 174             BigInteger mod = new BigInteger(lenInBits , 2, rnd);
 175             BigInteger r = BigInteger.ONE.shiftLeft(lenInInts*32);
 176             BigInteger n_prime = mod.modInverse(r).negate();
 177 
 178             for (int i = 0; i < 10000; i++) {
 179                 // multiply
 180                 check(random_val(lenInInts), random_val(lenInInts), mag(mod), lenInInts, n_prime);
 181                 // square
 182                 int[] tmp = random_val(lenInInts);
 183                 check(tmp, tmp, mag(mod), lenInInts, n_prime);
 184             }
 185         }
 186     }
 187 
 188     // Range checks
 189     void testOneMontgomeryMultiplyCheck(int[] a, int[] b, int[] n, int len, long inv,
 190                                         int[] product, Class klass) {
 191         try {
 192             montgomeryMultiply(a, b, n, len, inv, product);
 193         } catch (Throwable ex) {
 194             if (klass.isAssignableFrom(ex.getClass()))
 195                 return;
 196             throw new RuntimeException(klass + " expected, " + ex + " was thrown");
 197         }
 198         throw new RuntimeException(klass + " expected, was not thrown");
 199     }
 200 
 201     void testOneMontgomeryMultiplyCheck(int[] a, int[] b, BigInteger n, int len, BigInteger inv,
 202             Class klass) {
 203         testOneMontgomeryMultiplyCheck(a, b, mag(n), len, inv.longValue(), null, klass);
 204     }
 205 
 206     void testOneMontgomeryMultiplyCheck(int[] a, int[] b, BigInteger n, int len, BigInteger inv,
 207             int[] product, Class klass) {
 208         testOneMontgomeryMultiplyCheck(a, b, mag(n), len, inv.longValue(), product, klass);
 209     }
 210 
 211     void testMontgomeryMultiplyChecks() {
 212         int[] blah = random_val(40);
 213         int[] small = random_val(39);
 214         BigInteger mod = new BigInteger(40*32 , 2, rnd);
 215         BigInteger r = BigInteger.ONE.shiftLeft(40*32);
 216         BigInteger n_prime = mod.modInverse(r).negate();
 217 
 218         // Length out of range: square
 219         testOneMontgomeryMultiplyCheck(blah, blah, mod, 41, n_prime, IllegalArgumentException.class);
 220         testOneMontgomeryMultiplyCheck(blah, blah, mod, 0, n_prime, IllegalArgumentException.class);
 221         testOneMontgomeryMultiplyCheck(blah, blah, mod, -1, n_prime, IllegalArgumentException.class);
 222         // As above, but for multiply
 223         testOneMontgomeryMultiplyCheck(blah, blah.clone(), mod, 41, n_prime, IllegalArgumentException.class);
 224         testOneMontgomeryMultiplyCheck(blah, blah.clone(), mod, 0, n_prime, IllegalArgumentException.class);
 225         testOneMontgomeryMultiplyCheck(blah, blah.clone(), mod, 0, n_prime, IllegalArgumentException.class);
 226 
 227         // Length odd
 228         testOneMontgomeryMultiplyCheck(small, small, mod, 39, n_prime, IllegalArgumentException.class);
 229         testOneMontgomeryMultiplyCheck(small, small, mod, 0, n_prime, IllegalArgumentException.class);
 230         testOneMontgomeryMultiplyCheck(small, small, mod, -1, n_prime, IllegalArgumentException.class);
 231         // As above, but for multiply
 232         testOneMontgomeryMultiplyCheck(small, small.clone(), mod, 39, n_prime, IllegalArgumentException.class);
 233         testOneMontgomeryMultiplyCheck(small, small.clone(), mod, 0, n_prime, IllegalArgumentException.class);
 234         testOneMontgomeryMultiplyCheck(small, small.clone(), mod, -1, n_prime, IllegalArgumentException.class);
 235 
 236         // array too small
 237         testOneMontgomeryMultiplyCheck(blah, blah, mod, 40, n_prime, small, IllegalArgumentException.class);
 238         testOneMontgomeryMultiplyCheck(blah, blah.clone(), mod, 40, n_prime, small, IllegalArgumentException.class);
 239         testOneMontgomeryMultiplyCheck(small, blah, mod, 40, n_prime, blah, IllegalArgumentException.class);
 240         testOneMontgomeryMultiplyCheck(blah, small, mod, 40, n_prime, blah, IllegalArgumentException.class);
 241         testOneMontgomeryMultiplyCheck(blah, blah, mod, 40, n_prime, small, IllegalArgumentException.class);
 242         testOneMontgomeryMultiplyCheck(small, small, mod, 40, n_prime, blah, IllegalArgumentException.class);
 243     }
 244 
 245     public static void main(String args[]) {
 246         try {
 247             new MontgomeryMultiplyTest().testMontgomeryMultiplyChecks();
 248             new MontgomeryMultiplyTest().testResultValues();
 249         } catch (Throwable ex) {
 250             throw new RuntimeException(ex);
 251         }
 252      }
 253 }