diff --git a/spec/std/random_spec.cr b/spec/std/random_spec.cr index 450c5040f4ca..3895aff8903f 100644 --- a/spec/std/random_spec.cr +++ b/spec/std/random_spec.cr @@ -190,6 +190,18 @@ describe "Random" do end describe "random_bytes" do + it "generates random bytes" do + rng = TestRNG.new([0xfa19443eu32, 1u32, 0x12345678u32]) + rng.random_bytes(9).should eq Bytes[0x3e, 0x44, 0x19, 0xfa, 1, 0, 0, 0, 0x78] + rng.random_bytes(1).should eq Bytes[0x3e] + rng.random_bytes(4).should eq Bytes[1, 0, 0, 0] + rng.random_bytes(3).should eq Bytes[0x78, 0x56, 0x34] + rng.random_bytes(0).should eq Bytes.new(0) + + rng = TestRNG.new([12u8, 255u8, 11u8, 5u8, 122u8, 200u8, 192u8]) + rng.random_bytes(7).should eq Bytes[12, 255, 11, 5, 122, 200, 192] + end + it "gets random bytes with default number of digits" do bytes = TestRNG.new(RNG_DATA_32).random_bytes bytes.size.should eq(16) diff --git a/src/random.cr b/src/random.cr index 80de6b2b745d..117582daff53 100644 --- a/src/random.cr +++ b/src/random.cr @@ -302,19 +302,17 @@ module Random # slice # => [217, 118, 38, 196] # ``` def random_bytes(buf : Bytes) : Nil - n = buf.size / sizeof(typeof(next_u)) - remaining = buf.size - n * sizeof(typeof(next_u)) - - slice = buf.to_unsafe.as(typeof(next_u)*).to_slice(n) - slice.each_index { |i| slice[i] = next_u } - - if remaining > 0 - bytes = next_u - remaining.times do |i| - bits = i * 8 - mask = typeof(next_u).new(0xff << bits) - buf[-i - 1] = UInt8.new((bytes & mask) >> bits) + ptr = buf.to_unsafe + finish = buf.to_unsafe + buf.size + + while ptr < finish + random = next_u + rand_ptr = pointerof(random).as(UInt8*) + if IO::ByteFormat::SystemEndian != IO::ByteFormat::LittleEndian + rand_ptr.to_slice(sizeof(typeof(next_u))).reverse! end + rand_ptr.copy_to(ptr, {finish - ptr, sizeof(typeof(next_u))}.min) + ptr += sizeof(typeof(next_u)) end end