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 rand *mathrand.Rand
13 sync.Mutex
14}
15
16// NewPseudoRand returns a new PRNG seeded with random bytes from crypto/rand. Its
17// functions can be called concurrently.
18func NewPseudoRand() *rand {
19 return &rand{rand: mathrand.New(mathrand.NewSource(CryptoRandInt()))}
20}
21
22func (r *rand) Float64() float64 {
23 r.Lock()
24 defer r.Unlock()
25 return r.rand.Float64()
26}
27
28func (r *rand) Intn(n int) int {
29 r.Lock()
30 defer r.Unlock()
31 return r.rand.Intn(n)
32}
33
34func (r *rand) Read(buf []byte) (int, error) {
35 r.Lock()
36 defer r.Unlock()
37 return r.rand.Read(buf)
38}
39
40// CryptoRandInt returns a cryptographically random number.
41func CryptoRandInt() int64 {
42 buf := make([]byte, 8)
43 _, err := cryptorand.Read(buf)
44 if err != nil {
45 panic(fmt.Errorf("reading random bytes: %v", err))
46 }
47 return int64(binary.LittleEndian.Uint64(buf))
48}
49