1 module chloride.random; 2 3 import chloride.core; 4 5 import std.array : uninitializedArray; 6 import std.traits; 7 8 import deimos.sodium.randombytes; 9 10 11 /** 12 * Allocate `n` bytes of cryptographic random data. 13 */ 14 ubyte[] randomBytes(int n) { 15 ubyte[] buf = uninitializedArray!(ubyte[])(n); 16 fillRandom(buf); 17 return buf; 18 } 19 20 /** 21 * Create an array of `n` elements filled with random data. 22 * The array can be static or dynamic. If the array is dynamic, the size 23 * must be passed as a runtime argument. 24 */ 25 U randomArray(U: T[n], T, int n)() if (isScalarType!T) { 26 U data = void; 27 fillRandom(data); 28 return data; 29 } 30 31 /// 32 U randomArray(U: T[], T)(int n) if (isScalarType!T) { 33 U data = uninitializedArray!(U)(n); 34 fillRandom(data); 35 return data; 36 } 37 38 39 /** 40 * Fill `buf` with cryptographic random data. 41 */ 42 void fillRandom(void[] buf) { 43 randombytes_buf(buf.ptr, buf.length); 44 } 45 46 /** 47 * Get a single random Integer of type T. T can be any 48 * integral type with four or fewer bytes. 49 */ 50 T random(T)() if (isIntegral!T && (T.sizeof < 4)) { 51 uint bytes = random(Unsigned!T.max); 52 return cast(T) bytes; 53 } 54 55 /// ditto 56 T random(T : uint = uint)() { 57 return randombytes_random(); 58 } 59 60 /** 61 * Get a random integer between 0 and n (excluded). It does its best 62 * to guarantee a uniform distribution. 63 */ 64 uint random(uint n) { 65 return randombytes_uniform(n); 66 } 67 68 69 /** 70 * An input range that generates random bytes. 71 */ 72 struct RandomByteRange { 73 private uint data; 74 private ubyte count; 75 76 @property ubyte front() const pure { 77 return cast(ubyte) data; 78 } 79 80 void popFront() { 81 count++; 82 if (count < 4) { 83 data >>= 8; 84 } else { 85 count = 0; 86 data = random(); 87 } 88 } 89 90 enum empty = false; 91 } 92 93 /** 94 * Create an instance of RandomByteRange 95 */ 96 RandomByteRange randomByteRange() { 97 return RandomByteRange(random(), 0); 98 }