mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-15 06:11:20 +00:00
common: Rand* warnings about cryptographic unsafety
Lesson articulated by @jaekwon on why we need 80 bits of entropy at least before we can think of cryptographic safety. math/rand's seed is a max of 64 bits so can never be cryptographically secure. Also added some benchmarks for RandBytes
This commit is contained in:
@ -35,6 +35,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Constructs an alphanumeric string of given length.
|
// Constructs an alphanumeric string of given length.
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandStr(length int) string {
|
func RandStr(length int) string {
|
||||||
chars := []byte{}
|
chars := []byte{}
|
||||||
MAIN_LOOP:
|
MAIN_LOOP:
|
||||||
@ -58,10 +59,12 @@ MAIN_LOOP:
|
|||||||
return string(chars)
|
return string(chars)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandUint16() uint16 {
|
func RandUint16() uint16 {
|
||||||
return uint16(RandUint32() & (1<<16 - 1))
|
return uint16(RandUint32() & (1<<16 - 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandUint32() uint32 {
|
func RandUint32() uint32 {
|
||||||
prng.Lock()
|
prng.Lock()
|
||||||
u32 := prng.Uint32()
|
u32 := prng.Uint32()
|
||||||
@ -69,10 +72,12 @@ func RandUint32() uint32 {
|
|||||||
return u32
|
return u32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandUint64() uint64 {
|
func RandUint64() uint64 {
|
||||||
return uint64(RandUint32())<<32 + uint64(RandUint32())
|
return uint64(RandUint32())<<32 + uint64(RandUint32())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandUint() uint {
|
func RandUint() uint {
|
||||||
prng.Lock()
|
prng.Lock()
|
||||||
i := prng.Int()
|
i := prng.Int()
|
||||||
@ -80,18 +85,22 @@ func RandUint() uint {
|
|||||||
return uint(i)
|
return uint(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandInt16() int16 {
|
func RandInt16() int16 {
|
||||||
return int16(RandUint32() & (1<<16 - 1))
|
return int16(RandUint32() & (1<<16 - 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandInt32() int32 {
|
func RandInt32() int32 {
|
||||||
return int32(RandUint32())
|
return int32(RandUint32())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandInt64() int64 {
|
func RandInt64() int64 {
|
||||||
return int64(RandUint64())
|
return int64(RandUint64())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandInt() int {
|
func RandInt() int {
|
||||||
prng.Lock()
|
prng.Lock()
|
||||||
i := prng.Int()
|
i := prng.Int()
|
||||||
@ -99,6 +108,7 @@ func RandInt() int {
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandInt31() int32 {
|
func RandInt31() int32 {
|
||||||
prng.Lock()
|
prng.Lock()
|
||||||
i31 := prng.Int31()
|
i31 := prng.Int31()
|
||||||
@ -106,6 +116,7 @@ func RandInt31() int32 {
|
|||||||
return i31
|
return i31
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandInt63() int64 {
|
func RandInt63() int64 {
|
||||||
prng.Lock()
|
prng.Lock()
|
||||||
i63 := prng.Int63()
|
i63 := prng.Int63()
|
||||||
@ -114,6 +125,7 @@ func RandInt63() int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Distributed pseudo-exponentially to test for various cases
|
// Distributed pseudo-exponentially to test for various cases
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandUint16Exp() uint16 {
|
func RandUint16Exp() uint16 {
|
||||||
bits := RandUint32() % 16
|
bits := RandUint32() % 16
|
||||||
if bits == 0 {
|
if bits == 0 {
|
||||||
@ -125,6 +137,7 @@ func RandUint16Exp() uint16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Distributed pseudo-exponentially to test for various cases
|
// Distributed pseudo-exponentially to test for various cases
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandUint32Exp() uint32 {
|
func RandUint32Exp() uint32 {
|
||||||
bits := RandUint32() % 32
|
bits := RandUint32() % 32
|
||||||
if bits == 0 {
|
if bits == 0 {
|
||||||
@ -136,6 +149,7 @@ func RandUint32Exp() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Distributed pseudo-exponentially to test for various cases
|
// Distributed pseudo-exponentially to test for various cases
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandUint64Exp() uint64 {
|
func RandUint64Exp() uint64 {
|
||||||
bits := RandUint32() % 64
|
bits := RandUint32() % 64
|
||||||
if bits == 0 {
|
if bits == 0 {
|
||||||
@ -146,6 +160,7 @@ func RandUint64Exp() uint64 {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandFloat32() float32 {
|
func RandFloat32() float32 {
|
||||||
prng.Lock()
|
prng.Lock()
|
||||||
f32 := prng.Float32()
|
f32 := prng.Float32()
|
||||||
@ -153,17 +168,26 @@ func RandFloat32() float32 {
|
|||||||
return f32
|
return f32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandTime() time.Time {
|
func RandTime() time.Time {
|
||||||
return time.Unix(int64(RandUint64Exp()), 0)
|
return time.Unix(int64(RandUint64Exp()), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandBytes returns n random bytes from the OS's source of entropy ie. via crypto/rand.
|
// 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 RandBytes(n int) []byte {
|
||||||
return cRandBytes(n)
|
// 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)
|
||||||
|
}
|
||||||
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandIntn returns, as an int, a non-negative pseudo-random number in [0, n).
|
// RandIntn returns, as an int, a non-negative pseudo-random number in [0, n).
|
||||||
// It panics if n <= 0
|
// It panics if n <= 0.
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandIntn(n int) int {
|
func RandIntn(n int) int {
|
||||||
prng.Lock()
|
prng.Lock()
|
||||||
i := prng.Intn(n)
|
i := prng.Intn(n)
|
||||||
@ -172,6 +196,7 @@ func RandIntn(n int) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RandPerm returns a pseudo-random permutation of n integers in [0, n).
|
// RandPerm returns a pseudo-random permutation of n integers in [0, n).
|
||||||
|
// It is not safe for cryptographic usage.
|
||||||
func RandPerm(n int) []int {
|
func RandPerm(n int) []int {
|
||||||
prng.Lock()
|
prng.Lock()
|
||||||
perm := prng.Perm(n)
|
perm := prng.Perm(n)
|
||||||
|
@ -92,3 +92,29 @@ func TestRngConcurrencySafety(t *testing.T) {
|
|||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkRandBytes10B(b *testing.B) {
|
||||||
|
benchmarkRandBytes(b, 10)
|
||||||
|
}
|
||||||
|
func BenchmarkRandBytes100B(b *testing.B) {
|
||||||
|
benchmarkRandBytes(b, 100)
|
||||||
|
}
|
||||||
|
func BenchmarkRandBytes1KiB(b *testing.B) {
|
||||||
|
benchmarkRandBytes(b, 1024)
|
||||||
|
}
|
||||||
|
func BenchmarkRandBytes10KiB(b *testing.B) {
|
||||||
|
benchmarkRandBytes(b, 10*1024)
|
||||||
|
}
|
||||||
|
func BenchmarkRandBytes100KiB(b *testing.B) {
|
||||||
|
benchmarkRandBytes(b, 100*1024)
|
||||||
|
}
|
||||||
|
func BenchmarkRandBytes1MiB(b *testing.B) {
|
||||||
|
benchmarkRandBytes(b, 1024*1024)
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkRandBytes(b *testing.B, n int) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = RandBytes(n)
|
||||||
|
}
|
||||||
|
b.ReportAllocs()
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user