github.com/vipernet-xyz/tm@v0.34.24/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/vipernet-xyz/tm/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,nolintlint // 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/vipernet-xyz/tm/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  }