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 "crypto/rand"
9 "io"
10)
11
12// idLen is a length of captcha id string.
13const idLen = 20
14
15// idChars are characters allowed in captcha id.
16var idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
17
18// RandomDigits returns a byte slice of the given length containing
19// pseudorandom numbers in range 0-9. The slice can be used as a captcha
20// solution.
21func RandomDigits(length int) []byte {
22 return randomBytesMod(length, 10)
23}
24
25// randomBytes returns a byte slice of the given length read from CSPRNG.
26func randomBytes(length int) (b []byte) {
27 b = make([]byte, length)
28 if _, err := io.ReadFull(rand.Reader, b); err != nil {
29 panic("captcha: error reading random source: " + err.Error())
30 }
31 return
32}
33
34// randomBytesMod returns a byte slice of the given length, where each byte is
35// a random number modulo mod.
36func randomBytesMod(length int, mod byte) (b []byte) {
37 b = make([]byte, length)
38 maxrb := byte(256 - (256 % int(mod)))
39 i := 0
40 for {
41 r := randomBytes(length + (length / 4))
42 for _, c := range r {
43 if c >= maxrb {
44 // Skip this number to avoid modulo bias.
45 continue
46 }
47 b[i] = c % mod
48 i++
49 if i == length {
50 return
51 }
52 }
53 }
54 panic("unreachable")
55}
56
57// randomId returns a new random id string.
58func randomId() string {
59 b := randomBytesMod(idLen, byte(len(idChars)))
60 for i, c := range b {
61 b[i] = idChars[c]
62 }
63 return string(b)
64}
65
66var prng = &siprng{}
67
68// randIntn returns a pseudorandom non-negative int in range [0, n).
69func randIntn(n int) int {
70 return prng.Intn(n)
71}
72
73// randInt returns a pseudorandom int in range [from, to].
74func randInt(from, to int) int {
75 return prng.Intn(to+1-from) + from
76}
77
78// randFloat returns a pseudorandom float64 in range [from, to].
79func randFloat(from, to float64) float64 {
80 return (to-from)*prng.Float64() + from
81}