1 module dcrypt.crypto.random.prng;
2 
3 import std.range;
4 import dcrypt.crypto.random.fortuna.fortuna;
5 import dcrypt.crypto.random.fortuna.generator;
6 
7 import dcrypt.crypto.engines.aes;
8 import dcrypt.crypto.digests.sha2;
9 
10 alias FortunaGenerator!(AES, SHA256) DRNG; /// Deterministic PRNG
11 
12 // TODO implement PRNGs as input ranges
13 
14 ///
15 /// Test if T is a random number generator.
16 /// Returns: Returns $(D true) if T can be used as a PRNG.
17 /// 
18 @safe
19 template isRNG(T)
20 {
21 	enum bool isRNG = 
22 		is(T == struct) &&
23 			is(typeof(
24 					{
25 						ubyte[] buf;
26 						T rng = void;
27 						string name = rng.name;
28 						rng.nextBytes(buf);
29 						rng.addSeed(cast(const ubyte[]) buf);
30 					}));
31 }
32 
33 @safe
34 public abstract class RNG {
35 
36 // TODO: default RNG
37 //	/**
38 //	 * Creates a default PRNG. Type depends on your system.
39 //	 */
40 //	public static PRNG getInstance() nothrow
41 //	out (result) {
42 //		assert(result !is null, "failed to initialize PRNG instance");
43 //	}
44 //	body {
45 //		return new Fortuna();
46 //	}
47 	
48 	/// Fill the buffer with random bytes.
49 	/// Params:
50 	/// buf = output buffer to be filled with PRNG data
51 	public abstract void nextBytes(ubyte[] buf) nothrow;
52 	
53 	/// Returns: The name of the RNG algorithm.
54 	@property
55 	public abstract string name() pure nothrow;
56 
57 	///
58 	/// Add a seed value to the PRNG.
59 	/// 
60 	/// Params:
61 	/// seed = The seed value to add to the PRNG.
62 	public abstract void addSeed(in ubyte[] seed) nothrow;
63 	
64 }
65 
66 ///
67 ///	Wrapper class for PRNGs.
68 ///
69 @safe
70 public class WrapperPRNG(R) if(isRNG!R): RNG {
71 
72 	private R rng;
73 
74 override:
75 	/// fill the buffer with random bytes
76 	/// Params:
77 	/// buf = output buffer to be filled with PRNG data
78 	public void nextBytes(ubyte[] buf) nothrow @nogc {
79 		rng.nextBytes(buf);
80 	}
81 	
82 	/// Returns: the name of the RNG algorithm
83 	@property
84 	public string name() pure nothrow @nogc {
85 		return rng.name;
86 	}
87 	
88 	///
89 	/// Add a seed value to the PRNG.
90 	/// 
91 	/// Params:
92 	/// seed = the seed value to add to the PRNG
93 	public void addSeed(in ubyte[] seed) nothrow @nogc {
94 		rng.addSeed(seed);
95 	}
96 	
97 }