github.com/number571/tendermint@v0.34.11-gost/libs/rand/random.go (about)

     1  package rand
     2  
     3  import (
     4  	crand "crypto/rand"
     5  	"encoding/binary"
     6  	"fmt"
     7  	mrand "math/rand"
     8  )
     9  
    10  const (
    11  	strChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // 62 characters
    12  )
    13  
    14  func init() {
    15  	Reseed()
    16  }
    17  
    18  // NewRand returns a prng, that is seeded with OS randomness.
    19  // The OS randomness is obtained from crypto/rand, however, like with any math/rand.Rand
    20  // object none of the provided methods are suitable for cryptographic usage.
    21  //
    22  // Note that the returned instance of math/rand's Rand is not
    23  // suitable for concurrent use by multiple goroutines.
    24  //
    25  // For concurrent use, call Reseed to reseed math/rand's default source and
    26  // use math/rand's top-level convenience functions instead.
    27  func NewRand() *mrand.Rand {
    28  	seed := crandSeed()
    29  	// nolint:gosec // G404: Use of weak random number generator
    30  	return mrand.New(mrand.NewSource(seed))
    31  }
    32  
    33  // Reseed conveniently re-seeds the default Source of math/rand with
    34  // randomness obtained from crypto/rand.
    35  //
    36  // Note that this does not make math/rand suitable for cryptographic usage.
    37  //
    38  // Use math/rand's top-level convenience functions remain suitable
    39  // for concurrent use by multiple goroutines.
    40  func Reseed() {
    41  	seed := crandSeed()
    42  	mrand.Seed(seed)
    43  }
    44  
    45  // Str constructs a random alphanumeric string of given length
    46  // from math/rand's global default Source.
    47  func Str(length int) string {
    48  	if length <= 0 {
    49  		return ""
    50  	}
    51  
    52  	chars := make([]byte, 0, length)
    53  	for {
    54  		// nolint:gosec // G404: Use of weak random number generator
    55  		val := mrand.Int63()
    56  		for i := 0; i < 10; i++ {
    57  			v := int(val & 0x3f) // rightmost 6 bits
    58  			if v >= 62 {         // only 62 characters in strChars
    59  				val >>= 6
    60  				continue
    61  			} else {
    62  				chars = append(chars, strChars[v])
    63  				if len(chars) == length {
    64  					return string(chars)
    65  				}
    66  				val >>= 6
    67  			}
    68  		}
    69  	}
    70  }
    71  
    72  // Bytes returns n random bytes generated from math/rand's global default Source.
    73  func Bytes(n int) []byte {
    74  	bs := make([]byte, n)
    75  	for i := 0; i < len(bs); i++ {
    76  		// nolint:gosec // G404: Use of weak random number generator
    77  		bs[i] = byte(mrand.Int() & 0xFF)
    78  	}
    79  	return bs
    80  }
    81  
    82  func crandSeed() int64 {
    83  	var seed int64
    84  	err := binary.Read(crand.Reader, binary.BigEndian, &seed)
    85  	if err != nil {
    86  		panic(fmt.Sprintf("could nor read random seed from crypto/rand: %v", err))
    87  	}
    88  	return seed
    89  }