securerandom 0.2.2 → 0.3.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ae0b7af17b7e1ae5e5538a9faf771856d7052e570dd2edb7f3876b44ff73caa
4
- data.tar.gz: 99bbfb8ac5dfa0f2089e4b8ab18a9dcf3628bb1b2564778b14045056e6473879
3
+ metadata.gz: 6f14853630e9280f98e432e1da48fd1eb894a7376c4e3678dc97639e28929c3d
4
+ data.tar.gz: 79846163a70d7b0198271a61ce63a7320c9a141dd59d0912a91e9a5259353999
5
5
  SHA512:
6
- metadata.gz: 5a6b61eecc2cf9681ea54abc84909635dca596e1ff453c5af84e75e87b042345e5d9b55f30a99149c61f7407e9238993dbc836efc9feb03067cb0538770cfa5d
7
- data.tar.gz: c458cecffdea575d9eea0ec41341520d1465d359dda792b8448149a5c32b6e76ccf8f85074c919a97d916dfe379e41f97d461e5dd242a155708808cf99dc7e07
6
+ metadata.gz: 7d448c439592c67f07e543c855fa4c06e6da72ce84d31ade33ea97d76d5ee90952b575c938a34bf8e11453353920582d0d5311cf9212b6ba7397fa3d038bc2e5
7
+ data.tar.gz: c3080d88c1a11a88ca3a28ddc6e173ab5afbf6027d60c353263ed9f78b8982a55dcc15c4a88cc3f2a44ba6e8a5933d7283af91b2f38965f67ebd68e636d78922
@@ -4,10 +4,10 @@ Redistribution and use in source and binary forms, with or without
4
4
  modification, are permitted provided that the following conditions
5
5
  are met:
6
6
  1. Redistributions of source code must retain the above copyright
7
- notice, this list of conditions and the following disclaimer.
7
+ notice, this list of conditions and the following disclaimer.
8
8
  2. Redistributions in binary form must reproduce the above copyright
9
- notice, this list of conditions and the following disclaimer in the
10
- documentation and/or other materials provided with the distribution.
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
11
 
12
12
  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
13
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
data/COPYING ADDED
@@ -0,0 +1,56 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the
3
+ 2-clause BSDL (see the file BSDL), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a. place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b. use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c. give non-standard binaries non-standard names, with
21
+ instructions on where to get the original software distribution.
22
+
23
+ d. make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or binary form,
26
+ provided that you do at least ONE of the following:
27
+
28
+ a. distribute the binaries and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b. accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c. give non-standard binaries non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d. make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under these terms.
43
+
44
+ For the list of those files and their copying conditions, see the
45
+ file LEGAL.
46
+
47
+ 5. The scripts and library files supplied as input to or produced as
48
+ output from the software do not automatically fall under the
49
+ copyright of the software, but belong to whomever generated them,
50
+ and may be sold commercially, and may be aggregated with this
51
+ software.
52
+
53
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
54
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
55
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56
+ PURPOSE.
@@ -165,15 +165,133 @@ module Random::Formatter
165
165
  #
166
166
  # The result contains 122 random bits (15.25 random bytes).
167
167
  #
168
- # See RFC4122[https://datatracker.ietf.org/doc/html/rfc4122] for details of UUID.
168
+ # See RFC9562[https://www.rfc-editor.org/rfc/rfc9562] for details of UUIDv4.
169
169
  #
170
170
  def uuid
171
- ary = random_bytes(16).unpack("NnnnnN")
172
- ary[2] = (ary[2] & 0x0fff) | 0x4000
173
- ary[3] = (ary[3] & 0x3fff) | 0x8000
174
- "%08x-%04x-%04x-%04x-%04x%08x" % ary
171
+ ary = random_bytes(16)
172
+ ary.setbyte(6, (ary.getbyte(6) & 0x0f) | 0x40)
173
+ ary.setbyte(8, (ary.getbyte(8) & 0x3f) | 0x80)
174
+ ary.unpack("H8H4H4H4H12").join(?-)
175
175
  end
176
176
 
