1386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari/*
2386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari * stats.c
3386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari *
4386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari * statistical tests for randomness (FIPS 140-2, Section 4.9)
5386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari *
6386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari * David A. McGrew
7386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari * Cisco Systems, Inc.
8386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari */
9386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
10386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari#include "stat.h"
11386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
12386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagaridebug_module_t mod_stat = {
13386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  0,                 /* debugging is off by default */
14386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  (char *)"stat test"        /* printable module name       */
15386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari};
16386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
17386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari/*
18386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari * each test assumes that 20,000 bits (2500 octets) of data is
19386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari * provided as input
20386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari */
21386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
22386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari#define STAT_TEST_DATA_LEN 2500
23386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
24386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagarierr_status_t
25386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagaristat_test_monobit(uint8_t *data) {
26386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint8_t *data_end = data + STAT_TEST_DATA_LEN;
27386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint16_t ones_count;
28386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
29386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  ones_count = 0;
30386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  while (data < data_end) {
31386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    ones_count += octet_get_weight(*data);
32386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    data++;
33386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  }
34386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
35386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  debug_print(mod_stat, "bit count: %d", ones_count);
36386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
37386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  if ((ones_count < 9725) || (ones_count > 10275))
38386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    return err_status_algo_fail;
39386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
40386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  return err_status_ok;
41386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari}
42386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
43386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagarierr_status_t
44386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagaristat_test_poker(uint8_t *data) {
45386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  int i;
46386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint8_t *data_end = data + STAT_TEST_DATA_LEN;
47386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  double poker;
48386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint16_t f[16] = {
49386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    0, 0, 0, 0, 0, 0, 0, 0,
50386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    0, 0, 0, 0, 0, 0, 0, 0
51386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  };
52386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
53386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  while (data < data_end) {
54386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    f[*data & 0x0f]++;    /* increment freq. count for low nibble  */
55386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    f[(*data) >> 4]++;    /* increment freq. count for high nibble */
56386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    data++;
57386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  }
58386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
59386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  poker = 0.0;
60386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  for (i=0; i < 16; i++)
61386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    poker += (double) f[i] * f[i];
62386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
63386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  poker *= (16.0 / 5000.0);
64386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  poker -= 5000.0;
65386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
66386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  debug_print(mod_stat, "poker test: %f\n", poker);
67386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
68386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  if ((poker < 2.16) || (poker > 46.17))
69386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    return err_status_algo_fail;
70386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
71386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  return err_status_ok;
72386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari}
73386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
74386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
75386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari/*
76386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari * runs[i] holds the number of runs of size (i-1)
77386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari */
78386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
79386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagarierr_status_t
80386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagaristat_test_runs(uint8_t *data) {
81386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint8_t *data_end = data + STAT_TEST_DATA_LEN;
82386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint16_t runs[6] = { 0, 0, 0, 0, 0, 0 };
83386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint16_t gaps[6] = { 0, 0, 0, 0, 0, 0 };
84386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint16_t lo_value[6] = { 2315, 1114, 527, 240, 103, 103 };
85386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint16_t hi_value[6] = { 2685, 1386, 723, 384, 209, 209 };
86386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  int state = 0;
87386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint16_t mask;
88386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  int i;
89386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
90386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  /*
91386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari   * the state variable holds the number of bits in the
92386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari   * current run (or gap, if negative)
93386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari   */
94386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
95386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  while (data < data_end) {
96386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
97386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    /* loop over the bits of this byte */
98386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    for (mask = 1; mask < 256; mask <<= 1) {
99386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      if (*data & mask) {
100386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
101386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari 	/* next bit is a one  */
102386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	if (state > 0) {
103386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
104386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  /* prefix is a run, so increment the run-count  */
105386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  state++;
106386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
107386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  /* check for long runs */
108386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  if (state > 25) {
109386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari		debug_print(mod_stat, ">25 runs: %d", state);
110386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari		return err_status_algo_fail;
111386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  }
112386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
113386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	} else if (state < 0) {
114386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
115386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  /* prefix is a gap  */
116386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  if (state < -25) {
117386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari		debug_print(mod_stat, ">25 gaps: %d", state);
118386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    return err_status_algo_fail;    /* long-runs test failed   */
119386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  }
120386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  if (state < -6) {
121386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    state = -6;                     /* group together gaps > 5 */
122386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  }
123386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  gaps[-1-state]++;                 /* increment gap count      */
124386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari          state = 1;                        /* set state at one set bit */
125386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	} else {
126386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
127386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  /* state is zero; this happens only at initialization        */
128386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  state = 1;
129386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	}
130386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      } else {
131386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
132386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	/* next bit is a zero  */
133386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	if (state > 0) {
134386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
135386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  /* prefix is a run */
136386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  if (state > 25) {
137386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari		debug_print(mod_stat, ">25 runs (2): %d", state);
138386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    return err_status_algo_fail;    /* long-runs test failed   */
139386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  }
140386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  if (state > 6) {
141386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    state = 6;                      /* group together runs > 5 */
142386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  }
143386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  runs[state-1]++;                  /* increment run count       */
144386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari          state = -1;                       /* set state at one zero bit */
145386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	} else if (state < 0) {
146386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
147386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  /* prefix is a gap, so increment gap-count (decrement state) */
148386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  state--;
149386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
150386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  /* check for long gaps */
151386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  if (state < -25) {
152386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari		debug_print(mod_stat, ">25 gaps (2): %d", state);
153386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    return err_status_algo_fail;
154386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  }
155386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
156386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	} else {
157386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
158386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  /* state is zero; this happens only at initialization        */
159386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  state = -1;
160386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	}
161386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      }
162386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    }
163386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
164386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    /* move along to next octet */
165386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    data++;
166386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  }
167386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
168386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  if (mod_stat.on) {
169386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    debug_print(mod_stat, "runs test", NULL);
170386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    for (i=0; i < 6; i++)
171386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      debug_print(mod_stat, "  runs[]: %d", runs[i]);
172386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    for (i=0; i < 6; i++)
173386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      debug_print(mod_stat, "  gaps[]: %d", gaps[i]);
174386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  }
175386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
176386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  /* check run and gap counts against the fixed limits */
177386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  for (i=0; i < 6; i++)
178386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    if (   (runs[i] < lo_value[i] ) || (runs[i] > hi_value[i])
179386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	|| (gaps[i] < lo_value[i] ) || (gaps[i] > hi_value[i]))
180386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      return err_status_algo_fail;
181386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
182386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
183386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  return err_status_ok;
184386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari}
185386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
186386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
187386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari/*
188386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari * the function stat_test_rand_source applys the FIPS-140-2 statistical
189386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari * tests to the random source defined by rs
190386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari *
191386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari */
192386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
193386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari#define RAND_SRC_BUF_OCTETS 50 /* this value MUST divide 2500! */
194386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
195386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagarierr_status_t
196386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagaristat_test_rand_source(rand_source_func_t get_rand_bytes) {
197386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  int i;
198386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  double poker;
199386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint8_t *data, *data_end;
200386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint16_t f[16] = {
201386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    0, 0, 0, 0, 0, 0, 0, 0,
202386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    0, 0, 0, 0, 0, 0, 0, 0
203386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  };
204386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint8_t buffer[RAND_SRC_BUF_OCTETS];
205386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  err_status_t status;
206386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  int ones_count = 0;
207386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint16_t runs[6] = { 0, 0, 0, 0, 0, 0 };
208386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint16_t gaps[6] = { 0, 0, 0, 0, 0, 0 };
209386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint16_t lo_value[6] = { 2315, 1114, 527, 240, 103, 103 };
210386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint16_t hi_value[6] = { 2685, 1386, 723, 384, 209, 209 };
211386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  int state = 0;
212386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  uint16_t mask;
213386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
214386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  /* counters for monobit, poker, and runs tests are initialized above */
215386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
216386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  /* main loop: fill buffer, update counters for stat tests */
217386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  for (i=0; i < 2500; i+=RAND_SRC_BUF_OCTETS) {
218386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
219386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    /* fill data buffer */
220386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    status = get_rand_bytes(buffer, RAND_SRC_BUF_OCTETS);
221386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    if (status) {
222386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  debug_print(mod_stat, "couldn't get rand bytes: %d",status);
223386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      return status;
224386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	}
225386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
226386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari#if 0
227386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    debug_print(mod_stat, "%s",
228386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari		octet_string_hex_string(buffer, RAND_SRC_BUF_OCTETS));
229386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari#endif
230386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
231386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    data = buffer;
232386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    data_end = data + RAND_SRC_BUF_OCTETS;
233386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    while (data < data_end) {
234386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
235386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      /* update monobit test counter */
236386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      ones_count += octet_get_weight(*data);
237386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
238386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      /* update poker test counters */
239386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      f[*data & 0x0f]++;    /* increment freq. count for low nibble  */
240386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      f[(*data) >> 4]++;    /* increment freq. count for high nibble */
241386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
242386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      /* update runs test counters */
243386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      /* loop over the bits of this byte */
244386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      for (mask = 1; mask < 256; mask <<= 1) {
245386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	if (*data & mask) {
246386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
247386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  /* next bit is a one  */
248386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  if (state > 0) {
249386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
250386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    /* prefix is a run, so increment the run-count  */
251386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    state++;
252386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
253386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    /* check for long runs */
254386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    if (state > 25) {
255386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari		  debug_print(mod_stat, ">25 runs (3): %d", state);
256386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	      return err_status_algo_fail;
257386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari		}
258386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
259386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  } else if (state < 0) {
260386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
261386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    /* prefix is a gap  */
262386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    if (state < -25) {
263386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari		  debug_print(mod_stat, ">25 gaps (3): %d", state);
264386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	      return err_status_algo_fail;    /* long-runs test failed   */
265386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    }
266386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    if (state < -6) {
267386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	      state = -6;                     /* group together gaps > 5 */
268386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    }
269386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    gaps[-1-state]++;                 /* increment gap count      */
270386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    state = 1;                        /* set state at one set bit */
271386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  } else {
272386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
273386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    /* state is zero; this happens only at initialization        */
274386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    state = 1;
275386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  }
276386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	} else {
277386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
278386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  /* next bit is a zero  */
279386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  if (state > 0) {
280386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
281386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    /* prefix is a run */
282386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    if (state > 25) {
283386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari		  debug_print(mod_stat, ">25 runs (4): %d", state);
284386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	      return err_status_algo_fail;    /* long-runs test failed   */
285386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    }
286386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    if (state > 6) {
287386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	      state = 6;                      /* group together runs > 5 */
288386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    }
289386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    runs[state-1]++;                  /* increment run count       */
290386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    state = -1;                       /* set state at one zero bit */
291386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  } else if (state < 0) {
292386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
293386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    /* prefix is a gap, so increment gap-count (decrement state) */
294386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    state--;
295386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
296386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    /* check for long gaps */
297386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    if (state < -25) {
298386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari		  debug_print(mod_stat, ">25 gaps (4): %d", state);
299386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	      return err_status_algo_fail;
300386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari		}
301386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
302386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  } else {
303386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
304386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    /* state is zero; this happens only at initialization        */
305386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	    state = -1;
306386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	  }
307386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	}
308386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      }
309386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
310386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      /* advance data pointer */
311386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      data++;
312386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    }
313386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  }
314386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
315386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  /* check to see if test data is within bounds */
316386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
317386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  /* check monobit test data */
318386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
319386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  debug_print(mod_stat, "stat: bit count: %d", ones_count);
320386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
321386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  if ((ones_count < 9725) || (ones_count > 10275)) {
322386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    debug_print(mod_stat, "stat: failed monobit test %d", ones_count);
323386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    return err_status_algo_fail;
324386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  }
325386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
326386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  /* check poker test data */
327386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  poker = 0.0;
328386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  for (i=0; i < 16; i++)
329386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    poker += (double) f[i] * f[i];
330386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
331386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  poker *= (16.0 / 5000.0);
332386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  poker -= 5000.0;
333386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
334386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  debug_print(mod_stat, "stat: poker test: %f", poker);
335386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
336386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  if ((poker < 2.16) || (poker > 46.17)) {
337386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    debug_print(mod_stat, "stat: failed poker test", NULL);
338386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    return err_status_algo_fail;
339386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  }
340386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
341386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  /* check run and gap counts against the fixed limits */
342386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  for (i=0; i < 6; i++)
343386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    if ((runs[i] < lo_value[i] ) || (runs[i] > hi_value[i])
344386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari	 || (gaps[i] < lo_value[i] ) || (gaps[i] > hi_value[i])) {
345386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      debug_print(mod_stat, "stat: failed run/gap test", NULL);
346386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      return err_status_algo_fail;
347386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    }
348386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
349386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  debug_print(mod_stat, "passed random stat test", NULL);
350386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  return err_status_ok;
351386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari}
352386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
353386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagarierr_status_t
354386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagaristat_test_rand_source_with_repetition(rand_source_func_t source, unsigned num_trials) {
355386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  unsigned int i;
356386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  err_status_t err = err_status_algo_fail;
357386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
358386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  for (i=0; i < num_trials; i++) {
359386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    err = stat_test_rand_source(source);
360386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    if (err == err_status_ok) {
361386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari      return err_status_ok;
362386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    }
363386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari    debug_print(mod_stat, "failed stat test (try number %d)\n", i);
364386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  }
365386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari
366386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari  return err;
367386ce4d9144fc190797f4e43a31aeaf76ca2e373Param Reddappagari}
368