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

Update Shuffle Function to Swap-or-not #1643

Closed
wants to merge 61 commits into from
Closed
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
f7a4b2f
testing swapornotshuffle
cyberbono3 Feb 11, 2019
a741e65
list 1 and 2 were incorrectly shuffled
cyberbono3 Feb 13, 2019
e3edd50
testing swapornotshuffle
cyberbono3 Feb 11, 2019
31c53ce
panic index out of range
cyberbono3 Feb 13, 2019
2159e4a
list 1 and 2 were incorrectly shuffled
cyberbono3 Feb 13, 2019
b8eb65b
multiple tests failed due to timeout
cyberbono3 Feb 17, 2019
e57c0b6
tests fail with timeout errors
cyberbono3 Feb 17, 2019
23b43c2
GetPermutedIndex modification
cyberbono3 Feb 20, 2019
e87f6f8
GetPermutedIndex
cyberbono3 Feb 22, 2019
9a077b4
shuffleIndices and 9 tests fail locally
cyberbono3 Feb 22, 2019
046614d
shuffleIndices debugging
cyberbono3 Feb 22, 2019
66f0b12
shuffleIndices
cyberbono3 Feb 25, 2019
40fbbe7
testing swapornotshuffle
cyberbono3 Feb 11, 2019
dbb3c62
list 1 and 2 were incorrectly shuffled
cyberbono3 Feb 13, 2019
ed15da3
testing swapornotshuffle
cyberbono3 Feb 11, 2019
9b51ff5
panic index out of range
cyberbono3 Feb 13, 2019
69da5b1
list 1 and 2 were incorrectly shuffled
cyberbono3 Feb 13, 2019
01930cb
multiple tests failed due to timeout
cyberbono3 Feb 17, 2019
95e8084
tests fail with timeout errors
cyberbono3 Feb 17, 2019
988e87a
GetPermutedIndex modification
cyberbono3 Feb 20, 2019
9e12c00
shuffleIndices and 9 tests fail locally
cyberbono3 Feb 22, 2019
0fb0523
shuffleIndices debugging
cyberbono3 Feb 22, 2019
5e56b15
rebased + conflicts resolved
cyberbono3 Feb 26, 2019
2915917
ready for review
cyberbono3 Feb 26, 2019
7cdc6c5
testing swapornotshuffle
cyberbono3 Feb 11, 2019
9b65615
list 1 and 2 were incorrectly shuffled
cyberbono3 Feb 13, 2019
9a95940
testing swapornotshuffle
cyberbono3 Feb 11, 2019
bf4089b
panic index out of range
cyberbono3 Feb 13, 2019
6e1f979
list 1 and 2 were incorrectly shuffled
cyberbono3 Feb 13, 2019
fd0f01d
multiple tests failed due to timeout
cyberbono3 Feb 17, 2019
2ffddf1
tests fail with timeout errors
cyberbono3 Feb 17, 2019
95312e4
GetPermutedIndex modification
cyberbono3 Feb 20, 2019
e81c0ed
shuffleIndices and 9 tests fail locally
cyberbono3 Feb 22, 2019
cf30fce
shuffleIndices debugging
cyberbono3 Feb 22, 2019
e094231
testing swapornotshuffle
cyberbono3 Feb 11, 2019
e401cc9
list 1 and 2 were incorrectly shuffled
cyberbono3 Feb 13, 2019
a40c884
testing swapornotshuffle
cyberbono3 Feb 11, 2019
9e4e76a
panic index out of range
cyberbono3 Feb 13, 2019
267cc3b
list 1 and 2 were incorrectly shuffled
cyberbono3 Feb 13, 2019
122c325
multiple tests failed due to timeout
cyberbono3 Feb 17, 2019
b020492
tests fail with timeout errors
cyberbono3 Feb 17, 2019
37db9c4
GetPermutedIndex modification
cyberbono3 Feb 20, 2019
057c5c8
shuffleIndices and 9 tests fail locally
cyberbono3 Feb 22, 2019
c88f30e
shuffleIndices debugging
cyberbono3 Feb 22, 2019
ac631df
rebased and conflicts resolved
cyberbono3 Feb 26, 2019
5b3c156
6 tests fail , still debugging
cyberbono3 Feb 27, 2019
454b217
6 tests fail and still debugging
cyberbono3 Feb 27, 2019
653be75
Merge commit 'refs/pull/1643/head' of https://github.com/prysmaticlab…
nisdas Mar 1, 2019
cd5ca0b
fix shuffle
nisdas Mar 1, 2019
a3b2eb6
fix shuffle for overflows and fix
nisdas Mar 1, 2019
79c6b58
Merge branch 'master' into swapshuffle
nisdas Mar 1, 2019
626c121
change back rounds
nisdas Mar 1, 2019
e12ee69
Merge branch 'master' into swapshuffle
prestonvanloon Mar 1, 2019
2a51ea5
Fixing tests in progress
cyberbono3 Mar 3, 2019
a1bcef1
Fix up some of the shuffling
Mar 5, 2019
d2d09ad
Fixing tests in progress yaml_test.go:21: Failed to run yaml tests ch…
cyberbono3 Mar 3, 2019
71e7edb
Undo a few unneeded changes
Mar 5, 2019
b09cc25
Merge branch 'swapshuffle' of https://github.com/cyberbono3/prysm int…
Mar 5, 2019
6fb60ec
Make more changes for optimizations and corrections
Mar 5, 2019
73558ff
Merge branch 'master' of https://github.com/prysmaticlabs/prysm into …
Mar 5, 2019
22ce764
Change 0x7 to 8 to prevent errors
Mar 5, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion beacon-chain/utils/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ go_library(
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//shared/hashutil:go_default_library",
"//shared/params:go_default_library",
"//shared/mathutil:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_urfave_cli//:go_default_library",
],
Expand Down
90 changes: 48 additions & 42 deletions beacon-chain/utils/shuffle.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,67 @@
package utils

