github.com/Finschia/ostracon@v1.1.5/libs/rand/random.go (about) 1 package rand 2 3 import ( 4 crand "crypto/rand" 5 mrand "math/rand" 6 "time" 7 8 tmsync "github.com/Finschia/ostracon/libs/sync" 9 ) 10 11 const ( 12 strChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // 62 characters 13 ) 14 15 // Rand is a prng, that is seeded with OS randomness. 16 // The OS randomness is obtained from crypto/rand, however none of the provided 17 // methods are suitable for cryptographic usage. 18 // They all utilize math/rand's prng internally. 19 // 20 // All of the methods here are suitable for concurrent use. 21 // This is achieved by using a mutex lock on all of the provided methods. 22 type Rand struct { 23 tmsync.Mutex 24 rand *mrand.Rand 25 } 26 27 var grand *Rand 28 29 func init() { 30 grand = NewRand() 31 } 32 33 func NewRand() *Rand { 34 rand := &Rand{} 35 rand.init() 36 return rand 37 } 38 39 func (r *Rand) init() { 40 bz := cRandBytes(8) 41 var seed uint64 42 for i := 0; i < 8; i++ { 43 seed |= uint64(bz[i]) 44 seed <<= 8 45 } 46 r.reset(int64(seed)) 47 } 48 49 func (r *Rand) reset(seed int64) { 50 r.rand = mrand.New(mrand.NewSource(seed)) //nolint:gosec,nolintlint // G404: Use of weak random number generator 51 } 52 53 //---------------------------------------- 54 // Global functions 55 56 func Seed(seed int64) { 57 grand.Seed(seed) 58 } 59 60 func Str(length int) string { 61 return grand.Str(length) 62 } 63 64 func Uint16() uint16 { 65 return grand.Uint16() 66 } 67 68 func Uint32() uint32 { 69 return grand.Uint32() 70 } 71 72 func Uint64() uint64 { 73 return grand.Uint64() 74 } 75 76 func Uint() uint { 77 return grand.Uint() 78 } 79 80 func Int16() int16 { 81 return grand.Int16() 82 } 83 84 func Int32() int32 { 85 return grand.Int32() 86 } 87 88 func Int64() int64 { 89 return grand.Int64() 90 } 91 92 func Int() int { 93 return grand.Int() 94 } 95 96 func Int31() int32 { 97 return grand.Int31() 98 } 99 100 func Int31n(n int32) int32 { 101 return grand.Int31n(n) 102 } 103 104 func Int63() int64 { 105 return grand.Int63() 106 } 107 108 func Int63n(n int64) int64 { 109 return grand.Int63n(n) 110 } 111 112 func Bool() bool { 113 return grand.Bool() 114 } 115 116 func Float32() float32 { 117 return grand.Float32() 118 } 119 120 func Float64() float64 { 121 return grand.Float64() 122 } 123 124 func Time() time.Time { 125 return grand.Time() 126 } 127 128 func Bytes(n int) []byte { 129 return grand.Bytes(n) 130 } 131 132 func Intn(n int) int { 133 return grand.Intn(n) 134 } 135 136 func Perm(n int) []int { 137 return grand.Perm(n) 138 } 139 140 //---------------------------------------- 141 // Rand methods 142 143 func (r *Rand) Seed(seed int64) { 144 r.Lock() 145 r.reset(seed) 146 r.Unlock() 147 } 148 149 // Str constructs a random alphanumeric string of given length. 150 func (r *Rand) Str(length int) string { 151 if length <= 0 { 152 return "" 153 } 154 155 chars := []byte{} 156 MAIN_LOOP: 157 for { 158 val := r.Int63() 159 for i := 0; i < 10; i++ { 160 v := int(val & 0x3f) // rightmost 6 bits 161 if v >= 62 { // only 62 characters in strChars 162 val >>= 6 163 continue 164 } else { 165 chars = append(chars, strChars[v]) 166 if len(chars) == length { 167 break MAIN_LOOP 168 } 169 val >>= 6 170 } 171 } 172 } 173 174 return string(chars) 175 } 176 177 func (r *Rand) Uint16() uint16 { 178 return uint16(r.Uint32() & (1<<16 - 1)) 179 } 180 181 func (r *Rand) Uint32() uint32 { 182 r.Lock() 183 u32 := r.rand.Uint32() 184 r.Unlock() 185 return u32 186 } 187 188 func (r *Rand) Uint64() uint64 { 189 return uint64(r.Uint32())<<32 + uint64(r.Uint32()) 190 } 191 192 func (r *Rand) Uint() uint { 193 r.Lock() 194 i := r.rand.Int() 195 r.Unlock() 196 return uint(i) 197 } 198 199 func (r *Rand) Int16() int16 { 200 return int16(r.Uint32() & (1<<16 - 1)) 201 } 202 203 func (r *Rand) Int32() int32 { 204 return int32(r.Uint32()) 205 } 206 207 func (r *Rand) Int64() int64 { 208 return int64(r.Uint64()) 209 } 210 211 func (r *Rand) Int() int { 212 r.Lock() 213 i := r.rand.Int() 214 r.Unlock() 215 return i 216 } 217 218 func (r *Rand) Int31() int32 { 219 r.Lock() 220 i31 := r.rand.Int31() 221 r.Unlock() 222 return i31 223 } 224 225 func (r *Rand) Int31n(n int32) int32 { 226 r.Lock() 227 i31n := r.rand.Int31n(n) 228 r.Unlock() 229 return i31n 230 } 231 232 func (r *Rand) Int63() int64 { 233 r.Lock() 234 i63 := r.rand.Int63() 235 r.Unlock() 236 return i63 237 } 238 239 func (r *Rand) Int63n(n int64) int64 { 240 r.Lock() 241 i63n := r.rand.Int63n(n) 242 r.Unlock() 243 return i63n 244 } 245 246 func (r *Rand) Float32() float32 { 247 r.Lock() 248 f32 := r.rand.Float32() 249 r.Unlock() 250 return f32 251 } 252 253 func (r *Rand) Float64() float64 { 254 r.Lock() 255 f64 := r.rand.Float64() 256 r.Unlock() 257 return f64 258 } 259 260 func (r *Rand) Time() time.Time { 261 return time.Unix(int64(r.Uint64()), 0) 262 } 263 264 // Bytes returns n random bytes generated from the internal 265 // prng. 266 func (r *Rand) Bytes(n int) []byte { 267 // cRandBytes isn't guaranteed to be fast so instead 268 // use random bytes generated from the internal PRNG 269 bs := make([]byte, n) 270 for i := 0; i < len(bs); i++ { 271 bs[i] = byte(r.Int() & 0xFF) 272 } 273 return bs 274 } 275 276 // Intn returns, as an int, a uniform pseudo-random number in the range [0, n). 277 // It panics if n <= 0. 278 func (r *Rand) Intn(n int) int { 279 r.Lock() 280 i := r.rand.Intn(n) 281 r.Unlock() 282 return i 283 } 284 285 // Bool returns a uniformly random boolean 286 func (r *Rand) Bool() bool { 287 // See https://github.com/golang/go/issues/23804#issuecomment-365370418 288 // for reasoning behind computing like this 289 return r.Int63()%2 == 0 290 } 291 292 // Perm returns a pseudo-random permutation of n integers in [0, n). 293 func (r *Rand) Perm(n int) []int { 294 r.Lock() 295 perm := r.rand.Perm(n) 296 r.Unlock() 297 return perm 298 } 299 300 // NOTE: This relies on the os's random number generator. 301 // For real security, we should salt that with some seed. 302 // See github.com/Finschia/ostracon/crypto for a more secure reader. 303 func cRandBytes(numBytes int) []byte { 304 b := make([]byte, numBytes) 305 _, err := crand.Read(b) 306 if err != nil { 307 panic(err) 308 } 309 return b 310 }