iTranslated by AI
Using crypto/rand as math/rand
Haven't you ever wondered? Why are the internal structures of math/rand and crypto/rand so completely different? Well, since their purposes are different, it's not surprising that their structures are different, but I've often thought it would be nice if we could at least use crypto/rand as a source for math/rand.
Actually, it's not that difficult to use crypto/rand as a source for math/rand. The definition of a source in math/rand is as follows:
// A Source represents a source of uniformly-distributed
// pseudo-random int64 values in the range [0, 1<<63).
type Source interface {
Int63() int64
Seed(seed int64)
}
// A Source64 is a Source that can also generate
// uniformly-distributed pseudo-random uint64 values in
// the range [0, 1<<64) directly.
// If a Rand r's underlying Source s implements Source64,
// then r.Uint64 returns the result of one call to s.Uint64
// instead of making two calls to s.Int63.
type Source64 interface {
Source
Uint64() uint64
}
Since it is defined this way, all we need to do is create a wrapper that matches it. For example, something like this:
type Source struct{}
// Seed method is dummy function for rand.Source interface.
func (s Source) Seed(seed int64) {}
// Uint64 method generates a random number in the range [0, 1<<64).
func (s Source) Uint64() uint64 {
b := [8]byte{}
ct, _ := rand.Read(b[:])
return binary.BigEndian.Uint64(b[:ct])
}
// Int63 method generates a random number in the range [0, 1<<63).
func (s Source) Int63() int64 {
return (int64)(s.Uint64() >> 1)
}
By doing this,
fmt.Println(rand.New(Source{}).Float64()) // 0.9581627789424901
you can use the methods provided by the rand.Rand type in this way[1]. The full code looks like this.
//go:build run
// +build run
package main
import (
"crypto/rand"
"encoding/binary"
"fmt"
mrand "math/rand"
)
type Source struct{}
// Seed method is dummy function for rand.Source interface.
func (s Source) Seed(seed int64) {}
// Uint64 method generates a random number in the range [0, 1<<64).
func (s Source) Uint64() uint64 {
b := [8]byte{}
ct, _ := rand.Read(b[:])
return binary.BigEndian.Uint64(b[:ct])
}
// Int63 method generates a random number in the range [0, 1<<63).
func (s Source) Int63() int64 {
return (int64)(s.Uint64() >> 1)
}
func main() {
fmt.Println(mrand.New(Source{}).Float64())
}
So, I decided to package this. That said, it seemed like a waste to create a whole repository for such a small feature, so I integrated it as a bonus feature into my own pseudo-random number package, github.com/goark/mt. You can use it like this:
//go:build run
// +build run
package main
import (
"fmt"
"math/rand"
"github.com/goark/mt/secure"
)
func main() {
fmt.Println(rand.New(secure.Source{}).Uint64())
}
All right, yep, yep, okay. Well, time to get back to work.
Discussion