import (
"encoding/binary"
"errors"
"math"

"github.com/ethereum/go-ethereum/common"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
//"github.com/prysmaticlabs/prysm/shared/params"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this, if you are not using. dont comment it out

"github.com/prysmaticlabs/prysm/shared/mathutil"
)

// ShuffleIndices returns a list of pseudorandomly sampled
// indices. This is used to shuffle validators on ETH2.0 beacon chain.
func ShuffleIndices(seed common.Hash, indicesList []uint64) ([]uint64, error) {
// Each entropy is consumed from the seed in randBytes chunks.
randBytes := params.BeaconConfig().RandBytes
func GetPermutedIndex(index uint64, listSize uint64, seed common.Hash) (uint64, error) {
if index >= listSize {
err := errors.New("index is greater or equal than listSize")
return 0, err
}

maxValidatorsPerRandBytes := params.BeaconConfig().MaxNumLog2Validators / randBytes
upperBound := 1<<(randBytes*maxValidatorsPerRandBytes) - 1
// Since we are consuming randBytes of entropy at a time in the loop,
// we have a bias at 2**24, this check defines our max list size and is used to remove the bias.
// more info on modulo bias: https://stackoverflow.com/questions/10984974/why-do-people-say-there-is-modulo-bias-when-using-a-random-number-generator.
if len(indicesList) >= upperBound {
return nil, errors.New("input list exceeded upper bound and reached modulo bias")
if listSize > mathutil.PowerOf2(40) {
err := errors.New("listSize is greater than 2**40")
return 0, err
}

// Rehash the seed to obtain a new pattern of bytes.
hashSeed := hashutil.Hash(seed[:])
totalCount := len(indicesList)
index := 0
for index < totalCount-1 {
// Iterate through the hashSeed bytes in chunks of size randBytes.
for i := 0; i < 32-(32%int(randBytes)); i += int(randBytes) {
// Determine the number of indices remaining and exit if last index reached.
remaining := totalCount - index
if remaining == 1 {
break
}
// Read randBytes of hashSeed as a maxValidatorsPerRandBytes x randBytes big-endian integer.
randChunk := hashSeed[i : i+int(randBytes)]
var randValue int
for j := 0; j < int(randBytes); j++ {
randValue |= int(randChunk[j])
}
bs4 := make([]byte, 4)
bs2 := make([]byte, 2)

// Sample values greater than or equal to sampleMax will cause
// modulo bias when mapped into the remaining range.
randMax := upperBound - upperBound%remaining
for round := 0; round < 90; round++ {
binary.LittleEndian.PutUint16(bs2[:], uint16(round))
bs1 := bs2[:1]
hashedValue := hashutil.Hash(append(seed[:], bs1...))
hashedValue8 := hashedValue[:8]
pivot := binary.LittleEndian.Uint64(hashedValue8[:]) % listSize
flip := (pivot - index) % listSize
position := index
if flip > position {
position = flip
}
positionVal := uint32(math.Floor(float64(position / 256)))
binary.LittleEndian.PutUint32(bs4[:], positionVal)
bs := append(bs1, bs4...)
source := hashutil.Hash(append(seed[:], bs...))
positionIndex := uint64(mathutil.CeilDiv8(int(position) % 256))
byteV := source[positionIndex]
bitV := (byteV >> (position % 8)) % 2
if bitV == 1 {
index = flip
}
}
return index, nil
}

// Perform swap if the consumed entropy will not cause modulo bias.
if randValue < randMax {
// Select replacement index from the current index.
replacementIndex := (randValue % remaining) + index
indicesList[index], indicesList[replacementIndex] = indicesList[replacementIndex], indicesList[index]
index++
}
// ShuffleIndices returns a list of pseudorandomly sampled
// indices. This is used to shuffle validators on ETH2.0 beacon chain.
func ShuffleIndices(seed common.Hash, indicesList []uint64) ([]uint64, error) {
var permutedIndicesList []uint64
for _, index := range indicesList {
permutedIndex, err := GetPermutedIndex(index, uint64(len(indicesList)), seed)
if err != nil {
return nil, errors.New("GetPermutedIndex error")
}
permutedIndicesList = append(permutedIndicesList, permutedIndex)
}
return indicesList, nil
return permutedIndicesList, nil
}

// SplitIndices splits a list into n pieces.
Expand Down
21 changes: 4 additions & 17 deletions beacon-chain/utils/shuffle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,7 @@ import (
"github.com/prysmaticlabs/prysm/shared/params"
)

func TestShuffleIndices_InvalidValidatorCount(t *testing.T) {
var list []uint64

upperBound := 1<<(params.BeaconConfig().RandBytes*8) - 1

for i := 0; i < upperBound+1; i++ {
list = append(list, uint64(i))
}

if _, err := ShuffleIndices(common.Hash{'a'}, list); err == nil {
t.Error("Shuffle should have failed when validator count exceeds ModuloBias")
}
}

func TestShuffleIndices_OK(t *testing.T) {
func TestShuffleIndices(t *testing.T) {
hash1 := common.BytesToHash([]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'c', 'd', 'e', 'f', 'g'})
hash2 := common.BytesToHash([]byte{'1', '2', '3', '4', '5', '6', '7', '1', '2', '3', '4', '5', '6', '7', '1', '2', '3', '4', '5', '6', '7', '1', '2', '3', '4', '5', '6', '7', '1', '2', '3', '4', '5', '6', '7'})
var list1 []uint64
Expand All @@ -47,12 +33,13 @@ func TestShuffleIndices_OK(t *testing.T) {
if reflect.DeepEqual(list1, list2) {
t.Errorf("2 shuffled lists shouldn't be equal")
}
if !reflect.DeepEqual(list1, []uint64{5, 4, 9, 6, 7, 3, 0, 1, 8, 2}) {
if !reflect.DeepEqual(list1, []uint64{8, 6, 8, 8, 8, 8, 8, 6, 8, 6}) {
t.Errorf("list 1 was incorrectly shuffled")
}
if !reflect.DeepEqual(list2, []uint64{9, 0, 1, 5, 3, 2, 4, 7, 8, 6}) {
if !reflect.DeepEqual(list2, []uint64{4, 4, 4, 4, 4, 4, 4, 4, 4, 4}) {
t.Errorf("list 2 was incorrectly shuffled")
}

}

func TestSplitIndices_OK(t *testing.T) {
Expand Down