forked from dchest/captcha
-
Notifications
You must be signed in to change notification settings - Fork 0
/
random.go
80 lines (69 loc) · 1.91 KB
/
random.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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// Copyright 2011 Dmitry Chestnykh. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package captcha
import (
crand "crypto/rand"
"io"
"math/rand"
"time"
)
// idLen is a length of captcha id string.
const idLen = 20
// idChars are characters allowed in captcha id.
var idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
func init() {
rand.Seed(time.Now().UnixNano())
}
// RandomDigits returns a byte slice of the given length containing
// pseudorandom numbers in range 0-9. The slice can be used as a captcha
// solution.
func RandomDigits(length int) []byte {
return randomBytesMod(length, 10)
}
// randomBytes returns a byte slice of the given length read from CSPRNG.
func randomBytes(length int) (b []byte) {
b = make([]byte, length)
if _, err := io.ReadFull(crand.Reader, b); err != nil {
panic("captcha: error reading random source: " + err.Error())
}
return
}
// randomBytesMod returns a byte slice of the given length, where each byte is
// a random number modulo mod.
func randomBytesMod(length int, mod byte) (b []byte) {
b = make([]byte, length)
maxrb := byte(256 - (256 % int(mod)))
i := 0
for {
r := randomBytes(length + (length / 4))
for _, c := range r {
if c >= maxrb {
// Skip this number to avoid modulo bias.
continue
}
b[i] = c % mod
i++
if i == length {
return
}
}
}
panic("unreachable")
}
// randomId returns a new random id string.
func randomId() string {
b := randomBytesMod(idLen, byte(len(idChars)))
for i, c := range b {
b[i] = idChars[c]
}
return string(b)
}
// rnd returns a non-crypto pseudorandom int in range [from, to].
func rnd(from, to int) int {
return rand.Intn(to+1-from) + from
}
// rndf returns a non-crypto pseudorandom float64 in range [from, to].
func rndf(from, to float64) float64 {
return (to-from)*rand.Float64() + from
}