Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/util/Random/RandomTestBsi1999.java
41152 views
1
/*
2
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
import java.util.ArrayList;
24
import java.util.List;
25
import java.util.PrimitiveIterator;
26
27
import java.util.random.*;
28
29
import java.util.Set;
30
import java.util.concurrent.CompletableFuture;
31
import java.util.concurrent.ExecutionException;
32
import java.util.concurrent.ThreadLocalRandom;
33
import java.util.concurrent.TimeUnit;
34
import java.util.concurrent.TimeoutException;
35
import java.util.function.IntSupplier;
36
import java.util.function.LongSupplier;
37
import java.util.function.BooleanSupplier;
38
import java.util.function.Supplier;
39
import java.util.stream.Stream;
40
41
import static java.util.stream.Collectors.toList;
42
import static java.util.stream.Collectors.toSet;
43
44
/**
45
* @test
46
* @summary test bit sequences produced by clases that implement interface RandomGenerator
47
* @bug 8248862
48
* @run main RandomTestBsi1999
49
* @key randomness
50
*/
51
52
public class RandomTestBsi1999 {
53
54
/* A set of tests for pseudorandom number generators inspired by this report:
55
*
56
* Werner Schindler. Functionality Classes and Evaluation Methodology for
57
* Deterministic Random Number Generators, Version 2.0.
58
* Bundesamt fur Sicherheit in der Informationstechnik (BSI). December 2, 1999.
59
* https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Zertifizierung/Interpretationen/AIS_20_Functionality_Classes_Evaluation_Methodology_DRNG_e.pdf
60
*
61
* Section F of this report (pp. 19-20) recommends the use of five tests to evaluate a
62
* sequence of bits:
63
*
64
* Monobit test
65
* Poker test
66
* Run test
67
* Long run test
68
* Autocorrelation test
69
*
70
* The first four of these tests are in turn taken from this report:
71
*
72
* National Institute of Standards and Technology (NIST),
73
* U.S. Department of Commerce. Security Requirements for
74
* Cryptographic Modules. Federal Information Processing
75
* Standard (FIPS) 140-1, January 11, 1994.
76
* https://csrc.nist.gov/csrc/media/publications/fips/140/1/archive/1994-01-11/documents/fips1401.pdf
77
*
78
* The BSI report appears to contain a few typos in transcribing the FIPS 140-1
79
* requirements (pp. 44-45); specifically, the last three intervals for the runs test
80
* (for lengths 4, 5, and 6+) are given as "223 - 402, 90 - 223, 90 - 223" in the FIPS
81
* standard but as "233-402, 90-223, 90-233" in the BSI publication. A quick
82
* mathematical check indicates that the FIPS 140-1 values are correct; therefore we
83
* use those values here. In addition, the BSI report specifies a test interval of
84
* 2326-2674 for the autocorrelation test, which provides an appropriately small
85
* rejection rate if the test were done for only a single value of tau; but because we
86
* wish to perform 5000 distinct tests, one for each value of tau in the range 1-5000,
87
* that test interval produces too many false positives. Some calculation shows that
88
* the interval 2267-2733 used by the FIPS 140-1 run test for runs of length 1 is
89
* appropriate, so we use that interval here for each of the 5000 individual
90
* autocorrelation tests.
91
*
92
* Each of the four FIPS 140-1 tests examines a sequence of 20000 bits. The
93
* autocorrelation test examines a sequence of 10000 bits. It is convenient to
94
* generate a sequence of 20000 bits (which we represent as an array of 20000 bytes)
95
* and then apply all five tests, knowing that the autocorrelation test will examine
96
* only the first half of the byte array.
97
*
98
* The descriptions of the tests are quoted from the FIPS 140-1 and BSI reports
99
* (with some adjustments of punctuation and mathematical symbols, as well as
100
* for our specific choices of test intervals).
101
*/
102
103
static String currentRNG = "";
104
static int failCount = 0;
105
106
static void exceptionOnFail() {
107
if (failCount != 0) {
108
throw new RuntimeException(failCount + " fails detected");
109
}
110
}
111
112
static void setRNG(String rng) {
113
currentRNG = rng;
114
}
115
116
static void fail(String format, Object... args) {
117
if (currentRNG.length() != 0) {
118
System.err.println(currentRNG);
119
currentRNG = "";
120
}
121
122
System.err.format(" " + format, args);
123
failCount++;
124
}
125
126
private static final int SEQUENCE_SIZE = 20000;
127
128
/* The Monobit Test
129
*
130
* 1. Count the number of ones in the 20,000 bit stream. Denote this quantity by X.
131
*
132
* 2. The test is passed if 9,654 < X < 10,346.
133
*/
134
static int monobitTest(String id, byte[] s) {
135
// System.out.println("monobit test");
136
int count = 0;
137
for (int j = 0; j < s.length; j++) {
138
count += s[j];
139
}
140
int monobitFailure = ((9654 < count) && (count < 10346)) ? 0 : 1;
141
if (monobitFailure != 0) fail("monobit test failure for %s: count=%d (should be in [9654,10346])\n", id, count);
142
return monobitFailure;
143
}
144
145
/* The Poker Test
146
*
147
* 1. Divide the 20,000 bit stream into 5,000 contiguous 4-bit segments. Count and
148
* store the number of occurrences of each of the 16 possible 4-bit values. Denote
149
* f(i) as the number of each 4-bit value i where 0 <= i <= 15.
150
*
151
* 2. Evaluate the following: X = (16/5000)(sum[i=0,15] (f(i))**2) - 5000
152
*
153
* 3. The test is passed if 1.03 < X < 57.4.
154
*/
155
156
static int pokerTest(String id, byte[] s) {
157
// System.out.println("poker test");
158
// Divide the bit sequence into 4-bit chunks, and count the number of times each 4-bit value appears.
159
int[] stats = new int[16];
160
int v = 0;
161
for (int j = 0; j < s.length; j++) {
162
v = (v << 1) | s[j];
163
if ((j & 3) == 3) {
164
++stats[v];
165
v = 0;
166
}
167
}
168
int z = 0;
169
for (int k = 0; k < stats.length; k++) {
170
z += stats[k]*stats[k];
171
}
172
double x = (16.0 / (s.length / 4)) * z - (s.length / 4);
173
int pokerFailure = ((1.03 < x) && (x < 57.4)) ? 0 : 1;
174
if (pokerFailure != 0) fail("poker test failure for %s: x=%g (should be in [1.03,57.4])\n", id, x);
175
return pokerFailure;
176
}
177
178
/* The Runs Test
179
*
180
* 1. A run is defined as a maximal sequence of consecutive bits of either all ones
181
* or all zeros, which is part of the 20,000 bit sample stream. The incidences of
182
* runs (for both consecutive zeros and consecutive ones) of all lengths (>= 1) in
183
* the sample stream should be counted and stored.
184
*
185
* 2. The test is passed if the number of runs that occur (of lengths 1 through 6)
186
* is each within the corresponding interval specified below. This must hold for
187
* both the zeros and ones; that is, all 12 counts must lie in the specified
188
* interval. For the purpose of this test, runs of greater than 6 are considered to
189
* be of length 6.
190
*
191
* Length of run Required Interval
192
* 1 2,267 - 2,733
193
* 2 1,079 - 1,421
194
* 3 502 - 748
195
* 4 223 - 402
196
* 5 90 - 223
197
* 6+ 90 - 223
198
*
199
* The Long Run Test
200
*
201
* 1 . A long run is defined to be a run of length 34 or more (of either zeros or ones).
202
*
203
* 2. On the sample of 20,000 bits, the test is passed if there are NO long runs.
204
*/
205
static int runTestAndLongRunTest(String id, byte[] s) {
206
// System.out.println("run test");
207
int[][] stats = new int[2][8];
208
int count = 0;
209
for (int j = 0; j < s.length; j++) {
210
++count;
211
if ((j == (s.length - 1)) || (s[j+1] != s[j])) {
212
++stats[s[j]][(count < 6) ? count : (count < 34) ? 6 : 7];
213
count = 0;
214
}
215
}
216
stats[0][6] += stats[0][7];
217
stats[1][6] += stats[1][7];
218
int runFailure = checkRunStats(stats[0]) | checkRunStats(stats[1]);
219
if (runFailure != 0) fail("run test failure for %s\n", id);
220
int longRunFailure = ((stats[0][7] == 0) && (stats[1][7] == 0)) ? 0 : 1;
221
if (longRunFailure != 0) fail("long run test failure for %s\n", id);
222
return (runFailure + longRunFailure);
223
}
224
225
static int checkRunStats(int[] stats) {
226
int runFailure = 0;
227
runFailure |= ((2267 <= stats[1]) && (stats[1] <= 2733)) ? 0 : 1;
228
runFailure |= ((1079 <= stats[2]) && (stats[2] <= 1421)) ? 0 : 1;
229
runFailure |= (( 502 <= stats[3]) && (stats[3] <= 748)) ? 0 : 1;
230
runFailure |= (( 223 <= stats[4]) && (stats[4] <= 402)) ? 0 : 1;
231
runFailure |= (( 90 <= stats[5]) && (stats[5] <= 223)) ? 0 : 1;
232
runFailure |= (( 90 <= stats[6]) && (stats[6] <= 223)) ? 0 : 1;
233
return runFailure;
234
}
235
236
/* Autocorrelation Test
237
*
238
* For tau in {1, ..., 5000}, Z[tau] := sum[j=1,5000] (b[j] ^ b[j+tau]).
239
*
240
* The sequence passes the autocorrelation test if every Z[tau] lies within the
241
* interval 2267-2733.
242
*/
243
static int autocorrelationTest(String id, byte[] s) {
244
// System.out.println("autocorrelation test");
245
int autocorrelationFailure = 0;
246
int N = s.length / 4;
247
for (int tau = 1; tau <= N; tau++) {
248
int count = 0;
249
for (int j = 0; j < N; j++) {
250
count += (s[j] ^ s[j+tau]);
251
}
252
// We intentionally use bounds [2267, 2733], which are wider than
253
// the bounds [2326, 2674] specified by BSI for this test.
254
// The latter bounds produce way too many false positives.
255
int singleAutocorrelationFailure = ((2267 < count) && (count < 2733)) ? 0 : 1;
256
if (singleAutocorrelationFailure != 0) {
257
if (autocorrelationFailure < 8) {
258
fail("autocorrelation failure for %s: count=%d (should be in [2267,2733]), tau=%d\n", id, count, tau);
259
if (count < 100 || count > 4900) {
260
System.out.print(" ");
261
for (int q = 0; q < 50; q++) System.out.print(s[q]);
262
System.out.println();
263
}
264
}
265
}
266
autocorrelationFailure += singleAutocorrelationFailure;
267
}
268
return (autocorrelationFailure == 0) ? 0 : 1;
269
}
270
271
static int entireBsi1999Test(String id, byte[] s) {
272
return (monobitTest(id, s) +
273
pokerTest(id, s) +
274
runTestAndLongRunTest(id, s) +
275
autocorrelationTest(id, s)
276
);
277
}
278
279
/* To test a sequence of boolean values from a BooleanSupplier,
280
* sequentially extract 20000 boolean values, convert to an array
281
* of bytes, and feed them to method {@code entireBsi1999Test}.
282
*/
283
284
static int testRngBsi1999BooleanOnce(String id, BooleanSupplier theSupplier) {
285
int failureCount = 0;
286
byte[] s = new byte[SEQUENCE_SIZE];
287
// Take the next SEQUENCE_SIZE booleans and test them
288
for (int j = 0; j < s.length; j++) {
289
s[j] = (theSupplier.getAsBoolean() ? (byte)1 : (byte)0);
290
}
291
failureCount += entireBsi1999Test(id + " consecutive", s);
292
return failureCount;
293
}
294
295
/* To test a sequence of long values from a LongSupplier,
296
* two kinds of tests are performed.
297
*
298
* The first kind of test extracts 313=ceiling(20000/64) long
299
* values and concatenates all their bits; the first 20000 bits
300
* are converted to a byte array of bits to be tested. This test is
301
* repeated 64 times.
302
*
303
* The second kind of test focuses on one bit position m (0 <= m < 64);
304
* it extracts 20000 long values and uses just bit m from each value
305
* to produce an array of bytes to be tested. This test is performed
306
* once for each possible value of m (64 times in all).
307
*/
308
static int testRngBsi1999LongOnce(String id, LongSupplier theSupplier) {
309
int failureCount = 0;
310
byte[] s = new byte[SEQUENCE_SIZE];
311
// Part 1: 64 times, take the next SEQUENCE_SIZE bits and test them
312
for (int m = 0; m < 64; m++) {
313
long bits = 0;
314
int bitCount = 0;
315
for (int j = 0; j < s.length; j++) {
316
if ((j & 0x3f) == 0) {
317
bits = theSupplier.getAsLong();
318
// System.out.printf("0x%016x\n", bits);
319
bitCount += Long.bitCount((j == (20000 - 32)) ? ((bits << 32) >>> 32) : bits);
320
}
321
s[j] = (byte)(bits & 1);
322
bits >>>= 1;
323
}
324
// System.out.println(m + ": " + bitCount + " 1-bits");
325
failureCount += entireBsi1999Test(id + " consecutive (" + bitCount + " 1-bits)", s);
326
}
327
// Part 2: for 0 <= m < 64, use bit m from each of the next SEQUENCE_SIZE longs
328
for (int m = 0; m < 64; m++) {
329
for (int j = 0; j < s.length; j++) {
330
s[j] = (byte)((theSupplier.getAsLong() >>> m) & 1);
331
}
332
failureCount += entireBsi1999Test(id + " bit " + m, s);
333
}
334
return failureCount;
335
}
336
337
/* To test a sequence of ing values from an IntSupplier,
338
* two kinds of tests are performed.
339
*
340
* The first kind of test extracts 625=20000/32 int values and
341
* concatenates all their bits; these 20000 bits are converted to
342
* a byte array of bits to be tested. This test is repeated 64
343
* times.
344
*
345
* The second kind of test focuses on one bit position m (0 <= m < 32);
346
* it extracts 20000 int values and uses just bit m from each value
347
* to produce an array of bytes to be tested. This test is performed
348
* once for each possible value of m (32 times in all).
349
*/
350
static int testRngBsi1999IntOnce(String id, IntSupplier theSupplier) {
351
int failureCount = 0;
352
byte[] s = new byte[SEQUENCE_SIZE];
353
// Part 1: 64 times, take the next SEQUENCE_SIZE bits and test them
354
for (int m = 0; m < 64; m++) {
355
int bits = 0;
356
int bitCount = 0;
357
for (int j = 0; j < s.length; j++) {
358
if ((j & 0x1f) == 0) {
359
bits = theSupplier.getAsInt();
360
bitCount += Integer.bitCount(bits);
361
}
362
s[j] = (byte)(bits & 1);
363
bits >>>= 1;
364
}
365
// System.out.println(m + ": " + bitCount + " 1-bits");
366
failureCount += entireBsi1999Test(id + " consecutive (" + bitCount + " 1-bits)", s);
367
}
368
// Part 2: for 0 <= m < 32, use bit m from each of the next SEQUENCE_SIZE ints
369
for (int m = 0; m < 32; m++) {
370
for (int j = 0; j < s.length; j++) {
371
s[j] = (byte)((theSupplier.getAsInt() >>> m) & 1);
372
}
373
failureCount += entireBsi1999Test(id + " bit " + m, s);
374
}
375
return failureCount;
376
}
377
378
/* A call to {@code entireBsi1999Test} may report failure even if the source of random
379
* bits is quite good, because the test is statistical in nature. To make the testing
380
* procedure more robust, if the first call to {@code entireBsi1999Test} fails, then
381
* the failure is ignored if two more calls to {@code entireBsi1999Test} both succeed.
382
*/
383
384
static boolean testRngBsi1999Boolean(String id, BooleanSupplier theSupplier, int failureTolerance) {
385
if (testRngBsi1999BooleanOnce(id, theSupplier) <= failureTolerance) return true;
386
fail("testRngBsi1999Boolean glitch");
387
return ((testRngBsi1999BooleanOnce(id, theSupplier) <= failureTolerance) &&
388
(testRngBsi1999BooleanOnce(id, theSupplier) <= failureTolerance));
389
}
390
391
static boolean testRngBsi1999Long(String id, LongSupplier theSupplier, int failureTolerance) {
392
if (testRngBsi1999LongOnce(id, theSupplier) <= failureTolerance) return true;
393
fail("testRngBsi1999Long glitch");
394
return ((testRngBsi1999LongOnce(id, theSupplier) <= failureTolerance) &&
395
(testRngBsi1999LongOnce(id, theSupplier) <= failureTolerance));
396
}
397
398
static boolean testRngBsi1999Int(String id, IntSupplier theSupplier, int failureTolerance) {
399
if (testRngBsi1999IntOnce(id, theSupplier) <= failureTolerance) return true;
400
fail("testRngBsi1999Int glitch");
401
return ((testRngBsi1999IntOnce(id, theSupplier) <= failureTolerance) &&
402
(testRngBsi1999IntOnce(id, theSupplier) <= failureTolerance));
403
}
404
405
static void tryIt(RandomGenerator rng, String id, BooleanSupplier theSupplier) {
406
System.out.printf("Testing %s %s\n", rng.getClass().getName(), id);
407
boolean success = theSupplier.getAsBoolean();
408
if (!success) {
409
fail("*** Failure of %s %s\n", rng.getClass().getName(), id);
410
}
411
}
412
413
static void testOneRng(RandomGenerator rng, int failureTolerance) {
414
String name = rng.getClass().getName();
415
tryIt(rng, "nextInt", () -> testRngBsi1999Int(name + " nextInt", rng::nextInt, failureTolerance));
416
tryIt(rng, "nextLong", () -> testRngBsi1999Long(name + " nextLong", rng::nextLong, failureTolerance));
417
tryIt(rng, "nextBoolean", () -> testRngBsi1999Boolean(name + " nextBoolean", rng::nextBoolean, failureTolerance));
418
tryIt(rng, "ints", () -> testRngBsi1999Int(name + " ints", rng.ints().iterator()::next, failureTolerance));
419
tryIt(rng, "longs", () -> testRngBsi1999Long(name + " longs", rng.longs().iterator()::next, failureTolerance));
420
{
421
PrimitiveIterator.OfDouble iter = rng.doubles().iterator();
422
tryIt(rng, "doubles",
423
() -> testRngBsi1999Int(name + " doubles",
424
() -> (int)(long)Math.floor(iter.next() * 0x1.0p32),
425
failureTolerance));
426
}
427
tryIt(rng, "nextDouble",
428
() -> testRngBsi1999Int(name + " nextDouble",
429
() -> (int)(long)Math.floor(rng.nextDouble() * 0x1.0p32),
430
failureTolerance));
431
tryIt(rng, "nextFloat",
432
() -> testRngBsi1999Int(name + " nextFloat",
433
() -> (((int)(long)Math.floor(rng.nextFloat() * 0x1.0p16f) << 16)
434
| (int)(long)Math.floor(rng.nextFloat() * 0x1.0p16f)),
435
failureTolerance));
436
}
437
438
public static void main(String[] args) {
439
RandomGeneratorFactory.all().forEach(factory -> {
440
setRNG(factory.name());
441
442
if (currentRNG.equals("SecureRandom")) {
443
// skip because stochastic
444
} else if (currentRNG.equals("Random")) {
445
// testOneRng(factory.create(59), 1);
446
// autocorrelation failure for java.util.Random longs bit 0: count=2207 (should be in [2267,2733]), tau=2819
447
448
} else {
449
testOneRng(factory.create(59), 0);
450
}
451
});
452
453
exceptionOnFail();
454
}
455
}
456
457
458