How to generate a cryptographically secure Double between 0 and 1? - c#

I know how to generate a random number between 0 and 1 using the NextDouble method of the pseudo-random number generator.
var rng1 = new System.Random();
var random1 = rng1.NextDouble(); // generates a random double between 0 and 1.0
And I know how to fill a random byte array using the cryptographically secure random number generator.
Byte[] bytes = new Byte[8];
var rng2 = new System.Security.Cryptography.RNGCryptoServiceProvider();
rng2.GetBytes(bytes); // generates 8 random bytes
But how can I convert the byte-array output of RNGCryptoServiceProvider into a random number uniformly distributed between 0 (inclusive) and 1 (exclusive)?

It appears to me that the solutions so far will have uneven distribution due to taking the inverse. For an even distribution I'd think you want something like this.
// Step 1: fill an array with 8 random bytes
var rng = new RNGCryptoServiceProvider();
var bytes = new Byte[8];
rng.GetBytes(bytes);
// Step 2: bit-shift 11 and 53 based on double's mantissa bits
var ul = BitConverter.ToUInt64(bytes, 0) / (1 << 11);
Double d = ul / (Double)(1UL << 53);
Note that you can't just divide the UInt64 into UInt64.MaxValue, because a double doesn't have enough bits, and there's no way to get unique outputs for all your inputs. So you can/must throw some bits away.

Well, I would not call a 64-bit random number "cryptographically secure" - you'd want a lot more bits than that to be "cryptographically secure". But anyway, you could do something like this:
var bytes = // assume this contains 8 bytes of random numbers
long l = BitConverter.ToInt64(bytes);
double d = Math.Abs(1 / (double)l);

Since RNGCryptoServiceProvider is obsolete in .NET 6
https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rngcryptoserviceprovider?view=net-6.0
if you want "real" NextDouble you can use RandomNumberGenerator like this
How to get NextDouble from cryptogaphy random RandomNumberGenerator

Related

RNGCryptoServiceProvider to get a random 256 bit integer in c#

I am trying to generate a 256 bit integer in c# using RNGCryptoServiceProvider. My code is:
// 256 bits random number
byte[] random = new Byte[32];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(random); Debug.WriteLine(BitConverter.ToUInt64(random,0));
return BitConverter.ToUInt64(random,0);
However, the output are integers like 6958393268188363168, which is not 77 digits long. Any ideas? Thanks

Using RNGCryptoServiceProvider to "simulate" throwing a dice

I've been trying to simulate rolling a 6-faces dice in C#. I thought using RNGCSP was better than Random because it is more secure.
I tried using MSDN's example code to achieve this, but there are a few things that I didn't understand from the code:
How do you generate 5 digit long numbers with RNGCSP?
How do you generate numbers from 1 to 6 (excluding zeroes)?
1. How do you generate 5 digit long numbers with RNGCSP?
For the numbers, you can use a range. You'll have to think of the lower bound yourself though. Ranges for number are treated in RNGCryptoServiceProvider.
So for a 5 digit number min would be 0 or 10000 and max would be 100000, because max is exclusive.
2. How do you generate numbers from 1 to 6 (excluding zeroes)?
Basically the same way, you generate a range [1, 7) where 7 - the max value - is exclusive.
If you just want a dice result you can just do something like this (untested!):
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] singleByteBuf = new byte[1];
int max = Byte.MaxValue - Byte.MaxValue % 6;
while (true) {
rng.GetBytes(singleByteBuf);
int b = singleByteBuf[0];
if (b < max) {
return b % 6 + 1;
}
}
Basically the same idea, but is only requests 1 byte at a time from the RNGCryptoServiceProvider, so it doesn't waste 3 additional bytes.

C# A random BigInt generator

I'm about to implement the DSA algorithm, but there is a problem:
choose "p", a prime number with L bits, where 512 <= L <= 1024 and L is a multiple of 64
How can I implement a random generator of that number? Int64 has "only" 63 bits length.
You can generate a random number with n bits using this code:
var rng = new RNGCryptoServiceProvider();
byte[] bytes = new byte[n / 8];
rng.GetBytes(bytes);
BigInteger p = new BigInteger(bytes);
The result is, of course, random and not necessarily a prime.
The BigInteger class was introduced in the .NET 4.0 Framework.
For generating large prime numbers, Wikipedia says:
For the large primes used in cryptography, it is usual to use a modified form of sieving: a randomly-chosen range of odd numbers of the desired size is sieved against a number of relatively small odd primes (typically all primes less than 65,000). The remaining candidate primes are tested in random order with a standard primality test such as the Miller-Rabin primality test for probable primes.
So you could do something like this:
var p = Enumerable.Range(0, numberOfCandidates)
.Select(i => RandomOddNumber(bits))
.Where(x => !primesLessThan65000.Contains(x))
.Where(x => PrimalityTest(x))
.FirstOrDefault();

Generate random values in C#

