1package mox
2
3import (
4 cryptorand "crypto/rand"
5 "encoding/binary"
6 "fmt"
7 mathrand2 "math/rand/v2"
8 "sync"
9)
10
11type rand struct {
12 rand *mathrand2.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 var seed [32]byte
20 if _, err := cryptorand.Read(seed[:]); err != nil {
21 panic(err)
22 }
23 return &rand{rand: mathrand2.New(mathrand2.NewChaCha8(seed))}
24}
25
26func (r *rand) Float64() float64 {
27 r.Lock()
28 defer r.Unlock()
29 return r.rand.Float64()
30}
31
32func (r *rand) IntN(n int) int {
33 r.Lock()
34 defer r.Unlock()
35 return r.rand.IntN(n)
36}
37
38// CryptoRandInt returns a cryptographically random number.
39func CryptoRandInt() int64 {
40 buf := make([]byte, 8)
41 _, err := cryptorand.Read(buf)
42 if err != nil {
43 panic(fmt.Errorf("reading random bytes: %v", err))
44 }
45 return int64(binary.LittleEndian.Uint64(buf))
46}
47