Avoid modulo bias.

This commit is contained in:
Dmitry Chestnykh 2011-06-06 14:34:01 +02:00
parent ecf15fa52a
commit 958b406e0e

View File

@ -45,12 +45,25 @@ func NewLen(length int) string {
// of the provided byte slice of allowed characters (maximum 256). // of the provided byte slice of allowed characters (maximum 256).
func NewLenChars(length int, chars []byte) string { func NewLenChars(length int, chars []byte) string {
b := make([]byte, length) b := make([]byte, length)
if _, err := io.ReadFull(rand.Reader, b); err != nil { r := make([]byte, length+(length/4)) // storage for random bytes.
clen := byte(len(chars))
maxrb := byte(256 - (256 % len(chars)))
i := 0
for {
if _, err := io.ReadFull(rand.Reader, r); err != nil {
panic("error reading from random source: " + err.String()) panic("error reading from random source: " + err.String())
} }
alen := byte(len(chars)) for _, c := range r {
for i, c := range b { if c >= maxrb {
b[i] = chars[c%alen] // Skip this number to avoid modulo bias.
continue
} }
b[i] = chars[c%clen]
i++
if i == length {
return string(b) return string(b)
} }
}
}
panic("unreachable")
}