random.go (view raw)
1// Copyright 2011 Dmitry Chestnykh. All rights reserved.
2// Use of this source code is governed by a MIT-style
3// license that can be found in the LICENSE file.
4
5package captcha
6
7import (
8 crand "crypto/rand"
9 "io"
10 "math/rand"
11 "time"
12)
13
14// idLen is a length of captcha id string.
15const idLen = 20
16
17// idChars are characters allowed in captcha id.
18var idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
19
20func init() {
21 rand.Seed(time.Now().UnixNano())
22}
23
24// RandomDigits returns a byte slice of the given length containing
25// pseudorandom numbers in range 0-9. The slice can be used as a captcha
26// solution.
27func RandomDigits(length int) []byte {
28 return randomBytesMod(length, 10)
29}
30
31// randomBytes returns a byte slice of the given length read from CSPRNG.
32func randomBytes(length int) (b []byte) {
33 b = make([]byte, length)
34 if _, err := io.ReadFull(crand.Reader, b); err != nil {
35 panic("captcha: error reading random source: " + err.Error())
36 }
37 return
38}
39
40// randomBytesMod returns a byte slice of the given length, where each byte is
41// a random number modulo mod.
42func randomBytesMod(length int, mod byte) (b []byte) {
43 b = make([]byte, length)
44 maxrb := byte(256 - (256 % int(mod)))
45 i := 0
46 for {
47 r := randomBytes(length + (length / 4))
48 for _, c := range r {
49 if c >= maxrb {
50 // Skip this number to avoid modulo bias.
51 continue
52 }
53 b[i] = c % mod
54 i++
55 if i == length {
56 return
57 }
58 }
59 }
60 panic("unreachable")
61}
62
63// randomId returns a new random id string.
64func randomId() string {
65 b := randomBytesMod(idLen, byte(len(idChars)))
66 for i, c := range b {
67 b[i] = idChars[c]
68 }
69 return string(b)
70}
71
72// rnd returns a non-crypto pseudorandom int in range [from, to].
73func rnd(from, to int) int {
74 return rand.Intn(to+1-from) + from
75}
76
77// rndf returns a non-crypto pseudorandom float64 in range [from, to].
78func rndf(from, to float64) float64 {
79 return (to-from)*rand.Float64() + from
80}