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.bitmanip; 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 /// Generate random data with rdrand instruction. 46 /// Params: 47 /// buf = Buffer for random data. 48 /// 49 /// Throws: Throws an Error if your platform does not support the RDRAND instruction. 50 @trusted 51 public static void nextBytes(ubyte[] buf) nothrow @nogc 52 { 53 54 if(!isSupported) { 55 assert(false, "RDRAND is not supported by your platform!"); 56 } 57 58 size_t len = buf.length / 8; 59 60 asm nothrow @nogc { 61 62 mov RDI, buf+8; // load pointer to destination buffer 63 mov RCX, len; // set counter to len 64 65 // fill buf with random data 66 fillLoop: 67 rdrand R8; 68 mov R8, RAX; 69 mov [RDI], R8; 70 add RDI, 8; 71 72 loop fillLoop; 73 } 74 75 76 if(buf.length % 8 > 0) { 77 78 assert(buf.length-len*8 < 8); 79 80 // fill remainder with random bytes 81 ulong r = nextLong(); 82 83 foreach(ref b; buf[len*8 .. $]) { 84 b = cast(ubyte) r; 85 r >>= 8; 86 } 87 } 88 } 89 90 // public void nextBytes(ubyte[] buf) nothrow @nogc 91 // { 92 // 93 // if(!isSupported) { 94 // assert(false, "RDRAND is not supported by your platform!"); 95 // } 96 // 97 // while(buf.length > 0) { 98 // long r = nextLong(); 99 // for(uint i = 0; i < 8 && buf.length > 0; ++i) { 100 // buf[0] = cast(ubyte) r & 0xFF; 101 // r >>= 8; 102 // } 103 // } 104 // } 105 106 /// Returns: A uniformly random ulong. 107 /// 108 // TODO: optimize to fill an array 109 @trusted 110 private static ulong nextLong() nothrow @nogc { 111 ulong r; 112 113 asm nothrow @nogc { 114 rdrand R8; 115 mov r, R8; 116 } 117 118 return r; 119 } 120 121 122 unittest { 123 if(isSupported) { 124 long r1 = nextLong(); 125 long r2 = nextLong(); 126 127 assert(r1 != r2, "rdrand produced twice the same output!"); 128 } 129 } 130 131 }