2 // RandomNumberGeneratorTest.cs - NUnit Test Cases for RNG
5 // Sebastien Pouliot <sebastien@ximian.com>
7 // (C) 2002 Motus Technologies Inc. (http://www.motus.com)
8 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
11 using NUnit.Framework;
14 using System.Security.Cryptography;
17 namespace MonoTests.System.Security.Cryptography {
20 // a. NIST FIPS PUB 140-2: Security requirements for Cryptographic Modules
21 // http://csrc.nist.gov/publications/fips/fips140-2/fips1402.pdf
22 // b. NIST SP 800-22: A Statistical Test Suite for Random and Pseudorandom Number Generators for Cryptographic Applications
24 // http://csrc.nist.gov/publications/nistpubs/800-22/sp-800-22-051501.pdf
25 // c. IETF RFC1750: Randomness Recommendations for Security
27 // http://www.ietf.org/rfc/rfc1750.txt
30 public class RandomNumberGeneratorTest {
33 private byte[] sample;
38 // all tests should be done on the same random sample
39 RandomNumberGenerator rng = RandomNumberGenerator.Create ();
40 name = rng.ToString ();
42 sample = new byte[2500];
43 rng.GetBytes (sample);
46 // count the number of 1
48 public void Monobit ()
51 for (int i=0; i < sample.Length; i++) {
53 for (int j = 0; j < 8; j++) {
54 if ((b & 0x01) == 0x01)
60 Assert.IsTrue ((9725 < x), String.Format ("{0} Monobit x={1} > 9725", name, x));
61 Assert.IsTrue ((x < 10275), String.Format ("{0} Monobit x={1} < 10275", name, x));
64 // 16 patterns (nibbles)
68 int[] pattern = new int[16];
69 for (int i = 0; i < sample.Length; i++) {
78 for (int i = 0; i < 16; i++)
79 result += (pattern[i] * pattern[i]);
80 result = ((16 * result) / 5000) - 5000;
82 Assert.IsTrue (((result > 2.16) && (result < 46.17)), name + " Poker: " + result);
89 int[,] runs = new int[6,2];
93 for (int i = sample.Length - 1; i >= 0 ; i--) {
95 for (int j = 0; j < 8; j++) {
96 if ((b & 0x01) == 0x01) {
100 int p = Math.Min (x, 6) - 1;
110 int p = Math.Min (x, 6) - 1;
121 // don't forget the ast run
123 int p = Math.Min (x, 6) - 1;
125 runs [p, zero ? 0 : 1]++;
127 // Updated ranges as per FIPS140-2 Change Notice #1
128 // check for runs of zeros
129 Assert.IsTrue (((runs[0,0] >= 2315) && (runs[0,0] <= 2685)), name + " 0-Runs length=1: " + runs[0,0]);
130 Assert.IsTrue (((runs[1,0] >= 1114) && (runs[1,0] <= 1386)), name + " 0-Runs length=2: " + runs[1,0]);
131 Assert.IsTrue (((runs[2,0] >= 527) && (runs[2,0] <= 723)), name + " 0-Runs length=3: " + runs[2,0]);
132 Assert.IsTrue (((runs[3,0] >= 240) && (runs[3,0] <= 384)), name + " 0-Runs length=4: " + runs[3,0]);
133 Assert.IsTrue (((runs[4,0] >= 103) && (runs[4,0] <= 209)), name + " 0-Runs length=5: " + runs[4,0]);
134 Assert.IsTrue (((runs[5,0] >= 103) && (runs[5,0] <= 209)), name + " 0-Runs length=6+ " + runs[5,0]);
135 // check for runs of ones
136 Assert.IsTrue (((runs[0,1] >= 2315) && (runs[0,1] <= 2685)), name + " 1-Runs length=1: " + runs[0,1]);
137 Assert.IsTrue (((runs[1,1] >= 1114) && (runs[1,1] <= 1386)), name + " 1-Runs length=2: " + runs[1,1]);
138 Assert.IsTrue (((runs[2,1] >= 527) && (runs[2,1] <= 723)), name + " 1-Runs length=3: " + runs[2,1]);
139 Assert.IsTrue (((runs[3,1] >= 240) && (runs[3,1] <= 384)), name + " 1-Runs length=4: " + runs[3,1]);
140 Assert.IsTrue (((runs[4,1] >= 103) && (runs[4,1] <= 209)), name + " 1-Runs length=5: " + runs[4,1]);
141 Assert.IsTrue (((runs[5,1] >= 103) && (runs[5,1] <= 209)), name + " 1-Runs length=6+ " + runs[5,1]);
144 // no long runs of 26 or more (0 or 1)
146 public void LongRuns ()
152 for (int i = sample.Length - 1; i >= 0 ; i--) {
154 for (int j = 0; j < 8; j++) {
155 if ((b & 0x01) == 0x01) {
159 longestRun = Math.Max (longestRun, currentRun);
168 longestRun = Math.Max (longestRun, currentRun);
177 Assert.IsTrue ((longestRun < 26), name + " Long Runs max = " + longestRun);