TinyHash.cs 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. using System;
  2. using System.Security.Cryptography;
  3. namespace Quadarax.Foundation.Core.Value.Generators
  4. {
  5. public class TinyHash : IIdGenerator<string>
  6. {
  7. #region *** Constants ***
  8. public const string DefaultCharset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  9. public const int DefaultLength = 5;
  10. #endregion
  11. #region *** Private fields ***
  12. private readonly int _length;
  13. private readonly string _charset;
  14. #endregion
  15. #region *** Constructors ***
  16. public TinyHash(string charset, int length)
  17. {
  18. if (string.IsNullOrEmpty(charset)) throw new ArgumentNullException(nameof(charset));
  19. if (length < 1) throw new ArgumentOutOfRangeException(nameof(length));
  20. _charset = charset;
  21. _length = length;
  22. }
  23. public TinyHash(int length) : this(DefaultCharset, length)
  24. {
  25. }
  26. public TinyHash() : this(DefaultCharset, DefaultLength)
  27. {
  28. }
  29. #endregion
  30. #region *** Public Operations ***
  31. public string NewId()
  32. {
  33. var outputChars = new char[_length];
  34. using var rnd = RandomNumberGenerator.Create();
  35. var diff = _charset.Length;
  36. var upperBound = uint.MaxValue / diff * diff;
  37. var randomBuffer = new byte[sizeof(int)];
  38. for (var i = 0; i < outputChars.Length; i++)
  39. {
  40. // Generate a fair, random number between minIndex and maxIndex
  41. uint randomUInt;
  42. do
  43. {
  44. rnd.GetBytes(randomBuffer);
  45. randomUInt = BitConverter.ToUInt32(randomBuffer, 0);
  46. }
  47. while (randomUInt >= upperBound);
  48. var charIndex = (int)(randomUInt % diff);
  49. // Set output character based on random index
  50. outputChars[i] = _charset[charIndex];
  51. }
  52. return new string(outputChars);
  53. }
  54. #endregion
  55. }
  56. }