Remove modulo bias from generated IDs

This commit is contained in:
2026-09-08 20:18:52 +02:00
parent bd291e841b
commit fede4e4971
+25 -8
View File
@@ -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 {