diff options
Diffstat (limited to 'lib/hcrypto/test_rand.c')
-rw-r--r-- | lib/hcrypto/test_rand.c | 68 |
1 files changed, 49 insertions, 19 deletions
diff --git a/lib/hcrypto/test_rand.c b/lib/hcrypto/test_rand.c index c90ed3cba0b9..b3ee2b104a63 100644 --- a/lib/hcrypto/test_rand.c +++ b/lib/hcrypto/test_rand.c @@ -34,10 +34,9 @@ */ #include <config.h> - -#include <stdio.h> - #include <roken.h> +#include <math.h> + #include <getarg.h> #include "rand.h" @@ -104,10 +103,7 @@ main(int argc, char **argv) exit(0); } - argc -= idx; - argv += idx; - - if (argc != 0) + if (argc != idx) usage(1); buffer = emalloc(len); @@ -123,10 +119,6 @@ main(int argc, char **argv) else if (strcasecmp(rand_method, "unix") == 0) RAND_set_rand_method(RAND_unix_method()); #endif -#ifndef NO_RAND_EGD_METHOD - else if (strcasecmp(rand_method, "egd") == 0) - RAND_set_rand_method(RAND_egd_method()); -#endif #ifdef WIN32 else if (strcasecmp(rand_method, "w32crypto") == 0) RAND_set_rand_method(RAND_w32crypto_method()); @@ -149,12 +141,20 @@ main(int argc, char **argv) /* head vs tail */ if (len >= 100000) { - int bit, i; + unsigned bytes[256]; + unsigned bits[8]; + size_t bit, i; double res; - int bits[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + double slen = sqrt((double)len); + + memset(bits, 0, sizeof(bits)); + memset(bytes, 0, sizeof(bytes)); for (i = 0; i < len; i++) { unsigned char c = ((unsigned char *)buffer)[i]; + + bytes[c]++; + for (bit = 0; bit < 8 && c; bit++) { if (c & 1) bits[bit]++; @@ -162,14 +162,44 @@ main(int argc, char **argv) } } + /* + * The count for each bit value has a mean of n*p = len/2, + * and a standard deviation of sqrt(n*p*q) ~ sqrt(len/4). + * Normalizing by dividing by "n*p", we get a mean of 1 and + * a standard deviation of sqrt(q/n*p) = 1/sqrt(len). + * + * A 5.33-sigma event happens 1 time in 10 million. + * A 5.73-sigma event happens 1 time in 100 million. + * A 6.11-sigma event happens 1 time in 1000 million. + * + * We tolerate 5.33-sigma events (we have 8 not entirely + * independent chances of skewed results) and want to fail + * with a good RNG less often than 1 time in million. + */ for (bit = 0; bit < 8; bit++) { + res = slen * fabs(1.0 - 2 * (double)bits[bit] / len); + if (res > 5.33) + errx(1, "head%d vs tail%d: %.1f-sigma (%d of %d)", + (int)bit, (int)bit, res, bits[bit], len); + printf("head vs tails bit%d: %f-sigma\n", (int)bit, res); + } - res = ((double)abs(len - bits[bit] * 2)) / (double)len; - if (res > 0.005) - errx(1, "head%d vs tail%d > 0.5%%%% %lf == %d vs %d", - bit, bit, res, len, bits[bit]); - - printf("head vs tails bit%d: %lf\n", bit, res); + /* + * The count of each byte value has a mean of n*p = len/256, + * and a standard deviation of sqrt(n*p*q) ~ sqrt(len/256). + * Normalizing by dividing by "n*p", we get a mean of 1 and + * a standard deviation of sqrt(q/n*p) ~ 16/sqrt(len). + * + * We tolerate 5.73-sigma events (we have 256 not entirely + * independent chances of skewed results). Note, for example, + * a 5.2-sigma event was observed in ~5,000 runs. + */ + for (i = 0; i < 256; i++) { + res = (slen / 16) * fabs(1.0 - 256 * (double)bytes[i] / len); + if (res > 5.73) + errx(1, "byte %d: %.1f-sigma (%d of %d)", + (int) i, res, bytes[i], len); + printf("byte %d: %f-sigma\n", (int)i, res); } } |