1 module dcrypt.crypto.random.rdrand; 2 3 4 /// The RDRand PRNG generates random data with intels rdrand instruction. 5 /// Use `RDRand.isSupported` to check at runntime if rdrand is supported. 6 /// 7 /// TODO: This module is not yet tested. 8 9 import dcrypt.crypto.random.prng; 10 import dcrypt.util.pack; 11 import core.cpuid; 12 import std.range: chunks; 13 14 unittest { 15 if(RDRand.isSupported) { 16 ubyte[71] buf1; 17 ubyte[71] buf2; 18 19 RDRand rand; 20 21 rand.nextBytes(buf1); 22 rand.nextBytes(buf2); 23 24 assert(buf1 != buf2, "rdrand produced twice the same output!"); 25 } 26 } 27 28 static assert(isRNG!RDRand); 29 30 @safe 31 public struct RDRand { 32 33 public { 34 35 enum name = "RDRand"; 36 37 } 38 39 /// Returns: `true` if your platform supports the rdrand instruction. Evaluated at runtime. 40 @property 41 public static bool isSupported() nothrow @nogc { 42 return hasRdrand(); 43 } 44 45 /// Dummy function. Has no effect at all. 46 public void addSeed(in ubyte[]) nothrow @nogc pure {} 47 48 49 /// Generate random data with rdrand instruction. 50 /// Params: 51 /// buf = Buffer for random data. 52 /// 53 /// Throws: Throws an Error if your platform does not support the RDRAND instruction. 54 @trusted 55 public static void nextBytes(ubyte[] buf) nothrow @nogc 56 { 57 58 if(!isSupported) { 59 assert(false, "RDRAND is not supported by your platform!"); 60 } 61 62 size_t len = buf.length / 8; 63 64 asm nothrow @nogc { 65 66 mov RDI, buf+8; // load pointer to destination buffer 67 mov RCX, len; // set counter to len 68 69 // fill buf with random data 70 fillLoop: 71 rdrand R8; 72 mov R8, RAX; 73 mov [RDI], R8; 74 add RDI, 8; 75 76 loop fillLoop; 77 } 78 79 80 if(buf.length % 8 > 0) { 81 82 assert(buf.length-len*8 < 8); 83 84 // fill remainder with random bytes 85 ulong r = nextLong(); 86 87 foreach(ref b; buf[len*8 .. $]) { 88 b = cast(ubyte) r; 89 r >>= 8; 90 } 91 } 92 } 93 94 // public void nextBytes(ubyte[] buf) nothrow @nogc 95 // { 96 // 97 // if(!isSupported) { 98 // assert(false, "RDRAND is not supported by your platform!"); 99 // } 100 // 101 // while(buf.length > 0) { 102 // long r = nextLong(); 103 // for(uint i = 0; i < 8 && buf.length > 0; ++i) { 104 // buf[0] = cast(ubyte) r & 0xFF; 105 // r >>= 8; 106 // } 107 // } 108 // } 109 110 /// Returns: A uniformly random ulong. 111 /// 112 // TODO: optimize to fill an array 113 @trusted 114 private static ulong nextLong() nothrow @nogc { 115 ulong r; 116 117 asm nothrow @nogc { 118 rdrand R8; 119 mov r, R8; 120 } 121 122 return r; 123 } 124 125 126 unittest { 127 if(isSupported) { 128 long r1 = nextLong(); 129 long r2 = nextLong(); 130 131 assert(r1 != r2, "rdrand produced twice the same output!"); 132 } 133 } 134 135 }