Skip to content

Commit

Permalink
use math/rand/v2's fisher-yates impl. pretty sure the one copied from…
Browse files Browse the repository at this point in the history
… dcrd code introduces bias
  • Loading branch information
jrick committed Jun 13, 2024
1 parent 7c01f86 commit aab8903
Showing 1 changed file with 12 additions and 3 deletions.
15 changes: 12 additions & 3 deletions crypto/rand/uniform.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,18 @@ func (p *PRNG) Duration(n time.Duration) time.Duration {
// Shuffle randomizes the order of n elements by swapping the elements at
// indexes i and j.
func (p *PRNG) Shuffle(n int, swap func(i, j int)) {
// Fisher-Yates shuffle.
for i := int64(0); i < int64(n); i++ {
j := p.Int64n(int64(n)-i) + i
if n < 0 {
panic("rand: invalid argument to Shuffle")
}

// Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
// Shuffle really ought not be called with n that doesn't fit in 32 bits.
// Not only will it take a very long time, but with 2³¹! possible permutations,
// there's no way that any PRNG can have a big enough internal state to
// generate even a minuscule percentage of the possible permutations.
// Nevertheless, the right API signature accepts an int n, so handle it as best we can.
for i := n - 1; i > 0; i-- {
j := int(p.Uint64n(uint64(i + 1)))
swap(int(i), int(j))
}
}

0 comments on commit aab8903

Please sign in to comment.