1package mox
2
3import (
4 cryptorand "crypto/rand"
5 "encoding/binary"
6 "fmt"
7 mathrand "math/rand"
8 "sync"
9)
10
11type rand struct {
12 *mathrand.Rand
13 sync.Mutex
14}
15
16// NewPseudoRand returns a new PRNG seeded with random bytes from crypto/rand.
17func NewPseudoRand() *rand {
18 return &rand{Rand: mathrand.New(mathrand.NewSource(CryptoRandInt()))}
19}
20
21// Read can be called concurrently.
22func (r *rand) Read(buf []byte) (int, error) {
23 r.Lock()
24 defer r.Unlock()
25 return r.Rand.Read(buf)
26}
27
28// CryptoRandInt returns a cryptographically random number.
29func CryptoRandInt() int64 {
30 buf := make([]byte, 8)
31 _, err := cryptorand.Read(buf)
32 if err != nil {
33 panic(fmt.Errorf("reading random bytes: %v", err))
34 }
35 return int64(binary.LittleEndian.Uint64(buf))
36}
37