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