177
+ alias uuid_v4 uuid
178
+
179
+ # Generate a random v7 UUID (Universally Unique IDentifier).
180
+ #
181
+ # require 'random/formatter'
182
+ #
183
+ # Random.uuid_v7 # => "0188d4c3-1311-7f96-85c7-242a7aa58f1e"
184
+ # Random.uuid_v7 # => "0188d4c3-16fe-744f-86af-38fa04c62bb5"
185
+ # Random.uuid_v7 # => "0188d4c3-1af8-764f-b049-c204ce0afa23"
186
+ # Random.uuid_v7 # => "0188d4c3-1e74-7085-b14f-ef6415dc6f31"
187
+ # # |<--sorted-->| |<----- random ---->|
188
+ #
189
+ # # or
190
+ # prng = Random.new
191
+ # prng.uuid_v7 # => "0188ca51-5e72-7950-a11d-def7ff977c98"
192
+ #
193
+ # The version 7 UUID starts with the least significant 48 bits of a 64 bit
194
+ # Unix timestamp (milliseconds since the epoch) and fills the remaining bits
195
+ # with random data, excluding the version and variant bits.
196
+ #
197
+ # This allows version 7 UUIDs to be sorted by creation time. Time ordered
198
+ # UUIDs can be used for better database index locality of newly inserted
199
+ # records, which may have a significant performance benefit compared to random
200
+ # data inserts.
201
+ #
202
+ # The result contains 74 random bits (9.25 random bytes).
203
+ #
204
+ # Note that this method cannot be made reproducible because its output
205
+ # includes not only random bits but also timestamp.
206
+ #
207
+ # See RFC9562[https://www.rfc-editor.org/rfc/rfc9562] for details of UUIDv7.
208
+ #
209
+ # ==== Monotonicity
210
+ #
211
+ # UUIDv7 has millisecond precision by default, so multiple UUIDs created
212
+ # within the same millisecond are not issued in monotonically increasing
213
+ # order. To create UUIDs that are time-ordered with sub-millisecond
214
+ # precision, up to 12 bits of additional timestamp may added with
215
+ # +extra_timestamp_bits+. The extra timestamp precision comes at the expense
216
+ # of random bits. Setting <tt>extra_timestamp_bits: 12</tt> provides ~244ns
217
+ # of precision, but only 62 random bits (7.75 random bytes).
218
+ #
219
+ # prng = Random.new
220
+ # Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 12) }
221
+ # # =>
222
+ # ["0188d4c7-13da-74f9-8b53-22a786ffdd5a",
223
+ # "0188d4c7-13da-753b-83a5-7fb9b2afaeea",
224
+ # "0188d4c7-13da-754a-88ea-ac0baeedd8db",
225
+ # "0188d4c7-13da-7557-83e1-7cad9cda0d8d"]
226
+ # # |<--- sorted --->| |<-- random --->|
227
+ #
228
+ # Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 8) }
229
+ # # =>
230
+ # ["0188d4c7-3333-7a95-850a-de6edb858f7e",
231
+ # "0188d4c7-3333-7ae8-842e-bc3a8b7d0cf9", # <- out of order
232
+ # "0188d4c7-3333-7ae2-995a-9f135dc44ead", # <- out of order
233
+ # "0188d4c7-3333-7af9-87c3-8f612edac82e"]
234
+ # # |<--- sorted -->||<---- random --->|
235
+ #
236
+ # Any rollbacks of the system clock will break monotonicity. UUIDv7 is based
237
+ # on UTC, which excludes leap seconds and can rollback the clock. To avoid
238
+ # this, the system clock can synchronize with an NTP server configured to use
239
+ # a "leap smear" approach. NTP or PTP will also be needed to synchronize
240
+ # across distributed nodes.
241
+ #
242
+ # Counters and other mechanisms for stronger guarantees of monotonicity are
243
+ # not implemented. Applications with stricter requirements should follow
244
+ # {Section 6.2}[https://www.rfc-editor.org/rfc/rfc9562.html#name-monotonicity-and-counters]
245
+ # of the specification.
246
+ #
247
+ def uuid_v7(extra_timestamp_bits: 0)
248
+ case (extra_timestamp_bits = Integer(extra_timestamp_bits))
249
+ when 0 # min timestamp precision
250
+ ms = Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
251
+ rand = random_bytes(10)
252
+ rand.setbyte(0, rand.getbyte(0) & 0x0f | 0x70) # version
253
+ rand.setbyte(2, rand.getbyte(2) & 0x3f | 0x80) # variant
254
+ "%08x-%04x-%s" % [
255
+ (ms & 0x0000_ffff_ffff_0000) >> 16,
256
+ (ms & 0x0000_0000_0000_ffff),
257
+ rand.unpack("H4H4H12").join("-")
258
+ ]
259
+
260
+ when 12 # max timestamp precision
261
+ ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
262
+ .divmod(1_000_000)
263
+ extra_bits = ns * 4096 / 1_000_000
264
+ rand = random_bytes(8)
265
+ rand.setbyte(0, rand.getbyte(0) & 0x3f | 0x80) # variant
266
+ "%08x-%04x-7%03x-%s" % [
267
+ (ms & 0x0000_ffff_ffff_0000) >> 16,
268
+ (ms & 0x0000_0000_0000_ffff),
269
+ extra_bits,
270
+ rand.unpack("H4H12").join("-")
271
+ ]
272
+
273
+ when (0..12) # the generic version is slower than the special cases above
274
+ rand_a, rand_b1, rand_b2, rand_b3 = random_bytes(10).unpack("nnnN")
275
+ rand_mask_bits = 12 - extra_timestamp_bits
276
+ ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
277
+ .divmod(1_000_000)
278
+ "%08x-%04x-%04x-%04x-%04x%08x" % [
279
+ (ms & 0x0000_ffff_ffff_0000) >> 16,
280
+ (ms & 0x0000_0000_0000_ffff),
281
+ 0x7000 |
282
+ ((ns * (1 << extra_timestamp_bits) / 1_000_000) << rand_mask_bits) |
283
+ rand_a & ((1 << rand_mask_bits) - 1),
284
+ 0x8000 | (rand_b1 & 0x3fff),
285
+ rand_b2,
286
+ rand_b3
287
+ ]
288
+
289
+ else
290
+ raise ArgumentError, "extra_timestamp_bits must be in 0..12"
291
+ end
292
+ end
293
+
294
+ # Internal interface to Random; Generate random data _n_ bytes.
177
295
  private def gen_random(n)
