drgaeqdqiiyg14608 2016-02-04 14:28
浏览 109
已采纳

Golang加密洗牌

I'm trying to implement a string shuffle function in Go that uses crypto/rand instead of math/rand. The Fisher-Yates Shuffle requires random integers so I've tried to implement that functionality, without having to use crypto/rand Int which relies on math/big. Below is the best I've come up with so far but is there a better method? The fact that I can't find existing examples leads me to wonder if there's a good reason why nobody does this!

package main

import "crypto/rand"
import "fmt"
import "encoding/binary"

func randomInt(max int) int {
    var n uint16
    binary.Read(rand.Reader, binary.LittleEndian, &n)
    return int(n) % max
}

func shuffle(s *[]string) {
        slice := *s
        for i := range slice {
                j := randomInt(i + 1)
                slice[i], slice[j] = slice[j], slice[i]
        }
        *s = slice
    }

func main() {
        slice := []string{"a", "b", "c", "d", "e", "f", "h", "i", "j", "k"}
        shuffle(&slice)
        fmt.Println(slice)
}
  • 写回答

3条回答 默认 最新

  • duangou2046 2016-02-04 18:20
    关注

    Go's math/rand library has good facilities for producing random numerical primitives from a Source.

    // 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)
    }
    

    NewSource(seed int64) returns the builtin, deterministic PRNG, but New(source Source) will allow anything that satisfies the Source interface.

    Here is an example of a Source that is backed by crypto/rand.

    type CryptoRandSource struct{}
    
    func NewCryptoRandSource() CryptoRandSource {
        return CryptoRandSource{}
    }
    
    func (_ CryptoRandSource) Int63() int64 {
        var b [8]byte
        rand.Read(b[:])
        // mask off sign bit to ensure positive number
        return int64(binary.LittleEndian.Uint64(b[:]) & (1<<63 - 1))
    }
    
    func (_ CryptoRandSource) Seed(_ int64) {}
    

    You can use it like this:

    r := rand.New(NewCryptoRandSource())
    
    for i := 0; i < 10; i++ {
        fmt.Println(r.Int())
    }
    

    The math/rand library has a properly implemented Intn() method which ensures a uniform distribution.

    func (r *Rand) Intn(n int) int {
        if n <= 0 {
            panic("invalid argument to Intn")
        }
        if n <= 1<<31-1 {
            return int(r.Int31n(int32(n)))
        }
        return int(r.Int63n(int64(n)))
    }
    
    func (r *Rand) Int31n(n int32) int32 {
        if n <= 0 {
            panic("invalid argument to Int31n")
        }
        if n&(n-1) == 0 { // n is power of two, can mask
            return r.Int31() & (n - 1)
        }
        max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
        v := r.Int31()
        for v > max {
            v = r.Int31()
        }
        return v % n
    }
    
    func (r *Rand) Int63n(n int64) int64 {
        if n <= 0 {
            panic("invalid argument to Int63n")
        }
        if n&(n-1) == 0 { // n is power of two, can mask
            return r.Int63() & (n - 1)
        }
        max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
        v := r.Int63()
        for v > max {
            v = r.Int63()
        }
        return v % n
    }
    

    Cryptographic hash functions also can be wrapped as a Source for alternate means of randomness.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题