s4:heimdal: import lorikeet-heimdal-202201172009 (commit 5a0b45cd723628b3690ea848548b...
[samba.git] / source4 / heimdal / lib / hcrypto / test_rand.c
1 /*
2  * Copyright (c) 2007 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35
36 #include <config.h>
37 #include <roken.h>
38 #include <math.h>
39
40 #include <getarg.h>
41
42 #include "rand.h"
43
44
45 /*
46  *
47  */
48
49 static int version_flag;
50 static int help_flag;
51 static int len = 1024 * 1024;
52 static char *rand_method;
53 static char *filename;
54
55 static struct getargs args[] = {
56     { "length", 0,      arg_integer,    &len,
57       "length", NULL },
58     { "file",   0,      arg_string,     &filename,
59       "file name", NULL },
60     { "method", 0,      arg_string,     &rand_method,
61       "method", NULL },
62     { "version",        0,      arg_flag,       &version_flag,
63       "print version", NULL },
64     { "help",           0,      arg_flag,       &help_flag,
65       NULL,     NULL }
66 };
67
68 /*
69  *
70  */
71
72 /*
73  *
74  */
75
76 static void
77 usage (int ret)
78 {
79     arg_printusage (args,
80                     sizeof(args)/sizeof(args[0]),
81                     NULL,
82                     "");
83     exit (ret);
84 }
85
86 int
87 main(int argc, char **argv)
88 {
89     int idx = 0;
90     char *buffer;
91     char path[MAXPATHLEN];
92
93     setprogname(argv[0]);
94
95     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &idx))
96         usage(1);
97
98     if (help_flag)
99         usage(0);
100
101     if(version_flag){
102         print_version(NULL);
103         exit(0);
104     }
105
106     if (argc != idx)
107         usage(1);
108
109     buffer = emalloc(len);
110
111     if (rand_method) {
112         if (0) {
113         }
114 #ifndef NO_RAND_FORTUNA_METHOD
115         else if (strcasecmp(rand_method, "fortuna") == 0)
116             RAND_set_rand_method(RAND_fortuna_method());
117 #endif
118 #ifndef NO_RAND_UNIX_METHOD
119         else if (strcasecmp(rand_method, "unix") == 0)
120             RAND_set_rand_method(RAND_unix_method());
121 #endif
122 #ifdef WIN32
123         else if (strcasecmp(rand_method, "w32crypto") == 0)
124             RAND_set_rand_method(RAND_w32crypto_method());
125 #endif
126         else
127             errx(1, "unknown method %s", rand_method);
128     }
129
130     if (RAND_file_name(path, sizeof(path)) == NULL)
131         errx(1, "RAND_file_name failed");
132
133     if (RAND_status() != 1)
134         errx(1, "random not ready yet");
135
136     if (RAND_bytes(buffer, len) != 1)
137         errx(1, "RAND_bytes");
138
139     if (filename)
140         rk_dumpdata(filename, buffer, len);
141
142     /* head vs tail */
143     if (len >= 100000) {
144         unsigned bytes[256]; 
145         unsigned bits[8];
146         size_t bit, i;
147         double res;
148         double slen = sqrt((double)len);
149
150         memset(bits, 0, sizeof(bits));
151         memset(bytes, 0, sizeof(bytes));
152
153         for (i = 0; i < len; i++) {
154             unsigned char c = ((unsigned char *)buffer)[i];
155
156             bytes[c]++;
157
158             for (bit = 0; bit < 8 && c; bit++) {
159                 if (c & 1)
160                     bits[bit]++;
161                 c = c >> 1;
162             }
163         }
164
165         /*
166          * The count for each bit value has a mean of n*p = len/2,
167          * and a standard deviation of sqrt(n*p*q) ~ sqrt(len/4).
168          * Normalizing by dividing by "n*p", we get a mean of 1 and
169          * a standard deviation of sqrt(q/n*p) = 1/sqrt(len).
170          *
171          * A 5.33-sigma event happens 1 time in 10 million.
172          * A 5.73-sigma event happens 1 time in 100 million.
173          * A 6.11-sigma event happens 1 time in 1000 million.
174          *
175          * We tolerate 5.33-sigma events (we have 8 not entirely
176          * independent chances of skewed results) and want to fail
177          * with a good RNG less often than 1 time in million.
178          */
179         for (bit = 0; bit < 8; bit++) {
180             res = slen * fabs(1.0 - 2 * (double)bits[bit] / len);
181             if (res > 5.33)
182                 errx(1, "head%d vs tail%d: %.1f-sigma (%d of %d)",
183                      (int)bit, (int)bit, res, bits[bit], len);
184             printf("head vs tails bit%d: %f-sigma\n", (int)bit, res);
185         }
186
187         /*
188          * The count of each byte value has a mean of n*p = len/256,
189          * and a standard deviation of sqrt(n*p*q) ~ sqrt(len/256).
190          * Normalizing by dividing by "n*p", we get a mean of 1 and
191          * a standard deviation of sqrt(q/n*p) ~ 16/sqrt(len).
192          *
193          * We tolerate 5.73-sigma events (we have 256 not entirely
194          * independent chances of skewed results).  Note, for example,
195          * a 5.2-sigma event was observed in ~5,000 runs.
196          */
197         for (i = 0; i < 256; i++) {
198             res = (slen / 16) * fabs(1.0 - 256 * (double)bytes[i] / len);
199             if (res > 5.73)
200                 errx(1, "byte %d: %.1f-sigma (%d of %d)",
201                      (int) i, res, bytes[i], len);
202             printf("byte %d: %f-sigma\n", (int)i, res);
203         }
204     }
205
206     free(buffer);
207
208     /* test write random file */
209     {
210         static const char *file = "test.file";
211         if (RAND_write_file(file) != 1)
212             errx(1, "RAND_write_file");
213         if (RAND_load_file(file, 1024) != 1)
214             errx(1, "RAND_load_file");
215         unlink(file);
216     }
217
218     return 0;
219 }