super_random 1.2.200123 → 2.0.210126

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aeb192c166b91d82fb0a4b535d851a5479c5bae43bf4a37d607ae199b128d83d
4
- data.tar.gz: 6fb7ad8629f9775183a65c040dc762d48e178a761c545008028e57c0002162dd
3
+ metadata.gz: 2480d12416526288677a0a9203d7e63ae666eb70b59fc792cc1a67bc2c35978a
4
+ data.tar.gz: 52d9c2e334770c1498f6afffc1bc967db38686a1d5098882f2b1290bbf5f1e60
5
5
  SHA512:
6
- metadata.gz: c51049b6220c0c971146cd2ddc0463dcbd7037c7bc7695aca8a50653d8acd22cc2964d85f66d667ad311526f2e0a8748d0e4a2e501f9621aa64db0f524d78883
7
- data.tar.gz: f583c0095ca47c209730afa445bca8304f041d55de8c0f26e599e9cac7770bbdc3f4001e2e9fc82fe8e24ea70a5c9063d01e12e616a6708bc88dcfd71c990f8d
6
+ metadata.gz: 3dcb0cb30658abd969e2930cc60bc9d0ff33bca7b4dc7ee0e418c43ba6f9815d52c7af4c21346320ff7941422e2ff8fbbb75a3e0453c9172edf3f05e5a0609ff
7
+ data.tar.gz: c0b24a58b9a236992b615a3bad666af0d5377575dabed3fd760cc3b2857904f9bec41ed3ee0f186c11820979c0bea50cf4f52de580ff6a576d3dc253a2644f43
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SuperRandom
2
2
 
