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