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