@@ -3,194 +3,58 @@ package cryptorand
3
3
import (
4
4
"crypto/rand"
5
5
"encoding/binary"
6
- "time"
7
-
8
- "golang.org/x/xerrors"
6
+ insecurerand "math/rand"
9
7
)
10
8
11
- // Most of this code is inspired by math/rand, so shares similar
12
- // functions and implementations, but uses crypto/rand to generate
13
- // random Int63 data.
14
-
15
- // Int64 returns a non-negative random 63-bit integer as a int64.
16
- func Int63 () (int64 , error ) {
17
- var i int64
18
- err := binary .Read (rand .Reader , binary .BigEndian , & i )
19
- if err != nil {
20
- return 0 , xerrors .Errorf ("read binary: %w" , err )
21
- }
22
-
23
- if i < 0 {
24
- return - i , nil
25
- }
26
- return i , nil
9
+ type cryptoSource struct {
10
+ err error
27
11
}
28
12
29
- // Uint64 returns a random 64-bit integer as a uint64.
30
- func Uint64 () (uint64 , error ) {
31
- upper , err := Int63 ()
32
- if err != nil {
33
- return 0 , xerrors .Errorf ("read upper: %w" , err )
34
- }
35
-
36
- lower , err := Int63 ()
37
- if err != nil {
38
- return 0 , xerrors .Errorf ("read lower: %w" , err )
39
- }
40
-
41
- return uint64 (lower )>> 31 | uint64 (upper )<< 32 , nil
13
+ func (* cryptoSource ) Seed (_ int64 ) {
14
+ // Intentionally disregard seed
42
15
}
43
16
44
- // Int31 returns a non-negative random 31-bit integer as a int32.
45
- func Int31 () ( int32 , error ) {
46
- i , err := Int63 ( )
17
+ func ( c * cryptoSource ) Int63 () int64 {
18
+ var n int64
19
+ err := binary . Read ( rand . Reader , binary . BigEndian , & n )
47
20
if err != nil {
48
- return 0 , err
21
+ c . err = err
49
22
}
50
-
51
- return int32 (i >> 32 ), nil
23
+ // The sign bit must be cleared to ensure the final value is non-negative.
24
+ n &= 0x7fffffffffffffff
25
+ return n
52
26
}
53
27
54
- // Uint32 returns a 32-bit value as a uint32.
55
- func Uint32 () ( uint32 , error ) {
56
- i , err := Int63 ( )
28
+ func ( c * cryptoSource ) Uint64 () uint64 {
29
+ var n uint64
30
+ err := binary . Read ( rand . Reader , binary . BigEndian , & n )
57
31
if err != nil {
58
- return 0 , err
32
+ c . err = err
59
33
}
60
-
61
- return uint32 (i >> 31 ), nil
62
- }
63
-
64
- // Int returns a non-negative random integer as a int.
65
- func Int () (int , error ) {
66
- i , err := Int63 ()
67
- if err != nil {
68
- return 0 , err
69
- }
70
-
71
- if i < 0 {
72
- return int (- i ), nil
73
- }
74
- return int (i ), nil
75
- }
76
-
77
- // Int63n returns a non-negative random integer in [0,max) as a int64.
78
- func Int63n (max int64 ) (int64 , error ) {
79
- if max <= 0 {
80
- panic ("invalid argument to Int63n" )
81
- }
82
-
83
- trueMax := int64 ((1 << 63 ) - 1 - (1 << 63 )% uint64 (max ))
84
- i , err := Int63 ()
85
- if err != nil {
86
- return 0 , err
87
- }
88
-
89
- for i > trueMax {
90
- i , err = Int63 ()
91
- if err != nil {
92
- return 0 , err
93
- }
94
- }
95
-
96
- return i % max , nil
34
+ return n
97
35
}
98
36
99
- // Int31n returns a non-negative integer in [0,max) as a int32.
100
- func Int31n (max int32 ) (int32 , error ) {
101
- i , err := Uint32 ()
102
- if err != nil {
103
- return 0 , err
104
- }
105
-
106
- return UnbiasedModulo32 (i , max )
37
+ // secureRand returns a cryptographically secure random number generator.
38
+ func secureRand () (* insecurerand.Rand , * cryptoSource ) {
39
+ var cs cryptoSource
40
+ //nolint:gosec
41
+ return insecurerand .New (& cs ), & cs
107
42
}
108
43
109
- // UnbiasedModulo32 uniformly modulos v by n over a sufficiently large data
110
- // set, regenerating v if necessary. n must be > 0. All input bits in v must be
111
- // fully random, you cannot cast a random uint8/uint16 for input into this
112
- // function.
113
- //
114
- //nolint:varnamelen
115
- func UnbiasedModulo32 (v uint32 , n int32 ) (int32 , error ) {
116
- prod := uint64 (v ) * uint64 (n )
117
- low := uint32 (prod )
118
- if low < uint32 (n ) {
119
- thresh := uint32 (- n ) % uint32 (n )
120
- for low < thresh {
121
- var err error
122
- v , err = Uint32 ()
123
- if err != nil {
124
- return 0 , err
125
- }
126
- prod = uint64 (v ) * uint64 (n )
127
- low = uint32 (prod )
128
- }
129
- }
130
- return int32 (prod >> 32 ), nil
44
+ // Int64 returns a non-negative random 63-bit integer as a int64.
45
+ func Int63 () (int64 , error ) {
46
+ rng , cs := secureRand ()
47
+ return rng .Int63 (), cs .err
131
48
}
132
49
133
- // Intn returns a non-negative integer in [0,max) as a int.
50
+ // Intn returns a non-negative integer in [0,max) as an int.
134
51
func Intn (max int ) (int , error ) {
135
- if max <= 0 {
136
- panic ("n must be a positive nonzero number" )
137
- }
138
-
139
- if max <= 1 << 31 - 1 {
140
- i , err := Int31n (int32 (max ))
141
- if err != nil {
142
- return 0 , err
143
- }
144
-
145
- return int (i ), nil
146
- }
147
-
148
- i , err := Int63n (int64 (max ))
149
- if err != nil {
150
- return 0 , err
151
- }
152
-
153
- return int (i ), nil
52
+ rng , cs := secureRand ()
53
+ return rng .Intn (max ), cs .err
154
54
}
155
55
156
56
// Float64 returns a random number in [0.0,1.0) as a float64.
157
57
func Float64 () (float64 , error ) {
158
- again:
159
- i , err := Int63n (1 << 53 )
160
- if err != nil {
161
- return 0 , err
162
- }
163
-
164
- f := (float64 (i ) / (1 << 53 ))
165
- if f == 1 {
166
- goto again
167
- }
168
-
169
- return f , nil
170
- }
171
-
172
- // Float32 returns a random number in [0.0,1.0) as a float32.
173
- func Float32 () (float32 , error ) {
174
- again:
175
- i , err := Float64 ()
176
- if err != nil {
177
- return 0 , err
178
- }
179
-
180
- f := float32 (i )
181
- if f == 1 {
182
- goto again
183
- }
184
-
185
- return f , nil
186
- }
187
-
188
- // Duration returns a random time.Duration value
189
- func Duration () (time.Duration , error ) {
190
- i , err := Int63 ()
191
- if err != nil {
192
- return time .Duration (0 ), err
193
- }
194
-
195
- return time .Duration (i ), nil
58
+ rng , cs := secureRand ()
59
+ return rng .Float64 (), cs .err
196
60
}
0 commit comments