| package random |
| |
| import ( |
| cryptorand "crypto/rand" |
| "io" |
| "math" |
| "math/big" |
| "math/rand" |
| "sync" |
| "time" |
| ) |
| |
| // Rand is a global *rand.Rand instance, which initialized with NewSource() source. |
| var Rand = rand.New(NewSource()) |
| |
| // Reader is a global, shared instance of a pseudorandom bytes generator. |
| // It doesn't consume entropy. |
| var Reader io.Reader = &reader{rnd: Rand} |
| |
| // copypaste from standard math/rand |
| type lockedSource struct { |
| lk sync.Mutex |
| src rand.Source |
| } |
| |
| func (r *lockedSource) Int63() (n int64) { |
| r.lk.Lock() |
| n = r.src.Int63() |
| r.lk.Unlock() |
| return |
| } |
| |
| func (r *lockedSource) Seed(seed int64) { |
| r.lk.Lock() |
| r.src.Seed(seed) |
| r.lk.Unlock() |
| } |
| |
| // NewSource returns math/rand.Source safe for concurrent use and initialized |
| // with current unix-nano timestamp |
| func NewSource() rand.Source { |
| var seed int64 |
| if cryptoseed, err := cryptorand.Int(cryptorand.Reader, big.NewInt(math.MaxInt64)); err != nil { |
| // This should not happen, but worst-case fallback to time-based seed. |
| seed = time.Now().UnixNano() |
| } else { |
| seed = cryptoseed.Int64() |
| } |
| return &lockedSource{ |
| src: rand.NewSource(seed), |
| } |
| } |
| |
| type reader struct { |
| rnd *rand.Rand |
| } |
| |
| func (r *reader) Read(b []byte) (int, error) { |
| i := 0 |
| for { |
| val := r.rnd.Int63() |
| for val > 0 { |
| b[i] = byte(val) |
| i++ |
| if i == len(b) { |
| return i, nil |
| } |
| val >>= 8 |
| } |
| } |
| } |