github.com/clubpay/ronykit/kit@v0.14.4-0.20240515065620-d0dace45cbc7/utils/random.go (about)

     1  package utils
     2  
     3  import (
     4  	"crypto/rand"
     5  	"encoding/binary"
     6  	mathRand "math/rand"
     7  	"sync"
     8  	_ "unsafe"
     9  )
    10  
    11  /*
    12     Creation Time: 2019 - Oct - 03
    13     Created by:  (ehsan)
    14     Maintainers:
    15        1.  Ehsan N. Moosa (E2)
    16     Auditor: Ehsan N. Moosa (E2)
    17  */
    18  
    19  func init() {
    20  	rndGen.New = func() any {
    21  		x := mathRand.New(mathRand.NewSource(CPUTicks()))
    22  
    23  		return x
    24  	}
    25  }
    26  
    27  const (
    28  	digits              = "0123456789"
    29  	digitsLength        = uint32(len(digits))
    30  	alphaNumerics       = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    31  	alphaNumericsLength = uint32(len(alphaNumerics))
    32  )
    33  
    34  // FastRand is a fast thread local random function.
    35  //
    36  //go:linkname FastRand runtime.fastrand
    37  func FastRand() uint32
    38  
    39  type randomGenerator struct {
    40  	sync.Pool
    41  }
    42  
    43  func (rg *randomGenerator) GetRand() *mathRand.Rand {
    44  	return rg.Get().(*mathRand.Rand) //nolint:forcetypeassert
    45  }
    46  
    47  func (rg *randomGenerator) PutRand(r *mathRand.Rand) {
    48  	rg.Put(r)
    49  }
    50  
    51  var rndGen randomGenerator
    52  
    53  // RandomID generates a pseudo-random string with length 'n' which characters are alphanumerics.
    54  func RandomID(n int) string {
    55  	rnd := rndGen.GetRand()
    56  	b := make([]byte, n)
    57  
    58  	for i := range b {
    59  		b[i] = alphaNumerics[FastRand()%alphaNumericsLength]
    60  	}
    61  	rndGen.PutRand(rnd)
    62  
    63  	return ByteToStr(b)
    64  }
    65  
    66  func RandomIDs(n ...int) []string {
    67  	str := make([]string, 0, len(n))
    68  	for _, x := range n {
    69  		str = append(str, RandomID(x))
    70  	}
    71  
    72  	return str
    73  }
    74  
    75  // RandomDigit generates a pseudo-random string with length 'n' which characters are only digits (0-9)
    76  func RandomDigit(n int) string {
    77  	rnd := rndGen.GetRand()
    78  	b := make([]byte, n)
    79  	for i := 0; i < len(b); i++ {
    80  		b[i] = digits[FastRand()%digitsLength]
    81  	}
    82  	rndGen.PutRand(rnd)
    83  
    84  	return ByteToStr(b)
    85  }
    86  
    87  // RandomInt64 produces a pseudo-random 63bit number, if n == 0 there will be no limit otherwise
    88  // the output will be smaller than n
    89  func RandomInt64(n int64) (x int64) {
    90  	rnd := rndGen.GetRand()
    91  	if n == 0 {
    92  		x = rnd.Int63()
    93  	} else {
    94  		x = rnd.Int63n(n)
    95  	}
    96  	rndGen.PutRand(rnd)
    97  
    98  	return
    99  }
   100  
   101  // RandomInt32 produces a pseudo-random 31bit number, if n == 0 there will be no limit otherwise
   102  // the output will be smaller than n
   103  func RandomInt32(n int32) (x int32) {
   104  	rnd := rndGen.GetRand()
   105  	if n == 0 {
   106  		x = rnd.Int31()
   107  	} else {
   108  		x = rnd.Int31n(n)
   109  	}
   110  	rndGen.PutRand(rnd)
   111  
   112  	return
   113  }
   114  
   115  // SecureRandomInt63 produces a secure pseudo-random 63bit number
   116  func SecureRandomInt63(n int64) (x int64) {
   117  	var b [8]byte
   118  	_, _ = rand.Read(b[:])
   119  	xx := binary.BigEndian.Uint64(b[:])
   120  	if n > 0 {
   121  		x = int64(xx) % n
   122  	} else {
   123  		x = int64(xx >> 1)
   124  	}
   125  
   126  	return
   127  }
   128  
   129  func RandomInt(n int) (x int) {
   130  	rnd := rndGen.GetRand()
   131  	if n == 0 {
   132  		x = rnd.Int()
   133  	} else {
   134  		x = rnd.Intn(n)
   135  	}
   136  	rndGen.PutRand(rnd)
   137  
   138  	return
   139  }
   140  
   141  // RandomUint64 produces a pseudo-random unsigned number
   142  func RandomUint64(n uint64) (x uint64) {
   143  	rnd := rndGen.GetRand()
   144  	if n == 0 {
   145  		x = rnd.Uint64()
   146  	} else {
   147  		x = rnd.Uint64() % n
   148  	}
   149  	rndGen.PutRand(rnd)
   150  
   151  	return
   152  }
   153  
   154  // SecureRandomUint64 produces a secure pseudo-random 64bit number
   155  func SecureRandomUint64() (x uint64) {
   156  	var b [8]byte
   157  	_, _ = rand.Read(b[:])
   158  	x = binary.BigEndian.Uint64(b[:])
   159  
   160  	return
   161  }