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  }