blob: 26917d17e26ebd4db24bd5ee1870bb7fec80ec17 [file] [log] [blame]
/*
These are the Random Number Generator tests suggested by the
FIPS 140-1 spec section 4.11.1 (http://csrc.nist.gov/fips/fips1401.htm)
The Monobit, Poker, Runs, and Long Runs tests are implemented below.
*/
#define RNG_DEVICE "/dev/hwrandom"
#define RNG_LOOPS 25
#include <stdio.h>
FILE *dev;
char read_rng_byte() {
char random;
fscanf(dev,"%c",&random);
return random;
}
int do_test() {
unsigned char rbyte = 0;
int poker[16],runs[12],i,j;
double pokertest;
int longrun = 0;
int current = 0;
int rlength = 0;
int ones = 0;
for(i=0; i<16; i++) {
poker[i] = 0;
}
for(i=0; i<12; i++) {
runs[i] = 0;
}
rlength = 999;
ones = 0;
for(i=0; i<2500; i++) {
rbyte = read_rng_byte();
// printf("%d: %x\n",i,rbyte);
ones += rbyte & 1;
ones += (rbyte & 2)>>1;
ones += (rbyte & 4)>>2;
ones += (rbyte & 8)>>3;
ones += (rbyte & 16)>>4;
ones += (rbyte & 32)>>5;
ones += (rbyte & 64)>>6;
ones += (rbyte & 128)>>7;
poker[rbyte>>4] += 1;
poker[rbyte & 15] += 1;
/* Trick to make sure current != the first bit so we don't screw
up the first runlength */
if(rlength == 999) {
current = !((rbyte & 128)>>7);
rlength = 1;
}
for(j=7; j>=0; j--) {
// printf("%d %d %d\n",rlength,current,((rbyte & 1<<j)>>j) );
if(((rbyte & 1<<j)>>j) == current) {
rlength++;
}
else {
/* If runlength is 1-6 count it in correct bucket. 0's go in
runs[0-5] 1's go in runs[6-11] hence the 6*current below */
if(rlength < 6) {
runs[rlength - 1 + (6*current)]++;
}
if(rlength >= 6) {
runs[5 + (6*current)]++;
}
/* Check if we just failed longrun test */
if(rlength > longrun) {
longrun = rlength;
}
rlength=1;
/* flip the current run type */
current = (rbyte & 1<<j)>>j;
}
}
}
/* add in the last (possibly incomplete) run */
if(rlength <= 6) {
runs[rlength - 1 + (6*current)]++;
}
if(rlength > longrun) {
longrun = rlength;
}
/* To poker test */
pokertest = 0;
for(i=0; i<16; i++) {
// printf("P%d: %d\n",i,poker[i]);
pokertest += (double)(poker[i] * poker[i]);
}
pokertest = (16.0/5000.0) * pokertest - 5000.0;
/* Data is all gathered, do the tests */
printf("Ones: %d\nPokertest: %f\nRuns: %d %d %d %d %d %d\n %d %d %d %d %d %d\nLong Run: %d\n\n",ones,(float)pokertest,runs[0],runs[1],runs[2],runs[3],runs[4],runs[5],runs[6],runs[7],runs[8],runs[9],runs[10],runs[11],longrun);
if(! ((ones < 10346) && (ones > 9654)) ){
printf(" RNG failed Monobit test.\n");
return 1;
}
if(! ((pokertest < 57.4) && (pokertest > 1.03)) ){
printf(" RNG failed Poker test.\n");
return 1;
}
if(! ((runs[0] >= 2267) && (runs[0] <= 2733) &&
(runs[1] >= 1079) && (runs[1] <= 1421) &&
(runs[2] >= 502) && (runs[2] <= 748) &&
(runs[3] >= 223) && (runs[3] <= 402) &&
(runs[4] >= 90) && (runs[4] <= 223) &&
(runs[5] >= 90) && (runs[5] <= 223) &&
(runs[6] >= 2267) && (runs[6] <= 2733) &&
(runs[7] >= 1079) && (runs[7] <= 1421) &&
(runs[8] >= 502) && (runs[8] <= 748) &&
(runs[9] >= 223) && (runs[9] <= 402) &&
(runs[10] >= 90) && (runs[10] <= 223) &&
(runs[11] >= 90) && (runs[11] <= 223)) ) {
printf(" RNG failed Runs test.\n");
return 1;
}
if(longrun >= 34) {
printf(" RNG failed LongRun test.\n");
return 1;
}
return 0;
}
int main(int argv,char **argc) {
unsigned char random;
int i=0;
if(! (dev = fopen(RNG_DEVICE,"r"))) {
printf("Open of "RNG_DEVICE" failed\n");
exit(1);
}
for(i=0; i<RNG_LOOPS; i++){
printf("Test: %d\n",(i+1));
if(do_test()) {
printf("Failed on test %d\n",i);
}
}
printf("RNG correctly completed %d FIPS tests.\n",i);
return 0;
}