64 Bit Random Number Generator Using RNGCryptoServiceProvider
using System; using System.Security.Cryptography; [Serializable] public class Random64csp : RandomNumberGenerator { private byte[] _buffer; private RNGCryptoServiceProvider _crng; private double _dBi; private ulong UpperLimit = ulong.MaxValue; public Random64csp() { SetDataUse = 8; _crng = new RNGCryptoServiceProvider(); } public Random64csp(int dataSize) { SetDataUse = dataSize; _crng = new RNGCryptoServiceProvider(); } 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; } } } /// <summary> /// Will generate only odd values /// </summary> 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; } /// <summary> /// Next(0,2)==0?false:true; has a distribution error of 1% weighted toward zero. /// The distribution error here is 0.000000046% which is statistically insignificant in this context. /// </summary> /// <param name="size"></param> /// <returns></returns> 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; } } } }