-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Random::ISAAC: fix initial seed #7977
Conversation
it "different instances generate different numbers (#7976)" do | ||
isaacs = Array.new(1000) { Random::ISAAC.new } | ||
values = isaacs.map(&.rand(10_000_000)) | ||
values.uniq.size.should be > 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This spec might fail, but it's veeeeery unlikely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any other way to test this? Otherwise I can remove the test altogether.
What about an uninitialized That would spare 7 unbuffered reads from urandom (or 7 calls to getrandom, arc4random, ...) yet fix the issue, wouldn't it? |
I think so, yes, but to do that we need to use "unsafe_as". I wanted to avoid unsafe code. But I'll try it anyway. Another idea is to have such code in Secure::Random, somehow, so that it's unsafe but in a single place. |
4fcdc1b
to
f9d82cf
Compare
Updated! I added a general Then I used that method in the initialization of In the future I'd also like to be able to do |
I'll do it differently. |
f9d82cf
to
b99133d
Compare
Added more things and implemented it in a way that's easier to read in docs (now there's one overload per static array type). Also added the ability to do |
35cbc08
to
c31f080
Compare
# rand({{type}}) # => {{values[0].id}} | ||
# ``` | ||
def rand(type : {{type}}.class) : {{type}} | ||
rand_type_from_bytes(type) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's strange to have a separate implementation for this when rand(type::MIN..type::MAX)
works fine.
Also kind of funny that random_bytes
unrolls integers into bytes (and inverts for endinanness) and then this rolls them back into an integer (without inverting for endianness - though double-inverting would also be weird).
So yes, this implementation is endianness-dependent, unlike everything else.
And then, just by coincidence,
Random.new(x).rand(Int32::MIN..Int32::MAX) == Random.new(x).rand(Int32)
but
Random.new(x).rand(Int64::MIN..Int64::MAX) != Random.new(x).rand(Int64)
Fixes #7976
In the old code
unsafe_as
returned a copy of the static array and so it was initializing something else other than what was returned.