Skip to content
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

crypto/rand: rand.Int consumes and wastes a large percentage of bytes #18165

Closed
wadey opened this issue Dec 2, 2016 · 7 comments
Closed

crypto/rand: rand.Int consumes and wastes a large percentage of bytes #18165

wadey opened this issue Dec 2, 2016 · 7 comments
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@wadey
Copy link
Contributor

wadey commented Dec 2, 2016

go1.7.3

calling rand.Int(rand.Reader, 256) should only consume 1 byte from the reader to provide a random number from 0-255. Instead it consumes at least 2 bytes and on average 4 bytes. This means that 300% extra bytes are read from the random source. If the cryptographic random source is expensive, this is a lot of wasted reads.

The issue is an off-by-one error when selecting how many bytes are necessary to read from the source. For max=256, only 1 byte should be read as any bit still set in the extra byte after filtering will cause the function to re-run anyways (it will be greater than or equal to the max).

examples for the common cases of reading a random int8, int16 and int32:
https://play.golang.org/p/gWXjn51ehn

The off-by-one error is here (should be equivalent of (max-1).BitLen()): https://github.com/golang/go/blob/go1.7.4/src/crypto/rand/util.go#L110

@bradfitz bradfitz added this to the Go1.9 milestone Dec 2, 2016
@wadey
Copy link
Contributor Author

wadey commented Dec 2, 2016

A better way to word this might be that 75% of the bytes read from the source are wasted unnecessarily. To generate 1,000 random bytes, 4,000 bytes are read from the random source.

@robpike
Copy link
Contributor

robpike commented Dec 2, 2016

See also https://go-review.googlesource.com/c/10161/. I am planning to push on it a bit. It probably won't go in the core as it stands, but might become available as an alternative, or just stay in exp. Better properties across the board, at least potentially, yet has fundamentally the same interface.

Will need some assembly language to increase the entropy of the source, but it's been "abandoned" for now to avoid confusing people.

@bradfitz bradfitz added the NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. label May 22, 2017
@bradfitz
Copy link
Contributor

@robpike, @rsc, can you decide whether this is fixable within the spirit of go1compat? Or is this just Unfortunate?

@wadey
Copy link
Contributor Author

wadey commented May 22, 2017

I have a patch that fixes the off by 1 that I can submit for review if there is interest in merging this.

@bradfitz bradfitz added NeedsFix The path to resolution is known, but the work has not been done. and removed NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. labels May 22, 2017
@rsc
Copy link
Contributor

rsc commented May 22, 2017

crypto/rand not math/rand so no compatibility problem. But also "if the cryptographic random source is expensive" seems not to be true, right? We use /dev/urandom.

@wadey
Copy link
Contributor Author

wadey commented May 23, 2017

I've submitted my patch here: https://go-review.googlesource.com/c/43891/

@gopherbot
Copy link

CL https://golang.org/cl/43891 mentions this issue.

wadey added a commit to wadey/cryptorand that referenced this issue Feb 20, 2018
The test relies on this fix:

- golang/go#18165
@golang golang locked and limited conversation to collaborators May 23, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

5 participants