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 }