locked
Generating a unique 4 digit random number RRS feed

  • Question

  • User767034699 posted

    Hi there guys,

    i have two methods,

    one uses  RNGCryptoServiceProvider and the second uses normal Random method.

    what are the chances for duplication on booth methods...

    first method

     private static string CreateCryptographicallySecure()
            {
    
                 byte[] buffer = new byte[sizeof(UInt64)];
                cryptoRng.GetBytes(buffer);
                var num = BitConverter.ToUInt64(buffer, 0);
                var pin = num % 10000;
    
                return pin.ToString("D4");
            }

    second method

     private static int CreateCryptographicallySecure()
            {
                Random generator = new Random();//NumberGenerator();
                int billId;
    
                do
                {
                    billId = generator.Next(10000, 99999);
                } while (Test.IdList.Contains(billId));
                Test.IdList.Add(billId);
    
                return billId;
    
            }
    by the way the Test class has a static list variable as follows
      public static HashSet<int> IdList = new HashSet<int>();

    kind regards

    Tony

    Thursday, June 14, 2018 9:03 AM

Answers

  • User753101303 posted

    It doesn't seems it needs to be unique. Once again you could have 10000 customers only and being able to start a banking transaction with ONLY a 4 digit PIN number would be a huge concern  !?

    IMO for some reason you though about "non sequential" as "unique" but it doesn't have to be. Exactly as I guess many other customers in my bank do have the same 4 digit pin number which is  not a problem as they it used WITH their own credit card.

    Motre liekly they have to provide both a credit card number or something else which is truly unique all along with their random PIN code.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 20, 2018 11:32 AM
  • User475983607 posted

    tonyR6

    if it doent require to be unique in every generation i will go with a simple random generation.

    Please read the documentation first.  Random will generate the same sequence given the same seed value.

    tonyR6

    I can use DateTime timestamp converted to Milliseconds or something for a pin that wont repeat as each day and time is different. is the range specified important also?

    Sure, but a date and time is larger than 4 digits.  I think you need to take a step back and think about what you are doing.  Crafting a 4 digit random number is a very simple operation and should not take this many posts to handle.  Perhaps there is other design problems you are facing like joining the pin to a phone number?  I image you have to expire the pin etc.  Maybe this is causing conflict in the design.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 20, 2018 1:12 PM
  • User753101303 posted

    Your app doesn't handle customer accounts ? Usually it is linked to a registered user account all along with an expiration date. The user can then use this code for a limited amount of time,  for example to reset a password (using a previously registered phone number or mail address used to deliver this code).

    You should be best placed to understand the whole workflow. For now it seems something I would expect rather to be done on a payment API side rather than on the API consumer side. Or this code is not used to confirm the payment before it is done but so that it can be used on your side to confirm the payment has been done for somethjng in particular and that the corresponding item could be delivered (or downloaded ?)

    It seems you should stop coding and make sure first to understand  the exact process you are trying to implement and who is responsible for doing what in this process (ie you create this "code" but who will send that ( the bank ?)  and who will check this value (your app ?).

    On our side we can only guess what you are really trying to do.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 20, 2018 3:42 PM

All replies

  • User753101303 posted

    Hi,

    RNGCryptoServiceProvider creates "better" random numbers but I'm not sure to have ever seen someone checking the actual difference. You could easily write some code and see what you really get.

    In therory you should have x over y chances to have a collision (x being how many numbers you want to avoid because they are still used and y how many possible numbers you have). I would keep the "anti collision" code in both cases.

    Depending on how it is used I would perhaps use another mechanism (the method name seeems to hint it is really for a cryptographic context in which case you should definetely use it but does it have really to be unique ?)

    Edit: or maybe you actually try to generate a primary key value ???

    Thursday, June 14, 2018 9:35 AM
  • User767034699 posted

    Hi there PatriceSc,

    thanks for the response,

    actually the 4 digit random number , it will be used for pins. More like a one time pin to access your funds from the ATM machine, we doing integration with the bank. So one of the method requires me to generate unique 4 digit pins.

    so i believe the 1st method will suffice?

    kind regards

    Tony

    Thursday, June 14, 2018 12:45 PM
  • User753101303 posted

    Seems enough to me and are you sure it needs to be unique ? A pin code is usually used with something else (for example my credit card has a 4 digit pin numbers and many customers have the same than me or a confirmation code you receive by SMS is still linked to your account etc...)

    Edit: I would even say that if it really needs to be unique, it seems to be some kind of design issue regarding security ?

    Thursday, June 14, 2018 1:01 PM
  • User475983607 posted

    so i believe the 1st method will suffice?

    Did you test this or read the docs?  AFAIK, the random() generator produces the same series of random numbers given the same seed value.

    https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx

    The Random code will run through the same series, each time increasing the list by one.  Obviously with 4 digits you'll run out of uniques numbers after 10,000 iterations.  If you are using Random then I would populate the 10,000 numbers and put the numbers in a DB or indexed list.  Grab the number by incrementing the list. 

    It seems to me that you also need a way to retire old pins as 10,000 numbers is not that large.

    Anyway, it seem like you're missing some logic.

    Thursday, June 14, 2018 1:12 PM
  • User303363814 posted

    what are the chances for duplication on booth methods...

    Your first method generates 4 character strings.  It will produce a string every time it is called.  It will produce duplicates because there is no code to stop it from doing so.  The second string generated has one chance in 10,000 of being the same as the first string.  The third string has a little less than one chance in 5,000 of being the same as one of the first two strings.  The fourth string has a little less than one chance in 3,333 of being the same as one of the first three strings.  Each string produced will have an increasing chance of being a duplicate until eventually all 4 character strings have been produced and then it will certainly produce a duplicate.

    The second method produces 5 digit numbers.  It will produce all 90,000 numbers (that do not start with a leading zero) at an increasingly slow rate until it eventually hangs.  It will never produce a duplicate because your code prevents it from doing so.

    Friday, June 15, 2018 3:03 AM
  • User767034699 posted

    Hi there guys,

    thanks for the response,

    i decided to go with the 1st method, it will never produce duplication. But there's also some performance issues here as im planning to add it on windows service which will be running on timer.

    here is my logic in checking for duplication. generate the 4 pin add it intto hashset list and then the db. if the service was stopped. I will have to read out the pins from the db store it into a list and generate the pins

    kind regards

    Tony

    Monday, June 18, 2018 3:11 PM
  • User475983607 posted

    I can't wrap my head around your logic. 

    No matter how the 4 digits are generated, there can be only 0000 to 9999 variations.  If we assume the app can never reach 10,000 pins then simply generate the pins now and store them in a database. There is no logical reason to generate the pins on the fly as there is a finite number of pin combinations using number characters; 0-9

    If it is possible to generate more than 10,000 pins, you need at least one more bit of information to make the pin unique like a userId or account number.

    Monday, June 18, 2018 3:44 PM
  • User303363814 posted

    the 1st method, it will never produce duplication.

    Why not?  The first string is generated

    The second string is generated - it has one chance in 10,000 of being the same as the first string. 

    If you modify the first method to use the HashSet method from the second method then you have created a problem.  After all 10,000 strings have been generated the method will hang forever.  (Not to mention that every call of the code will be slower and slower).

    It sounds like you are trying to shuffle the numbers from 0 to 9999 and deliver them one at a time (much like shuffling a pack of cards and dealing them one by one).  To do that you should generate the list of all 10,000 four digit codes and store them somewhere (a pretty small amount of data).  Each code has an index.  Start the index at zero.  The first request for a PIN gets the item at index zero.  Increment the index and remember the value.  Each request for a PIN gets given the value at the next index (which is then incremented).  If the index increments to 10,000 then reset it to zero.

    Monday, June 18, 2018 11:40 PM
  • User767034699 posted

    Hi there guys,

    thanks again for the wonderful responses,

    @PaulTheSmith, your suggesting is very good. This was suggested by mgebhard. But now the logic in doing the incremention on the index. The only thing i can think of is doing it from a stored procedure inside a temp table...

    kind regards

    Tony

    Wednesday, June 20, 2018 9:10 AM
  • User767034699 posted

    Hi there PaulTheSmith,

    It sounds like you are trying to shuffle the numbers from 0 to 9999 and deliver them one at a time (much like shuffling a pack of cards and dealing them one by one).  To do that you should generate the list of all 10,000 four digit codes and store them somewhere (a pretty small amount of data).  Each code has an index.  Start the index at zero.  The first request for a PIN gets the item at index zero.  Increment the index and remember the value.  Each request for a PIN gets given the value at the next index (which is then incremented).  If the index increments to 10,000 then reset it to zero.

    Do i really need to generate 10000 pins? why not generate 4 digit 1000 pins store them in a db. Do the increment from a stored proceudre inside a temp table doing the increments. ?

    kind regards

    Tony

    Wednesday, June 20, 2018 9:15 AM
  • User475983607 posted

    There's bits missing from you design question or you are overthinking the design.

    First, a temp table exists for single connection.  The pins are finite and can be created once and during design time.  It does not make sense to create pins during run-time given the current requirement.

    Wednesday, June 20, 2018 10:36 AM
  • User753101303 posted

    We can speculate but we would need to first understand how you are using them. Usually they are not used alone so my guess is that they don't need to be unique? You may not even have to generate in advance.

    If used alone and half of the code are used, what prevents me to try some other code and have 50% chance of success. For now I feel you have some kind of design issue. Once agzin a credit card code is useless without the corresponding credit card and is not unique (this is the kind of usage you gave so far).

    Wednesday, June 20, 2018 11:04 AM
  • User767034699 posted

    Hi there mgebhard,

    thanks for the response,

    well i think im overthinking at this,

    okay i twirked at my code and did something like this below

     private static int CreateCryptographicallySecureGuid(int count)
            {
                Random generator = new Random();//NumberGenerator();
                int billId;
               
                do
                {
                    billId = generator.Next(0000, 10000 + count);
                } while (Test.IdList.Contains(billId));
                Test.IdList.Add(billId);
    
                //List<int> randomlist= Test.IdList.ToList();
                //for (int i = randomlist.Count - 1; i > 0; i--)
                //{
                //    int T = generator.Next(i + 1);
                //    int tmp = randomlist[T];
                //    randomlist[T] = randomlist[i];
                //    randomlist[i] = tmp;
                //}
                return billId;
    
             }
    

    there in the method im passing a count all the way up to 1000 and adding it into the max side of the random generation. Also talked about incremention. Does that makes sense to add the increment  on the max ?

    kind regards

    Tony

    Wednesday, June 20, 2018 11:05 AM
  • User767034699 posted

    Hi there PatriceSc,

    basically we integrating with the bank for some of our clients so that we can do some payouts.

    In the document it states that they require 

    • A 4 digit pin
    • No-sequential Pin only(Not allowed 1234, 3456 etc)

    so this pin it will be used by clients to pin out their funds from ATMS more like a wallet.

    kind regards

    Tony

    Wednesday, June 20, 2018 11:22 AM
  • User753101303 posted

    It doesn't seems it needs to be unique. Once again you could have 10000 customers only and being able to start a banking transaction with ONLY a 4 digit PIN number would be a huge concern  !?

    IMO for some reason you though about "non sequential" as "unique" but it doesn't have to be. Exactly as I guess many other customers in my bank do have the same 4 digit pin number which is  not a problem as they it used WITH their own credit card.

    Motre liekly they have to provide both a credit card number or something else which is truly unique all along with their random PIN code.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 20, 2018 11:32 AM
  • User475983607 posted

    Given this requirement your current design approach is irrelevant.   The pin and user (or something) else like a card number makes the pin unique.

    It sounds like you do not have a solid understanding of the application flow.  When this happens to me, I setup a meeting with the end users and flush out the process flow.

    Wednesday, June 20, 2018 11:33 AM
  • User767034699 posted

    oh yes, the funds wont be withdrawn using any cards. This is a plain instant cash out sent by the bank through sms linked with cell phone number.

    if it doent require to be unique in every generation i will go with a simple random generation.

    I can use DateTime timestamp converted to Milliseconds or something for a pin that wont repeat as each day and time is different. is the range specified important also?

    kind regards

    Tony

    Wednesday, June 20, 2018 12:01 PM
  • User753101303 posted

    It should be the default already (I checked https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx which confirms that). The range is just whatever fit your needs (maybe you want to start from 1000 to always have 4 significant digits ?)

    A common catch when generating multiple numbers is callling new Random() inside a loop causing to take the first number of a the same random sequence  based on the same date/time seed rather than multiple numbers from a single random sequence.

    Wednesday, June 20, 2018 12:17 PM
  • User475983607 posted

    tonyR6

    if it doent require to be unique in every generation i will go with a simple random generation.

    Please read the documentation first.  Random will generate the same sequence given the same seed value.

    tonyR6

    I can use DateTime timestamp converted to Milliseconds or something for a pin that wont repeat as each day and time is different. is the range specified important also?

    Sure, but a date and time is larger than 4 digits.  I think you need to take a step back and think about what you are doing.  Crafting a 4 digit random number is a very simple operation and should not take this many posts to handle.  Perhaps there is other design problems you are facing like joining the pin to a phone number?  I image you have to expire the pin etc.  Maybe this is causing conflict in the design.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 20, 2018 1:12 PM
  • User767034699 posted

    yes, just went through the documentation. adding seconds wont make any difference. Actually joining the pin to the phone number and retiring the pins is a bit confusing me. How should be going with joining the pin to the phone number

    2nd retiring the pins?

    kind regards

    Tony

    Wednesday, June 20, 2018 2:00 PM
  • User475983607 posted

    yes, just went through the documentation. adding seconds wont make any difference. Actually joining the pin to the phone number and retiring the pins is a bit confusing me. How should be going with joining the pin to the phone number

    2nd retiring the pins?

    kind regards

    Tony

    Tony, you're asking an ASP forum how to design an application with little to no information.  I have no idea how the pins work and assume they are for one-time use.

    You should be asking the people that want this feature how they expect it to work.   

    Wednesday, June 20, 2018 2:13 PM
  • User753101303 posted

    Your app doesn't handle customer accounts ? Usually it is linked to a registered user account all along with an expiration date. The user can then use this code for a limited amount of time,  for example to reset a password (using a previously registered phone number or mail address used to deliver this code).

    You should be best placed to understand the whole workflow. For now it seems something I would expect rather to be done on a payment API side rather than on the API consumer side. Or this code is not used to confirm the payment before it is done but so that it can be used on your side to confirm the payment has been done for somethjng in particular and that the corresponding item could be delivered (or downloaded ?)

    It seems you should stop coding and make sure first to understand  the exact process you are trying to implement and who is responsible for doing what in this process (ie you create this "code" but who will send that ( the bank ?)  and who will check this value (your app ?).

    On our side we can only guess what you are really trying to do.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 20, 2018 3:42 PM
  • User767034699 posted

    Hi there PatriceSc, 

    after taking sometime with the client and the bank. They dont require a pin to be unique. As long its not in sequential :). I dont even need to keep the pins in the database. But the bank do keep them on their side. I can always request the details anytime. They have a method that allows me to request such information like pins...

    i would like to thank you guys for wonderfull suggestion and spending sometime to assist me on this. really appreciate it guys.

    i will be closing the thread...

    :)

    kind regards

    Tony

    Monday, July 2, 2018 1:15 PM