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
This commit is contained in:
parent
2fb9dfbf14
commit
5252b54a04
@ -5,3 +5,6 @@ authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
|
||||
[dependencies]
|
||||
hashing = { path = "../hashing" }
|
||||
|
||||
[dev-dependencies]
|
||||
yaml-rust = "0.4.2"
|
||||
|
@ -25,9 +25,15 @@ pub fn shuffle<T>(
|
||||
-> Result<Vec<T>, 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<T>(
|
||||
|
||||
#[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<usize> = (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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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".
|
||||
|
169
beacon_chain/utils/shuffling/src/specs/shuffle_test_vectors.yaml
Normal file
169
beacon_chain/utils/shuffling/src/specs/shuffle_test_vectors.yaml
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user