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
Exclude Property on Update in Entity Framework
What's the Difference Between Application.Run() and Form.Showdialog()
What's Better: Dataset or Datareader
Illustrating Usage of the Volatile Keyword in C#
Differencebetween Linq to Xml Descendants and Elements
Detecting Network Connection Speed and Bandwidth Usage in C#
Programmatically Get the Version Number of a Dll
Convert String to Hex-String in C#
Getting Checkbox Value in ASP.NET MVC 4
Linq Order by Null Column Where Order Is Ascending and Nulls Should Be Last
Copy Rows from One Datatable to Another Datatable
Optimal Way to Read an Excel File (.Xls/.Xlsx)
How to Use the C#6 "Using Static" Feature
Why Use Async/Await All the Way Down