3
- * [VERSION 1.2.200123](https://github.com/carlosjhr64/super_random/releases)
3
+ * [VERSION 2.0.210126](https://github.com/carlosjhr64/super_random/releases)
4
4
  * [github](https://github.com/carlosjhr64/super_random)
5
5
  * [rubygems](https://rubygems.org/gems/super_random)
6
6
 
@@ -8,45 +8,51 @@
8
8
 
9
9
  You can't get more random than random, but you can try really, really, really hard.
10
10
 
11
- SuperRandom combines five online real random services to create a more perfect random byte.
12
-
13
- ## SYNOPSIS:
14
-
15
- require 'super_random'
16
- super_random = SuperRandom.new
17
-
18
- super_random.bytes(32) #~> ^\[\d+(, \d+){31}\]$
19
- # Example:
20
- # [142, 36, 107, 199, 1, 222, 69, 238, 130, 159, 236, 201, 199,
21
- # 33, 237, 166, 189, 166, 95, 246, 111, 103, 113, 126, 27, 31,
22
- # 244, 215, 200, 60, 255, 184]
23
-
24
- super_random.hexadecimal(32) #~> ^\h{64}$
25
- # Example:
26
- # "3e0dffe42c08b849dc3c1290e7aa87dff4ad3037b29694136786a4db1e3efab8"
27
-
28
- super_random.random_number(100.0) #~> ^\d{1,2}\.\d+$
29
- # Example:
30
- # 16.882225652425537
31
-
32
- super_random.random_number(100) #~> ^\d{1,2}$
33
- # Example:
34
- # 85
35
-
36
- # The "services" attribute gives the number of online services used.
37
- # It's possible for a service to fail.
38
- # Ultimately, SuperRandom uses SecureRandom as a failsafe.
39
- super_random.services #=> 5
11
+ SuperRandom combines three online real random services to create a more perfect random byte.
40
12
 
41
13
  ## INSTALL:
42
14
 
43
15
  $ gem install super_random
44
16
 
17
+ ## SYNOPSIS:
18
+
19
+ ```ruby
20
+ require 'super_random'
21
+ super_random = SuperRandom.new
22
+
23
+ super_random.bytes(32) #~> ^\[\d+(, \d+){31}\]$
24
+ # Example:
25
+ # [142, 36, 107, 199, 1, 222, 69, 238, 130, 159, 236, 201, 199,
26
+ # 33, 237, 166, 189, 166, 95, 246, 111, 103, 113, 126, 27, 31,
27
+ # 244, 215, 200, 60, 255, 184]
28
+
29
+ sleep 1 # rate limit to be nice
30
+ super_random.hexadecimal(32) #~> ^\h{64}$
31
+ # Example:
32
+ # "3e0dffe42c08b849dc3c1290e7aa87dff4ad3037b29694136786a4db1e3efab8"
33
+
34
+ sleep 1
35
+ super_random.random_number(100.0) #~> ^\d{1,2}\.\d+$
36
+ # Example:
37
+ # 16.882225652425537
38
+
39
+ sleep 1
40
+ super_random.random_number(100) #~> ^\d{1,2}$
41
+ # Example:
42
+ # 85
43
+
44
+ # The "services" attribute gives the number of online services used.
45
+ # It's possible for a service to fail.
46
+ # Ultimately, SuperRandom uses SecureRandom as a failsafe.
47
+ super_random.services #=> 3
48
+ super_random.randomness #=> 3.0
49
+ ```
50
+
45
51
  ## LICENSE:
46
52
 
47
53
  (The MIT License)
48
54
 
49
- Copyright (c) 2020 carlosjhr64
55
+ Copyright (c) 2021 carlosjhr64
50
56
 
51
57
  Permission is hereby granted, free of charge, to any person obtaining
52
58
  a copy of this software and associated documentation files (the
@@ -1,15 +1,15 @@
1
- class SuperRandom
2
- VERSION = '1.2.200123'
3
- end
4
-
5
1
  # Standard Libraries
6
2
  require 'timeout'
7
3
  require 'securerandom'
8
4
  require 'net/http'
9
5
  require 'json'
10
6
 
11
- # This Gem
12
- require 'super_random/super_random.rb'
7
+ class SuperRandom
8
+ VERSION = '2.0.210126'
9
+ # This Gem
10
+ require 'super_random/services'
11
+ require 'super_random/generator'
12
+ end
13
13
 
14
14
  # Requires:
15
15
  #`ruby`
@@ -0,0 +1,99 @@
1
+ class SuperRandom
2
+ DEFAULT_BYTES = 32
3
+
4
+ attr_accessor :first_timeout, :second_timeout, :nevermind
5
+ attr_reader :randomness, :services
6
+
7
+ def initialize
8
+ @first_timeout = 3
9
+ @second_timeout = 6
10
+ @nevermind = true
11
+ @randomness = 0.0
12
+ @services = 0
13
+ end
14
+
15
+ def bytes(n=DEFAULT_BYTES)
16
+ @randomness = 0.0
17
+ @services = 0
18
+
19
+ m = SuperRandom.services
20
+ a = Array.new m.length
21
+ t = Array.new m.length
22
+ m.each_with_index do |k,i|
23
+ t[i] = Thread.new{ a[i] = SuperRandom.send(k, n) }
24
+ end
25
+
26
+ begin
27
+ Timeout.timeout(@first_timeout) do
28
+ # Initially, would like to get them all.
29
+ t.each{_1.join}
30
+ end
31
+ rescue Timeout::Error
32
+ begin
33
+ Timeout.timeout(@second_timeout) do
34
+ # But at this point,
35
+ # would like to get at least one.
36
+ while a.all?{_1.nil?} and t.any?{_1.alive?}
37
+ Thread.pass
38
+ end
39
+ end
40
+ rescue Timeout::Error
41
+ # If we don't care that we got nothing, go on.
42
+ raise $! unless @nevermind
43
+ end
44
+ end
45
+
46
+ r = Array.new n
47
+ n.times{|i| r[i] = SecureRandom.random_number(256)}
48
+
49
+ a.each do |b|
50
+ next if b.nil?
51
+ l = b.length
52
+ @randomness += l.to_f/n.to_f
53
+ @services += 1
54
+ n.times{|i|r[i]=(r[i]+b[i%l])%256}
55
+ end
56
+
57
+ return r
58
+ end
59
+
60
+ def hexadecimal(n=DEFAULT_BYTES)
61
+ bytes(n).map{|i|i.to_s(16).rjust(2,'0')}.join
62
+ end
63
+
64
+ def random_number(scale=1.0, minbytes=6, maxbytes=[minbytes,DEFAULT_BYTES].max)
65
+ case scale
66
+ when Float
67
+ div = minbytes.times.inject(''){|s,i| s+'FF'}.to_i(16)
68
+ den = hexadecimal(minbytes).to_i(16)
69
+ return scale * den.to_f / div.to_f
70
+ when Integer
71
+ n = n0 = Math.log(scale, 256).ceil
72
+ e = e0 = 256**n
73
+ r = r0 = e0 % scale
74
+ while r > 0
75
+ n0 += 1
76
+ e0 *= 256
77
+ r0 = e0 % scale
78
+ if r0 <= r
79
+ # break if repeating pattern with big enough integer
80
+ break if r0 == r and n0 > minbytes
81
+ r,n,e = r0,n0,e0
82
+ end
83
+ break if n0 >= maxbytes
84
+ end
85
+ max = (e/scale)*scale
86
+ loop do
87
+ number = hexadecimal(n).to_i(16)
88
+ return number % scale if number < max
89
+ # On a relatively small chance that we're above max...
90
+ if @nevermind
91
+ warn "using SecureRandom.random_number(#{scale})"
92
+ return SecureRandom.random_number(scale)
93
+ end
94
+ end
95
+ end
96
+ raise "rand(scale Integer|Float)"
97
+ end
98
+ alias rand random_number
99
+ end
@@ -0,0 +1,45 @@
1
+ class SuperRandom
2
+ def self.services
3
+ [:quantum, :atmospheric, :hotbits]
4
+ end
5
+
6
+ # https://qrng.anu.edu.au/
7
+ # https://qrng.anu.edu.au/contact/api-documentation/
8
+ def self.quantum(n)
9
+ s = Net::HTTP.get(URI(
10
+ "https://qrng.anu.edu.au/API/jsonI.php?length=#{n}&type=uint8"))
11
+ a = JSON.parse(s)['data']
12
+ raise unless a.is_a?(Array) and a.length==n
13
+ raise unless a.all?{|i| i.is_a?(Integer) and i.between?(0,255)}
14
+ return a
15
+ rescue StandardError
16
+ warn "quantum (qrng.anu.edu.au) failed."
17
+ return nil
18
+ end
19
+
20
+ # https://www.random.org/
21
+ # https://www.random.org/integers/
22
+ def self.atmospheric(n)
23
+ s = Net::HTTP.get(URI(
24
+ "https://www.random.org/integers/?num=#{n}&min=0&max=255&col=1&base=10&format=plain&rnd=new"))
25
+ a = s.strip.split(/\s+/).map{|j|j.to_i}
26
+ raise unless a.length==n
27
+ raise unless a.all?{|i| i.between?(0,255)}
28
+ return a
29
+ rescue StandardError
30
+ warn "atmospheric (www.random.org) failed."
31
+ return nil
32
+ end
33
+
34
+ # https://www.fourmilab.ch/hotbits/
35
+ def self.hotbits(n, k='Pseudorandom')
36
+ s = Net::HTTP.get(URI(
37
+ "https://www.fourmilab.ch/cgi-bin/Hotbits.api?nbytes=#{n}&fmt=bin&apikey=#{k}"))
38
+ a = s.bytes
39
+ raise unless a.length==n
40
+ return a
41
+ rescue StandardError
42
+ warn "hotbits (www.fourmilab.ch) failed."
43
+ return nil
44
+ end
45
+ end
metadata CHANGED
@@ -1,19 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: super_random
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.200123
4
+ version: 2.0.210126
5
5
  platform: ruby
6
6
  authors:
7
7
  - carlosjhr64
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-23 00:00:00.000000000 Z
11
+ date: 2021-01-26 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  You can't get more random than random, but you can try really, really, really hard.
15
15
 
16
- SuperRandom combines five online real random services to create a more perfect random byte.
16
+ SuperRandom combines three online real random services to create a more perfect random byte.
17
17
  email: carlosjhr64@gmail.com
18
18
  executables: []
19
19
  extensions: []
@@ -21,12 +21,13 @@ extra_rdoc_files: []
21
21
  files:
22
22
  - README.md
23
23
  - lib/super_random.rb
24
- - lib/super_random/super_random.rb
24
+ - lib/super_random/generator.rb
25
+ - lib/super_random/services.rb
25
26
  homepage: https://github.com/carlosjhr64/super_random
26
27
  licenses:
27
28
  - MIT
28
29
  metadata: {}
29
- post_install_message:
30
+ post_install_message:
30
31
  rdoc_options: []
31
32
  require_paths:
32
33
  - lib
@@ -41,9 +42,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
41
42
  - !ruby/object:Gem::Version
42
43
  version: '0'
43
44
  requirements:
44
- - 'ruby: ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux]'
45
- rubygems_version: 3.1.2
46
- signing_key:
45
+ - 'ruby: ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux]'
46
+ rubygems_version: 3.2.3
47
+ signing_key:
47
48
  specification_version: 4
48
49
  summary: You can't get more random than random, but you can try really, really, really
49
50
  hard.
@@ -1,165 +0,0 @@
1
- class SuperRandom
2
- DEFAULT_BYTES = 32
3
-
4
- # http://qrng.anu.edu.au/index.php
5
- # https://qrng.anu.edu.au/API/api-demo.php
6
- def self.quantum(n)
7
- s = Net::HTTP.get(URI(
8
- "https://qrng.anu.edu.au/API/jsonI.php?length=#{n}&type=uint8"))
9
- a = JSON.parse(s)['data']
10
- raise unless a.is_a?(Array) and a.length==n
11
- raise unless a.all?{|i| i.is_a?(Integer) and i.between?(0,255)}
12
- return a
13
- rescue StandardError
14
- warn "quantum (qrng.anu.edu.au) failed."
15
- return nil
16
- end
17
-
18
- # https://www.random.org/
19
- # https://www.random.org/integers/
20
- def self.atmospheric(n)
21
- s = Net::HTTP.get(URI(
22
- "https://www.random.org/integers/?num=#{n}&min=0&max=255&col=1&base=10&format=plain&rnd=new"))
23
- a = s.strip.split(/\s+/).map{|j|j.to_i}
24
- raise unless a.length==n
25
- raise unless a.all?{|i| i.between?(0,255)}
26
- return a
27
- rescue StandardError
28
- warn "atmospheric (www.random.org) failed."
29
- return nil
30
- end
31
-
32
- # http://random.hd.org/
33
- # http://random.hd.org/getBits.jsp
34
- def self.entropy_pool(n)
35
- s = Net::HTTP.get(URI(
36
- "http://random.hd.org/getBits.jsp?numBytes=#{n}&type=bin"))
37
- a = s.bytes
38
- # As of the time of this writting, not guaranteed to get more than 8 bytes.
39
- raise unless (n>8)? a.length.between?(8,n) : a.length==n
40
- return a
41
- rescue StandardError
42
- warn "entropy_pool (random.hd.org) failed."
43
- return nil
44
- end
45
-
46
- # https://www.fourmilab.ch/hotbits/
47
- def self.hotbits(n, k='Pseudorandom')
48
- s = Net::HTTP.get(URI(
49
- "https://www.fourmilab.ch/cgi-bin/Hotbits.api?nbytes=#{n}&fmt=bin&apikey=#{k}"))
50
- a = s.bytes
51
- raise unless a.length==n
52
- return a
53
- rescue StandardError
54
- warn "hotbits (www.fourmilab.ch) failed."
55
- return nil
56
- end
57
-
58
- # http://www.randomnumbers.info
59
- def self.quantis(n)
60
- s = Net::HTTP.get(URI(
61
- "http://www.randomnumbers.info/cgibin/wqrng.cgi?amount=#{n}&limit=255"))
62
- a = s.scan( /\s\d\d?\d?\b/ ).map{|i| i.to_i}
63
- raise unless a.length == n and a.all?{|i| i.between?(0,255)}
64
- return a
65
- rescue
66
- warn "quantis (www.randomnumbers.info) failed."
67
- return nil
68
- end
69
-
70
- attr_accessor :first_timeout, :second_timeout, :nevermind
71
- attr_reader :randomness, :services
72
-
73
- def initialize
74
- @first_timeout = 3
75
- @second_timeout = 6
76
- @nevermind = true
77
- @randomness = 0.0
78
- @services = 0
79
- end
80
-
81
- def bytes(n=DEFAULT_BYTES)
82
- @randomness = 0.0
83
- @services = 0
84
-
85
- a1 = a2 = a3 = a4 = a5 = nil
86
-
87
- t1 = Thread.new{ a1 = SuperRandom.quantum(n)}
88
- t2 = Thread.new{ a2 = SuperRandom.atmospheric(n)}
89
- t3 = Thread.new{ a3 = SuperRandom.entropy_pool(n)}
90
- t4 = Thread.new{ a4 = SuperRandom.hotbits(n)}
91
- t5 = Thread.new{ a5 = SuperRandom.quantis(n)}
92
-
93
- begin
94
- Timeout.timeout(@first_timeout) do
95
- # Initially, would like to get them all.
96
- t1.join and t2.join and t3.join and t4.join and t5.join
97
- end
98
- rescue Timeout::Error
99
- begin
100
- Timeout.timeout(@second_timeout) do
101
- # But at this point,
102
- # would like to get at least one.
103
- while [a1,a2,a3,a4,a5].all?{|a|a.nil?} and [t1,t2,t3,t4,t5].any?{|t|t.alive?}
104
- Thread.pass
105
- end
106
- end
107
- rescue Timeout::Error
108
- # If we don't care that we got nothing, go on.
109
- raise $! unless @nevermind
110
- end
111
- end
112
-
113
- a = n.times.inject([]){|b,i|b.push(SecureRandom.random_number(256))}
114
- [a1, a2, a3, a4, a5].each do |b|
115
- if b
116
- bl = b.length
117
- @randomness += bl.to_f/n.to_f
118
- @services += 1
119
- n.times{|i|a[i]=(a[i]+b[i%bl])%256}
120
- end
121
- end
122
-
123
- return a
124
- end
125
-
126
- def hexadecimal(n=DEFAULT_BYTES)
127
- bytes(n).map{|i|i.to_s(16).rjust(2,'0')}.join
128
- end
129
-
130
- def random_number(scale=1.0, minbytes=6, maxbytes=[minbytes,DEFAULT_BYTES].max)
131
- case scale
132
- when Float
133
- div = minbytes.times.inject(''){|s,i| s+'FF'}.to_i(16)
134
- den = hexadecimal(minbytes).to_i(16)
135
- return scale * den.to_f / div.to_f
136
- when Integer
137
- n = n0 = Math.log(scale, 256).ceil
138
- e = e0 = 256**n
139
- r = r0 = e0 % scale
140
- while r > 0
141
- n0 += 1
142
- e0 *= 256
143
- r0 = e0 % scale
144
- if r0 <= r
145
- # break if repeating pattern with big enough integer
146
- break if r0 == r and n0 > minbytes
147
- r,n,e = r0,n0,e0
148
- end
149
- break if n0 >= maxbytes
150
- end
151
- max = (e/scale)*scale
152
- loop do
153
- number = hexadecimal(n).to_i(16)
154
- return number % scale if number < max
155
- # On a relatively small chance that we're above max...
156
- if @nevermind
157
- warn "using SecureRandom.random_number(#{scale})"
158
- return SecureRandom.random_number(scale)
159
- end
160
- end
161
- end
162
- raise "rand(scale Integer|Float)"
163
- end
164
- alias rand random_number
165
- end