all repos — captcha @ 7633411f435abe1ce534409eaf47a96f230908fb

Go package captcha implements generation and verification of image and audio CAPTCHAs.

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	"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.Nanoseconds())
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.String())
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}