OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * stats.c |
| 3 * |
| 4 * statistical tests for randomness (FIPS 140-2, Section 4.9) |
| 5 * |
| 6 * David A. McGrew |
| 7 * Cisco Systems, Inc. |
| 8 */ |
| 9 |
| 10 #include "stat.h" |
| 11 |
| 12 debug_module_t mod_stat = { |
| 13 0, /* debugging is off by default */ |
| 14 (char *)"stat test" /* printable module name */ |
| 15 }; |
| 16 |
| 17 /* |
| 18 * each test assumes that 20,000 bits (2500 octets) of data is |
| 19 * provided as input |
| 20 */ |
| 21 |
| 22 #define STAT_TEST_DATA_LEN 2500 |
| 23 |
| 24 err_status_t |
| 25 stat_test_monobit(uint8_t *data) { |
| 26 uint8_t *data_end = data + STAT_TEST_DATA_LEN; |
| 27 uint16_t ones_count; |
| 28 |
| 29 ones_count = 0; |
| 30 while (data < data_end) { |
| 31 ones_count += octet_get_weight(*data); |
| 32 data++; |
| 33 } |
| 34 |
| 35 debug_print(mod_stat, "bit count: %d", ones_count); |
| 36 |
| 37 if ((ones_count < 9725) || (ones_count > 10275)) |
| 38 return err_status_algo_fail; |
| 39 |
| 40 return err_status_ok; |
| 41 } |
| 42 |
| 43 err_status_t |
| 44 stat_test_poker(uint8_t *data) { |
| 45 int i; |
| 46 uint8_t *data_end = data + STAT_TEST_DATA_LEN; |
| 47 double poker; |
| 48 uint16_t f[16] = { |
| 49 0, 0, 0, 0, 0, 0, 0, 0, |
| 50 0, 0, 0, 0, 0, 0, 0, 0 |
| 51 }; |
| 52 |
| 53 while (data < data_end) { |
| 54 f[*data & 0x0f]++; /* increment freq. count for low nibble */ |
| 55 f[(*data) >> 4]++; /* increment freq. count for high nibble */ |
| 56 data++; |
| 57 } |
| 58 |
| 59 poker = 0.0; |
| 60 for (i=0; i < 16; i++) |
| 61 poker += (double) f[i] * f[i]; |
| 62 |
| 63 poker *= (16.0 / 5000.0); |
| 64 poker -= 5000.0; |
| 65 |
| 66 debug_print(mod_stat, "poker test: %f\n", poker); |
| 67 |
| 68 if ((poker < 2.16) || (poker > 46.17)) |
| 69 return err_status_algo_fail; |
| 70 |
| 71 return err_status_ok; |
| 72 } |
| 73 |
| 74 |
| 75 /* |
| 76 * runs[i] holds the number of runs of size (i-1) |
| 77 */ |
| 78 |
| 79 err_status_t |
| 80 stat_test_runs(uint8_t *data) { |
| 81 uint8_t *data_end = data + STAT_TEST_DATA_LEN; |
| 82 uint16_t runs[6] = { 0, 0, 0, 0, 0, 0 }; |
| 83 uint16_t gaps[6] = { 0, 0, 0, 0, 0, 0 }; |
| 84 uint16_t lo_value[6] = { 2315, 1114, 527, 240, 103, 103 }; |
| 85 uint16_t hi_value[6] = { 2685, 1386, 723, 384, 209, 209 }; |
| 86 int state = 0; |
| 87 uint16_t mask; |
| 88 int i; |
| 89 |
| 90 /* |
| 91 * the state variable holds the number of bits in the |
| 92 * current run (or gap, if negative) |
| 93 */ |
| 94 |
| 95 while (data < data_end) { |
| 96 |
| 97 /* loop over the bits of this byte */ |
| 98 for (mask = 1; mask < 256; mask <<= 1) { |
| 99 if (*data & mask) { |
| 100 |
| 101 /* next bit is a one */ |
| 102 if (state > 0) { |
| 103 |
| 104 /* prefix is a run, so increment the run-count */ |
| 105 state++; |
| 106 |
| 107 /* check for long runs */ |
| 108 if (state > 25) { |
| 109 debug_print(mod_stat, ">25 runs: %d", state); |
| 110 return err_status_algo_fail; |
| 111 } |
| 112 |
| 113 } else if (state < 0) { |
| 114 |
| 115 /* prefix is a gap */ |
| 116 if (state < -25) { |
| 117 debug_print(mod_stat, ">25 gaps: %d", state); |
| 118 return err_status_algo_fail; /* long-runs test failed */ |
| 119 } |
| 120 if (state < -6) { |
| 121 state = -6; /* group together gaps > 5 */ |
| 122 } |
| 123 gaps[-1-state]++; /* increment gap count */ |
| 124 state = 1; /* set state at one set bit */ |
| 125 } else { |
| 126 |
| 127 /* state is zero; this happens only at initialization */ |
| 128 state = 1; |
| 129 } |
| 130 } else { |
| 131 |
| 132 /* next bit is a zero */ |
| 133 if (state > 0) { |
| 134 |
| 135 /* prefix is a run */ |
| 136 if (state > 25) { |
| 137 debug_print(mod_stat, ">25 runs (2): %d", state); |
| 138 return err_status_algo_fail; /* long-runs test failed */ |
| 139 } |
| 140 if (state > 6) { |
| 141 state = 6; /* group together runs > 5 */ |
| 142 } |
| 143 runs[state-1]++; /* increment run count */ |
| 144 state = -1; /* set state at one zero bit */ |
| 145 } else if (state < 0) { |
| 146 |
| 147 /* prefix is a gap, so increment gap-count (decrement state) */ |
| 148 state--; |
| 149 |
| 150 /* check for long gaps */ |
| 151 if (state < -25) { |
| 152 debug_print(mod_stat, ">25 gaps (2): %d", state); |
| 153 return err_status_algo_fail; |
| 154 } |
| 155 |
| 156 } else { |
| 157 |
| 158 /* state is zero; this happens only at initialization */ |
| 159 state = -1; |
| 160 } |
| 161 } |
| 162 } |
| 163 |
| 164 /* move along to next octet */ |
| 165 data++; |
| 166 } |
| 167 |
| 168 if (mod_stat.on) { |
| 169 debug_print(mod_stat, "runs test", NULL); |
| 170 for (i=0; i < 6; i++) |
| 171 debug_print(mod_stat, " runs[]: %d", runs[i]); |
| 172 for (i=0; i < 6; i++) |
| 173 debug_print(mod_stat, " gaps[]: %d", gaps[i]); |
| 174 } |
| 175 |
| 176 /* check run and gap counts against the fixed limits */ |
| 177 for (i=0; i < 6; i++) |
| 178 if ( (runs[i] < lo_value[i] ) || (runs[i] > hi_value[i]) |
| 179 || (gaps[i] < lo_value[i] ) || (gaps[i] > hi_value[i])) |
| 180 return err_status_algo_fail; |
| 181 |
| 182 |
| 183 return err_status_ok; |
| 184 } |
| 185 |
| 186 |
| 187 /* |
| 188 * the function stat_test_rand_source applys the FIPS-140-2 statistical |
| 189 * tests to the random source defined by rs |
| 190 * |
| 191 */ |
| 192 |
| 193 #define RAND_SRC_BUF_OCTETS 50 /* this value MUST divide 2500! */ |
| 194 |
| 195 err_status_t |
| 196 stat_test_rand_source(rand_source_func_t get_rand_bytes) { |
| 197 int i; |
| 198 double poker; |
| 199 uint8_t *data, *data_end; |
| 200 uint16_t f[16] = { |
| 201 0, 0, 0, 0, 0, 0, 0, 0, |
| 202 0, 0, 0, 0, 0, 0, 0, 0 |
| 203 }; |
| 204 uint8_t buffer[RAND_SRC_BUF_OCTETS]; |
| 205 err_status_t status; |
| 206 int ones_count = 0; |
| 207 uint16_t runs[6] = { 0, 0, 0, 0, 0, 0 }; |
| 208 uint16_t gaps[6] = { 0, 0, 0, 0, 0, 0 }; |
| 209 uint16_t lo_value[6] = { 2315, 1114, 527, 240, 103, 103 }; |
| 210 uint16_t hi_value[6] = { 2685, 1386, 723, 384, 209, 209 }; |
| 211 int state = 0; |
| 212 uint16_t mask; |
| 213 |
| 214 /* counters for monobit, poker, and runs tests are initialized above */ |
| 215 |
| 216 /* main loop: fill buffer, update counters for stat tests */ |
| 217 for (i=0; i < 2500; i+=RAND_SRC_BUF_OCTETS) { |
| 218 |
| 219 /* fill data buffer */ |
| 220 status = get_rand_bytes(buffer, RAND_SRC_BUF_OCTETS); |
| 221 if (status) { |
| 222 debug_print(mod_stat, "couldn't get rand bytes: %d",status); |
| 223 return status; |
| 224 } |
| 225 |
| 226 #if 0 |
| 227 debug_print(mod_stat, "%s", |
| 228 octet_string_hex_string(buffer, RAND_SRC_BUF_OCTETS)); |
| 229 #endif |
| 230 |
| 231 data = buffer; |
| 232 data_end = data + RAND_SRC_BUF_OCTETS; |
| 233 while (data < data_end) { |
| 234 |
| 235 /* update monobit test counter */ |
| 236 ones_count += octet_get_weight(*data); |
| 237 |
| 238 /* update poker test counters */ |
| 239 f[*data & 0x0f]++; /* increment freq. count for low nibble */ |
| 240 f[(*data) >> 4]++; /* increment freq. count for high nibble */ |
| 241 |
| 242 /* update runs test counters */ |
| 243 /* loop over the bits of this byte */ |
| 244 for (mask = 1; mask < 256; mask <<= 1) { |
| 245 if (*data & mask) { |
| 246 |
| 247 /* next bit is a one */ |
| 248 if (state > 0) { |
| 249 |
| 250 /* prefix is a run, so increment the run-count */ |
| 251 state++; |
| 252 |
| 253 /* check for long runs */ |
| 254 if (state > 25) { |
| 255 debug_print(mod_stat, ">25 runs (3): %d", state); |
| 256 return err_status_algo_fail; |
| 257 } |
| 258 |
| 259 } else if (state < 0) { |
| 260 |
| 261 /* prefix is a gap */ |
| 262 if (state < -25) { |
| 263 debug_print(mod_stat, ">25 gaps (3): %d", state); |
| 264 return err_status_algo_fail; /* long-runs test failed */ |
| 265 } |
| 266 if (state < -6) { |
| 267 state = -6; /* group together gaps > 5 */ |
| 268 } |
| 269 gaps[-1-state]++; /* increment gap count */ |
| 270 state = 1; /* set state at one set bit */ |
| 271 } else { |
| 272 |
| 273 /* state is zero; this happens only at initialization */ |
| 274 state = 1; |
| 275 } |
| 276 } else { |
| 277 |
| 278 /* next bit is a zero */ |
| 279 if (state > 0) { |
| 280 |
| 281 /* prefix is a run */ |
| 282 if (state > 25) { |
| 283 debug_print(mod_stat, ">25 runs (4): %d", state); |
| 284 return err_status_algo_fail; /* long-runs test failed */ |
| 285 } |
| 286 if (state > 6) { |
| 287 state = 6; /* group together runs > 5 */ |
| 288 } |
| 289 runs[state-1]++; /* increment run count */ |
| 290 state = -1; /* set state at one zero bit */ |
| 291 } else if (state < 0) { |
| 292 |
| 293 /* prefix is a gap, so increment gap-count (decrement state) */ |
| 294 state--; |
| 295 |
| 296 /* check for long gaps */ |
| 297 if (state < -25) { |
| 298 debug_print(mod_stat, ">25 gaps (4): %d", state); |
| 299 return err_status_algo_fail; |
| 300 } |
| 301 |
| 302 } else { |
| 303 |
| 304 /* state is zero; this happens only at initialization */ |
| 305 state = -1; |
| 306 } |
| 307 } |
| 308 } |
| 309 |
| 310 /* advance data pointer */ |
| 311 data++; |
| 312 } |
| 313 } |
| 314 |
| 315 /* check to see if test data is within bounds */ |
| 316 |
| 317 /* check monobit test data */ |
| 318 |
| 319 debug_print(mod_stat, "stat: bit count: %d", ones_count); |
| 320 |
| 321 if ((ones_count < 9725) || (ones_count > 10275)) { |
| 322 debug_print(mod_stat, "stat: failed monobit test %d", ones_count); |
| 323 return err_status_algo_fail; |
| 324 } |
| 325 |
| 326 /* check poker test data */ |
| 327 poker = 0.0; |
| 328 for (i=0; i < 16; i++) |
| 329 poker += (double) f[i] * f[i]; |
| 330 |
| 331 poker *= (16.0 / 5000.0); |
| 332 poker -= 5000.0; |
| 333 |
| 334 debug_print(mod_stat, "stat: poker test: %f", poker); |
| 335 |
| 336 if ((poker < 2.16) || (poker > 46.17)) { |
| 337 debug_print(mod_stat, "stat: failed poker test", NULL); |
| 338 return err_status_algo_fail; |
| 339 } |
| 340 |
| 341 /* check run and gap counts against the fixed limits */ |
| 342 for (i=0; i < 6; i++) |
| 343 if ((runs[i] < lo_value[i] ) || (runs[i] > hi_value[i]) |
| 344 || (gaps[i] < lo_value[i] ) || (gaps[i] > hi_value[i])) { |
| 345 debug_print(mod_stat, "stat: failed run/gap test", NULL); |
| 346 return err_status_algo_fail; |
| 347 } |
| 348 |
| 349 debug_print(mod_stat, "passed random stat test", NULL); |
| 350 return err_status_ok; |
| 351 } |
| 352 |
| 353 err_status_t |
| 354 stat_test_rand_source_with_repetition(rand_source_func_t source, unsigned num_tr
ials) { |
| 355 unsigned int i; |
| 356 err_status_t err = err_status_algo_fail; |
| 357 |
| 358 for (i=0; i < num_trials; i++) { |
| 359 err = stat_test_rand_source(source); |
| 360 if (err == err_status_ok) { |
| 361 return err_status_ok; |
| 362 } |
| 363 debug_print(mod_stat, "failed stat test (try number %d)\n", i); |
| 364 } |
| 365 |
| 366 return err; |
| 367 } |
OLD | NEW |