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  }