178
296
  self.bytes(n)
179
297
  end
@@ -221,16 +339,20 @@ module Random::Formatter
221
339
  result
222
340
  end
223
341
 
342
+ # The default character list for #alphanumeric.
224
343
  ALPHANUMERIC = [*'A'..'Z', *'a'..'z', *'0'..'9']
344
+
225
345
  # Generate a random alphanumeric string.
226
346
  #
227
347
  # The argument _n_ specifies the length, in characters, of the alphanumeric
228
348
  # string to be generated.
349
+ # The argument _chars_ specifies the character list which the result is
350
+ # consist of.
229
351
  #
230
352
  # If _n_ is not specified or is nil, 16 is assumed.
231
353
  # It may be larger in the future.
232
354
  #
233
- # The result may contain A-Z, a-z and 0-9.
355
+ # The result may contain A-Z, a-z and 0-9, unless _chars_ is specified.
234
356
  #
235
357
  # require 'random/formatter'
236
358
  #
@@ -238,8 +360,13 @@ module Random::Formatter
238
360
  # # or
239
361
  # prng = Random.new
240
362
  # prng.alphanumeric(10) #=> "i6K93NdqiH"
241
- def alphanumeric(n=nil)
363
+ #
364
+ # Random.alphanumeric(4, chars: [*"0".."9"]) #=> "2952"
365
+ # # or
366
+ # prng = Random.new
367
+ # prng.alphanumeric(10, chars: [*"!".."/"]) #=> ",.,++%/''."
368
+ def alphanumeric(n = nil, chars: ALPHANUMERIC)
242
369
  n = 16 if n.nil?
243
- choose(ALPHANUMERIC, n)
370
+ choose(chars, n)
244
371
  end
245
372
  end
data/lib/securerandom.rb CHANGED
@@ -39,28 +39,28 @@ require 'random/formatter'
39
39
  # +NotImplementedError+ is raised.
40
40
 
41
41
  module SecureRandom
42
+
43
+ # The version
44
+ VERSION = "0.3.2"
45
+
42
46
  class << self
47
+ # Returns a random binary string containing +size+ bytes.
48
+ #
49
+ # See Random.bytes
43
50
  def bytes(n)
44
51
  return gen_random(n)
45
52
  end
46
53
 
47
54
  private
48
55
 
56
+ # :stopdoc:
57
+
58
+ # Implementation using OpenSSL
49
59
  def gen_random_openssl(n)
50
- @pid = 0 unless defined?(@pid)
51
- pid = $$
52
- unless @pid == pid
53
- now = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
54
- OpenSSL::Random.random_add([now, @pid, pid].join(""), 0.0)
55
- seed = Random.urandom(16)
56
- if (seed)
57
- OpenSSL::Random.random_add(seed, 16)
58
- end
59
- @pid = pid
60
- end
61
60
  return OpenSSL::Random.random_bytes(n)
62
61
  end
63
62
 