How can I generate random Int64 and UInt64 values using the Random class in C#?
This should do the trick. (It's an extension method so that you can call it just as you call the normal Next or NextDouble methods on a Random object).
public static Int64 NextInt64(this Random rnd)
{
var buffer = new byte[sizeof(Int64)];
rnd.NextBytes(buffer);
return BitConverter.ToInt64(buffer, 0);
}
Just replace Int64 with UInt64 everywhere if you want unsigned integers instead and all should work fine.
Note: Since no context was provided regarding security or the desired randomness of the generated numbers (in fact the OP specifically mentioned the Random class), my example simply deals with the Random class, which is the preferred solution when randomness (often quantified as information entropy) is not an issue. As a matter of interest, see the other answers that mention RNGCryptoServiceProvider (the RNG provided in the System.Security namespace), which can be used almost identically.
Use Random.NextBytes() and BitConverter.ToInt64 / BitConverter.ToUInt64.
// Assume rng refers to an instance of System.Random
byte[] bytes = new byte[8];
rng.NextBytes(bytes);
long int64 = BitConverter.ToInt64(bytes, 0);
ulong uint64 = BitConverter.ToUInt64(bytes, 0);
Note that using Random.Next() twice, shifting one value and then ORing/adding doesn't work. Random.Next() only produces non-negative integers, i.e. it generates 31 bits, not 32, so the result of two calls only produces 62 random bits instead of the 64 bits required to cover the complete range of Int64/UInt64. (Guffa's answer shows how to do it with three calls to Random.Next() though.)
Here you go, this uses the crytpo services (not the Random class), which is (theoretically) a better RNG then the Random class. You could easily make this an extension of Random or make your own Random class where the RNGCryptoServiceProvider is a class-level object.
using System.Security.Cryptography;
public static Int64 NextInt64()
{
var bytes = new byte[sizeof(Int64)];
RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
Gen.GetBytes(bytes);
return BitConverter.ToInt64(bytes , 0);
}
You can use bit shift to put together a 64 bit random number from 31 bit random numbers, but you have to use three 31 bit numbers to get enough bits:
long r = rnd.Next();
r <<= 31;
r |= rnd.Next();
r <<= 31;
r |= rnd.Next();
I always use this to get my random seed (error checking removed for brevity):
m_randomURL = "https://www.random.org/cgi-bin/randnum?num=1&min=1&max=1000000000";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(m_randomURL);
StreamReader stIn = new StreamReader(req.GetResponse().GetResponseStream());
Random rand = new Random(Convert.ToInt32(stIn.ReadToEnd()));
random.org uses atmospheric noise to generate the randomness and is apparently used for lotteries and such.
You don't say how you're going to use these random numbers...keep in mind that values returned by Random are not "cryptographically secure" and they shouldn't be used for things involving (big) secrets or (lots of) money.
You could create a byte array, fill it with random data and then convert it to long (Int64) or ulong (UInt64).
byte[] buffer = new byte[sizeof(Int64)];
Random random = new Random();
random.NextBytes(buffer);
long signed = BitConverter.ToInt64(buffer, 0);
random.NextBytes(buffer);
long unsigned = BitConverter.ToUInt64(buffer, 0);
Another answer with RNGCryptoServiceProvider instead of Random. Here you can see how to remove the MSB so the result is always positive.
public static Int64 NextInt64()
{
var buffer = new byte[8];
new RNGCryptoServiceProvider().GetBytes(buffer);
return BitConverter.ToInt64(buffer, 0) & 0x7FFFFFFFFFFFFFFF;
}
As of .NET 6, the Random class has a method for generating a random long.
var r = new Random();
long randomLong = r.NextInt64();
Random r=new Random();
int j=r.next(1,23);
Console.WriteLine(j);

How do you generate a random number in C#?

I would like to generate a random floating point number between 2 values. What is the best way to do this in C#?
The only thing I'd add to Eric's response is an explanation; I feel that knowledge of why code works is better than knowing what code works.
The explanation is this: let's say you want a number between 2.5 and 4.5. The range is 2.0 (4.5 - 2.5). NextDouble only returns a number between 0 and 1.0, but if you multiply this by the range you will get a number between 0 and range.
So, this would give us random doubles between 0.0 and 2.0:
rng.NextDouble() * 2.0
But, we want them between 2.5 and 4.5! How do we do this? Add the smallest number, 2.5:
2.5 + rng.NextDouble() * 2.0
Now, we get a number between 0.0 and 2.0; if you add 2.5 to each of these values we see that the range is now between 2.5 and 4.5.
At first I thought that it mattered if b > a or a > b, but if you work it out both ways you'll find it works out identically so long as you don't mess up the order of the variables used. I like to express it with longer variable names so I don't get mixed up:
double NextDouble(Random rng, double min, double max)
{
return min + (rng.NextDouble() * (max - min));
}
System.Random r = new System.Random();
double rnd( double a, double b )
{
return a + r.NextDouble()*(b-a);
}
// generate a random number starting with 5 and less than 15
Random r = new Random();
int num = r.Next(5, 15);
For doubles you can replace Next with NextDouble
Here is a snippet of how to get Cryographically safe random numbers:
This will fill in the 8 bytes with a crytographically strong sequence of random values.
byte[] salt = new byte[8];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(salt);
For more details see How Random is your Random??" (inspired by a CodingHorror article on deck shuffling)
How random? If you can deal with pseudo-random then simply:
Random randNum = new Random();
randNum. NextDouble(Min, Max);
If you want a "better" random number, then you probably should look at the Mersenne Twister algorithm. Plenty of people hav already implemented it for you though
For an explaination of why Longhorn has been downmodded so much: http://msdn.microsoft.com/en-us/magazine/cc163367.aspx Look for the implementation of NextDouble and the explanation of what is a random double.
That link is also a goo example of how to use cryptographic random numbers (like Sameer mentioned) only with actual useful outputs instead of a bit stream.

Categories

Resources