1 module dcrypt.random.prng; 2 3 import std.range; 4 import dcrypt.random.fortuna.fortuna; 5 import dcrypt.random.fortuna.generator; 6 7 import dcrypt.blockcipher.aes; 8 import dcrypt.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) && // isInputRange!T && 23 is(typeof( 24 { 25 ubyte[] buf; 26 T rng = T.init; 27 string name = rng.name; 28 rng.nextBytes(buf); 29 })); 30 } 31 32 @safe 33 template isRNGWithInput(T) 34 { 35 enum bool isRNGWithInput = isRNG!T && 36 is(typeof( 37 { 38 ubyte[] buf; 39 T rng = T.init; 40 rng.addSeed(cast(const ubyte[]) buf); 41 rng.addSeed(cast(ubyte) 0); 42 rng.addSeed(cast(ubyte) 0, cast(ubyte) 0); 43 })); 44 } 45 46 /// Helper function for prng. 47 /// 48 /// Params: 49 /// rng = The RNG to put the data into. 50 /// seed = The seed to update the RNG with. 51 /// 52 /// Example: 53 /// ubyte[4] buf; 54 /// RNG rng; 55 /// rng.addSeed(cast(ubyte) 0x01, buf, buf[0..2]); 56 @safe 57 public void addSeed(R, T...)(ref R rng, in T seed) nothrow @nogc 58 if(isRNGWithInput!D) { 59 foreach(s; seed) { 60 digest.addSeed(s); 61 } 62 } 63 64 @safe 65 public abstract class PRNG { 66 67 // TODO: default RNG 68 // /** 69 // * Creates a default PRNG. Type depends on your system. 70 // */ 71 // public static PRNG getInstance() nothrow 72 // out (result) { 73 // assert(result !is null, "failed to initialize PRNG instance"); 74 // } 75 // body { 76 // return new Fortuna(); 77 // } 78 79 /// Fill the buffer with random bytes. 80 /// 81 /// Params: 82 /// buf = Output buffer to be filled with PRNG data. 83 public abstract void nextBytes(ubyte[] buf) nothrow; 84 85 /// Returns: The name of the RNG algorithm. 86 @property 87 public abstract string name() pure nothrow; 88 89 /// 90 /// Add a seed value to the PRNG. 91 /// 92 /// Params: 93 /// seed = The seed value to add to the PRNG. 94 public abstract void addSeed(in ubyte[] seed) nothrow; 95 96 } 97 98 /// 99 /// Wrapper class for PRNGs. 100 /// 101 @safe 102 public class WrapperPRNG(R) if(isRNGWithInput!R): PRNG { 103 104 private R rng; 105 106 override: 107 /// Fill the buffer with random bytes. 108 /// 109 /// Params: 110 /// buf = Output buffer to be filled with PRNG data. 111 public void nextBytes(ubyte[] buf) nothrow { 112 rng.nextBytes(buf); 113 } 114 115 /// Returns: the name of the RNG algorithm 116 @property 117 public string name() pure nothrow @nogc { 118 return rng.name; 119 } 120 121 /// 122 /// Add a seed value to the PRNG. 123 /// 124 /// Params: 125 /// seed = the seed value to add to the PRNG 126 public void addSeed(in ubyte[] seed) nothrow @nogc { 127 rng.addSeed(seed); 128 } 129 }