You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

311 lines
5.2 KiB

9 years ago
9 years ago
9 years ago
6 years ago
6 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. package rand
  2. import (
  3. crand "crypto/rand"
  4. mrand "math/rand"
  5. "time"
  6. tmsync "github.com/tendermint/tendermint/libs/sync"
  7. )
  8. const (
  9. strChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // 62 characters
  10. )
  11. // Rand is a prng, that is seeded with OS randomness.
  12. // The OS randomness is obtained from crypto/rand, however none of the provided
  13. // methods are suitable for cryptographic usage.
  14. // They all utilize math/rand's prng internally.
  15. //
  16. // All of the methods here are suitable for concurrent use.
  17. // This is achieved by using a mutex lock on all of the provided methods.
  18. type Rand struct {
  19. tmsync.Mutex
  20. rand *mrand.Rand
  21. }
  22. var grand *Rand
  23. func init() {
  24. grand = NewRand()
  25. grand.init()
  26. }
  27. func NewRand() *Rand {
  28. rand := &Rand{}
  29. rand.init()
  30. return rand
  31. }
  32. func (r *Rand) init() {
  33. bz := cRandBytes(8)
  34. var seed uint64
  35. for i := 0; i < 8; i++ {
  36. seed |= uint64(bz[i])
  37. seed <<= 8
  38. }
  39. r.reset(int64(seed))
  40. }
  41. func (r *Rand) reset(seed int64) {
  42. r.rand = mrand.New(mrand.NewSource(seed)) // nolint:gosec // G404: Use of weak random number generator
  43. }
  44. //----------------------------------------
  45. // Global functions
  46. func Seed(seed int64) {
  47. grand.Seed(seed)
  48. }
  49. func Str(length int) string {
  50. return grand.Str(length)
  51. }
  52. func Uint16() uint16 {
  53. return grand.Uint16()
  54. }
  55. func Uint32() uint32 {
  56. return grand.Uint32()
  57. }
  58. func Uint64() uint64 {
  59. return grand.Uint64()
  60. }
  61. func Uint() uint {
  62. return grand.Uint()
  63. }
  64. func Int16() int16 {
  65. return grand.Int16()
  66. }
  67. func Int32() int32 {
  68. return grand.Int32()
  69. }
  70. func Int64() int64 {
  71. return grand.Int64()
  72. }
  73. func Int() int {
  74. return grand.Int()
  75. }
  76. func Int31() int32 {
  77. return grand.Int31()
  78. }
  79. func Int31n(n int32) int32 {
  80. return grand.Int31n(n)
  81. }
  82. func Int63() int64 {
  83. return grand.Int63()
  84. }
  85. func Int63n(n int64) int64 {
  86. return grand.Int63n(n)
  87. }
  88. func Bool() bool {
  89. return grand.Bool()
  90. }
  91. func Float32() float32 {
  92. return grand.Float32()
  93. }
  94. func Float64() float64 {
  95. return grand.Float64()
  96. }
  97. func Time() time.Time {
  98. return grand.Time()
  99. }
  100. func Bytes(n int) []byte {
  101. return grand.Bytes(n)
  102. }
  103. func Intn(n int) int {
  104. return grand.Intn(n)
  105. }
  106. func Perm(n int) []int {
  107. return grand.Perm(n)
  108. }
  109. //----------------------------------------
  110. // Rand methods
  111. func (r *Rand) Seed(seed int64) {
  112. r.Lock()
  113. r.reset(seed)
  114. r.Unlock()
  115. }
  116. // Str constructs a random alphanumeric string of given length.
  117. func (r *Rand) Str(length int) string {
  118. if length <= 0 {
  119. return ""
  120. }
  121. chars := []byte{}
  122. MAIN_LOOP:
  123. for {
  124. val := r.Int63()
  125. for i := 0; i < 10; i++ {
  126. v := int(val & 0x3f) // rightmost 6 bits
  127. if v >= 62 { // only 62 characters in strChars
  128. val >>= 6
  129. continue
  130. } else {
  131. chars = append(chars, strChars[v])
  132. if len(chars) == length {
  133. break MAIN_LOOP
  134. }
  135. val >>= 6
  136. }
  137. }
  138. }
  139. return string(chars)
  140. }
  141. func (r *Rand) Uint16() uint16 {
  142. return uint16(r.Uint32() & (1<<16 - 1))
  143. }
  144. func (r *Rand) Uint32() uint32 {
  145. r.Lock()
  146. u32 := r.rand.Uint32()
  147. r.Unlock()
  148. return u32
  149. }
  150. func (r *Rand) Uint64() uint64 {
  151. return uint64(r.Uint32())<<32 + uint64(r.Uint32())
  152. }
  153. func (r *Rand) Uint() uint {
  154. r.Lock()
  155. i := r.rand.Int()
  156. r.Unlock()
  157. return uint(i)
  158. }
  159. func (r *Rand) Int16() int16 {
  160. return int16(r.Uint32() & (1<<16 - 1))
  161. }
  162. func (r *Rand) Int32() int32 {
  163. return int32(r.Uint32())
  164. }
  165. func (r *Rand) Int64() int64 {
  166. return int64(r.Uint64())
  167. }
  168. func (r *Rand) Int() int {
  169. r.Lock()
  170. i := r.rand.Int()
  171. r.Unlock()
  172. return i
  173. }
  174. func (r *Rand) Int31() int32 {
  175. r.Lock()
  176. i31 := r.rand.Int31()
  177. r.Unlock()
  178. return i31
  179. }
  180. func (r *Rand) Int31n(n int32) int32 {
  181. r.Lock()
  182. i31n := r.rand.Int31n(n)
  183. r.Unlock()
  184. return i31n
  185. }
  186. func (r *Rand) Int63() int64 {
  187. r.Lock()
  188. i63 := r.rand.Int63()
  189. r.Unlock()
  190. return i63
  191. }
  192. func (r *Rand) Int63n(n int64) int64 {
  193. r.Lock()
  194. i63n := r.rand.Int63n(n)
  195. r.Unlock()
  196. return i63n
  197. }
  198. func (r *Rand) Float32() float32 {
  199. r.Lock()
  200. f32 := r.rand.Float32()
  201. r.Unlock()
  202. return f32
  203. }
  204. func (r *Rand) Float64() float64 {
  205. r.Lock()
  206. f64 := r.rand.Float64()
  207. r.Unlock()
  208. return f64
  209. }
  210. func (r *Rand) Time() time.Time {
  211. return time.Unix(int64(r.Uint64()), 0)
  212. }
  213. // Bytes returns n random bytes generated from the internal
  214. // prng.
  215. func (r *Rand) Bytes(n int) []byte {
  216. // cRandBytes isn't guaranteed to be fast so instead
  217. // use random bytes generated from the internal PRNG
  218. bs := make([]byte, n)
  219. for i := 0; i < len(bs); i++ {
  220. bs[i] = byte(r.Int() & 0xFF)
  221. }
  222. return bs
  223. }
  224. // Intn returns, as an int, a uniform pseudo-random number in the range [0, n).
  225. // It panics if n <= 0.
  226. func (r *Rand) Intn(n int) int {
  227. r.Lock()
  228. i := r.rand.Intn(n)
  229. r.Unlock()
  230. return i
  231. }
  232. // Bool returns a uniformly random boolean
  233. func (r *Rand) Bool() bool {
  234. // See https://github.com/golang/go/issues/23804#issuecomment-365370418
  235. // for reasoning behind computing like this
  236. return r.Int63()%2 == 0
  237. }
  238. // Perm returns a pseudo-random permutation of n integers in [0, n).
  239. func (r *Rand) Perm(n int) []int {
  240. r.Lock()
  241. perm := r.rand.Perm(n)
  242. r.Unlock()
  243. return perm
  244. }
  245. // NOTE: This relies on the os's random number generator.
  246. // For real security, we should salt that with some seed.
  247. // See github.com/tendermint/tendermint/crypto for a more secure reader.
  248. func cRandBytes(numBytes int) []byte {
  249. b := make([]byte, numBytes)
  250. _, err := crand.Read(b)
  251. if err != nil {
  252. panic(err)
  253. }
  254. return b
  255. }