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;
}
}
}
}