在指定范围内使用RNGCRYPTOSERVICEPROVIDER生成随机数

San*_*NET 2 .net vb.net random cryptography

我已经通过以下编码来生成1000-9999范围内的范围:

Dim byt As Byte() = New Byte(1000) {}

Dim rngCrypto As New RNGCryptoServiceProvider()
rngCrypto.GetBytes(byt)

Dim randomNumber As Integer = BitConverter.ToInt32(byt, 9999)
Label4.Text = randomNumber
Run Code Online (Sandbox Code Playgroud)

它显示错误:

指数超出范围.必须是非负数且小于集合的大小.参数名称:startIndex

我做了以下代码.这是对的吗?

Public Sub secrand()

    Static r As Random = Nothing

    If r Is Nothing Then
        Dim seed() As Byte = New Byte(4) {}
        Dim rng As New RNGCryptoServiceProvider
        rng.GetBytes(seed)
        r = New Random(BitConverter.ToInt32(seed, 0))
        Label4.Text = r.Next(1000, 9999)
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

Cod*_*aos 5

第二个参数BitConverter.ToInt32是字节数组的偏移量.它应该是0.如果你只使用其中的4个,也没有理由获得1000个字节.

C#中的工作版本:

public static int RandomUniform(int count)
{
    if(count <= 0)
         throw new ArgumentOutOfRangeException("count");
    var rng=new RNGCryptoServiceProvider();
    var bytes=new byte[8];
    rng.GetBytes(bytes, 0);
    return BitConverter.ToUInt64() % (uint)count;
}

Label4.Text = 1000 + RandomUniform(9000);
Run Code Online (Sandbox Code Playgroud)

在VB.net中,这看起来类似于

Public Shared Function RandomUniform(count As Integer) As Integer
    If count <= 0 Then
        Throw New ArgumentOutOfRangeException("count")
    End If
    Dim rng = New RNGCryptoServiceProvider()
    Dim bytes = New Byte(8) {}
    rng.GetBytes(bytes, 0)
    Return BitConverter.ToUInt64() Mod CUInt(count)
End Function
Run Code Online (Sandbox Code Playgroud)

这段代码有两个缺点:

  1. 这很慢.每次呼叫的开销RNGCryptoServiceProvider.GetBytes很大.为了获得更好的性能,请使用几千字节的缓冲区,并且只有GetBytes在用完时才调用.
  2. 它并不完全一致,但偏差应该足够小,适合大多数应用.

    即使使用count显示最大偏差的值,您也需要超过100亿个样本来检测它,而System.Random少数样本就足够了.即偏差约为80亿倍System.Random.

如果您无法接受任何一个弱点,您可以查看我的随机数生成器项目,该项目提供快速,安全且无偏的数字.但这是以添加外部库而不是简单地编写几行代码为代价的.