Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/compiler/intrinsics/bigInteger/MontgomeryMultiplyTest.java
41153 views
1
/*
2
* Copyright (c) 2000, 2021, 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
* @test
27
* @bug 8130150 8131779 8139907
28
* @summary Verify that the Montgomery multiply and square intrinsic works and correctly checks their arguments.
29
* @requires vm.flavor == "server" & !vm.emulatedClient
30
* @modules java.base/jdk.internal.misc:open
31
* @modules java.base/java.math:open
32
* @library /test/lib /
33
*
34
* @build sun.hotspot.WhiteBox
35
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
36
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
37
* compiler.intrinsics.bigInteger.MontgomeryMultiplyTest
38
*/
39
40
package compiler.intrinsics.bigInteger;
41
42
import jdk.test.lib.Platform;
43
import sun.hotspot.WhiteBox;
44
import compiler.whitebox.CompilerWhiteBoxTest;
45
46
import java.lang.invoke.MethodHandle;
47
import java.lang.invoke.MethodHandles;
48
import java.lang.reflect.Constructor;
49
import java.lang.reflect.Executable;
50
import java.lang.reflect.Field;
51
import java.lang.reflect.Method;
52
import java.math.BigInteger;
53
import java.util.Arrays;
54
import java.util.Random;
55
56
public class MontgomeryMultiplyTest {
57
58
private static final WhiteBox wb = WhiteBox.getWhiteBox();
59
60
static final MethodHandles.Lookup lookup = MethodHandles.lookup();
61
62
static final MethodHandle montgomeryMultiplyHandle, montgomerySquareHandle;
63
static final MethodHandle bigIntegerConstructorHandle;
64
static final Field bigIntegerMagField;
65
66
static {
67
// Use reflection to gain access to the methods we want to test.
68
try {
69
Method m = BigInteger.class.getDeclaredMethod("montgomeryMultiply",
70
/*a*/int[].class, /*b*/int[].class, /*n*/int[].class, /*len*/int.class,
71
/*inv*/long.class, /*product*/int[].class);
72
m.setAccessible(true);
73
montgomeryMultiplyHandle = lookup.unreflect(m);
74
75
m = BigInteger.class.getDeclaredMethod("montgomerySquare",
76
/*a*/int[].class, /*n*/int[].class, /*len*/int.class,
77
/*inv*/long.class, /*product*/int[].class);
78
m.setAccessible(true);
79
montgomerySquareHandle = lookup.unreflect(m);
80
81
Constructor c
82
= BigInteger.class.getDeclaredConstructor(int.class, int[].class);
83
c.setAccessible(true);
84
bigIntegerConstructorHandle = lookup.unreflectConstructor(c);
85
86
bigIntegerMagField = BigInteger.class.getDeclaredField("mag");
87
bigIntegerMagField.setAccessible(true);
88
89
} catch (Throwable ex) {
90
throw new RuntimeException(ex);
91
}
92
}
93
94
/* Obtain executable for the intrinsics tested. Depending on the
95
* value of 'isMultiply', the executable corresponding to either
96
* implMontgomerMultiply or implMontgomerySqure is returned. */
97
static Executable getExecutable(boolean isMultiply) throws RuntimeException {
98
try {
99
Class aClass = Class.forName("java.math.BigInteger");
100
Method aMethod;
101
if (isMultiply) {
102
aMethod = aClass.getDeclaredMethod("implMontgomeryMultiply",
103
int[].class,
104
int[].class,
105
int[].class,
106
int.class,
107
long.class,
108
int[].class);
109
} else {
110
aMethod = aClass.getDeclaredMethod("implMontgomerySquare",
111
int[].class,
112
int[].class,
113
int.class,
114
long.class,
115
int[].class);
116
}
117
return aMethod;
118
} catch (NoSuchMethodException e) {
119
throw new RuntimeException("Test bug, method is unavailable. " + e);
120
} catch (ClassNotFoundException e) {
121
throw new RuntimeException("Test bug, class is unavailable. " + e);
122
}
123
}
124
125
// Invoke either BigInteger.montgomeryMultiply or BigInteger.montgomerySquare.
126
int[] montgomeryMultiply(int[] a, int[] b, int[] n, int len, long inv,
127
int[] product) throws Throwable {
128
int[] result =
129
(a == b) ? (int[]) montgomerySquareHandle.invokeExact(a, n, len, inv, product)
130
: (int[]) montgomeryMultiplyHandle.invokeExact(a, b, n, len, inv, product);
131
return Arrays.copyOf(result, len);
132
}
133
134
// Invoke the private constructor BigInteger(int[]).
135
BigInteger newBigInteger(int[] val) throws Throwable {
136
return (BigInteger) bigIntegerConstructorHandle.invokeExact(1, val);
137
}
138
139
// Get the private field BigInteger.mag
140
int[] mag(BigInteger n) {
141
try {
142
return (int[]) bigIntegerMagField.get(n);
143
} catch (Exception ex) {
144
throw new RuntimeException(ex);
145
}
146
}
147
148
// Montgomery multiplication
149
// Calculate a * b * r^-1 mod n)
150
//
151
// R is a power of the word size
152
// N' = R^-1 mod N
153
//
154
// T := ab
155
// m := (T mod R)N' mod R [so 0 <= m < R]
156
// t := (T + mN)/R
157
// if t >= N then return t - N else return t
158
//
159
BigInteger montgomeryMultiply(BigInteger a, BigInteger b, BigInteger N,
160
int len, BigInteger n_prime)
161
throws Throwable {
162
BigInteger T = a.multiply(b);
163
BigInteger R = BigInteger.ONE.shiftLeft(len*32);
164
BigInteger mask = R.subtract(BigInteger.ONE);
165
BigInteger m = (T.and(mask)).multiply(n_prime);
166
m = m.and(mask); // i.e. m.mod(R)
167
T = T.add(m.multiply(N));
168
T = T.shiftRight(len*32); // i.e. T.divide(R)
169
if (T.compareTo(N) > 0) {
170
T = T.subtract(N);
171
}
172
return T;
173
}
174
175
// Call the Montgomery multiply intrinsic.
176
BigInteger montgomeryMultiply(int[] a_words, int[] b_words, int[] n_words,
177
int len, BigInteger inv)
178
throws Throwable {
179
BigInteger t = montgomeryMultiply(
180
newBigInteger(a_words),
181
newBigInteger(b_words),
182
newBigInteger(n_words),
183
len, inv);
184
return t;
185
}
186
187
// Check that the Montgomery multiply intrinsic returns the same
188
// result as the longhand calculation.
189
void check(int[] a_words, int[] b_words, int[] n_words, int len, BigInteger inv)
190
throws Throwable {
191
BigInteger n = newBigInteger(n_words);
192
BigInteger slow = montgomeryMultiply(a_words, b_words, n_words, len, inv);
193
BigInteger fast
194
= newBigInteger(montgomeryMultiply
195
(a_words, b_words, n_words, len, inv.longValue(), null));
196
// The intrinsic may not return the same value as the longhand
197
// calculation but they must have the same residue mod N.
198
if (!slow.mod(n).equals(fast.mod(n))) {
199
throw new RuntimeException();
200
}
201
}
202
203
Random rnd = new Random(42);
204
205
// Return a random value of length <= bits in an array of even length
206
int[] random_val(int bits) {
207
int len = (bits+63)/64; // i.e. length in longs
208
int[] val = new int[len*2];
209
for (int i = 0; i < val.length; i++)
210
val[i] = rnd.nextInt();
211
int leadingZeros = 64 - (bits & 64);
212
if (leadingZeros >= 32) {
213
val[0] = 0;
214
val[1] &= ~(-1l << (leadingZeros & 31));
215
} else {
216
val[0] &= ~(-1l << leadingZeros);
217
}
218
return val;
219
}
220
221
void testOneLength(int lenInBits, int lenInInts) throws Throwable {
222
BigInteger mod = new BigInteger(lenInBits, 2, rnd);
223
BigInteger r = BigInteger.ONE.shiftLeft(lenInInts * 32);
224
BigInteger n_prime = mod.modInverse(r).negate();
225
226
// Make n.length even, padding with a zero if necessary
227
int[] n = mag(mod);
228
if (n.length < lenInInts) {
229
int[] x = new int[lenInInts];
230
System.arraycopy(n, 0, x, lenInInts-n.length, n.length);
231
n = x;
232
}
233
234
for (int i = 0; i < 10000; i++) {
235
// multiply
236
check(random_val(lenInBits), random_val(lenInBits), n, lenInInts, n_prime);
237
// square
238
int[] tmp = random_val(lenInBits);
239
check(tmp, tmp, n, lenInInts, n_prime);
240
}
241
}
242
243
// Test the Montgomery multiply intrinsic with a bunch of random
244
// values of varying lengths. Do this for long enough that the
245
// caller of the intrinsic is C2-compiled.
246
void testResultValues() throws Throwable {
247
// Test a couple of interesting edge cases.
248
testOneLength(1024, 32);
249
testOneLength(1025, 34);
250
for (int j = 10; j > 0; j--) {
251
// Construct a random prime whose length in words is even
252
int lenInBits = rnd.nextInt(2048) + 64;
253
int lenInInts = (lenInBits + 63)/64*2;
254
testOneLength(lenInBits, lenInInts);
255
}
256
}
257
258
// Range checks
259
void testOneMontgomeryMultiplyCheck(int[] a, int[] b, int[] n, int len, long inv,
260
int[] product, Class klass) {
261
try {
262
montgomeryMultiply(a, b, n, len, inv, product);
263
} catch (Throwable ex) {
264
if (klass.isAssignableFrom(ex.getClass()))
265
return;
266
throw new RuntimeException(klass + " expected, " + ex + " was thrown");
267
}
268
throw new RuntimeException(klass + " expected, was not thrown");
269
}
270
271
void testOneMontgomeryMultiplyCheck(int[] a, int[] b, BigInteger n, int len, BigInteger inv,
272
Class klass) {
273
testOneMontgomeryMultiplyCheck(a, b, mag(n), len, inv.longValue(), null, klass);
274
}
275
276
void testOneMontgomeryMultiplyCheck(int[] a, int[] b, BigInteger n, int len, BigInteger inv,
277
int[] product, Class klass) {
278
testOneMontgomeryMultiplyCheck(a, b, mag(n), len, inv.longValue(), product, klass);
279
}
280
281
void testMontgomeryMultiplyChecks() {
282
int[] blah = random_val(40);
283
int[] small = random_val(39);
284
BigInteger mod = new BigInteger(40*32 , 2, rnd);
285
BigInteger r = BigInteger.ONE.shiftLeft(40*32);
286
BigInteger n_prime = mod.modInverse(r).negate();
287
288
// Length out of range: square
289
testOneMontgomeryMultiplyCheck(blah, blah, mod, 41, n_prime, IllegalArgumentException.class);
290
testOneMontgomeryMultiplyCheck(blah, blah, mod, 0, n_prime, IllegalArgumentException.class);
291
testOneMontgomeryMultiplyCheck(blah, blah, mod, -1, n_prime, IllegalArgumentException.class);
292
// As above, but for multiply
293
testOneMontgomeryMultiplyCheck(blah, blah.clone(), mod, 41, n_prime, IllegalArgumentException.class);
294
testOneMontgomeryMultiplyCheck(blah, blah.clone(), mod, 0, n_prime, IllegalArgumentException.class);
295
testOneMontgomeryMultiplyCheck(blah, blah.clone(), mod, 0, n_prime, IllegalArgumentException.class);
296
297
// Length odd
298
testOneMontgomeryMultiplyCheck(small, small, mod, 39, n_prime, IllegalArgumentException.class);
299
testOneMontgomeryMultiplyCheck(small, small, mod, 0, n_prime, IllegalArgumentException.class);
300
testOneMontgomeryMultiplyCheck(small, small, mod, -1, n_prime, IllegalArgumentException.class);
301
// As above, but for multiply
302
testOneMontgomeryMultiplyCheck(small, small.clone(), mod, 39, n_prime, IllegalArgumentException.class);
303
testOneMontgomeryMultiplyCheck(small, small.clone(), mod, 0, n_prime, IllegalArgumentException.class);
304
testOneMontgomeryMultiplyCheck(small, small.clone(), mod, -1, n_prime, IllegalArgumentException.class);
305
306
// array too small
307
testOneMontgomeryMultiplyCheck(blah, blah, mod, 40, n_prime, small, IllegalArgumentException.class);
308
testOneMontgomeryMultiplyCheck(blah, blah.clone(), mod, 40, n_prime, small, IllegalArgumentException.class);
309
testOneMontgomeryMultiplyCheck(small, blah, mod, 40, n_prime, blah, IllegalArgumentException.class);
310
testOneMontgomeryMultiplyCheck(blah, small, mod, 40, n_prime, blah, IllegalArgumentException.class);
311
testOneMontgomeryMultiplyCheck(blah, blah, mod, 40, n_prime, small, IllegalArgumentException.class);
312
testOneMontgomeryMultiplyCheck(small, small, mod, 40, n_prime, blah, IllegalArgumentException.class);
313
}
314
315
public static void main(String args[]) {
316
if (!Platform.isServer() || Platform.isEmulatedClient()) {
317
throw new Error("TESTBUG: Not server mode");
318
}
319
if (wb.isIntrinsicAvailable(getExecutable(true), CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION) &&
320
wb.isIntrinsicAvailable(getExecutable(false), CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {
321
try {
322
new MontgomeryMultiplyTest().testMontgomeryMultiplyChecks();
323
new MontgomeryMultiplyTest().testResultValues();
324
} catch (Throwable ex) {
325
throw new RuntimeException(ex);
326
}
327
}
328
}
329
}
330
331