1/*
2 *      Physically random numbers (very nearly uniform)
3 *      D. P. Mitchell
4 *      Modified by Matt Blaze 7/95
5 */
6/*
7 * The authors of this software are Don Mitchell and Matt Blaze.
8 *              Copyright (c) 1995 by AT&T.
9 * Permission to use, copy, and modify this software without fee
10 * is hereby granted, provided that this entire notice is included in
11 * all copies of any software which is or includes a copy or
12 * modification of this software and in all copies of the supporting
13 * documentation for such software.
14 *
15 * This software may be subject to United States export controls.
16 *
17 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
19 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
20 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
21 */
22
23/*
24 * WARNING: depending on the particular platform, raw_truerand()
25 * output may be biased or correlated.  In general, you can expect
26 * about 16 bits of "pseudo-entropy" out of each 32 bit word returned
27 * by truerand(), but it may not be uniformly diffused.  You should
28 * raw_therefore run the output through some post-whitening function
29 * (like MD5 or DES or whatever) before using it to generate key
30 * material.  (RSAREF's random package does this for you when you feed
31 * raw_truerand() bits to the seed input function.)
32 *
33 * The application interface, for 8, 16, and 32 bit properly "whitened"
34 * random numbers, can be found in trand8(), trand16(), and trand32().
35 * Use those instead of calling raw_truerand() directly.
36 *
37 * The basic idea here is that between clock "skew" and various
38 * hard-to-predict OS event arrivals, counting a tight loop will yield
39 * a little (maybe a third of a bit or so) of "good" randomness per
40 * interval clock tick.  This seems to work well even on unloaded
41 * machines.  If there is a human operator at the machine, you should
42 * augment truerand with other measure, like keyboard event timing.
43 * On server machines (e.g., when you need to generate a
44 * Diffie-Hellman secret) truerand alone may be good enough.
45 *
46 * Test these assumptions on your own platform before fielding a
47 * system based on this software or these techniques.
48 *
49 * This software seems to work well (at 10 or so bits per
50 * raw_truerand() call) on a Sun Sparc-20 under SunOS 4.1.3 and on a
51 * P100 under BSDI 2.0.  You're on your own elsewhere.
52 *
53 */
54
55#include "t_defines.h"
56
57#include <signal.h>
58#include <setjmp.h>
59#include <sys/time.h>
60#include <math.h>
61#include <stdio.h>
62
63#ifdef OLD_TRUERAND
64static jmp_buf env;
65#endif
66static unsigned volatile count
67#ifndef OLD_TRUERAND
68  , done = 0
69#endif
70;
71
72static unsigned ocount;
73static unsigned buffer;
74
75static void
76tick()
77{
78	struct itimerval it, oit;
79
80	it.it_interval.tv_sec = 0;
81	it.it_interval.tv_usec = 0;
82	it.it_value.tv_sec = 0;
83	it.it_value.tv_usec = 16665;
84	if (setitimer(ITIMER_REAL, &it, &oit) < 0)
85		perror("tick");
86}
87
88static void
89interrupt()
90{
91	if (count) {
92#ifdef OLD_TRUERAND
93		longjmp(env, 1);
94#else
95		++done;
96		return;
97#endif
98	}
99
100	(void) signal(SIGALRM, interrupt);
101	tick();
102}
103
104static unsigned long
105roulette()
106{
107#ifdef OLD_TRUERAND
108	if (setjmp(env)) {
109		count ^= (count>>3) ^ (count>>6) ^ ocount;
110		count &= 0x7;
111		ocount=count;
112		buffer = (buffer<<3) ^ count;
113		return buffer;
114	}
115#else
116	done = 0;
117#endif
118	(void) signal(SIGALRM, interrupt);
119	count = 0;
120	tick();
121#ifdef OLD_TRUERAND
122	for (;;)
123#else
124	while(done == 0)
125#endif
126		count++;        /* about 1 MHz on VAX 11/780 */
127#ifndef OLD_TRUERAND
128	count ^= (count>>3) ^ (count>>6) ^ ocount;
129	count &= 0x7;
130	ocount=count;
131	buffer = (buffer<<3) ^ count;
132	return buffer;
133#endif
134}
135
136unsigned long
137raw_truerand()
138{
139	count=0;
140	(void) roulette();
141	(void) roulette();
142	(void) roulette();
143	(void) roulette();
144	(void) roulette();
145	(void) roulette();
146	(void) roulette();
147	(void) roulette();
148	(void) roulette();
149	(void) roulette();
150	return roulette();
151}
152