Skip to content

Commit 856eb2e

Browse files
committed
Adds test vectors for the Shuffling function.
Together with README and a generating script.
1 parent 7a96598 commit 856eb2e

File tree

3 files changed

+902
-0
lines changed

3 files changed

+902
-0
lines changed

shuffle/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Fisher-Yates Shuffle function test vectors
2+
3+
We offer test vectors for the implementation of the shuffle function as described in Appendix F of the Gray Paper.
4+
This section presents two definitions, a recursive one that uses an integer sequence as random seeds in Eq 329, and one (Eq 331) which takes a 32-byte hash as entropy, and is defined in terms of the previous one.
5+
6+
The implementation of Eq 329 is not generally used in the Gray Paper, and so we present test vectors only for the version of Eq 331. However, the present script creates these test cases with recourse to the Eq 329 implementation, to reproduce exactly the definition of the Gray Paper.
7+
8+
## Notes about test parameters
9+
10+
In every case, the output must be a permutation of the input sequence, and this is checked by the generating script.
11+
In the GP, at the moment, this function is used only to shuffle sequences of validators or cores, both of which are identified by integers. For that reason, all test cases use integers as the input type. All the input elements are distinct to ensure the final positions of each element are unambiguously determined.
12+
13+
All test cases use the same entropy, which is a 32-byte sequence with values from 0 to 31.
14+
15+
All the inputs to each test case are integer sequences, ranging from 0 to n-1, where n is the length. The test cases are described only by the entropy and the length of the input, and so the actual input sequence has to be recreated when using these test cases.
16+
17+
## Test vectors
18+
19+
The following test cases are given:
20+
- 0
21+
- 8
22+
- 16
23+
- 20
24+
- 50
25+
- 100
26+
- 200
27+
- 341
28+
29+
Each test case has this format is a Json object with 3 fields:
30+
* **[input]**: the length of the input sequence
31+
* **[entropy]**: a hex-string description of the 32 bytes used for entropy
32+
* **[output]**: an array containing the shuffled input sequence

shuffle/main.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#!/usr/bin/env python3
2+
3+
import hashlib
4+
import json
5+
import sys
6+
7+
def hash(data):
8+
return hashlib.blake2b(data, digest_size=32).digest()
9+
10+
def hex(data):
11+
return ''.join(f'{x:02x}' for x in data)
12+
13+
def compute_shuffle_eq329(s, r):
14+
if len(s) > 0:
15+
l = len(s)
16+
index = r[0] % l
17+
head = s[index]
18+
19+
s_post = s.copy()
20+
s_post[index] = s[l-1]
21+
22+
return [head] + compute_shuffle_eq329(s_post[:-1], r[1:])
23+
else:
24+
return []
25+
26+
def number_vector(n):
27+
return [x for x in range(n)]
28+
29+
def default_seed():
30+
return [i for i in range(32)]
31+
32+
def inputs_Eq331():
33+
seed = default_seed()
34+
35+
yield(number_vector(0), seed)
36+
yield(number_vector(8), seed)
37+
yield(number_vector(16), seed)
38+
yield(number_vector(20), seed)
39+
40+
yield(number_vector(50), seed)
41+
yield(number_vector(100), seed)
42+
yield(number_vector(200), seed)
43+
yield(number_vector(341), seed)
44+
45+
46+
def to_le_bytes(n, k):
47+
return n.to_bytes(k, 'little')
48+
49+
def from_le_bytes(b):
50+
return int.from_bytes(b, 'little')
51+
52+
def compute_q(h, l):
53+
result = []
54+
for i in range(l):
55+
preimage = bytes(h.copy()) + to_le_bytes(i // 8, 4)
56+
offset = 4*i % 32
57+
slice = hash(preimage)[offset:offset + 4]
58+
result.append(from_le_bytes(slice))
59+
60+
return result
61+
62+
def compute_shuffle_eq331(s, h):
63+
l = len(s)
64+
r = compute_q(h, l)
65+
66+
return compute_shuffle_eq329(s, r)
67+
68+
def is_permutation(list1, list2):
69+
return set(list1) == set(list2)
70+
71+
def test_vectors_eq331():
72+
for term in inputs_Eq331():
73+
s, r = term
74+
output = compute_shuffle_eq331(s, r)
75+
assert(is_permutation(s, output))
76+
77+
yield {
78+
'input': len(s),
79+
'entropy': hex(r),
80+
'output': output,
81+
}
82+
83+
def main():
84+
json.dump(list(test_vectors_eq331()), sys.stdout, indent=' ')
85+
86+
main()

0 commit comments

Comments
 (0)