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.
RandomNumberGenerator (RNGCryptoServiceProvider)
System.Security.Cryptography
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:
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}
(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)
There is a class file RandomDigits & a Console application.
The class file
//M.C. Koutzarov Class file RandomDigits [0-9]
using System; using System.Security.Cryptography; using System.Text; namespace ps.security{ public class RandomDigits { ///<summary> /// Returns One random Digit of a value between 0 and 9. ///</summary> public static int getDigit(){ int[] Result = { 0, 0, 0 }; // this stores sum1 , sum2 and sum3 int R = 0; // Will hold the resulting integer Sum of Result{3} int b1 = 0; // byte one int b2 = 0; // byte two int offset = 0; // need an offset to loop 3 times. Each time i get 2 bytes to compare. //get 6 random bytes RandomNumberGenerator rng = new RNGCryptoServiceProvider(); byte[] b = new byte[6]; rng.GetNonZeroBytes(b); for (int i =0; i <=2; i++) // Loop 3 time i=2 i=1 and i=0 { //get the offset if (i == 2) { offset = 4; // 5th and 6th byte }else if(i == 1) { offset = 2; // 3th and 4th byte }else if (i == 0){ offset = 0; // 1th and 2th byte }; //(b1,2 MOD 2) b1 and b2 will be odd number is 1 and even if 0 b1 = ((int)b[offset] % 2); b2 = ((int)b[offset+1] % 2); if ((i == 0)) { if ((b1 == 1) && (b2 == 1)) { Result[i] = 0; //odd-odd = 0 } else if ((b1 == 0) && (b2 == 1)) { Result[i] = 1; //even-odd = 1 } else if ((b1 == 0) && (b2 == 0)) { Result[i] = 2; //even-even = 2 } else if ((b1 == 1) && (b2 == 0)) { Result[i] = 3; }; //odd-even = 3 } else if (i==1) { // on second round flip the values if ((b1 == 1) && (b2 == 1)) { Result[i] = 3; //odd-odd = 3 } else if ((b1 == 0) && (b2 == 1)) { Result[i] = 2; //even-odd = 2 } else if ((b1 == 0) && (b2 == 0)) { Result[i] = 1; //even-even = 1 } else if ((b1 == 1) && (b2 == 0)) { Result[i] = 0; //odd-even = 0 }; } else if (i == 2) { // on 3 round flip the values once more if ((b1 == 1) && (b2 == 1)) { Result[i] = 1; //odd-odd = 1 } else if ((b1 == 0) && (b2 == 1)) { Result[i] = 3; //even-odd = 3 } else if ((b1 == 0) && (b2 == 0)) { Result[i] = 0; //even-even = 0 } else if ((b1 == 1) && (b2 == 0)) { Result[i] = 2; //odd-even = 2 }; } b1 = 0; b2 = 0; };// end 3 for loops //Sum the results of round 1,2 and 3 together //this will make an Int between 0 - 9 R =(int)(Result[0] + Result[1] + Result[2]); //Return a Int valued between 0 - 9 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; //M.C. Koutzarov Testing Randomness for digits [0-9] class Program { static void Main(string[] args){ Program.DrawNumbersPerDigitTest(); Console.ReadKey(); Console.WriteLine(""); Console.WriteLine("Test 2"); Program.DrawDigitTest(1000000); } // Draws a the digits 0-9 // each digit(from 0-9) is being drawn untill it appears // At the end it shows the Total draws needed for all didigts to appear. // and the avg number of draws per digit. 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; } // Draws a the digits 0-9 // each digit(from 0-9) is being drawn untill it appears // At the end it shows the Total draws needed for all didigts to appear. // and the avg number of draws per digit. 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)); } }