Why Use the C# Class System.Random at All Instead of System.Security.Cryptography.Randomnumbergenerator

Why use the C# class System.Random at all instead of System.Security.Cryptography.RandomNumberGenerator?

Speed and intent. If you're generating a random number and have no need for security, why use a slow crypto function? You don't need security, so why make someone else think that the number may be used for something secure when it won't be?

RandomNumberGenerator vs RNGCryptoServiceProvider

The RandomNumberGenerator.Create() method calls RandomNumberGenerator.Create("System.Security.Cryptography.RandomNumberGenerator"), which will eventually create an instance of RNGCryptoServiceProvider.

(It does some lookups in a pair of dictionaries, so it's likely that you can change the behaviour of that call by registering a default random generator somewhere.)

The actual type of the object returned is not known at compile time, it's only known that it will inherit the RandomNumberGenerator class, so you can use a RandomNumberGenerator reference variable for it.

This way of creating different types of instances depending on the input is used in a couple of places in the framework, for example by the WebRequest.Create method.


Someone at Micrsoft has "fixed" the current documentation (framework 4.5) for the Create() method. It now says:

"When overridden in a derived class, creates an instance of the
default implementation of a cryptographic random number generator that
can be used to generate random data."

The documentation for framework 4.0 says:

"Creates an instance of the default implementation of a cryptographic
random number generator that can be used to generate random data."

This is the correct description of what the method does. I will put in a request to put that description back in the newer documentation.

How to implement a thread-safe random

From .NET 6 you can use Random.Shared to get a thread-safe instance of Random.

The documents say this:

Provides a thread-safe Random instance that may be used concurrently from any thread.

https://learn.microsoft.com/en-us/dotnet/api/system.random.shared?view=net-6.0

There's no need to get fancy anymore.

To get a random integer you just need to do:

int number = Random.Shared.Next();

If you want cryptographically strong randomness, then Eric Lippert's BetterRandom is the way to go:

public static class BetterRandom
{
private static readonly ThreadLocal<System.Security.Cryptography.RandomNumberGenerator> crng = new ThreadLocal<System.Security.Cryptography.RandomNumberGenerator>(System.Security.Cryptography.RandomNumberGenerator.Create);
private static readonly ThreadLocal<byte[]> bytes = new ThreadLocal<byte[]>(() => new byte[sizeof(int)]);
public static int NextInt()
{
crng.Value.GetBytes(bytes.Value);
return BitConverter.ToInt32(bytes.Value, 0) & int.MaxValue;
}
public static double NextDouble()
{
while (true)
{
long x = NextInt() & 0x001FFFFF;
x <<= 31;
x |= (long)NextInt();
double n = x;
const double d = 1L << 52;
double q = n / d;
if (q != 1.0)
return q;
}
}
}

Start here to read more: https://ericlippert.com/2019/01/31/fixing-random-part-1/

Is C# Random Number Generator thread safe?

There's nothing special done in the Next method to achieve thread safety. However, it's an instance method. If you don't share instances of Random across different threads, you don't have to worry about state corruption within an instance. Do not use a single instance of Random across different threads without holding an exclusive lock of some sort.

Jon Skeet has a couple nice posts on this subject:

StaticRandom
Revisiting randomness

As noted by some commentators, there is another potential problem in using different instances of Random that are thread-exclusive, but are seeded identically, and therefore induce the identical sequences of pseudorandom numbers, because they may be created at the same time or within close temporal proximity of each other. One way to alleviate that issue is to use a master Random instance (which is locked by a single thread) to generate some random seeds and initialize new Random instances for every other thread to use.

RandomNumberGenerator in ASP.NET5

I got it working thanks to Scott Chamberlain's comment by adding the System.Security.Cryptography.Algorithms NuGet package.

I also had to modify the project.json so it was only a dependency of dotnet5.4 and not a global dependency otherwise the compiler would complain that RandomNumberGenerator exists in both System.Security.Cryptography.Algorithms and mscorlib.

Pros and cons of RNGCryptoServiceProvider

A cryptographically strong RNG will be slower --- it takes more computation --- and will be spectrally white, but won't be as well suited to simulations or Monte Carlo methods, both because they do take more time, and because they may not be repeatable, which is nice for testing.

In general, you want to use a cryptographic PRNG when you want a unique number like a UUID, or as a key for encryption, and a deterministic PRNG for speed and in simulation.

RNGCryptoServiceProvider - Random Number Review

Well, using RNGCryptoServiceProvider gives you an unguessable crypto-strength seed whereas Environment.TickCount is, in theory, predictable.

Another crucial difference would be evident when calling your NextInt method several times in quick succession. Using RNGCryptoServiceProvider will seed the Random object with a different crypto-strength number each time, meaning that it will go on to return a different random number for each call. Using TickCount risks seeding the Random object with the same number each time (if the method is called several times during the same "tick"), meaning that it will go on to return the same (supposedly random) number for each call.

If you genuinely need truly random numbers then you shouldn't be using a computer to generate them at all: you should be measuring radioactive decay or something similarly, genuinely unpredictable.



Related Topics



Leave a reply



Submit