Click here to Skip to main content
Click here to Skip to main content

Getting a Strong random Digit using RNGCryptoServiceProvider

By , 12 May 2013
 

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:

  1. b(1)odd   b(0)even  = 0 
  2. b(1)odd   b(1)odd   = 1 
  3. b(0)even b(0)even  = 2 
  4. 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  

//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));
     
     }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

koetsie
Netherlands Netherlands
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
SuggestionSource code downloadable via GitHub.memberkoetsie10hrs 50mins ago 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130513.1 | Last Updated 13 May 2013
Article Copyright 2013 by koetsie
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid