英文:
Using crypto/rand for generating permutations with rand.Perm
问题
Go语言有两个用于生成随机数的包:
crypto/rand
,提供了获取随机字节的方法math/rand
,具有一个用于对整数进行洗牌的好算法
我想使用math/rand
中的Perm
算法,但是要提供高质量的随机数。
由于这两个rand
包都是标准库的一部分,应该有一种方法将它们结合起来,使得crypto/rand
提供一个好的随机数源,供math/rand.Perm
用于生成排列。
这里是我编写的连接这两个包的代码(在Playground上也有):
package main
import (
cryptoRand "crypto/rand"
"encoding/binary"
"fmt"
mathRand "math/rand"
)
type cryptoSource struct{}
func (s cryptoSource) Int63() int64 {
bytes := make([]byte, 8, 8)
cryptoRand.Read(bytes)
return int64(binary.BigEndian.Uint64(bytes) >> 1)
}
func (s cryptoSource) Seed(seed int64) {
panic("seed")
}
func main() {
rnd := mathRand.New(&cryptoSource{})
perm := rnd.Perm(52)
fmt.Println(perm)
}
这段代码是有效的。理想情况下,我不想自己定义cryptoSource
类型,而是将这两个rand
包组合在一起,使它们能够一起工作。所以是否有一个预定义版本的cryptoSource
类型存在?
英文:
Go has two packages for random numbers:
crypto/rand
, which provides a way to get random bytesmath/rand
, which has a nice algorithm for shuffling ints
I want to use the Perm
algorithm from math/rand
, but provide it with high-quality random numbers.
Since the two rand
packages are part of the same standard library there should be a way to combine them in a way so that crypto/rand
provides a good source of random numbers that is used by math/rand.Perm
to generate a permutation.
Here (and on the Playground) is the code I wrote to connect these two packages:
package main
import (
cryptoRand "crypto/rand"
"encoding/binary"
"fmt"
mathRand "math/rand"
)
type cryptoSource struct{}
func (s cryptoSource) Int63() int64 {
bytes := make([]byte, 8, 8)
cryptoRand.Read(bytes)
return int64(binary.BigEndian.Uint64(bytes) >> 1)
}
func (s cryptoSource) Seed(seed int64) {
panic("seed")
}
func main() {
rnd := mathRand.New(&cryptoSource{})
perm := rnd.Perm(52)
fmt.Println(perm)
}
This code works. Ideally I don't want to define the cryptoSource
type myself but just stick together the two rand
packages so that they work together. So is there a predefined version of this cryptoSource
type somewhere?
答案1
得分: 3
这基本上是你需要做的。通常情况下,对于math/rand
的常规用法,你不经常需要一个加密安全的随机源,所以没有提供适配器。你可以通过直接在值中分配缓冲区空间,而不是在每次调用时分配新的切片,使实现稍微更高效。然而,如果读取操作系统的随机源失败,这将需要引发 panic 来防止返回无效的结果。
type cryptoSource [8]byte
func (s *cryptoSource) Int63() int64 {
_, err := cryptoRand.Read(s[:])
if err != nil {
panic(err)
}
return int64(binary.BigEndian.Uint64(s[:]) & (1<<63 - 1))
}
英文:
That's basically what you need to do. It's not often that you need a cryptographically secure source of randomness for the common usage of math/rand
, so there's no adaptor provided. You can make the implementation slightly more efficient by allocating the buffer space directly in the value, rather than allocating a new slice on every call. However in the unlikely event that reading the OS random source fails, this will need to panic to prevent returning invalid results.
type cryptoSource [8]byte
func (s *cryptoSource) Int63() int64 {
_, err := cryptoRand.Read(s[:])
if err != nil {
panic(err)
}
return int64(binary.BigEndian.Uint64(s[:]) & (1<<63 - 1))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论