Remove modulo bias from generated IDs
This commit is contained in:
@@ -510,17 +510,34 @@ func generateUniqueID() (string, error) {
|
|||||||
return "", fmt.Errorf("failed to generate unique ID after %d retries", maxRetries)
|
return "", fmt.Errorf("failed to generate unique ID after %d retries", maxRetries)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generateID returns a random ID drawn uniformly from idCharset. Bytes landing
|
||||||
|
// in the last, partial repetition of the charset within a byte's range are
|
||||||
|
// discarded rather than folded in with a bare modulo: 256 = 7*36 + 4, so
|
||||||
|
// folding would make "a" through "d" about 14% more likely than the other 32
|
||||||
|
// characters. Only 4 of 256 values are rejected, so a second read is rarely
|
||||||
|
// needed.
|
||||||
func generateID() string {
|
func generateID() string {
|
||||||
bytes := make([]byte, idLength)
|
const unbiasedLimit = byte(256 - 256%len(idCharset))
|
||||||
if _, err := rand.Read(bytes); err != nil {
|
|
||||||
panic(err)
|
id := make([]byte, 0, idLength)
|
||||||
|
buf := make([]byte, idLength)
|
||||||
|
for len(id) < idLength {
|
||||||
|
if _, err := rand.Read(buf); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, b := range buf {
|
||||||
|
if b >= unbiasedLimit {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
id = append(id, idCharset[int(b)%len(idCharset)])
|
||||||
|
if len(id) == idLength {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, b := range bytes {
|
return string(id)
|
||||||
bytes[i] = idCharset[int(b)%len(idCharset)]
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(bytes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHost(r *http.Request) string {
|
func getHost(r *http.Request) string {
|
||||||
|
|||||||
Reference in New Issue
Block a user