github.com/prysmaticlabs/prysm@v1.4.4/shared/rand/rand.go (about)

     1  /*
     2  Package rand defines methods of obtaining cryptographically secure random number generators.
     3  
     4  One is expected to use randomness from this package only, without introducing any other packages.
     5  This limits the scope of code that needs to be hardened.
     6  
     7  There are two modes, one for deterministic and another non-deterministic randomness:
     8  1. If deterministic pseudo-random generator is enough, use:
     9  
    10  	import "github.com/prysmaticlabs/prysm/shared/rand"
    11  	randGen := rand.NewDeterministicGenerator()
    12  	randGen.Intn(32) // or any other func defined in math.rand API
    13  
    14     In this mode, only seed is generated using cryptographically secure source (crypto/rand). So,
    15     once seed is obtained, and generator is seeded, the next generations are deterministic, thus fast.
    16     This method is still better than using unix time for source of randomness - since time is not a
    17     good source of seed randomness, when you have many concurrent servers using it (and they have
    18     coinciding random generators' start times).
    19  
    20  2. For cryptographically secure non-deterministic mode (CSPRNG), use:
    21  
    22  	import "github.com/prysmaticlabs/prysm/shared/rand"
    23  	randGen := rand.NewGenerator()
    24  	randGen.Intn(32) // or any other func defined in math.rand API
    25  
    26     Again, any of the functions from `math/rand` can be used, however, they all use custom source
    27     of randomness (crypto/rand), on every step. This makes randomness non-deterministic. However,
    28     you take a performance hit -- as it is an order of magnitude slower.
    29  */
    30  package rand
    31  
    32  import (
    33  	"crypto/rand"
    34  	"encoding/binary"
    35  	mrand "math/rand"
    36  	"sync"
    37  )
    38  
    39  type source struct{}
    40  
    41  var lock sync.RWMutex
    42  var _ mrand.Source64 = (*source)(nil)
    43  
    44  // Seed does nothing when crypto/rand is used as source.
    45  func (s *source) Seed(_ int64) {}
    46  
    47  // Int63 returns uniformly-distributed random (as in CSPRNG) int64 value within [0, 1<<63) range.
    48  // Panics if random generator reader cannot return data.
    49  func (s *source) Int63() int64 {
    50  	return int64(s.Uint64() & ^uint64(1<<63))
    51  }
    52  
    53  // Uint64 returns uniformly-distributed random (as in CSPRNG) uint64 value within [0, 1<<64) range.
    54  // Panics if random generator reader cannot return data.
    55  func (s *source) Uint64() (val uint64) {
    56  	lock.RLock()
    57  	defer lock.RUnlock()
    58  	if err := binary.Read(rand.Reader, binary.BigEndian, &val); err != nil {
    59  		panic(err)
    60  	}
    61  	return
    62  }
    63  
    64  // Rand is alias for underlying random generator.
    65  type Rand = mrand.Rand
    66  
    67  // NewGenerator returns a new generator that uses random values from crypto/rand as a source
    68  // (cryptographically secure random number generator).
    69  // Panics if crypto/rand input cannot be read.
    70  // Use it for everything where crypto secure non-deterministic randomness is required. Performance
    71  // takes a hit, so use sparingly.
    72  func NewGenerator() *Rand {
    73  	return mrand.New(&source{})
    74  }
    75  
    76  // NewDeterministicGenerator returns a random generator which is only seeded with crypto/rand,
    77  // but is deterministic otherwise (given seed, produces given results, deterministically).
    78  // Panics if crypto/rand input cannot be read.
    79  // Use this method for performance, where deterministic pseudo-random behaviour is enough.
    80  // Otherwise, rely on NewGenerator().
    81  func NewDeterministicGenerator() *Rand {
    82  	randGen := NewGenerator()
    83  	return mrand.New(mrand.NewSource(randGen.Int63()))
    84  }