random.go 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. package captcha
  2. import (
  3. crand "crypto/rand"
  4. "io"
  5. "rand"
  6. "time"
  7. )
  8. // idLen is a length of captcha id string.
  9. const idLen = 20
  10. // idChars are characters allowed in captcha id.
  11. var idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
  12. func init() {
  13. rand.Seed(time.Nanoseconds())
  14. }
  15. // RandomDigits returns a byte slice of the given length containing
  16. // pseudorandom numbers in range 0-9. The slice can be used as a captcha
  17. // solution.
  18. func RandomDigits(length int) (b []byte) {
  19. b = randomBytes(length)
  20. for i := range b {
  21. b[i] %= 10
  22. }
  23. return
  24. }
  25. // randomBytes returns a byte slice of the given length read from CSPRNG.
  26. func randomBytes(length int) (b []byte) {
  27. b = make([]byte, length)
  28. if _, err := io.ReadFull(crand.Reader, b); err != nil {
  29. panic("captcha: error reading random source: " + err.String())
  30. }
  31. return
  32. }
  33. // randomId returns a new random id string.
  34. func randomId() string {
  35. b := randomBytes(idLen)
  36. alen := byte(len(idChars))
  37. for i, c := range b {
  38. b[i] = idChars[c%alen]
  39. }
  40. return string(b)
  41. }
  42. // rnd returns a non-crypto pseudorandom int in range [from, to].
  43. func rnd(from, to int) int {
  44. return rand.Intn(to+1-from) + from
  45. }
  46. // rndf returns a non-crypto pseudorandom float64 in range [from, to].
  47. func rndf(from, to float64) float64 {
  48. return (to-from)*rand.Float64() + from
  49. }