Introduction
I tried to write code that would return a Integer of a value between 0 and 9
without losing the Randomness strength provided in the class RandomNumberGenerator
(RNGCryptoServiceProvider) in the System.Security.Cryptography
Namespace. The hard part was that the byte array is filled with
random bytes valued between 0 and 255.
Basic Idea & method.
If we use only the integers 0,1,2,3 and we pick 3 times randomly one
from this collection, the sum of the 3 draws wil always have a value between 0 and
9.
If a byte has a value between 0 and 255 we also can say that his byte is
a EVEN or a ODD number. The even and ODD numbers are equally represented
in a set of (0-255).
Therefore if we take 2 Bytes the possibilities of the outcome for a byte
pair (b1 & b2) will always be:
- b(1)odd b(0)even = 0
- b(1)odd b(1)odd = 1
- b(0)even b(0)even = 2
- b(1)even b(2)odd = 3
If we populate a Byte array with random 6 bytes (3 pairs) and compare 3x
two Bytes. We will have 3x3 possible values between 0 and 3.
For example: Array X= {a,b,c,d,e,f}
- Bytes : [b1,b2] - [b3,b4] - [b5,b5]
- Valued: [11][34] -[55][47] - [55][66]
- Are: odd/even -odd/odd -odd/even
- Resulting in: 3 + 3 + 2 = 8
(After each round I opposite the Odd/even values. For better distribution. This
was also done in the Hot Bits Radiation project. Ater testing the Bell curve was
better distributed)
Using the code
There is a class file RandomDigits & a Console application.
The class file
using System;
using System.Security.Cryptography;
using System.Text;
namespace ps.security{
public class RandomDigits
{
public static int getDigit(){
int[] Result = { 0, 0, 0 }; int R = 0; int b1 = 0; int b2 = 0; int offset = 0;
RandomNumberGenerator rng = new RNGCryptoServiceProvider();
byte[] b = new byte[6];
rng.GetNonZeroBytes(b);
for (int i =0; i <=2; i++) {
if (i == 2) {
offset = 4; }else if(i == 1) {
offset = 2; }else if (i == 0){
offset = 0; };
b1 = ((int)b[offset] % 2);
b2 = ((int)b[offset+1] % 2);
if ((i == 0))
{
if ((b1 == 1) && (b2 == 1))
{
Result[i] = 0; }
else if ((b1 == 0) && (b2 == 1))
{
Result[i] = 1; }
else if ((b1 == 0) && (b2 == 0))
{
Result[i] = 2; }
else if ((b1 == 1) && (b2 == 0))
{
Result[i] = 3;
}; }
else if (i==1) {
if ((b1 == 1) && (b2 == 1))
{
Result[i] = 3; }
else if ((b1 == 0) && (b2 == 1))
{
Result[i] = 2; }
else if ((b1 == 0) && (b2 == 0))
{
Result[i] = 1; }
else if ((b1 == 1) && (b2 == 0))
{
Result[i] = 0; };
}
else if (i == 2) {
if ((b1 == 1) && (b2 == 1))
{
Result[i] = 1; }
else if ((b1 == 0) && (b2 == 1))
{
Result[i] = 3; }
else if ((b1 == 0) && (b2 == 0))
{
Result[i] = 0; }
else if ((b1 == 1) && (b2 == 0))
{
Result[i] = 2; };
}
b1 = 0;
b2 = 0;
};
R =(int)(Result[0] + Result[1] + Result[2]);
return R;
}
}
}
Here is the Console testing code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ps.security;
using System.Diagnostics;
class Program
{
static void Main(string[] args){
Program.DrawNumbersPerDigitTest();
Console.ReadKey();
Console.WriteLine("");
Console.WriteLine("Test 2");
Program.DrawDigitTest(1000000);
}
public static int[] DrawNumbersPerDigitTest()
{
Console.WriteLine("Random digits 0-9 generator test.");
double frequency = System.Diagnostics.Stopwatch.Frequency;
double nanosecPerTick = (1000 * 1000 * 1000) / frequency;
int totalItter = 0;
int[] Totaldistri = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
for (int AllDigits = 9; AllDigits >= 0; AllDigits--)
{
Stopwatch timer = new Stopwatch();
int avg = 0;
int itters = 0;
int[] distri = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
timer.Start();
for (int i = 1000000; i >= 1; i--)
{
int n = ps.security.RandomDigits.getDigit();
avg = (avg + n);
distri[n]++;
itters++;
if (n == AllDigits)
{
break;
}
};
timer.Stop();
double durNanosec = timer.ElapsedTicks * nanosecPerTick;
double durSecs = timer.ElapsedTicks * 1000 / frequency;
Console.WriteLine("");
Console.WriteLine("|----------------------------------|");
Console.WriteLine("Digit nr:\t" + AllDigits);
Console.WriteLine("");
Console.WriteLine("| int\t| freq\t percentage\t |");
Console.WriteLine("|----------------------------------|");
for (int i = 9; i >= 0; i--)
{
double p =Math.Round( ((double)distri[i])/((double)itters / 100),3);
Console.WriteLine("| " + i + "\t| " + +distri[i] + "\t " + p + "%\t");
}
Console.WriteLine("|----------------------------------|");
Console.WriteLine("");
Console.WriteLine(" Sum : >\t" + avg.ToString());
Console.WriteLine(" Average : >\t" + ((double)avg / (double)itters).ToString());
Console.WriteLine(" Count : >\t" + (itters).ToString());
Console.WriteLine("");
Console.WriteLine(" nSecs :\t" + Math.Round(durNanosec, 3));
Console.WriteLine(" mSecs :\t" + Math.Round(durSecs, 9));
totalItter += (itters);
Totaldistri[AllDigits] = itters;
};
Console.WriteLine("");
Console.WriteLine("|----------------------------------|");
Console.WriteLine("Average + total draws per Digit:");
Console.WriteLine("|----------------------------------|");
Console.WriteLine("");
Console.WriteLine(" total draws\t: >\t" + totalItter.ToString());
Console.WriteLine(" avg\t\t: >\t" + Math.Round((double)totalItter / 10, 3));
Console.WriteLine("| int\t| freq\t ");
Console.WriteLine("|----------------------------------|");
for (int i = 9; i >= 0; i--)
{
Console.WriteLine("| " + i + "\t| " + +Totaldistri[i] + "\t \t");
}
return Totaldistri;
}
public static void DrawDigitTest(int nrOfDigits)
{
Console.WriteLine("Random digits 0-9 generator test.");
double frequency = System.Diagnostics.Stopwatch.Frequency;
double nanosecPerTick = (1000 * 1000 * 1000) / frequency;
Stopwatch timer = new Stopwatch();
int avg = 0;
int itters = 0;
int[] distri = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
timer.Start();
for (int i = nrOfDigits; i >= 1; i--)
{
int n = ps.security.RandomDigits.getDigit();
avg = (avg + n);
distri[n]++;
itters++;
};
timer.Stop();
double durNanosec = timer.ElapsedTicks * nanosecPerTick;
double durSecs = timer.ElapsedTicks * 1000 / frequency;
Console.WriteLine("");
Console.WriteLine("| int\t| freq\t percentage\t |");
Console.WriteLine("|----------------------------------|");
for (int i = 9; i >= 0; i--)
{
double p = Math.Round(((double)distri[i]) / ((double)itters / 100), 1);
Console.WriteLine("| " + i + "\t| " + +distri[i] + "\t\t" + p + "%.");
}
Console.WriteLine("|----------------------------------|");
Console.WriteLine("");
Console.WriteLine(" #Digits : >\t\t" + (itters).ToString());
Console.WriteLine(" Sum : >\t\t" + avg.ToString());
Console.WriteLine(" Average : >\t\t" + ((double)avg / (double)itters).ToString());
Console.WriteLine("");
Console.WriteLine(" nSecs : >\t" + Math.Round(durNanosec, 3));
Console.WriteLine(" mSecs : >\t" + Math.Round(durSecs, 9));
}
}