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