2017-01-22

[golang] crypto/rand で疑似乱数生成器を初期化する

Go 言語で疑似乱数 math/rand を使うとき、実行ごとに別の乱数列を選択するための方法として、rand.Seed(time.Now().UnixNano()) とするのが人気があるようなのですが、より予測困難さを追加するためには以下のコードのようにすると良いです。

今日では、Perl, Ruby, Python などで、明示的な seed をせずに rand を使った場合に、内部的に行われる自動的な seed では、OS の乱数生成器由来の値が使われるようになっているので、Go でも同じ感じで良いと思います。


package main

import (
    cryptorand "crypto/rand"
    "encoding/binary"
    "math/rand"
)

func main() {
    randSeed()
    println("rand int:", rand.Int())
}

func randSeed() {
    var seed int64
    err := binary.Read(cryptorand.Reader, binary.LittleEndian, &seed)
    if err != nil {
        panic(err)
    }
    rand.Seed(seed)
}

LittleEndian は BigEndian でも良いです。crypto/rand には big.Int のインターフェースもありますが、こちらの方式の方が簡潔に書けると思います。

蛇足ですが、暗号化用の鍵や、何とかトークンのような、長さ分のエントロピーを持つ乱雑な文字列を作りたい場合は、math/rand ではなく、crypto/rand をそのまま使う必要があります。

リンク
math/rand: Deterministic random by default is dangerous #11871