pool_of_entropy 0.0.1

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.
@@ -0,0 +1,362 @@
1
+ require 'spec_helper'
2
+
3
+ describe PoolOfEntropy do
4
+ describe "class methods" do
5
+
6
+ describe "#new" do
7
+ it "should instantiate a default object" do
8
+ pool = PoolOfEntropy.new
9
+ pool.should be_a PoolOfEntropy
10
+ end
11
+
12
+ it "should allow setting number of blocks in pool" do
13
+ [1,3,5,8,13,21,34,55,89,144,233].each do |s|
14
+ pool = PoolOfEntropy.new( :size => 12 )
15
+ pool.should be_a PoolOfEntropy
16
+ num = pool.rand()
17
+ num.should be_a Float
18
+ num.should >= 0.0
19
+ num.should < 1.0
20
+ end
21
+ end
22
+
23
+ it "should fail with incorrect :size param" do
24
+ expect { PoolOfEntropy.new( :size => -12 ) }.to raise_error ArgumentError
25
+ expect { PoolOfEntropy.new( :size => -1 ) }.to raise_error ArgumentError
26
+ expect { PoolOfEntropy.new( :size => 0 ) }.to raise_error ArgumentError
27
+ expect { PoolOfEntropy.new( :size => 257 ) }.to raise_error ArgumentError
28
+ expect { PoolOfEntropy.new( :size => 1000 ) }.to raise_error ArgumentError
29
+ expect { PoolOfEntropy.new( :size => '' ) }.to raise_error ArgumentError
30
+ expect { PoolOfEntropy.new( :size => { :foo => 'bar' } ) }.to raise_error TypeError
31
+ end
32
+
33
+ it "should default to unpredicatble internal state" do
34
+ pool = PoolOfEntropy.new()
35
+ pool.should be_a PoolOfEntropy
36
+ (10..20).map { |x| pool.rand(x) }.should_not == [8, 3, 0, 12, 11, 2, 4, 8, 1, 11, 18]
37
+ end
38
+
39
+ it "should accept { :blank => false } as explicit statement of default" do
40
+ pool = PoolOfEntropy.new( :blank => false )
41
+ pool.should be_a PoolOfEntropy
42
+ (10..20).map { |x| pool.rand(x) }.should_not == [8, 3, 0, 12, 11, 2, 4, 8, 1, 11, 18]
43
+ end
44
+
45
+ it "should allow an initial blank internal state" do
46
+ pool = PoolOfEntropy.new( :blank => true )
47
+ pool.should be_a PoolOfEntropy
48
+ (10..20).map { |x| pool.rand(x) }.should == [8, 3, 0, 12, 11, 2, 4, 8, 1, 11, 18]
49
+ end
50
+
51
+ it "should accept and use :seed array" do
52
+ pool = PoolOfEntropy.new( :blank => true, :seeds => ['foo'] )
53
+ pool.should be_a PoolOfEntropy
54
+ (10..20).map { |x| pool.rand(x) }.should == [9, 1, 3, 7, 8, 12, 14, 5, 11, 5, 6]
55
+
56
+ pool = PoolOfEntropy.new( :blank => true, :seeds => ['foo', 'bar'] )
57
+ pool.should be_a PoolOfEntropy
58
+ (10..20).map { |x| pool.rand(x) }.should == [8, 1, 5, 8, 2, 7, 11, 8, 8, 13, 14]
59
+ end
60
+ end
61
+ end
62
+
63
+
64
+ describe "instance methods" do
65
+ pool_types = [
66
+ [
67
+ 'default instance',
68
+ PoolOfEntropy.new
69
+ ],
70
+ [
71
+ 'instance with 2KB pool size',
72
+ PoolOfEntropy.new( :size => 32 )
73
+ ],
74
+ [
75
+ 'instance with 1KB pool size, blank start',
76
+ PoolOfEntropy.new( :size => 16, :blank => true )
77
+ ],
78
+ [
79
+ 'instance with default size, seeded',
80
+ PoolOfEntropy.new( :blank => true, :seeds => ['of change'] )
81
+ ],
82
+ [
83
+ 'instance cloned from another instance',
84
+ PoolOfEntropy.new( :size => 3 ).clone
85
+ ],
86
+ [
87
+ 'instance with maximum size, 16KB pool',
88
+ PoolOfEntropy.new( :size => 256, :blank => true, :seeds => ['dgeq','dsfsf','dsafsaf'] )
89
+ ],
90
+ ]
91
+
92
+ # NB "probability" and "randomness" tests in the following block are very light, just
93
+ # intended to capture high-level failures in logic. See DIEHARDER_TEST.md for thorough
94
+ # checks on statistical randomness of PoolOfEntropy::CorePRNG
95
+ pool_types.each do |pool_name, pool|
96
+
97
+ context "using #{pool_name}" do
98
+ before do
99
+ pool.clear_all_modifiers
100
+ end
101
+
102
+ describe "#clone" do
103
+ it "should return a deep copy with same state and modifiers" do
104
+ pool.modify_next( *((0..4).map {|i| "foo" + i.to_s} ) )
105
+ pool.modify_all( 'bar' )
106
+
107
+ pool_copy = pool.clone
108
+ 100.times do
109
+ pool_copy.rand().should == pool.rand()
110
+ end
111
+ end
112
+ end
113
+
114
+ describe "#rand" do
115
+
116
+ context "with no param" do
117
+ it "should call PoolOfEntropy::CorePRNG::read_bytes internally" do
118
+ allow_any_instance_of( PoolOfEntropy::CorePRNG).
119
+ to receive( :read_bytes ).and_return( "\x1e\xfe" * 8 )
120
+ 20.times { pool.rand.should == 0.12106507972838931 }
121
+ end
122
+
123
+ it "should return a Float between 0.0 and 1.0" do
124
+ 100.times do
125
+ num = pool.rand
126
+ num.should be_a Float
127
+ num.should >= 0.0
128
+ num.should < 1.0
129
+ end
130
+ end
131
+
132
+ it "should return a different Float each time (with high probability) " do
133
+ Set[ *(1..100).map{ pool.rand } ].size.should == 100
134
+ end
135
+ end
136
+
137
+ context "with an Integer param" do
138
+ it "should call PoolOfEntropy::CorePRNG::read_bytes internally" do
139
+ allow_any_instance_of( PoolOfEntropy::CorePRNG).
140
+ to receive( :read_bytes ).and_return( "\x1e\xfe" * 8 )
141
+ 20.times { pool.rand(20).should == 2 }
142
+ end
143
+
144
+ it "should return an Integer between 0 and x (excluding x)" do
145
+ [ 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ].each do |x|
146
+ 100.times do
147
+ num = pool.rand( x )
148
+ num.should be_a Fixnum
149
+ num.should >= 0
150
+ num.should < x
151
+ end
152
+ end
153
+ end
154
+
155
+ # This is a very weak test of randomness, see DIEHARDER_TEST.md
156
+ it "should select values without obvious bias" do
157
+ Set[ *(1..200).map{ pool.rand( 20 ) } ].size.should == 20
158
+ end
159
+
160
+ it "should return a different Integer each time (with high probability for large x) " do
161
+ Set[ *(1..100).map{ pool.rand( 2**64 ) } ].size.should == 100
162
+ end
163
+ end
164
+
165
+ context "with a Range param" do
166
+ it "should call PoolOfEntropy::CorePRNG::read_bytes internally" do
167
+ allow_any_instance_of( PoolOfEntropy::CorePRNG).
168
+ to receive( :read_bytes ).and_return( "\x1e\xfe" * 8 )
169
+ 20.times { pool.rand( 7..28 ).should == 9 }
170
+ end
171
+
172
+ it "should return an Integer that is a member of the range" do
173
+ [ 1..2, 2..5, 3..8, 5..13, 21..34, 55..89 ].each do |r|
174
+ 100.times do
175
+ num = pool.rand( r )
176
+ num.should be_a Fixnum
177
+ num.should >= r.min
178
+ num.should <= r.max
179
+ end
180
+ end
181
+ end
182
+
183
+ it "should return a different Integer each time (with high probability for large range) " do
184
+ Set[ *(1..100).map{ pool.rand( 100000000000..200000000000 ) } ].size.should == 100
185
+ end
186
+
187
+ end
188
+
189
+ end
190
+
191
+
192
+ describe "#modify_next" do
193
+ it "changes output value from next call to #rand" do
194
+ pool_copy = pool.clone
195
+ 100.times do
196
+ modifier = SecureRandom.hex
197
+ pool_copy.modify_next( modifier ).rand.should_not == pool.rand
198
+ end
199
+ end
200
+
201
+ it "changes output value consistently" do
202
+ pool_copy = pool.clone
203
+ 100.times do
204
+ modifier = SecureRandom.hex
205
+ pool_copy.modify_next( modifier ).rand.should == pool.modify_next( modifier ).rand
206
+ end
207
+ end
208
+
209
+ it "changes next output value but not future ones" do
210
+ pool_copy = pool.clone
211
+ 100.times do
212
+ modifier = SecureRandom.hex
213
+ pool_copy.modify_next( modifier ).rand.should_not == pool.rand
214
+ pool_copy.rand.should == pool.rand
215
+ end
216
+ end
217
+
218
+ it "can create a 'queue' of modifiers, used in turn" do
219
+ pool_copy = pool.clone
220
+ 10.times do
221
+ modifiers = (0..5).map { SecureRandom.hex }
222
+
223
+ # Syntax for all-at-once
224
+ pool_copy.modify_next( *modifiers )
225
+ modifiers.each do |modifier|
226
+ pool_copy.rand.should == pool.modify_next( modifier ).rand
227
+ end
228
+ # Assert we're back in sync without modifiers
229
+ pool_copy.rand.should == pool.rand
230
+
231
+ # Adding to queue one-at-a-time
232
+ modifiers.each do |modifier|
233
+ pool_copy.modify_next( modifier )
234
+ end
235
+ modifiers.each do |modifier|
236
+ pool_copy.rand.should == pool.modify_next( modifier ).rand
237
+ end
238
+ # Assert we're back in sync without modifiers
239
+ pool_copy.rand.should == pool.rand
240
+ end
241
+ end
242
+ end # modify_next
243
+
244
+ describe "#modify_all" do
245
+ it "changes output value from future calls to #rand" do
246
+ pool_copy = pool.clone
247
+ 10.times do
248
+ modifier = SecureRandom.hex
249
+ pool_copy.modify_all( modifier ).rand.should_not == pool.rand
250
+ 10.times do
251
+ pool_copy.rand.should_not == pool.rand
252
+ end
253
+ end
254
+ end
255
+
256
+ it "changes output value consistently" do
257
+ pool_copy = pool.clone
258
+ 10.times do
259
+ modifier = SecureRandom.hex
260
+ pool_copy.modify_all( modifier ).rand.should == pool.modify_all( modifier ).rand
261
+ 10.times do
262
+ pool_copy.rand.should == pool.rand
263
+ end
264
+ end
265
+ end
266
+
267
+ it "changes output value consistently with #modify_next" do
268
+ pool_copy = pool.clone
269
+ 100.times do
270
+ modifier = SecureRandom.hex
271
+ pool_copy.modify_all( modifier ).rand.should == pool.modify_next( modifier ).rand
272
+ end
273
+ end
274
+
275
+ it "can be reset wih nil modifier" do
276
+ pool_copy = pool.clone
277
+ 10.times do
278
+ modifier = SecureRandom.hex
279
+ pool_copy.modify_all( modifier ).rand.should_not == pool.rand
280
+ pool_copy.rand.should_not == pool.rand
281
+ pool_copy.modify_all( nil )
282
+ 10.times do
283
+ pool_copy.rand.should == pool.rand
284
+ end
285
+ end
286
+ end
287
+
288
+ end
289
+
290
+ describe "#clear_all_modifiers" do
291
+
292
+ it "removes a queue of 'next' modifiers" do
293
+ pool_copy = pool.clone
294
+ 10.times do
295
+ modifiers = (0..5).map { SecureRandom.hex }
296
+ pool_copy.modify_next( *modifiers )
297
+ pool_copy.rand.should_not == pool.rand
298
+ pool_copy.clear_all_modifiers
299
+ 10.times do
300
+ pool_copy.rand.should == pool.rand
301
+ end
302
+ end
303
+ end
304
+
305
+ it "removes a current 'all' modifier" do
306
+ pool_copy = pool.clone
307
+ 10.times do
308
+ modifier = SecureRandom.hex
309
+ pool_copy.modify_all( modifier ).rand.should_not == pool.rand
310
+ pool_copy.rand.should_not == pool.rand
311
+ pool_copy.clear_all_modifiers
312
+ 10.times do
313
+ pool_copy.rand.should == pool.rand
314
+ end
315
+ end
316
+ end
317
+
318
+ it "removes both 'all' and 'next' modifiers in one go" do
319
+ pool_copy = pool.clone
320
+ 10.times do
321
+ modifier = SecureRandom.hex
322
+ pool_copy.modify_next( *(0..5).map { SecureRandom.hex } )
323
+ pool_copy.modify_all( modifier ).rand.should_not == pool.rand
324
+ pool_copy.rand.should_not == pool.rand
325
+ pool_copy.clear_all_modifiers
326
+ 10.times do
327
+ pool_copy.rand.should == pool.rand
328
+ end
329
+ end
330
+ end
331
+ end
332
+
333
+ describe "#add_to_pool" do
334
+
335
+ it "alters all future output values" do
336
+ pool_copy = pool.clone
337
+ pool_copy.add_to_pool( 'Some user data!' )
338
+ 100.times do
339
+ pool_copy.rand.should_not == pool.rand
340
+ end
341
+ end
342
+
343
+ it "alters all future output values consistently" do
344
+ pool_copy = pool.clone
345
+
346
+ 10.times do
347
+ user_data = SecureRandom.hex
348
+ pool_copy.add_to_pool( user_data )
349
+ pool.add_to_pool( user_data )
350
+
351
+ 10.times do
352
+ pool_copy.rand.should == pool.rand
353
+ end
354
+ end
355
+ end
356
+
357
+ end
358
+
359
+ end
360
+ end
361
+ end
362
+ end
@@ -0,0 +1,7 @@
1
+ require 'coveralls'
2
+ require 'set'
3
+
4
+ Coveralls.wear!
5
+
6
+ require 'pool_of_entropy'
7
+
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pool_of_entropy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Neil Slater
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: yard
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.7.2
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.7.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 2.13.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 2.13.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 1.9.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 1.9.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: coveralls
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 0.6.7
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.6.7
83
+ description: PoolOfEntropy is a PRNG based on cryptographic secure PRNGs, intended
84
+ to bring back the feeling of 'personal luck' that some gamers feel when rolling
85
+ their own dice.
86
+ email:
87
+ - slobo777@gmail.com
88
+ executables: []
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - ".gitignore"
93
+ - ".travis.yml"
94
+ - DIEHARDER_TEST.md
95
+ - Gemfile
96
+ - LICENSE.txt
97
+ - README.md
98
+ - Rakefile
99
+ - lib/pool_of_entropy.rb
100
+ - lib/pool_of_entropy/core_prng.rb
101
+ - lib/pool_of_entropy/version.rb
102
+ - pool_of_entropy.gemspec
103
+ - spec/core_prng_spec.rb
104
+ - spec/pool_of_entropy_spec.rb
105
+ - spec/spec_helper.rb
106
+ homepage: https://github.com/neilslater/pool_of_entropy
107
+ licenses:
108
+ - MIT
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 2.2.2
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: Random number generator with extra features for gamers.
130
+ test_files:
131
+ - spec/core_prng_spec.rb
132
+ - spec/pool_of_entropy_spec.rb
133
+ - spec/spec_helper.rb
134
+ has_rdoc: