aboutsummaryrefslogtreecommitdiff
path: root/lib/hcrypto/test_rand.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hcrypto/test_rand.c')
-rw-r--r--lib/hcrypto/test_rand.c68
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);
}
}