63
+ # Implementation using system random device
64
64
  def gen_random_urandom(n)
65
65
  ret = Random.urandom(n)
66
66
  unless ret
@@ -86,6 +86,9 @@ module SecureRandom
86
86
  end
87
87
  end
88
88
 
89
+ # :startdoc:
90
+
91
+ # Generate random data bytes for Random::Formatter
89
92
  public :gen_random
90
93
  end
91
94
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: securerandom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanaka Akira
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-14 00:00:00.000000000 Z
11
+ date: 2024-11-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Interface for secure random number generator.
14
14
  email:
@@ -17,19 +17,11 @@ executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
- - ".github/dependabot.yml"
21
- - ".github/workflows/test.yml"
22
- - ".gitignore"
23
- - Gemfile
24
- - LICENSE.txt
20
+ - BSDL
21
+ - COPYING
25
22
  - README.md
26
- - Rakefile
27
- - bin/console
28
- - bin/setup
29
23
  - lib/random/formatter.rb
30
24
  - lib/securerandom.rb
31
- - rakelib/epoch.rake
32
- - securerandom.gemspec
33
25
  homepage: https://github.com/ruby/securerandom
34
26
  licenses:
35
27
  - Ruby
@@ -37,7 +29,7 @@ licenses:
37
29
  metadata:
38
30
  homepage_uri: https://github.com/ruby/securerandom
39
31
  source_code_uri: https://github.com/ruby/securerandom
40
- post_install_message:
32
+ post_install_message:
41
33
  rdoc_options: []
42
34
  require_paths:
43
35
  - lib
@@ -52,8 +44,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
52
44
  - !ruby/object:Gem::Version
53
45
  version: '0'
54
46
  requirements: []
55
- rubygems_version: 3.4.0.dev
56
- signing_key:
47
+ rubygems_version: 3.5.11
48
+ signing_key:
57
49
  specification_version: 4
58
50
  summary: Interface for secure random number generator.
59
51
  test_files: []
@@ -1,6 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: 'github-actions'
4
- directory: '/'
5
- schedule:
6
- interval: 'weekly'
@@ -1,22 +0,0 @@
1
- name: build
2
-
3
- on: [push, pull_request]
4
-
5
- jobs:
6
- build:
7
- name: build (${{ matrix.ruby }} / ${{ matrix.os }})
8
- strategy:
9
- matrix:
10
- ruby: [ head, '3.0', '2.7', '2.6' ]
11
- os: [ ubuntu-latest, macos-latest, windows-latest ]
12
- runs-on: ${{ matrix.os }}
13
- steps:
14
- - uses: actions/checkout@v3
15
- - name: Set up Ruby
16
- uses: ruby/setup-ruby@v1
17
- with:
18
- ruby-version: ${{ matrix.ruby }}
19
- - name: Install dependencies
20
- run: bundle install
21
- - name: Run test
22
- run: rake test
data/.gitignore DELETED
@@ -1,8 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem "rake"
4
- gem "test-unit"
data/Rakefile DELETED
@@ -1,10 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
3
-
4
- Rake::TestTask.new(:test) do |t|
5
- t.libs << "test"
6
- t.libs << "lib"
7
- t.test_files = FileList["test/**/test_*.rb"]
8
- end
9
-
10
- task :default => :test
data/bin/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "securerandom"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
data/rakelib/epoch.rake DELETED
@@ -1,5 +0,0 @@
1
- task "build" => "date_epoch"
2
-
3
- task "date_epoch" do
4
- ENV["SOURCE_DATE_EPOCH"] = IO.popen(%W[git -C #{__dir__} log -1 --format=%ct], &:read).chomp
5
- end
data/securerandom.gemspec DELETED
@@ -1,22 +0,0 @@
1
- Gem::Specification.new do |spec|
2
- spec.name = "securerandom"
3
- spec.version = "0.2.2"
4
- spec.authors = ["Tanaka Akira"]
5
- spec.email = ["akr@fsij.org"]
6
-
7
- spec.summary = %q{Interface for secure random number generator.}
8
- spec.description = %q{Interface for secure random number generator.}
9
- spec.homepage = "https://github.com/ruby/securerandom"
10
- spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
11
- spec.licenses = ["Ruby", "BSD-2-Clause"]
12
-
13
- spec.metadata["homepage_uri"] = spec.homepage
14
- spec.metadata["source_code_uri"] = spec.homepage
15
-
16
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
17
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
- end
19
- spec.bindir = "exe"
20
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
- spec.require_paths = ["lib"]
22
- end