2

I have come with the following coding to generate range within 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

It shows the error:

Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: startIndex

i have done following code. is it correct?

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
Sanket.NET
  • 23
  • 1
  • 6
  • now i have did like this: 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) is it correct way???? – Sanket.NET Dec 03 '12 at 04:43

1 Answers1

5

The second parameter to BitConverter.ToInt32 is an offset into the byte array. It should be 0 for you. There is also no reason to get 1000 byttes if you're using only 4 of them.

A working version in 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);

In VB.net this will look similar to

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

This code has two weaknesses:

  1. It's quite slow. The per-call overhead of RNGCryptoServiceProvider.GetBytes is large. For better performance use a buffer of several kilobytes and only call GetBytes when it's used up.
  2. It's not perfectly uniform, but the bias should be small enough for most applications.

    Even when using a value for count that exhibits maximal bias you will need over ten billion samples to detect it, whereas for System.Random a handful are enough. i.e the bias is about 8 billion times smaller than for System.Random.

If either weakness is unacceptable for you, you can look into my random number generator project which offers fast, secure and unbiased numbers. But this comes at the cost of adding an external library instead of simply writing a few lines of code.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • Just in case, for those not familiar with c#, `%` would be the `mod` operator in [vb.net](http://msdn.microsoft.com/en-us/library/se0w9esz(v=vs.110).aspx) – jbtule Dec 03 '12 at 14:05
  • I have done this: is it correct??? dim rng as new rngcryptoserviceprovider Dim seed() As Byte = New Byte(4) {} rng.GetBytes(seed) r = New Random(BitConverter.ToInt32(seed, 0)) Label4.Text = r.Next(1000, 9999) – Sanket.NET Dec 03 '12 at 18:09
  • "Not perfectly uniform but it shouldn't matter" - if it doesn't matter you may as well just use Random. – Rawling Dec 03 '12 at 18:17
  • @Rawling The bias is *much* smaller than with `System.Random.` The distribution of a `UInt64` modulo a number smaller than two billion is *very good*, but not perfect. For crypto purposes you mainly need unpredictability and not perfect randomness. – CodesInChaos Dec 03 '12 at 19:07
  • @user1849470 Why are you using `System.Random`? Use the VB.net equivalent of my code, and not what you're using. – CodesInChaos Dec 03 '12 at 19:08
  • @CodesInChaos I'd hoped `Random` might be uniform over a (comparitively) small range, but if it's not... fair enough. – Rawling Dec 03 '12 at 19:14
  • @CodesInChaos whts the problem with random? i m not getting ur code so tht i can't put it in my scope... – Sanket.NET Dec 03 '12 at 19:34
  • 1
    @Rawling Expanded the answer a bit to talk about the size of the bias. For a reference of my `System.Random` is bad, see my rant at [Why use the C# class System.Random at all](http://stackoverflow.com/a/6842191/445517) – CodesInChaos Dec 03 '12 at 19:54
  • @user1849470 It's not designed to be secure. Your specific use is probably OK, but I wouldn't rely on it. I've added a VB version of my code. – CodesInChaos Dec 03 '12 at 19:56
  • @CodesInChaos it is showing error like this : Argument not specified for parameter 'startIndex' of 'Public Shared Function ToUInt64(value() As Byte, startIndex As Integer) As ULong – Sanket.NET Dec 03 '12 at 20:05
  • @CodesInChaos i have done this to overcome the error: Return BitConverter.ToUInt64(bytes, 0) Mod CUInt(count). Now it is working well. is it now a correct way of implementation of RNGCRYPTOSERVICEPROVIDER ??? – Sanket.NET Dec 03 '12 at 20:09
  • @CodesInChaos i have few queries for you. 1. what is signification of MOD operation? 2. why we are adding 1000 in generation, can't we add any number and what is its significanc?? 3. Is it satisfy the use of RNGcryptoserviceprovider?? – Sanket.NET Dec 03 '12 at 20:24
  • 1) It maps the large number returned by `BitConverter` to the range `0` to `9000 - 1`. Since you want the range `1000` to `9999` you need to add 1000. – CodesInChaos Dec 03 '12 at 21:36
  • @CodesInChaos i have done some manipulation on ur code i.e Return BitConverter.ToUInt64 **(bytes, 0)** Mod CUInt(count). is it correct?? – Sanket.NET Dec 04 '12 at 17:19
  • Post your new code, and I'll take a look. Adding the `0` param to `ToUInt64` is correct. – CodesInChaos Dec 04 '12 at 19:20
  • @CodesInChaos i just manipulated one line else the whole code is same. will the MOD operation really provide uniforms to our function? i dn't know how to test it hence – Sanket.NET Dec 05 '12 at 18:09
  • @CodesInChaos if i want to accomplished same thing for list of button from 0-9 then ??? – Sanket.NET Dec 06 '12 at 17:13
  • then you use `RandomUniform(10)` – CodesInChaos Dec 06 '12 at 20:04