File: RandomNumberGeneratorTest.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (181 lines) | stat: -rw-r--r-- 5,056 bytes parent folder | download | duplicates (15)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//
// RandomNumberGeneratorTest.cs - NUnit Test Cases for RNG
//
// Author:
//	Sebastien Pouliot  <sebastien@ximian.com>
//
// (C) 2002 Motus Technologies Inc. (http://www.motus.com)
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
//

using NUnit.Framework;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace MonoTests.System.Security.Cryptography {

// References:
// a.	NIST FIPS PUB 140-2: Security requirements for Cryptographic Modules 
//	http://csrc.nist.gov/publications/fips/fips140-2/fips1402.pdf
// b.	NIST SP 800-22: A Statistical Test Suite for Random and Pseudorandom Number Generators for Cryptographic Applications
//	not implemented
//	http://csrc.nist.gov/publications/nistpubs/800-22/sp-800-22-051501.pdf
// c.	IETF RFC1750: Randomness Recommendations for Security
//	not implemented
//	http://www.ietf.org/rfc/rfc1750.txt

[TestFixture]
public class RandomNumberGeneratorTest {

	private string name;
	private byte[] sample;

	[TestFixtureSetUp]
	public void SetUp () 
	{
		// all tests should be done on the same random sample
		RandomNumberGenerator rng = RandomNumberGenerator.Create ();
		name = rng.ToString ();
		// 20,000 bits
		sample = new byte[2500];
		rng.GetBytes (sample);
	}

	// count the number of 1
	[Test]
	public void Monobit () 
	{
		int x = 0;
		for (int i=0; i < sample.Length; i++) {
			byte b = sample[i];
			for (int j = 0; j < 8; j++) {
				if ((b & 0x01) == 0x01)
					x++;
				// next bit
				b >>= 1;
			}
		}
		Assert.IsTrue ((9725  < x), String.Format ("{0} Monobit x={1} > 9725",  name, x));
		Assert.IsTrue ((x < 10275), String.Format ("{0} Monobit x={1} < 10275", name, x));
	}

	// 16 patterns (nibbles)
	[Test]
	public void Poker () 
	{
		int[] pattern = new int[16];
		for (int i = 0; i < sample.Length; i++) {
			byte b = sample[i];
			int n = (b & 0x0F);
			pattern[n]++;
			b >>= 4;
			n = b;
			pattern[n]++;
		}
		double result = 0;
		for (int i = 0; i < 16; i++)
			result += (pattern[i] * pattern[i]);
		result = ((16 * result) / 5000) - 5000;

		Assert.IsTrue (((result > 2.16) && (result < 46.17)), name + " Poker: " + result);
	}

	// runs of 1 (or 0)
	[Test]
	public void Runs () 
	{
		int[,] runs = new int[6,2];
		int x = 0;
		bool one = false;
		bool zero = false;
		for (int i = sample.Length - 1; i >= 0 ; i--) {
			byte b = sample[i];
			for (int j = 0; j < 8; j++) {
				if ((b & 0x01) == 0x01) {
					if (!one) {
						one = true;
						zero = false;
						int p = Math.Min (x, 6) - 1;
						if (p >= 0)
							runs[p,0]++;
						x = 0;
					}
				}
				else {
					if (!zero) {
						one = false;
						zero = true;
						int p = Math.Min (x, 6) - 1;
						if (p >= 0)
							runs[p,1]++;
						x = 0;
					}
				}
				x++;
				// next bit
				b >>= 1;
			}
		}
		// don't forget the ast run
		if (x > 0) {
			int p = Math.Min (x, 6) - 1;
			if (p >= 0)
				runs [p, zero ? 0 : 1]++;
		}
		// Updated ranges as per FIPS140-2 Change Notice #1
		// check for runs of zeros
		Assert.IsTrue (((runs[0,0] >= 2315) && (runs[0,0] <= 2685)), name + " 0-Runs length=1: " + runs[0,0]);
		Assert.IsTrue (((runs[1,0] >= 1114) && (runs[1,0] <= 1386)), name + " 0-Runs length=2: " + runs[1,0]);
		Assert.IsTrue (((runs[2,0] >=  527) && (runs[2,0] <=  723)), name + " 0-Runs length=3: " + runs[2,0]);
		Assert.IsTrue (((runs[3,0] >=  240) && (runs[3,0] <=  384)), name + " 0-Runs length=4: " + runs[3,0]);
		Assert.IsTrue (((runs[4,0] >=  103) && (runs[4,0] <=  209)), name + " 0-Runs length=5: " + runs[4,0]);
		Assert.IsTrue (((runs[5,0] >=  103) && (runs[5,0] <=  209)), name + " 0-Runs length=6+ " + runs[5,0]);
		// check for runs of ones
		Assert.IsTrue (((runs[0,1] >= 2315) && (runs[0,1] <= 2685)), name + " 1-Runs length=1: " + runs[0,1]);
		Assert.IsTrue (((runs[1,1] >= 1114) && (runs[1,1] <= 1386)), name + " 1-Runs length=2: " + runs[1,1]);
		Assert.IsTrue (((runs[2,1] >=  527) && (runs[2,1] <=  723)), name + " 1-Runs length=3: " + runs[2,1]);
		Assert.IsTrue (((runs[3,1] >=  240) && (runs[3,1] <=  384)), name + " 1-Runs length=4: " + runs[3,1]);
		Assert.IsTrue (((runs[4,1] >=  103) && (runs[4,1] <=  209)), name + " 1-Runs length=5: " + runs[4,1]);
		Assert.IsTrue (((runs[5,1] >=  103) && (runs[5,1] <=  209)), name + " 1-Runs length=6+ " + runs[5,1]);
	}

	// no long runs of 26 or more (0 or 1)
	[Test]
	public void LongRuns () 
	{
		int longestRun = 0;
		int currentRun = 0;
		bool one = false;
		bool zero = false;
		for (int i = sample.Length - 1; i >= 0 ; i--) {
			byte b = sample[i];
			for (int j = 0; j < 8; j++) {
				if ((b & 0x01) == 0x01) {
					if (!one) {
						one = true;
						zero = false;
						longestRun = Math.Max (longestRun, currentRun);
						currentRun = 0;
					}
					currentRun++;
				}
				else {
					if (!zero) {
						one = false;
						zero = true;
						longestRun = Math.Max (longestRun, currentRun);
						currentRun = 0;
					}
					currentRun++;
				}
				// next bit
				b >>= 1;
			}
		}
		Assert.IsTrue ((longestRun < 26), name + " Long Runs max = " + longestRun);
	}
}

}