64 Bit RNG using RngJitterSource.cs
Updated: Dec-26,2020
Example Code: Add a 256x256 panel to a form. var lrng = new Random64(65536, 256, 2); var g = panel1.CreateGraphics(); var bm = new Bitmap(256, 256); var buf = lrng.GetNextBoolArrayLimit(65536); var ptr = 0; for (var y = 0; y < 256; y++) for (var x = 0; x < 256; x++) { var r = buf[ptr++]; if (r) { bm.SetPixel(x, y, Color.White); } else { bm.SetPixel(x, y, Color.Black); } } g.DrawImageUnscaled(bm, 0, 0);
using System; using System.Security.Cryptography; [Serializable] public class Random64 : RandomNumberGenerator { private byte[] _buffer; public RngJitterSource _crng; private double _dBi; private ulong UpperLimit = ulong.MaxValue; public Random64() { SetDataUse = 8; _crng = new RngJitterSource(); } public Random64(int cacheSize) { SetDataUse = 8; _crng = new RngJitterSource(cacheSize * 8, 256, 256, 4); } public Random64(int cacheSize, int seedSize) { SetDataUse = 8; _crng = new RngJitterSource(cacheSize * 8, seedSize, 256, 4); } public Random64(int cacheSize, int seedSize, int dataSize, int sha3Size = 256, int sha3Rounds = 4) { SetDataUse = dataSize; _crng = new RngJitterSource(cacheSize * dataSize, seedSize, sha3Size, sha3Rounds); } public int SetDataUse { get => _buffer.Length; set { var v = value; if (v < 1 || v > 8 || v == 3 || v == 5 || v == 6 || v == 7) throw new ArgumentException($"Value {v} must be either 1 or 2 or 4 or 8"); switch (v) { case 1: _dBi = 1.0D / byte.MaxValue; UpperLimit = byte.MaxValue; _buffer = new byte[1]; break; case 2: _dBi = 1.0D / ushort.MaxValue; UpperLimit = ushort.MaxValue; _buffer = new byte[2]; break; case 4: _dBi = 1.0D / uint.MaxValue; UpperLimit = uint.MaxValue; _buffer = new byte[4]; break; case 8: _dBi = 1.0D / ulong.MaxValue; UpperLimit = ulong.MaxValue; _buffer = new byte[8]; break; default: _dBi = 1.0D / ulong.MaxValue; UpperLimit = ulong.MaxValue; _buffer = new byte[8]; break; } } } public bool OddsOnly { get; set; } private double Sample() { ulong Internal() { _crng.GetBytes(_buffer); return BufferToLong(_buffer); } return Internal() * _dBi; } public ulong Next(ulong minValue, ulong maxValue) { var sa = Sample(); var fi = (double) (maxValue - minValue + minValue); var n = (ulong) (sa * fi); n = !OddsOnly ? n : n | 1; if (n < minValue) return Next(minValue, maxValue); return n; } public ulong Next(ulong maxValue) { return Next(0, maxValue); } public ulong Next() { return Next(0, UpperLimit); } public unsafe double NextDouble() { var buf = new byte[8]; GetBytes(buf); fixed (byte* ptr = buf) { return *(ulong*) ptr * _dBi * ulong.MaxValue; } } public char[] GetNextCharArray(int size) { var xbc = new byte[1]; var ca = new char[size]; var ptr = 0; do { _crng.GetBytes(xbc); var c = xbc[0]; if (c >= 32 && c <= 127) ca[ptr++] = (char) c; } while (ptr < size); return ca; } public char[] GetNextCharArrayX(int size) { var xbc = new byte[2]; var ca = new char[size]; var ptr = 0; do { _crng.GetBytes(xbc); ca[ptr++] = Convert.ToChar(xbc.ToShort()); } while (ptr < size); return ca; } public byte[] GetNextByteArray(int size) { var ba = new byte[size]; _crng.GetBytes(ba); return ba; } public bool[] GetNextBoolArrayLimit(int size) { var ba = new bool[size]; const uint ll = uint.MaxValue >> 1; for (var i = 0; i < size; ++i) ba[i] = Next(0, uint.MaxValue) > ll; return ba; } public byte[] GetNextByteArrayLimit(int size, ulong minValue, ulong maxValue) { var ba = new byte[size]; for (var i = 0; i < size; ++i) ba[i] = (byte) Next(minValue, maxValue); return ba; } public ushort[] GetNextUShortArrayLimit(int size, ulong minValue, ulong maxValue) { var ba = new ushort[size]; for (var i = 0; i < size; ++i) ba[i] = (ushort) Next(minValue, maxValue); return ba; } public uint[] GetNextUIntArrayLimit(int size, ulong minValue, ulong maxValue) { var ba = new uint[size]; for (var i = 0; i < size; ++i) ba[i] = (uint) Next(minValue, maxValue); return ba; } public ulong[] GetNextULongArrayLimit(int size, ulong minValue, ulong maxValue) { var ba = new ulong[size]; for (var i = 0; i < size; ++i) ba[i] = Next(minValue, maxValue); return ba; } public string GetRandomString(int minLen, int maxLen) { if (minLen == maxLen) return new string(GetNextCharArray(minLen)); return new string(GetNextCharArray((int) Next((ulong) minLen, (ulong) maxLen))); } public override void GetBytes(byte[] data) { if (data == null) throw new ArgumentException("The buffer cannot be null."); _crng.GetBytes(data); } public void NextBytes(byte[] buffer) { if (buffer == null) throw new ArgumentNullException("The buffer cannot be null."); for (var index = 0; index < buffer.Length; ++index) buffer[index] = (byte) (Sample() * byte.MaxValue + 1); } public override void GetNonZeroBytes(byte[] buffer) { if (buffer == null) throw new ArgumentNullException("The buffer cannot be null."); var index = 0; do { var v = (byte) (Sample() * byte.MaxValue + 1); if (v > 0) { buffer[index] = v; index++; } } while (index < buffer.Length); } private unsafe ulong BufferToLong(byte[] buffer) { var len = buffer.Length; if (len < 1 || len > 8) throw new ArgumentException($"The array length {len} must be between 1 and 8"); fixed (byte* Ptr = &buffer[0]) { switch (len) { case 1: return *Ptr; case 2: return (uint) (*Ptr | (Ptr[1] << 8)); case 3: return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16)); case 4: return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)); case 5: return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) Ptr[4] << 32); case 6: return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) (Ptr[4] | (Ptr[5] << 8)) << 32); case 7: return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) (Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16)) << 32); case 8: return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) (Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16) | (Ptr[7] << 24)) << 32); default: return 0; } } } }