From 5252b54a04458b6837c9dac30fbe2370e9370a19 Mon Sep 17 00:00:00 2001 From: pinkiebell <40266861+pinkiebell@users.noreply.github.com> Date: Sat, 20 Oct 2018 18:39:10 +0200 Subject: [PATCH 1/5] beacon_chain/utils/shuffling: Introduce test vectors from sigp/shuffling_sandbox Also: - return early if we shuffle an empty list - change RAND_MAX as per spec --- beacon_chain/utils/shuffling/Cargo.toml | 3 + beacon_chain/utils/shuffling/src/lib.rs | 46 ++++- beacon_chain/utils/shuffling/src/rng.rs | 2 +- .../src/specs/shuffle_test_vectors.yaml | 169 ++++++++++++++++++ 4 files changed, 212 insertions(+), 8 deletions(-) create mode 100644 beacon_chain/utils/shuffling/src/specs/shuffle_test_vectors.yaml diff --git a/beacon_chain/utils/shuffling/Cargo.toml b/beacon_chain/utils/shuffling/Cargo.toml index df0a108ee..31f4ce8cf 100644 --- a/beacon_chain/utils/shuffling/Cargo.toml +++ b/beacon_chain/utils/shuffling/Cargo.toml @@ -5,3 +5,6 @@ authors = ["Paul Hauner "] [dependencies] hashing = { path = "../hashing" } + +[dev-dependencies] +yaml-rust = "0.4.2" diff --git a/beacon_chain/utils/shuffling/src/lib.rs b/beacon_chain/utils/shuffling/src/lib.rs index 7acb7408a..9623a1fdc 100644 --- a/beacon_chain/utils/shuffling/src/lib.rs +++ b/beacon_chain/utils/shuffling/src/lib.rs @@ -25,9 +25,15 @@ pub fn shuffle( -> Result, ShuffleErr> { let mut rng = ShuffleRng::new(seed); + if list.len() > rng.rand_max as usize { return Err(ShuffleErr::ExceedsListLength); } + + if list.len() == 0 { + return Ok(list); + } + for i in 0..(list.len() - 1) { let n = list.len() - i; let j = rng.rand_range(n as u32) as usize + i; @@ -39,17 +45,43 @@ pub fn shuffle( #[cfg(test)] mod tests { + extern crate yaml_rust; + use super::*; use super::hashing::canonical_hash; + use std::fs::File; + use std::io::prelude::*; + use self::yaml_rust::yaml; #[test] fn test_shuffling() { - let seed = canonical_hash(b"4kn4driuctg8"); - let list: Vec = (0..12).collect(); - let s = shuffle(&seed, list).unwrap(); - assert_eq!( - s, - vec![7, 3, 2, 5, 11, 9, 1, 0, 4, 6, 10, 8], - ) + let mut file = File::open("./src/specs/shuffle_test_vectors.yaml").unwrap(); + let mut yaml_str = String::new(); + + file.read_to_string(&mut yaml_str).unwrap(); + + let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap(); + let doc = &docs[0]; + let test_cases = doc["test_cases"].as_vec(); + + for test_case in test_cases.unwrap() { + let input = test_case["input"].clone().into_vec().unwrap(); + let output = test_case["output"].clone().into_vec().unwrap(); + let seed_bytes = test_case["seed"].as_str().unwrap().as_bytes(); + let mut seed; + + if seed_bytes.len() > 0 { + seed = canonical_hash(seed_bytes); + } else { + seed = vec![]; + } + + let mut s = shuffle(&seed, input).unwrap(); + + assert_eq!( + s, + output, + ); + } } } diff --git a/beacon_chain/utils/shuffling/src/rng.rs b/beacon_chain/utils/shuffling/src/rng.rs index 7ca6f1866..37151825c 100644 --- a/beacon_chain/utils/shuffling/src/rng.rs +++ b/beacon_chain/utils/shuffling/src/rng.rs @@ -2,7 +2,7 @@ use super::hashing::canonical_hash; const SEED_SIZE_BYTES: usize = 32; const RAND_BYTES: usize = 3; // 24 / 8 -const RAND_MAX: u32 = 16_777_216; // 2**24 +const RAND_MAX: u32 = 16_777_215; // 2 ** (rand_bytes * 8) - 1 /// A pseudo-random number generator which given a seed /// uses successive blake2s hashing to generate "entropy". diff --git a/beacon_chain/utils/shuffling/src/specs/shuffle_test_vectors.yaml b/beacon_chain/utils/shuffling/src/specs/shuffle_test_vectors.yaml new file mode 100644 index 000000000..c75b6aeaa --- /dev/null +++ b/beacon_chain/utils/shuffling/src/specs/shuffle_test_vectors.yaml @@ -0,0 +1,169 @@ +# This file was generated with a modified version of shuffling_sandbox +# python3 sandbox.py test_vectors +#diff --git a/sandbox.py b/sandbox.py +#index 99b0ba7..cd7cafe 100644 +#--- a/sandbox.py +#+++ b/sandbox.py +#@@ -126,13 +126,13 @@ elif args.method == "test_vectors": +# results = [] +# +# seeds = [ +#- b"", +#- blake("4kn4driuctg8".encode()), # known to cause conflicts with old shuffler +#- blake("ytre1p".encode()), +#- blake("mytobcffnkvj".encode()), +#- blake("myzu3g7evxp5nkvj".encode()), +#- blake("xdpli1jsx5xb".encode()), +#- blake("oab3mbb3xe8qsx5xb".encode()), +#+ "", +#+ "4kn4driuctg8", # known to cause conflicts with old shuffler +#+ "ytre1p", +#+ "mytobcffnkvj", +#+ "myzu3g7evxp5nkvj", +#+ "xdpli1jsx5xb", +#+ "oab3mbb3xe8qsx5xb", +# ] +# lists = [ +# [], +#@@ -147,7 +147,8 @@ elif args.method == "test_vectors": +# +# for seed in seeds: +# for lst in lists: +#- output = shuffler(lst, seed) +#+ blake_seed = blake(seed.encode()) if len(seed) > 0 else b"" +#+ output = shuffler(lst, blake_seed) +# results.append({"seed": seed, "input": lst, "output": output}) +# +# body = { + +title: Shuffling Algorithm Tests +summary: Test vectors for shuffling a list based upon a seed. +test_suite: Shuffling + +test_cases: +- input: [] + output: [] + seed: '' +- input: [0] + output: [0] + seed: '' +- input: [255] + output: [255] + seed: '' +- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [1, 6, 4, 1, 6, 6, 2, 2, 4, 5] + seed: '' +- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + output: [4, 7, 10, 13, 3, 1, 2, 9, 12, 6, 11, 8, 5] + seed: '' +- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [1, 6, 65, 1, 6, 6, 2, 2, 4, 5] + seed: '' +- input: [] + output: [] + seed: 4kn4driuctg8 +- input: [0] + output: [0] + seed: 4kn4driuctg8 +- input: [255] + output: [255] + seed: 4kn4driuctg8 +- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [6, 4, 2, 5, 4, 2, 6, 6, 1, 1] + seed: 4kn4driuctg8 +- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + output: [13, 1, 9, 8, 3, 10, 6, 2, 5, 12, 11, 4, 7] + seed: 4kn4driuctg8 +- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [6, 65, 2, 5, 4, 2, 6, 6, 1, 1] + seed: 4kn4driuctg8 +- input: [] + output: [] + seed: ytre1p +- input: [0] + output: [0] + seed: ytre1p +- input: [255] + output: [255] + seed: ytre1p +- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [6, 2, 5, 1, 6, 4, 1, 2, 4, 6] + seed: ytre1p +- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + output: [3, 8, 10, 4, 7, 11, 6, 1, 2, 5, 13, 9, 12] + seed: ytre1p +- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [6, 2, 5, 1, 6, 4, 1, 2, 65, 6] + seed: ytre1p +- input: [] + output: [] + seed: mytobcffnkvj +- input: [0] + output: [0] + seed: mytobcffnkvj +- input: [255] + output: [255] + seed: mytobcffnkvj +- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [5, 6, 2, 1, 6, 4, 6, 4, 1, 2] + seed: mytobcffnkvj +- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + output: [12, 4, 11, 6, 13, 10, 9, 2, 3, 7, 8, 1, 5] + seed: mytobcffnkvj +- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [5, 6, 2, 1, 6, 65, 6, 4, 1, 2] + seed: mytobcffnkvj +- input: [] + output: [] + seed: myzu3g7evxp5nkvj +- input: [0] + output: [0] + seed: myzu3g7evxp5nkvj +- input: [255] + output: [255] + seed: myzu3g7evxp5nkvj +- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [6, 2, 6, 5, 4, 4, 1, 6, 2, 1] + seed: myzu3g7evxp5nkvj +- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + output: [10, 12, 13, 3, 7, 11, 2, 4, 9, 8, 6, 5, 1] + seed: myzu3g7evxp5nkvj +- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [6, 2, 6, 5, 65, 4, 1, 6, 2, 1] + seed: myzu3g7evxp5nkvj +- input: [] + output: [] + seed: xdpli1jsx5xb +- input: [0] + output: [0] + seed: xdpli1jsx5xb +- input: [255] + output: [255] + seed: xdpli1jsx5xb +- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [6, 2, 4, 1, 2, 6, 5, 1, 6, 4] + seed: xdpli1jsx5xb +- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + output: [11, 8, 12, 9, 2, 1, 10, 4, 13, 5, 7, 3, 6] + seed: xdpli1jsx5xb +- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [6, 2, 65, 1, 2, 6, 5, 1, 6, 4] + seed: xdpli1jsx5xb +- input: [] + output: [] + seed: oab3mbb3xe8qsx5xb +- input: [0] + output: [0] + seed: oab3mbb3xe8qsx5xb +- input: [255] + output: [255] + seed: oab3mbb3xe8qsx5xb +- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [2, 5, 1, 6, 1, 2, 6, 6, 4, 4] + seed: oab3mbb3xe8qsx5xb +- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + output: [5, 13, 9, 7, 11, 10, 12, 2, 6, 8, 3, 1, 4] + seed: oab3mbb3xe8qsx5xb +- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5] + output: [2, 5, 1, 6, 1, 2, 6, 6, 65, 4] + seed: oab3mbb3xe8qsx5xb From 6ee3ad10da432909a0eec3aaf40279a0de09a3b7 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 21 Oct 2018 20:07:57 +1100 Subject: [PATCH 2/5] Change integer literals to constants --- .../utils/ssz_helpers/src/ssz_beacon_block.rs | 73 ++++++++++--------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/beacon_chain/utils/ssz_helpers/src/ssz_beacon_block.rs b/beacon_chain/utils/ssz_helpers/src/ssz_beacon_block.rs index 7b2c2862b..d244fbb19 100644 --- a/beacon_chain/utils/ssz_helpers/src/ssz_beacon_block.rs +++ b/beacon_chain/utils/ssz_helpers/src/ssz_beacon_block.rs @@ -14,7 +14,16 @@ pub enum SszBeaconBlockError { TooLong, } -const LENGTH_BYTES: usize = 4; +/* + * Constants used for navigating the SSZ bytes. + */ +const LENGTH_PREFIX_BYTES: usize = 4; +const SLOT_BYTES: usize = 8; +const HASH_SIZE: usize = 32; +const RANDAO_REVEAL_BYTES: usize = HASH_SIZE; +const POW_CHAIN_REF_BYTES: usize = HASH_SIZE; +const ACTIVE_STATE_BYTES: usize = HASH_SIZE; +const CRYSTALLIZED_STATE_BYTES: usize = HASH_SIZE; /// Allows for reading of block values directly from serialized ssz bytes. /// @@ -74,41 +83,35 @@ impl<'a> SszBeaconBlock<'a> { * Determine how many bytes are used to store ancestor hashes. */ let ancestors_position = - 8 + // slot - 32 + // randao_reveal - 32; // pow_chain_reference - let ancestors_len = decode_length(untrimmed_ssz, ancestors_position, LENGTH_BYTES) + SLOT_BYTES + + RANDAO_REVEAL_BYTES + + POW_CHAIN_REF_BYTES; + let ancestors_len = decode_length(untrimmed_ssz, ancestors_position, LENGTH_PREFIX_BYTES) .map_err(|_| SszBeaconBlockError::TooShort)?; /* * Determine how many bytes are used to store attestation records. */ let attestations_position = - ancestors_position + LENGTH_BYTES + ancestors_len + // end of ancestor bytes - 32 + // active_state_root - 32; // crystallized_state_root - let attestations_len = decode_length(untrimmed_ssz, attestations_position, LENGTH_BYTES) + ancestors_position + LENGTH_PREFIX_BYTES + ancestors_len + // end of ancestor bytes + ACTIVE_STATE_BYTES + + CRYSTALLIZED_STATE_BYTES; + let attestations_len = decode_length(untrimmed_ssz, attestations_position, LENGTH_PREFIX_BYTES) .map_err(|_| SszBeaconBlockError::TooShort)?; /* * Determine how many bytes are used to store specials. */ - let specials_position = - attestations_position + // location of attestations - LENGTH_BYTES + // attestations length prefix - attestations_len; // # of attestation bytes - let specials_len = decode_length(untrimmed_ssz, specials_position, LENGTH_BYTES) + let specials_position = attestations_position + LENGTH_PREFIX_BYTES + attestations_len; + let specials_len = decode_length(untrimmed_ssz, specials_position, LENGTH_PREFIX_BYTES) .map_err(|_| SszBeaconBlockError::TooShort)?; /* * Now that all variable field lengths are known (ancestors, attestations, specials) we can * know the exact length of the block and reject it if the slice is too short. */ - let block_ssz_len = { - MIN_SSZ_BLOCK_LENGTH + ancestors_len + attestations_len + specials_len - }; + let block_ssz_len = MIN_SSZ_BLOCK_LENGTH + ancestors_len + attestations_len + specials_len; if vec.len() < block_ssz_len { - println!("block_ssz_len: {:?}, len: {:?}", block_ssz_len, vec.len()); return Err(SszBeaconBlockError::TooShort); } @@ -162,54 +165,54 @@ impl<'a> SszBeaconBlock<'a> { /// Return the `randao_reveal` field. pub fn randao_reveal(&self) -> &[u8] { - let start = 8; // slot is 8 bytes - &self.ssz[start..start + 32] + let start = SLOT_BYTES; + &self.ssz[start..start + RANDAO_REVEAL_BYTES] } /// Return the `pow_chain_reference` field. pub fn pow_chain_reference(&self) -> &[u8] { let start = - 8 + // slot - 32; // randao_reveal - &self.ssz[start..start + 32] + SLOT_BYTES + + RANDAO_REVEAL_BYTES; + &self.ssz[start..start + POW_CHAIN_REF_BYTES] } /// Return the serialized `ancestor_hashes` bytes, including length prefix. pub fn ancestor_hashes(&self) -> &[u8] { let start = self.ancestors_position; - &self.ssz[start..(start + self.ancestors_len + LENGTH_BYTES)] + &self.ssz[start..(start + self.ancestors_len + LENGTH_PREFIX_BYTES)] } /// Return the `active_state_root` field. pub fn act_state_root(&self) -> &[u8] { - let start = self.ancestors_position + LENGTH_BYTES + self.ancestors_len; + let start = self.ancestors_position + LENGTH_PREFIX_BYTES + self.ancestors_len; &self.ssz[start..(start + 32)] } /// Return the `active_state_root` field. pub fn cry_state_root(&self) -> &[u8] { let start = - self.ancestors_position + LENGTH_BYTES + self.ancestors_len + // ancestors - 32; // active_state_root; + self.ancestors_position + LENGTH_PREFIX_BYTES + self.ancestors_len + + ACTIVE_STATE_BYTES; &self.ssz[start..(start + 32)] } /// Return the serialized `attestations` bytes, including length prefix. pub fn attestations(&self) -> &[u8] { let start = self.attestations_position; - &self.ssz[start..(start + self.attestations_len + LENGTH_BYTES)] + &self.ssz[start..(start + self.attestations_len + LENGTH_PREFIX_BYTES)] } /// Return the serialized `attestations` bytes _without_ the length prefix. pub fn attestations_without_length(&self) -> &[u8] { - let start = self.attestations_position + LENGTH_BYTES; + let start = self.attestations_position + LENGTH_PREFIX_BYTES; &self.ssz[start..start + self.attestations_len] } /// Return the serialized `specials` bytes, including length prefix. pub fn specials(&self) -> &[u8] { let start = self.specials_position; - &self.ssz[start..(start + self.specials_len + LENGTH_BYTES)] + &self.ssz[start..(start + self.specials_len + LENGTH_PREFIX_BYTES)] } } @@ -349,7 +352,7 @@ mod tests { let serialized = get_block_ssz(&block); let ssz_block = SszBeaconBlock::from_slice(&serialized).unwrap(); - let mut expected = encode_length(32, LENGTH_BYTES); + let mut expected = encode_length(32, LENGTH_PREFIX_BYTES); expected.append(&mut h.to_vec()); assert_eq!(ssz_block.ancestor_hashes(), &expected[..]); @@ -383,7 +386,7 @@ mod tests { let ssz_block = SszBeaconBlock::from_slice(&serialized).unwrap(); let sr_ssz = get_special_record_ssz(&s); - let mut expected = encode_length(sr_ssz.len(), LENGTH_BYTES); + let mut expected = encode_length(sr_ssz.len(), LENGTH_PREFIX_BYTES); expected.append(&mut sr_ssz.to_vec()); assert_eq!(ssz_block.specials(), &expected[..]); @@ -399,7 +402,7 @@ mod tests { let ssz_block = SszBeaconBlock::from_slice(&serialized).unwrap(); let sr_ssz = get_special_record_ssz(&s); - let mut expected = encode_length(sr_ssz.len(), LENGTH_BYTES); + let mut expected = encode_length(sr_ssz.len(), LENGTH_PREFIX_BYTES); expected.append(&mut sr_ssz.to_vec()); assert_eq!(ssz_block.specials(), &expected[..]); @@ -417,7 +420,7 @@ mod tests { let ssz_block = SszBeaconBlock::from_slice(&serialized).unwrap(); let ssz_ar = get_attestation_record_ssz(&AttestationRecord::zero()); - let mut expected = encode_length(ssz_ar.len(), LENGTH_BYTES); + let mut expected = encode_length(ssz_ar.len(), LENGTH_PREFIX_BYTES); expected.append(&mut ssz_ar.to_vec()); assert_eq!(ssz_block.attestations(), &expected[..]); @@ -434,7 +437,7 @@ mod tests { let mut ssz_ar = get_attestation_record_ssz(&AttestationRecord::zero()); ssz_ar.append(&mut get_attestation_record_ssz(&AttestationRecord::zero())); - let mut expected = encode_length(ssz_ar.len(), LENGTH_BYTES); + let mut expected = encode_length(ssz_ar.len(), LENGTH_PREFIX_BYTES); expected.append(&mut ssz_ar.to_vec()); assert_eq!(ssz_block.attestations(), &expected[..]); From 694db90b8cdb166eff7bf26b756487c48f4d1ed7 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 21 Oct 2018 20:12:17 +1100 Subject: [PATCH 3/5] Simplify parent_hashes code --- beacon_chain/utils/ssz_helpers/src/ssz_beacon_block.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/beacon_chain/utils/ssz_helpers/src/ssz_beacon_block.rs b/beacon_chain/utils/ssz_helpers/src/ssz_beacon_block.rs index d244fbb19..3066f5679 100644 --- a/beacon_chain/utils/ssz_helpers/src/ssz_beacon_block.rs +++ b/beacon_chain/utils/ssz_helpers/src/ssz_beacon_block.rs @@ -138,12 +138,8 @@ impl<'a> SszBeaconBlock<'a> { /// The first hash in `ancestor_hashes` is the parent of the block. pub fn parent_hash(&self) -> Option<&[u8]> { let ancestor_ssz = self.ancestor_hashes(); - let start = LENGTH_BYTES; - if ancestor_ssz.len() >= 32 { - Some(&ancestor_ssz[start..start + 32]) - } else { - None - } + let start = LENGTH_PREFIX_BYTES; + ancestor_ssz.get(start..start + HASH_SIZE) } /// Return the `slot` field. From 78f9c092786cdacafcabf3e40ed58cf1d3927cad Mon Sep 17 00:00:00 2001 From: pinkiebell <40266861+pinkiebell@users.noreply.github.com> Date: Sun, 21 Oct 2018 13:01:00 +0200 Subject: [PATCH 4/5] beacon_chain/utils/shuffling: Resolve PR comments --- beacon_chain/utils/shuffling/src/lib.rs | 7 +--- .../src/specs/shuffle_test_vectors.yaml | 38 +------------------ 2 files changed, 3 insertions(+), 42 deletions(-) diff --git a/beacon_chain/utils/shuffling/src/lib.rs b/beacon_chain/utils/shuffling/src/lib.rs index 9623a1fdc..91a3a73e2 100644 --- a/beacon_chain/utils/shuffling/src/lib.rs +++ b/beacon_chain/utils/shuffling/src/lib.rs @@ -30,7 +30,7 @@ pub fn shuffle( return Err(ShuffleErr::ExceedsListLength); } - if list.len() == 0 { + if list.is_empty() { return Ok(list); } @@ -78,10 +78,7 @@ mod tests { let mut s = shuffle(&seed, input).unwrap(); - assert_eq!( - s, - output, - ); + assert_eq!(s, output); } } } diff --git a/beacon_chain/utils/shuffling/src/specs/shuffle_test_vectors.yaml b/beacon_chain/utils/shuffling/src/specs/shuffle_test_vectors.yaml index c75b6aeaa..c97d6d328 100644 --- a/beacon_chain/utils/shuffling/src/specs/shuffle_test_vectors.yaml +++ b/beacon_chain/utils/shuffling/src/specs/shuffle_test_vectors.yaml @@ -1,41 +1,5 @@ -# This file was generated with a modified version of shuffling_sandbox +# This file was generated with sigp/shuffling_sandbox # python3 sandbox.py test_vectors -#diff --git a/sandbox.py b/sandbox.py -#index 99b0ba7..cd7cafe 100644 -#--- a/sandbox.py -#+++ b/sandbox.py -#@@ -126,13 +126,13 @@ elif args.method == "test_vectors": -# results = [] -# -# seeds = [ -#- b"", -#- blake("4kn4driuctg8".encode()), # known to cause conflicts with old shuffler -#- blake("ytre1p".encode()), -#- blake("mytobcffnkvj".encode()), -#- blake("myzu3g7evxp5nkvj".encode()), -#- blake("xdpli1jsx5xb".encode()), -#- blake("oab3mbb3xe8qsx5xb".encode()), -#+ "", -#+ "4kn4driuctg8", # known to cause conflicts with old shuffler -#+ "ytre1p", -#+ "mytobcffnkvj", -#+ "myzu3g7evxp5nkvj", -#+ "xdpli1jsx5xb", -#+ "oab3mbb3xe8qsx5xb", -# ] -# lists = [ -# [], -#@@ -147,7 +147,8 @@ elif args.method == "test_vectors": -# -# for seed in seeds: -# for lst in lists: -#- output = shuffler(lst, seed) -#+ blake_seed = blake(seed.encode()) if len(seed) > 0 else b"" -#+ output = shuffler(lst, blake_seed) -# results.append({"seed": seed, "input": lst, "output": output}) -# -# body = { - title: Shuffling Algorithm Tests summary: Test vectors for shuffling a list based upon a seed. test_suite: Shuffling From db735a598ffd5ddb3faccf0412e5069cecefe8ad Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 22 Oct 2018 05:24:13 +1100 Subject: [PATCH 5/5] Fix underflow in shuffle with empty list --- beacon_chain/utils/shuffling/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon_chain/utils/shuffling/src/lib.rs b/beacon_chain/utils/shuffling/src/lib.rs index 91a3a73e2..9691240f8 100644 --- a/beacon_chain/utils/shuffling/src/lib.rs +++ b/beacon_chain/utils/shuffling/src/lib.rs @@ -34,7 +34,7 @@ pub fn shuffle( return Ok(list); } - for i in 0..(list.len() - 1) { + for i in 0..(list.len().saturating_sub(1)) { let n = list.len() - i; let j = rng.rand_range(n as u32) as usize + i; list.swap(i, j);