What is a random number? Well, even if you have never read any definition, you can still answer that question pretty easy. It’s the unpredictable result of some action like throwing a dice. We just can’t predict what the next number will be. The Lucky shoot is all we’ve got. In a real world, randomness is kind of natural “thing”, but it starts to be more complicated when it comes to machines. Why? Simply because of their deterministic characteristic which makes it really hard to generate random numbers (but it’s still possible). That’s why in most of the time we use the pseudorandom numbers – they look like a random but they are the result of some mathematical algorithms. Are they used in generator offered in C#? Let’s find out.

Is Random.Next() random?

If you’re a C# programmer, there’s a high probability that you’ve used Random class at least once in your life. They usage is very simple, so no explanation will be needed later in this paragraph. Let’s start with generating 10 numbers:

class Program { static void Main(string[] args) { var random = new Random(); for (var i = 0; i < 10; ++i) Console.WriteLine(random.Next()); Console.ReadKey(); } }

Here’s the result of the above code execution:

Do above numbers look random? Well, I think so. We can’t quickly find any pattern in the whole set. But if you take a closer look at the Random’s constructor overloads, you can spot that one of them requires some integer called a seed. What is that? I think that the answer will come up after you read the below code:

class Program { static void Main(string[] args) { var random1 = new Random(14); var random2 = new Random(14); Console.WriteLine("RANDOM 1:"); for (var i = 0; i < 10; ++i) Console.WriteLine(random1.Next()); Console.WriteLine(string.Empty); Console.WriteLine("RANDOM 2:"); for (var i = 0; i < 10; ++i) Console.WriteLine(random2.Next()); Console.ReadKey(); } }

The result looks as follows:

So what actually happened? The numbers in both sets are identical! Why? That is because as you probably guessed Random class is the generator for pseudorandom numbers, so they are calculated by some algorithm. To generate the sequence we need some starting value – the seed. So using other words, having the same seed we will always get the same sequence of numbers. That seems logical. Some questions could pop up in your minds right now. The first one is about the previous code. If Random’s algorithm requires seed, why does it have a parameterless constructor? The class summary gives us an answer:

Initializes a new instance of the System.Random class, using a time-dependent default seed value.

So that the reason why using Random in different time gives you a different result. Next question, why do we have an ability to create identical sequences of numbers since it has absolutely no sense? Well, there are cases when this is pretty handy. Two, the most common scenarios are testing and debugging when you care about the same state every time. The last question is the title of the next paragraph 😉

Should I even care about the way Random works?

Well, it depends on your domain in general. Sure, if you’re implementing some boardgame using Radom class is not dangerous. But what if your domain highly depends on randomness? Here an example. If you’ve ever played CS: GO you know there are a lot of jackpot sites where you can bet your skins. The rules are simple, each weapon skin has a real $ value on the market. Each player can bet some number of skins which are held in a shared pool. For each cent, you got one ticket, so betting 4 skins of total value 1$ will give you 100 tickets. The more tickets you have, the higher your chance to win the jackpot. When the time is over, a winning ticket number is generated and the player that owns it wins. You know the rules, let’s go back to the example. A few years ago, there was an affair related to one of the biggest jackpot sites. What happened? It turned out that developers used standard Math.random() function in Node.js to generate the number of winning ticket. One folk guesses the generator’s seed (based on previous games) and was able to predict next numbers in the sequence. He was always one step ahead of others and he always knows whether he should bet soon after the round starts or at the end. Here’s the video from the stream he made:

Now, that’s what I meant. In the described example the domain depended on that one random number, but developers didn’t secure themselves properly.

What can I do instead?

So, we know now that in some cases Random class is just not enough since knowing the seed you can reproduce the sequence. Therefore, what else can we use instead? C# offers another provider which is called RNGCryptoServiceProvider. Generated numbers are still not 100% random but the entropy is increased by taking parameters from plenty different sources so it’s almost impossible to guess them all and use to calculate the number. Some of the params are:

The current process ID (GetCurrentProcessID).

The current thread ID (GetCurrentThreadID).

The tick count since boot time (GetTickCount).

The current time (GetLocalTime).

Various high-precision performance counters (QueryPerformanceCounter).

An MD4 hash of the user’s environment block, which includes username, computer name, and search path. […]

High-precision internal CPU counters, such as RDTSC, RDMSR, RDPMC

https://en.m.wikipedia.org/wiki/CryptGenRandom

The usage of RNGCryptoServiceProvider is also quite simple:

class Program { static void Main(string[] args) { var randomNumbers = new byte[40]; using(var rng = new RNGCryptoServiceProvider()) { rng.GetBytes(randomNumbers); } Console.WriteLine($"RANDOM NUMBER: { BitConverter.ToInt32(randomNumbers, 0) }"); Console.ReadKey(); } }

Obviously, because calculation requires way more inputs to generate the number, this provider is slower than using Random class. But on the other hand using RNGCryptoServiceProvider is way safer. Like always, you should think twice before coding which one is going to be better in the specific scenario 🙂