-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
Copy pathbase62.go
50 lines (41 loc) · 1.28 KB
/
base62.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// Package base62 provides utilities for working with base62 strings.
// base62 strings will only contain characters: 0-9, a-z, A-Z
package base62
import (
"crypto/rand"
"io"
uuid "github.com/hashicorp/go-uuid"
)
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
const csLen = byte(len(charset))
// Random generates a random string using base-62 characters.
// Resulting entropy is ~5.95 bits/character.
func Random(length int) (string, error) {
return RandomWithReader(length, rand.Reader)
}
// RandomWithReader generates a random string using base-62 characters and a given reader.
// Resulting entropy is ~5.95 bits/character.
func RandomWithReader(length int, reader io.Reader) (string, error) {
if length == 0 {
return "", nil
}
output := make([]byte, 0, length)
// Request a bit more than length to reduce the chance
// of needing more than one batch of random bytes
batchSize := length + length/4
for {
buf, err := uuid.GenerateRandomBytesWithReader(batchSize, reader)
if err != nil {
return "", err
}
for _, b := range buf {
// Avoid bias by using a value range that's a multiple of 62
if b < (csLen * 4) {
output = append(output, charset[b%csLen])
if len(output) == length {
return string(output), nil
}
}
}
}
}