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) && // 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 RNG { 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 /// Params: 81 /// buf = output buffer to be filled with PRNG data 82 public abstract void nextBytes(ubyte[] buf) nothrow; 83 84 /// Returns: The name of the RNG algorithm. 85 @property 86 public abstract string name() pure nothrow; 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 abstract void addSeed(in ubyte[] seed) nothrow; 94 95 } 96 97 /// 98 /// Wrapper class for PRNGs. 99 /// 100 @safe 101 public class WrapperPRNG(R) if(isRNGWithInput!R): RNG { 102 103 private R rng; 104 105 override: 106 /// fill the buffer with random bytes 107 /// Params: 108 /// buf = output buffer to be filled with PRNG data 109 public void nextBytes(ubyte[] buf) nothrow @nogc { 110 rng.nextBytes(buf); 111 } 112 113 /// Returns: the name of the RNG algorithm 114 @property 115 public string name() pure nothrow @nogc { 116 return rng.name; 117 } 118 119 /// 120 /// Add a seed value to the PRNG. 121 /// 122 /// Params: 123 /// seed = the seed value to add to the PRNG 124 public void addSeed(in ubyte[] seed) nothrow @nogc { 125 rng.addSeed(seed); 126 } 127 128 }