mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-12 21:01:21 +00:00
common/random.go supports seeding and *Rand (#121)
* common/random.go supports seeding and *Rand * Ensure determinism
This commit is contained in:
244
common/random.go
244
common/random.go
@ -13,34 +13,138 @@ const (
|
||||
|
||||
// pseudo random number generator.
|
||||
// seeded with OS randomness (crand)
|
||||
var prng struct {
|
||||
|
||||
type Rand struct {
|
||||
sync.Mutex
|
||||
*mrand.Rand
|
||||
}
|
||||
|
||||
func reset() {
|
||||
b := cRandBytes(8)
|
||||
var seed uint64
|
||||
for i := 0; i < 8; i++ {
|
||||
seed |= uint64(b[i])
|
||||
seed <<= 8
|
||||
}
|
||||
prng.Lock()
|
||||
prng.Rand = mrand.New(mrand.NewSource(int64(seed)))
|
||||
prng.Unlock()
|
||||
}
|
||||
var grand *Rand
|
||||
|
||||
func init() {
|
||||
reset()
|
||||
grand = New()
|
||||
grand.init()
|
||||
}
|
||||
|
||||
func New() *Rand {
|
||||
rand := &Rand{}
|
||||
rand.init()
|
||||
return rand
|
||||
}
|
||||
|
||||
func (r *Rand) init() {
|
||||
bz := cRandBytes(8)
|
||||
var seed uint64
|
||||
for i := 0; i < 8; i++ {
|
||||
seed |= uint64(bz[i])
|
||||
seed <<= 8
|
||||
}
|
||||
r.reset(int64(seed))
|
||||
}
|
||||
|
||||
func (r *Rand) reset(seed int64) {
|
||||
r.Rand = mrand.New(mrand.NewSource(seed))
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Global functions
|
||||
|
||||
func Seed(seed int64) {
|
||||
grand.Seed(seed)
|
||||
}
|
||||
|
||||
func RandStr(length int) string {
|
||||
return grand.RandStr(length)
|
||||
}
|
||||
|
||||
func RandUint16() uint16 {
|
||||
return grand.RandUint16()
|
||||
}
|
||||
|
||||
func RandUint32() uint32 {
|
||||
return grand.RandUint32()
|
||||
}
|
||||
|
||||
func RandUint64() uint64 {
|
||||
return grand.RandUint64()
|
||||
}
|
||||
|
||||
func RandUint() uint {
|
||||
return grand.RandUint()
|
||||
}
|
||||
|
||||
func RandInt16() int16 {
|
||||
return grand.RandInt16()
|
||||
}
|
||||
|
||||
func RandInt32() int32 {
|
||||
return grand.RandInt32()
|
||||
}
|
||||
|
||||
func RandInt64() int64 {
|
||||
return grand.RandInt64()
|
||||
}
|
||||
|
||||
func RandInt() int {
|
||||
return grand.RandInt()
|
||||
}
|
||||
|
||||
func RandInt31() int32 {
|
||||
return grand.RandInt31()
|
||||
}
|
||||
|
||||
func RandInt63() int64 {
|
||||
return grand.RandInt63()
|
||||
}
|
||||
|
||||
func RandUint16Exp() uint16 {
|
||||
return grand.RandUint16Exp()
|
||||
}
|
||||
|
||||
func RandUint32Exp() uint32 {
|
||||
return grand.RandUint32Exp()
|
||||
}
|
||||
|
||||
func RandUint64Exp() uint64 {
|
||||
return grand.RandUint64Exp()
|
||||
}
|
||||
|
||||
func RandFloat32() float32 {
|
||||
return grand.RandFloat32()
|
||||
}
|
||||
|
||||
func RandTime() time.Time {
|
||||
return grand.RandTime()
|
||||
}
|
||||
|
||||
func RandBytes(n int) []byte {
|
||||
return grand.RandBytes(n)
|
||||
}
|
||||
|
||||
func RandIntn(n int) int {
|
||||
return grand.RandIntn(n)
|
||||
}
|
||||
|
||||
func RandPerm(n int) []int {
|
||||
return grand.RandPerm(n)
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Rand methods
|
||||
|
||||
func (r *Rand) Seed(seed int64) {
|
||||
r.Lock()
|
||||
r.reset(seed)
|
||||
r.Unlock()
|
||||
}
|
||||
|
||||
// Constructs an alphanumeric string of given length.
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandStr(length int) string {
|
||||
func (r *Rand) RandStr(length int) string {
|
||||
chars := []byte{}
|
||||
MAIN_LOOP:
|
||||
for {
|
||||
val := RandInt63()
|
||||
val := r.RandInt63()
|
||||
for i := 0; i < 10; i++ {
|
||||
v := int(val & 0x3f) // rightmost 6 bits
|
||||
if v >= 62 { // only 62 characters in strChars
|
||||
@ -60,127 +164,127 @@ MAIN_LOOP:
|
||||
}
|
||||
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandUint16() uint16 {
|
||||
return uint16(RandUint32() & (1<<16 - 1))
|
||||
func (r *Rand) RandUint16() uint16 {
|
||||
return uint16(r.RandUint32() & (1<<16 - 1))
|
||||
}
|
||||
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandUint32() uint32 {
|
||||
prng.Lock()
|
||||
u32 := prng.Uint32()
|
||||
prng.Unlock()
|
||||
func (r *Rand) RandUint32() uint32 {
|
||||
r.Lock()
|
||||
u32 := r.Uint32()
|
||||
r.Unlock()
|
||||
return u32
|
||||
}
|
||||
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandUint64() uint64 {
|
||||
return uint64(RandUint32())<<32 + uint64(RandUint32())
|
||||
func (r *Rand) RandUint64() uint64 {
|
||||
return uint64(r.RandUint32())<<32 + uint64(r.RandUint32())
|
||||
}
|
||||
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandUint() uint {
|
||||
prng.Lock()
|
||||
i := prng.Int()
|
||||
prng.Unlock()
|
||||
func (r *Rand) RandUint() uint {
|
||||
r.Lock()
|
||||
i := r.Int()
|
||||
r.Unlock()
|
||||
return uint(i)
|
||||
}
|
||||
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandInt16() int16 {
|
||||
return int16(RandUint32() & (1<<16 - 1))
|
||||
func (r *Rand) RandInt16() int16 {
|
||||
return int16(r.RandUint32() & (1<<16 - 1))
|
||||
}
|
||||
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandInt32() int32 {
|
||||
return int32(RandUint32())
|
||||
func (r *Rand) RandInt32() int32 {
|
||||
return int32(r.RandUint32())
|
||||
}
|
||||
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandInt64() int64 {
|
||||
return int64(RandUint64())
|
||||
func (r *Rand) RandInt64() int64 {
|
||||
return int64(r.RandUint64())
|
||||
}
|
||||
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandInt() int {
|
||||
prng.Lock()
|
||||
i := prng.Int()
|
||||
prng.Unlock()
|
||||
func (r *Rand) RandInt() int {
|
||||
r.Lock()
|
||||
i := r.Int()
|
||||
r.Unlock()
|
||||
return i
|
||||
}
|
||||
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandInt31() int32 {
|
||||
prng.Lock()
|
||||
i31 := prng.Int31()
|
||||
prng.Unlock()
|
||||
func (r *Rand) RandInt31() int32 {
|
||||
r.Lock()
|
||||
i31 := r.Int31()
|
||||
r.Unlock()
|
||||
return i31
|
||||
}
|
||||
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandInt63() int64 {
|
||||
prng.Lock()
|
||||
i63 := prng.Int63()
|
||||
prng.Unlock()
|
||||
func (r *Rand) RandInt63() int64 {
|
||||
r.Lock()
|
||||
i63 := r.Int63()
|
||||
r.Unlock()
|
||||
return i63
|
||||
}
|
||||
|
||||
// Distributed pseudo-exponentially to test for various cases
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandUint16Exp() uint16 {
|
||||
bits := RandUint32() % 16
|
||||
func (r *Rand) RandUint16Exp() uint16 {
|
||||
bits := r.RandUint32() % 16
|
||||
if bits == 0 {
|
||||
return 0
|
||||
}
|
||||
n := uint16(1 << (bits - 1))
|
||||
n += uint16(RandInt31()) & ((1 << (bits - 1)) - 1)
|
||||
n += uint16(r.RandInt31()) & ((1 << (bits - 1)) - 1)
|
||||
return n
|
||||
}
|
||||
|
||||
// Distributed pseudo-exponentially to test for various cases
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandUint32Exp() uint32 {
|
||||
bits := RandUint32() % 32
|
||||
func (r *Rand) RandUint32Exp() uint32 {
|
||||
bits := r.RandUint32() % 32
|
||||
if bits == 0 {
|
||||
return 0
|
||||
}
|
||||
n := uint32(1 << (bits - 1))
|
||||
n += uint32(RandInt31()) & ((1 << (bits - 1)) - 1)
|
||||
n += uint32(r.RandInt31()) & ((1 << (bits - 1)) - 1)
|
||||
return n
|
||||
}
|
||||
|
||||
// Distributed pseudo-exponentially to test for various cases
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandUint64Exp() uint64 {
|
||||
bits := RandUint32() % 64
|
||||
func (r *Rand) RandUint64Exp() uint64 {
|
||||
bits := r.RandUint32() % 64
|
||||
if bits == 0 {
|
||||
return 0
|
||||
}
|
||||
n := uint64(1 << (bits - 1))
|
||||
n += uint64(RandInt63()) & ((1 << (bits - 1)) - 1)
|
||||
n += uint64(r.RandInt63()) & ((1 << (bits - 1)) - 1)
|
||||
return n
|
||||
}
|
||||
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandFloat32() float32 {
|
||||
prng.Lock()
|
||||
f32 := prng.Float32()
|
||||
prng.Unlock()
|
||||
func (r *Rand) RandFloat32() float32 {
|
||||
r.Lock()
|
||||
f32 := r.Float32()
|
||||
r.Unlock()
|
||||
return f32
|
||||
}
|
||||
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandTime() time.Time {
|
||||
return time.Unix(int64(RandUint64Exp()), 0)
|
||||
func (r *Rand) RandTime() time.Time {
|
||||
return time.Unix(int64(r.RandUint64Exp()), 0)
|
||||
}
|
||||
|
||||
// RandBytes returns n random bytes from the OS's source of entropy ie. via crypto/rand.
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandBytes(n int) []byte {
|
||||
func (r *Rand) RandBytes(n int) []byte {
|
||||
// cRandBytes isn't guaranteed to be fast so instead
|
||||
// use random bytes generated from the internal PRNG
|
||||
bs := make([]byte, n)
|
||||
for i := 0; i < len(bs); i++ {
|
||||
bs[i] = byte(RandInt() & 0xFF)
|
||||
bs[i] = byte(r.RandInt() & 0xFF)
|
||||
}
|
||||
return bs
|
||||
}
|
||||
@ -188,19 +292,19 @@ func RandBytes(n int) []byte {
|
||||
// RandIntn returns, as an int, a non-negative pseudo-random number in [0, n).
|
||||
// It panics if n <= 0.
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandIntn(n int) int {
|
||||
prng.Lock()
|
||||
i := prng.Intn(n)
|
||||
prng.Unlock()
|
||||
func (r *Rand) RandIntn(n int) int {
|
||||
r.Lock()
|
||||
i := r.Intn(n)
|
||||
r.Unlock()
|
||||
return i
|
||||
}
|
||||
|
||||
// RandPerm returns a pseudo-random permutation of n integers in [0, n).
|
||||
// It is not safe for cryptographic usage.
|
||||
func RandPerm(n int) []int {
|
||||
prng.Lock()
|
||||
perm := prng.Perm(n)
|
||||
prng.Unlock()
|
||||
func (r *Rand) RandPerm(n int) []int {
|
||||
r.Lock()
|
||||
perm := r.Perm(n)
|
||||
r.Unlock()
|
||||
return perm
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user