require "crystal/system/random" # `Random::Secure` generates random numbers from a secure source provided by the system. # # It uses a [cryptographically secure pseudorandom number generator (CSPRNG)](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) # for cryptography and secure usages such as generating secret keys, or to seed # another pseudorandom number generator (PRNG). # # ``` # Random::Secure.rand(6) # => 4 # [1, 5, 6].shuffle(Random::Secure) # => [6, 1, 5] # ``` # # On BSD-based systems and macOS/Darwin, it uses [`arc4random`](https://man.openbsd.org/arc4random), # on Linux [`getrandom`](http://man7.org/linux/man-pages/man2/getrandom.2.html), # on Windows [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom), # and falls back to reading from `/dev/urandom` on UNIX systems. module Random::Secure extend Random extend self def next_u Crystal::System::Random.next_u end def random_bytes(buf : Bytes) : Nil Crystal::System::Random.random_bytes(buf) end {% for type in [UInt8, UInt16, UInt32, UInt64, UInt128] %} # Generates a random integer of a given type. The number of bytes to # generate can be limited; by default it will generate as many bytes as # needed to fill the integer size. private def rand_type(type : {{type}}.class, needed_parts = nil) : {{type}} needed_bytes = if needed_parts needed_parts * sizeof(typeof(next_u)) else sizeof({{type}}) end buf = uninitialized UInt8[sizeof({{type}})] if needed_bytes < sizeof({{type}}) bytes = Slice.new(buf.to_unsafe, needed_bytes) random_bytes(bytes) bytes.reduce({{type}}.new(0)) do |result, byte| (result << 8) | byte end else random_bytes(buf.to_slice) buf.unsafe_as({{type}}) end end {% end %} {% for type in [Int8, Int16, Int32, Int64, Int128] %} private def rand_type(type : {{type}}.class, needed_bytes = sizeof({{type}})) : {{type}} result = rand_type({{"U#{type}".id}}, needed_bytes) {{type}}.new!(result) end {% end %} end