pool_of_entropy 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/rspec.yml +23 -0
- data/.rubocop.yml +18 -0
- data/Gemfile +11 -1
- data/README.md +0 -5
- data/Rakefile +7 -5
- data/lib/pool_of_entropy/core_prng.rb +149 -143
- data/lib/pool_of_entropy/version.rb +3 -1
- data/lib/pool_of_entropy.rb +55 -59
- data/pool_of_entropy.gemspec +15 -16
- data/spec/pool_of_entropy/core_prng_spec.rb +386 -0
- data/spec/pool_of_entropy_spec.rb +264 -303
- data/spec/spec_helper.rb +49 -3
- metadata +12 -88
- data/.travis.yml +0 -11
- data/spec/core_prng_spec.rb +0 -543
data/spec/core_prng_spec.rb
DELETED
|
@@ -1,543 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe PoolOfEntropy::CorePRNG do
|
|
4
|
-
describe "class methods" do
|
|
5
|
-
|
|
6
|
-
describe "#new" do
|
|
7
|
-
it "should instantiate a default object" do
|
|
8
|
-
prng = PoolOfEntropy::CorePRNG.new
|
|
9
|
-
expect( prng ).to be_a PoolOfEntropy::CorePRNG
|
|
10
|
-
expect( prng.size ).to be 1
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it "should allow setting number of blocks in pool" do
|
|
14
|
-
prng = PoolOfEntropy::CorePRNG.new( 10 )
|
|
15
|
-
expect( prng ).to be_a PoolOfEntropy::CorePRNG
|
|
16
|
-
expect( prng.size ).to be 10
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it "should fail with incorrect block number" do
|
|
20
|
-
expect { PoolOfEntropy::CorePRNG.new( -43 ) }.to raise_error ArgumentError
|
|
21
|
-
expect { PoolOfEntropy::CorePRNG.new( -1 ) }.to raise_error ArgumentError
|
|
22
|
-
expect { PoolOfEntropy::CorePRNG.new( 0 ) }.to raise_error ArgumentError
|
|
23
|
-
expect { PoolOfEntropy::CorePRNG.new( 257 ) }.to raise_error ArgumentError
|
|
24
|
-
expect { PoolOfEntropy::CorePRNG.new( 1000) }.to raise_error ArgumentError
|
|
25
|
-
expect { PoolOfEntropy::CorePRNG.new( nil ) }.to raise_error TypeError
|
|
26
|
-
expect { PoolOfEntropy::CorePRNG.new( '' ) }.to raise_error ArgumentError
|
|
27
|
-
expect { PoolOfEntropy::CorePRNG.new( :foo => 2 ) }.to raise_error TypeError
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it "should allow setting internal state" do
|
|
31
|
-
prng = PoolOfEntropy::CorePRNG.new( 1, "\x0" * 64 )
|
|
32
|
-
expect( prng ).to be_a PoolOfEntropy::CorePRNG
|
|
33
|
-
expect( prng.size ).to be 1
|
|
34
|
-
expect( prng.state ).to eql "\x0" * 64
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it "should fail with bad state data" do
|
|
38
|
-
expect { PoolOfEntropy::CorePRNG.new( 1, :boo ) }.to raise_error TypeError
|
|
39
|
-
expect { PoolOfEntropy::CorePRNG.new( 1, [] ) }.to raise_error TypeError
|
|
40
|
-
expect { PoolOfEntropy::CorePRNG.new( 1, '' ) }.to raise_error ArgumentError
|
|
41
|
-
expect { PoolOfEntropy::CorePRNG.new( 1, "\x0" * 63 ) }.to raise_error ArgumentError
|
|
42
|
-
expect { PoolOfEntropy::CorePRNG.new( 1, "\x0" * 200 ) }.to raise_error ArgumentError
|
|
43
|
-
expect { PoolOfEntropy::CorePRNG.new( 2, "\x0" * 64 ) }.to raise_error ArgumentError
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it "should allow setting mix_block_id" do
|
|
47
|
-
prng = PoolOfEntropy::CorePRNG.new( 3, "\x12" * 192, 1 )
|
|
48
|
-
expect( prng ).to be_a PoolOfEntropy::CorePRNG
|
|
49
|
-
expect( prng.size ).to eql 3
|
|
50
|
-
expect( prng.state ).to eql "\x12" * 192
|
|
51
|
-
expect( prng.mix_block_id ).to eql 1
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
describe "instance methods" do
|
|
57
|
-
|
|
58
|
-
describe "#clone" do
|
|
59
|
-
it "should copy all attributes" do
|
|
60
|
-
prng_orig = PoolOfEntropy::CorePRNG.new
|
|
61
|
-
prng_copy = prng_orig.clone
|
|
62
|
-
|
|
63
|
-
expect( prng_copy.size ).to eql prng_orig.size
|
|
64
|
-
expect( prng_copy.state ).to eql prng_orig.state
|
|
65
|
-
expect( prng_copy.mix_block_id ).to eql prng_orig.mix_block_id
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
it "should deep clone the internal state string" do
|
|
69
|
-
prng_orig = PoolOfEntropy::CorePRNG.new
|
|
70
|
-
prng_copy = prng_orig.clone
|
|
71
|
-
expect( prng_copy.state ).to_not be prng_orig.state
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
describe "#update" do
|
|
76
|
-
it "should change the internal state" do
|
|
77
|
-
prng = PoolOfEntropy::CorePRNG.new
|
|
78
|
-
init_state = prng.state.clone
|
|
79
|
-
prng.update( 'boo' )
|
|
80
|
-
expect( prng.state ).to_not eql init_state
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
it "should not change the length of the internal state" do
|
|
84
|
-
prng = PoolOfEntropy::CorePRNG.new
|
|
85
|
-
prng.update( 'boo' )
|
|
86
|
-
expect( prng.state.length ).to eql 64
|
|
87
|
-
prng.update( 'boowgkjwrhqgioueqrhgiue2hguirhqwiughreuioghreuifhqwoifhr3iufghfwrgrwgetdfwd' )
|
|
88
|
-
expect( prng.state.length ).to eql 64
|
|
89
|
-
|
|
90
|
-
prng = PoolOfEntropy::CorePRNG.new( 5 )
|
|
91
|
-
prng.update( 'boo' )
|
|
92
|
-
expect( prng.state.length ).to eql 5 * 64
|
|
93
|
-
prng.update( 'getdfwd' * 1000 )
|
|
94
|
-
expect( prng.state.length ).to eql 5 * 64
|
|
95
|
-
prng.update( 'boefewfweo' )
|
|
96
|
-
expect( prng.state.length ).to eql 5 * 64
|
|
97
|
-
prng.update( 'geefewftdfwd' * 1000 )
|
|
98
|
-
expect( prng.state.length ).to eql 5 * 64
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
it "should only change 64 bytes of state at a time" do
|
|
102
|
-
prng = PoolOfEntropy::CorePRNG.new( 5 )
|
|
103
|
-
init_state = prng.state.clone
|
|
104
|
-
|
|
105
|
-
prng.update( 'boo' )
|
|
106
|
-
expect( prng.state[64,4*64] ).to eql init_state[64,4*64]
|
|
107
|
-
next_state = prng.state.clone
|
|
108
|
-
|
|
109
|
-
prng.update( 'getdfwd' * 1000 )
|
|
110
|
-
expect( prng.state[128,3*64] ).to eql init_state[128,3*64]
|
|
111
|
-
expect( prng.state[0,1*64] ).to eql next_state[0,1*64]
|
|
112
|
-
next_state = prng.state.clone
|
|
113
|
-
|
|
114
|
-
prng.update( 'boefewfweo' )
|
|
115
|
-
expect( prng.state[192,2*64] ).to eql init_state[192,2*64]
|
|
116
|
-
expect( prng.state[0,2*64] ).to eql next_state[0,2*64]
|
|
117
|
-
next_state = prng.state.clone
|
|
118
|
-
|
|
119
|
-
prng.update( 'geefewftdfwd' * 1000 )
|
|
120
|
-
expect( prng.state[256,1*64] ).to eql init_state[256,1*64]
|
|
121
|
-
expect( prng.state[0,3*64] ).to eql next_state[0,3*64]
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
instance01 = PoolOfEntropy::CorePRNG.new
|
|
126
|
-
instance01.update( 'QWertyuiopp' )
|
|
127
|
-
instance01.update( 'Asdfghjkjl' )
|
|
128
|
-
instance01.update( 'Zxcvbnm' )
|
|
129
|
-
|
|
130
|
-
pool_types = [
|
|
131
|
-
[
|
|
132
|
-
'default instance',
|
|
133
|
-
PoolOfEntropy::CorePRNG.new
|
|
134
|
-
],
|
|
135
|
-
[
|
|
136
|
-
'instance with 2KB pool size',
|
|
137
|
-
PoolOfEntropy::CorePRNG.new( 32 )
|
|
138
|
-
],
|
|
139
|
-
[
|
|
140
|
-
'instance with initial state all 0',
|
|
141
|
-
PoolOfEntropy::CorePRNG.new( 1, "\x0" * 64 )
|
|
142
|
-
],
|
|
143
|
-
[
|
|
144
|
-
'instance with fixed initial state',
|
|
145
|
-
PoolOfEntropy::CorePRNG.new( 5, "fiver" * 64, 3 )
|
|
146
|
-
],
|
|
147
|
-
[
|
|
148
|
-
'instance cloned from 2KB instance',
|
|
149
|
-
PoolOfEntropy::CorePRNG.new( 32 ).clone
|
|
150
|
-
],
|
|
151
|
-
[
|
|
152
|
-
'instance that has been updated with user data',
|
|
153
|
-
instance01
|
|
154
|
-
],
|
|
155
|
-
]
|
|
156
|
-
|
|
157
|
-
# NB "probability" and "randomness" tests in the following block are very light, just
|
|
158
|
-
# intended to capture high-level failures in logic. See DIEHARDER_TEST.md for thorough
|
|
159
|
-
# checks on statistical randomness of PoolOfEntropy::CorePRNG
|
|
160
|
-
pool_types.each do |prng_name, prng|
|
|
161
|
-
|
|
162
|
-
context "using #{prng_name}" do
|
|
163
|
-
|
|
164
|
-
describe "#read_bytes" do
|
|
165
|
-
it "always returns a 16 byte string" do
|
|
166
|
-
100.times { expect( prng.read_bytes.length ).to eql 16 }
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
it "has a high probability of returning a different string each time" do
|
|
170
|
-
expect( Set[ *(1..100).map {prng.read_bytes} ].size ).to eql 100
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
describe "with adjustments" do
|
|
174
|
-
it "always returns a 16 byte string" do
|
|
175
|
-
100.times { expect( prng.read_bytes('654321').length ).to eql 16 }
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
it "has a high probability of returning a different string each time" do
|
|
179
|
-
expect( Set[ *(1..100).map {prng.read_bytes('654321')} ].size ).to eql 100
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
it "changes output, but does not include adjustments in changes to state" do
|
|
183
|
-
prng_copy = prng.clone
|
|
184
|
-
10.times do
|
|
185
|
-
expect( prng.read_bytes('Hello!') ).to eql prng_copy.read_bytes('Hello!')
|
|
186
|
-
expect( prng.state ).to eql prng_copy.state
|
|
187
|
-
expect( prng.read_bytes('Hello!') ).to_not eql prng_copy.read_bytes('Goodbye!')
|
|
188
|
-
expect( prng.state ).to eql prng_copy.state
|
|
189
|
-
expect( prng.read_bytes ).to_not eql prng_copy.read_bytes('Goodbye!')
|
|
190
|
-
expect( prng.state ).to eql prng_copy.state
|
|
191
|
-
expect( prng.read_bytes('Hello!') ).to_not eql prng_copy.read_bytes
|
|
192
|
-
expect( prng.state ).to eql prng_copy.state
|
|
193
|
-
expect( prng.read_bytes('Hello','Goodbye') ).to_not eql prng_copy.read_bytes
|
|
194
|
-
expect( prng.state ).to eql prng_copy.state
|
|
195
|
-
# Verify that output remains same for next rolls
|
|
196
|
-
expect( prng.read_bytes('Foobar','Wibble') ).to eql prng_copy.read_bytes('Foobar','Wibble')
|
|
197
|
-
expect( prng.state ).to eql prng_copy.state
|
|
198
|
-
expect( prng.read_bytes ).to eql prng_copy.read_bytes
|
|
199
|
-
expect( prng.state ).to eql prng_copy.state
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
describe "#read_hex" do
|
|
206
|
-
it "always returns a 32 digit hex string" do
|
|
207
|
-
100.times do
|
|
208
|
-
hex = prng.read_hex
|
|
209
|
-
expect( hex.length ).to eql 32
|
|
210
|
-
expect( hex ).to match /\A[0-9a-f]{32}\z/
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
it "has a high probability of returning a different string each time" do
|
|
215
|
-
expect( Set[ *(1..100).map {prng.read_hex} ].size ).to eql 100
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
describe "with adjustments" do
|
|
219
|
-
it "always returns a 32 digit hex string" do
|
|
220
|
-
100.times do
|
|
221
|
-
hex = prng.read_hex('QWertyeu')
|
|
222
|
-
expect( hex.length ).to eql 32
|
|
223
|
-
expect( hex ).to match /\A[0-9a-f]{32}\z/
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
it "has a high probability of returning a different string each time" do
|
|
228
|
-
expect( Set[ *(1..100).map {prng.read_hex('654321')} ].size ).to eql 100
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
it "changes output, but does not include adjustments in changes to state" do
|
|
232
|
-
prng_copy = prng.clone
|
|
233
|
-
10.times do
|
|
234
|
-
expect( prng.read_hex('Hello!') ).to eql prng_copy.read_hex('Hello!')
|
|
235
|
-
expect( prng.state ).to eql prng_copy.state
|
|
236
|
-
expect( prng.read_hex('Hello!') ).to_not eql prng_copy.read_hex('Goodbye!')
|
|
237
|
-
expect( prng.state ).to eql prng_copy.state
|
|
238
|
-
expect( prng.read_hex ).to_not eql prng_copy.read_hex('Goodbye!')
|
|
239
|
-
expect( prng.state ).to eql prng_copy.state
|
|
240
|
-
expect( prng.read_hex('Hello!') ).to_not eql prng_copy.read_hex
|
|
241
|
-
expect( prng.state ).to eql prng_copy.state
|
|
242
|
-
expect( prng.read_hex('Hello','Goodbye') ).to_not eql prng_copy.read_hex
|
|
243
|
-
expect( prng.state ).to eql prng_copy.state
|
|
244
|
-
# Verify that output remains same for next rolls
|
|
245
|
-
expect( prng.read_hex('Foobar','Wibble') ).to eql prng_copy.read_hex('Foobar','Wibble')
|
|
246
|
-
expect( prng.state ).to eql prng_copy.state
|
|
247
|
-
expect( prng.read_hex ).to eql prng_copy.read_hex
|
|
248
|
-
expect( prng.state ).to eql prng_copy.state
|
|
249
|
-
end
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
describe "#read_bignum" do
|
|
255
|
-
it "always returns a 128-bit unsigned integer" do
|
|
256
|
-
100.times do
|
|
257
|
-
num = prng.read_bignum
|
|
258
|
-
expect( num ).to be >= 0
|
|
259
|
-
expect( num ).to be < 2**128
|
|
260
|
-
end
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
it "has a high probability of returning a different number each time" do
|
|
264
|
-
expect( Set[ *(1..100).map {prng.read_bignum} ].size ).to eql 100
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
describe "with adjustments" do
|
|
268
|
-
it "always returns a 128-bit unsigned integer" do
|
|
269
|
-
100.times do
|
|
270
|
-
num = prng.read_bignum( 'Biggest' )
|
|
271
|
-
expect( num ).to be >= 0
|
|
272
|
-
expect( num ).to be < 2**128
|
|
273
|
-
end
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
it "has a high probability of returning a different number each time" do
|
|
277
|
-
expect( Set[ *(1..100).map {prng.read_bignum('654321')} ].size ).to eql 100
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
it "changes output, but does not include adjustments in changes to state" do
|
|
281
|
-
prng_copy = prng.clone
|
|
282
|
-
10.times do
|
|
283
|
-
expect( prng.read_bignum('Hello!') ).to eql prng_copy.read_bignum('Hello!')
|
|
284
|
-
expect( prng.state ).to eql prng_copy.state
|
|
285
|
-
expect( prng.read_bignum('Hello!') ).to_not eql prng_copy.read_bignum('Goodbye!')
|
|
286
|
-
expect( prng.state ).to eql prng_copy.state
|
|
287
|
-
expect( prng.read_bignum ).to_not eql prng_copy.read_bignum('Goodbye!')
|
|
288
|
-
expect( prng.state ).to eql prng_copy.state
|
|
289
|
-
expect( prng.read_bignum('Hello!') ).to_not eql prng_copy.read_bignum
|
|
290
|
-
expect( prng.state ).to eql prng_copy.state
|
|
291
|
-
expect( prng.read_bignum('Hello','Goodbye') ).to_not eql prng_copy.read_bignum
|
|
292
|
-
expect( prng.state ).to eql prng_copy.state
|
|
293
|
-
# Verify that output remains same for next rolls
|
|
294
|
-
expect( prng.read_bignum('Foobar','Wibble') ).to eql prng_copy.read_bignum('Foobar','Wibble')
|
|
295
|
-
expect( prng.state ).to eql prng_copy.state
|
|
296
|
-
expect( prng.read_bignum ).to eql prng_copy.read_bignum
|
|
297
|
-
expect( prng.state ).to eql prng_copy.state
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
end
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
describe "#read_float" do
|
|
304
|
-
it "always returns a Float between 0.0 (inclusive) and 1.0 (exclusive)" do
|
|
305
|
-
100.times do
|
|
306
|
-
num = prng.read_float
|
|
307
|
-
expect( num ).to be_a Float
|
|
308
|
-
expect( num ).to be >= 0.0
|
|
309
|
-
expect( num ).to be < 1.0
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
it "has a high probability of returning a different Float each time" do
|
|
314
|
-
expect( Set[ *(1..100).map {prng.read_float} ].size ).to eql 100
|
|
315
|
-
end
|
|
316
|
-
|
|
317
|
-
describe "with adjustments" do
|
|
318
|
-
it "always returns a Float between 0.0 (inclusive) and 1.0 (exclusive)" do
|
|
319
|
-
100.times do
|
|
320
|
-
num = prng.read_float('Boom')
|
|
321
|
-
expect( num ).to be_a Float
|
|
322
|
-
expect( num ).to be >= 0.0
|
|
323
|
-
expect( num ).to be < 1.0
|
|
324
|
-
end
|
|
325
|
-
end
|
|
326
|
-
|
|
327
|
-
it "has a high probability of returning a different Float each time" do
|
|
328
|
-
expect( Set[ *(1..100).map {prng.read_float('654321')} ].size ).to eql 100
|
|
329
|
-
end
|
|
330
|
-
|
|
331
|
-
it "changes output, but does not include adjustments in changes to state" do
|
|
332
|
-
prng_copy = prng.clone
|
|
333
|
-
10.times do
|
|
334
|
-
expect( prng.read_float('Hello!') ).to eql prng_copy.read_float('Hello!')
|
|
335
|
-
expect( prng.state ).to eql prng_copy.state
|
|
336
|
-
expect( prng.read_float('Hello!') ).to_not eql prng_copy.read_float('Goodbye!')
|
|
337
|
-
expect( prng.state ).to eql prng_copy.state
|
|
338
|
-
expect( prng.read_float ).to_not eql prng_copy.read_float('Goodbye!')
|
|
339
|
-
expect( prng.state ).to eql prng_copy.state
|
|
340
|
-
expect( prng.read_float('Hello!') ).to_not eql prng_copy.read_float
|
|
341
|
-
expect( prng.state ).to eql prng_copy.state
|
|
342
|
-
expect( prng.read_float('Hello','Goodbye') ).to_not eql prng_copy.read_float
|
|
343
|
-
expect( prng.state ).to eql prng_copy.state
|
|
344
|
-
# Verify that output remains same for next rolls
|
|
345
|
-
expect( prng.read_float('Foobar','Wibble') ).to eql prng_copy.read_float('Foobar','Wibble')
|
|
346
|
-
expect( prng.state ).to eql prng_copy.state
|
|
347
|
-
expect( prng.read_float ).to eql prng_copy.read_float
|
|
348
|
-
expect( prng.state ).to eql prng_copy.state
|
|
349
|
-
end
|
|
350
|
-
end
|
|
351
|
-
end
|
|
352
|
-
end
|
|
353
|
-
|
|
354
|
-
describe "#generate_integer" do
|
|
355
|
-
it "always returns an integer between 0 (inclusive) and supplied top (exclusive)" do
|
|
356
|
-
100.times do
|
|
357
|
-
num = prng.generate_integer( 10 )
|
|
358
|
-
expect( num ).to be_a Fixnum
|
|
359
|
-
expect( num ).to be >= 0
|
|
360
|
-
expect( num ).to be < 10
|
|
361
|
-
end
|
|
362
|
-
|
|
363
|
-
100.times do
|
|
364
|
-
num = prng.generate_integer( 100 )
|
|
365
|
-
expect( num ).to be_a Fixnum
|
|
366
|
-
expect( num ).to be >= 0
|
|
367
|
-
expect( num ).to be < 100
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
100.times do
|
|
371
|
-
num = prng.generate_integer( 1000 )
|
|
372
|
-
expect( num ).to be_a Fixnum
|
|
373
|
-
expect( num ).to be >= 0
|
|
374
|
-
expect( num ).to be < 1000
|
|
375
|
-
end
|
|
376
|
-
|
|
377
|
-
100.times do
|
|
378
|
-
num = prng.generate_integer( 647218456 )
|
|
379
|
-
expect( num ).to be_a Fixnum
|
|
380
|
-
expect( num ).to be >= 0
|
|
381
|
-
expect( num ).to be < 647218456
|
|
382
|
-
end
|
|
383
|
-
end
|
|
384
|
-
|
|
385
|
-
it "can generate integers larger than 2**128" do
|
|
386
|
-
results = (0..100).map do
|
|
387
|
-
num = prng.generate_integer( 2 ** 1024 )
|
|
388
|
-
expect( num ).to be >= 0
|
|
389
|
-
expect( num ).to be < 2 ** 1024
|
|
390
|
-
num
|
|
391
|
-
end
|
|
392
|
-
expect( results.select { |n| n > 2 ** 1020 }.count ).to be > 50
|
|
393
|
-
end
|
|
394
|
-
|
|
395
|
-
it "with a large enough value for top, has a high probability of returning a different integer each time" do
|
|
396
|
-
expect( Set[ *(1..100).map {prng.generate_integer( 2**75 - 7 )} ].size ).to eql 100
|
|
397
|
-
end
|
|
398
|
-
|
|
399
|
-
it "covers a distribution 0...top" do
|
|
400
|
-
expect( Set[ *(1..100).map {prng.generate_integer(10)} ].size ).to eql 10
|
|
401
|
-
end
|
|
402
|
-
|
|
403
|
-
describe "with adjustments" do
|
|
404
|
-
it "always returns an integer between 0 (inclusive) and supplied top (exclusive)" do
|
|
405
|
-
100.times do
|
|
406
|
-
num = prng.generate_integer( 10, 'jkffwe' )
|
|
407
|
-
expect( num ).to be_a Fixnum
|
|
408
|
-
expect( num ).to be >= 0
|
|
409
|
-
expect( num ).to be < 10
|
|
410
|
-
end
|
|
411
|
-
|
|
412
|
-
100.times do
|
|
413
|
-
num = prng.generate_integer( 100, 'jkffweefewg' )
|
|
414
|
-
expect( num ).to be_a Fixnum
|
|
415
|
-
expect( num ).to be >= 0
|
|
416
|
-
expect( num ).to be < 100
|
|
417
|
-
end
|
|
418
|
-
|
|
419
|
-
100.times do
|
|
420
|
-
num = prng.generate_integer( 1000, 'jkffweefewg', 'efhwjkfgw' )
|
|
421
|
-
expect( num ).to be_a Fixnum
|
|
422
|
-
expect( num ).to be >= 0
|
|
423
|
-
expect( num ).to be < 1000
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
100.times do
|
|
427
|
-
num = prng.generate_integer( 647218456, 'j*****g', 'efhwjkfgw' )
|
|
428
|
-
expect( num ).to be_a Fixnum
|
|
429
|
-
expect( num ).to be >= 0
|
|
430
|
-
expect( num ).to be < 647218456
|
|
431
|
-
end
|
|
432
|
-
end
|
|
433
|
-
|
|
434
|
-
it "with a large enough value for top, has a high probability of returning a different integer each time" do
|
|
435
|
-
expect( Set[ *(1..100).map {prng.generate_integer( 2**80 - 5, '654321')} ].size ).to eql 100
|
|
436
|
-
end
|
|
437
|
-
|
|
438
|
-
it "changes output, but does not include adjustments in changes to state" do
|
|
439
|
-
prng_copy = prng.clone
|
|
440
|
-
big = 2 ** 64 - 3
|
|
441
|
-
small = 20
|
|
442
|
-
10.times do
|
|
443
|
-
expect( prng.generate_integer( small, 'Hello!') ).to eql prng_copy.generate_integer( small, 'Hello!')
|
|
444
|
-
expect( prng.state ).to eql prng_copy.state
|
|
445
|
-
expect( prng.generate_integer( big, 'Hello!') ).to_not eql prng_copy.generate_integer( big, 'Goodbye!')
|
|
446
|
-
expect( prng.state ).to eql prng_copy.state
|
|
447
|
-
expect( prng.generate_integer( big ) ).to_not eql prng_copy.generate_integer( big, 'Goodbye!')
|
|
448
|
-
expect( prng.state ).to eql prng_copy.state
|
|
449
|
-
expect( prng.generate_integer( big, 'Hello!') ).to_not eql prng_copy.generate_integer( big )
|
|
450
|
-
expect( prng.state ).to eql prng_copy.state
|
|
451
|
-
expect( prng.generate_integer( big, 'Hello','Goodbye') ).to_not eql prng_copy.generate_integer( big )
|
|
452
|
-
expect( prng.state ).to eql prng_copy.state
|
|
453
|
-
# Verify that output remains same for next rolls
|
|
454
|
-
expect( prng.generate_integer( small, 'Foobar','Wibble') ).to eql prng_copy.generate_integer( small, 'Foobar','Wibble')
|
|
455
|
-
expect( prng.state ).to eql prng_copy.state
|
|
456
|
-
expect( prng.generate_integer( big ) ).to eql prng_copy.generate_integer( big )
|
|
457
|
-
expect( prng.state ).to eql prng_copy.state
|
|
458
|
-
end
|
|
459
|
-
end
|
|
460
|
-
end
|
|
461
|
-
end
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
describe "all read methods" do
|
|
465
|
-
|
|
466
|
-
it "generate higher and lower values in sync" do
|
|
467
|
-
prngs = (0..4).map { prng.clone }
|
|
468
|
-
results = (1..20).map do
|
|
469
|
-
Hash[
|
|
470
|
-
:bytes => prngs[0].read_bytes,
|
|
471
|
-
:hex => prngs[1].read_hex,
|
|
472
|
-
:float => prngs[2].read_float,
|
|
473
|
-
:num => prngs[3].read_bignum,
|
|
474
|
-
:int => prngs[4].generate_integer( 1_000_000_000 ),
|
|
475
|
-
]
|
|
476
|
-
end
|
|
477
|
-
expect( results.sort_by { |h| h[:int] } ).to eql results.sort_by { |h| h[:hex] }
|
|
478
|
-
expect( results.sort_by { |h| h[:float] } ).to eql results.sort_by { |h| h[:hex] }
|
|
479
|
-
expect( results.sort_by { |h| h[:num] } ).to eql results.sort_by { |h| h[:bytes] }
|
|
480
|
-
expect( results.sort_by { |h| h[:float] } ).to eql results.sort_by { |h| h[:int] }
|
|
481
|
-
end
|
|
482
|
-
end
|
|
483
|
-
|
|
484
|
-
end
|
|
485
|
-
end
|
|
486
|
-
|
|
487
|
-
describe "using predictable sequences" do
|
|
488
|
-
it "generates expected hex strings from simple zeroed pool" do
|
|
489
|
-
prng = PoolOfEntropy::CorePRNG.new( 1, "\x0" * 64 )
|
|
490
|
-
expect( (0..24).map { prng.read_hex } ).to eql [ "da0cd77eb1c84458ddcc91e36b9dcb35",
|
|
491
|
-
"498ec24d1126440047eed396d836b5e1", "0b90df55c5e7c1513b072367eae4a4ce",
|
|
492
|
-
"f12b5b54b5594e785bbb9a4ac50ccec8", "d506bd4e201a00dc30499bd8e59a30d8",
|
|
493
|
-
"2557893cf995fe43bd00721fce6ab16a", "41ee50244cdd02334bafc3e9d8f564d9",
|
|
494
|
-
"8156c7c7bcfd856cb9d1012243cfc662", "1116f840e2aee924bd2c7d722c602635",
|
|
495
|
-
"96cf31967465b83f5ef3476c60afe20a", "f041f6df72aa2eab7394f08e83d52a0c",
|
|
496
|
-
"5ccbb30077f2433bd765ddc86840a880", "6a4339fd5d445024048ea8f91a3e02fd",
|
|
497
|
-
"707e9499b9f0e9e906a0c0ddd0530803", "553704d95703284df323f0aa4244cf81",
|
|
498
|
-
"cb1522ce0bdf2504fdd62df7416be73e", "05c4932cb9d3a7c0675b0228826e661a",
|
|
499
|
-
"59606f23e34e726a7912dacfde533d97", "188cf17dde6947264ce05f8274874ffa",
|
|
500
|
-
"24c184b56453891657953f557635b742", "a5f969e50228b2ee0f38cc37c5033541",
|
|
501
|
-
"f1de0e5d149cc5a7f0e38c0ee501d7bc", "5ca3a6beb0b810568be83ab2179eb550",
|
|
502
|
-
"756fb9c58277eb8c6092142224caecf4", "0ed9505eadb3def60ec42051f0bf15ef" ]
|
|
503
|
-
end
|
|
504
|
-
|
|
505
|
-
it "generates expected hex strings from simple zeroed pool and an adjustment" do
|
|
506
|
-
prng = PoolOfEntropy::CorePRNG.new( 1, "\x0" * 64 )
|
|
507
|
-
expect( (0..24).map { prng.read_hex( 'bananas' ) } ).to eql [
|
|
508
|
-
"fed9de9a612f4157ebb49582ca557a50", "a7adc2374a4df2ed67846ac09a3b6645",
|
|
509
|
-
"cbdf8bbbe6145751fe14004719915160", "8cd84be95376f72918c305bdea43e36d",
|
|
510
|
-
"9e08e80ff40c942f0cf4d479b5378fa0", "54d80c5330873f9733a0adef0197220f",
|
|
511
|
-
"2abe07bd85d2066a624dd3630e59730a", "88b6a697fe74aeb8ec83845e103b7b63",
|
|
512
|
-
"9c6c9d613855f6535adb419cc564fd10", "23f9b778b254035a0e4219423a52da77",
|
|
513
|
-
"4cd50c14ee17fa29c8b1f209432a36b3", "2b5646b164d863de716f67adef653859",
|
|
514
|
-
"fd81d0bbbd2828ecdfcba0b486ef786c", "08e6594fc277ff7fafbf37475ecadbf6",
|
|
515
|
-
"5e2333ecc800eb9a06e347924ed42e94", "8a14e48013028b2c9f174a07ddd5ef49",
|
|
516
|
-
"e9a5c331f54b155f570c2cf2bcd37209", "1ce84279195a5b23ffeb3063edbfab21",
|
|
517
|
-
"7422e19e58f2fcf20805f601266bf676", "8df0226465b74d830360ea8609d181bf",
|
|
518
|
-
"3e5d5e8cf8ad032fb4005826bdf7bb94", "65e3f9ab28c26bead6647c21bcc6245e",
|
|
519
|
-
"8ed5d8892d464ebeaa8dcbcef0968936", "2f000bc1ab14d914196cc1d5055db189",
|
|
520
|
-
"8e9c4b8152f14e47ac31f25a80765ebf" ]
|
|
521
|
-
end
|
|
522
|
-
|
|
523
|
-
it "generates expected hex strings from simple zeroed pool and alternating adjustments" do
|
|
524
|
-
prng = PoolOfEntropy::CorePRNG.new( 1, "\x0" * 64 )
|
|
525
|
-
expect( (0..24).map { |x| x.odd? ? prng.read_hex( 'bananas', x.to_s ) : prng.read_hex } ).to eql [
|
|
526
|
-
"da0cd77eb1c84458ddcc91e36b9dcb35", "de4b20a0560263090c6fe11ebba6256e",
|
|
527
|
-
"0b90df55c5e7c1513b072367eae4a4ce", "0c92d534160cb268cb3282a9dd3f1efe",
|
|
528
|
-
"d506bd4e201a00dc30499bd8e59a30d8", "089f799236a9cf64f22f1deafbe28214",
|
|
529
|
-
"41ee50244cdd02334bafc3e9d8f564d9", "84477b9a3d51bb72868ccb85bea71cad",
|
|
530
|
-
"1116f840e2aee924bd2c7d722c602635", "469e4bb2f38719c7f85d79c8900a8fa8",
|
|
531
|
-
"f041f6df72aa2eab7394f08e83d52a0c", "e21bf2508b8e1755ae70c74c0d36ec2e",
|
|
532
|
-
"6a4339fd5d445024048ea8f91a3e02fd", "a94a80c80c9edd95808a67775c2b42d4",
|
|
533
|
-
"553704d95703284df323f0aa4244cf81", "edd6aea5bda7b2d9c494067c5cdbe410",
|
|
534
|
-
"05c4932cb9d3a7c0675b0228826e661a", "cf81635ca2fa910fd11cf45508dc658b",
|
|
535
|
-
"188cf17dde6947264ce05f8274874ffa", "bb4aaeb98e13400c1216c674a872ba93",
|
|
536
|
-
"a5f969e50228b2ee0f38cc37c5033541", "1a795355f979575247b3fa9c92d97917",
|
|
537
|
-
"5ca3a6beb0b810568be83ab2179eb550", "1a98419cca1dd1b370ce8a4a2ab721b7",
|
|
538
|
-
"0ed9505eadb3def60ec42051f0bf15ef" ]
|
|
539
|
-
end
|
|
540
|
-
end
|
|
541
|
-
end
|
|
542
|
-
|
|
543
|
-
end
|