1 module dcrypt.random.random;
2 
3 /// Handling global source of randomness.
4 
5 
6 import dcrypt.random.fortuna.fortuna;
7 
8 import dcrypt.random.rdrand;
9 import dcrypt.random.urandom;
10 
11 import dcrypt.random.fortuna.entropysource;
12 import dcrypt.random.fortuna.sources.rdrand;
13 import dcrypt.random.fortuna.sources.systemtick;
14 import dcrypt.random.fortuna.sources.filesource;
15 
16 version = FortunaRNG;
17 
18 version (FortunaRNG) {
19 	private Fortuna globalRNG;
20 
21 	/// Initialize Fortuna
22 	private shared static this() {
23 		/// Initialize entropy sources.
24 		
25 		debug import std.stdio;
26 		
27 		if(RDRand.isSupported) {
28 			// start rdrand entropy source
29 			
30 			debug writeln("Starting RDRAND entropy source.");
31 			EntropySource rdrand_src = new RDRandEntropySource;
32 			rdrand_src.start();
33 			
34 		} else {
35 			debug writeln("RDRAND entropy source is not available.");
36 		}
37 		
38 		try {
39 			debug writeln("Starting /dev/urandom entropy source.");
40 			EntropySource urandom_src = new FileEntropySource(urandom);
41 			urandom_src.start();
42 		} catch(Exception e) {
43 			debug writeln("/dev/urandom entropy source is not available.", e);
44 		}
45 		
46 		debug writeln("Starting system-tick entropy source.");
47 		EntropySource systick_src = new SystemTickEntropySource;
48 		systick_src.start();
49 	}
50 } else {
51 	private PRNG globalRNG;
52 
53 	// Initialize the global random number generator.
54 	private shared static this() {
55 		if (URandomRNG.isAvailable) {
56 			globalRNG = new URandomRNG;
57 		}
58 		else if (RDRand.isSupported) {
59 			globalRNG = new RDRandRNG;
60 		}
61 	}
62 }
63 
64 private enum urandom = "/dev/urandom";
65 
66 /// Fill a buffer with random bytes from the default random number generator.
67 public void nextBytes(ubyte[] buf) @safe nothrow @nogc {
68 		globalRNG.nextBytes(buf);
69 }
70 
71 unittest {
72 	ubyte[50] buf1, buf2;
73 
74 	nextBytes(buf1);
75 	nextBytes(buf2);
76 
77 	assert(buf1 != buf2);
78 }
79