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 }