Update shuffle() as per review

- Add `rand_bytes`
- Change `for` loop condition for readability and generality.
- Ensure consistency of comment spacing
- Update comments
This commit is contained in:
Paul Hauner 2018-10-16 11:17:34 +11:00
parent 6700f283d5
commit 3791cb5a5d
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C

View File

@ -325,24 +325,32 @@ def shuffle(values: List[Any],
values_count = len(values) values_count = len(values)
# Entropy is consumed from the seed in 3-byte (24 bit) chunks. # Entropy is consumed from the seed in 3-byte (24 bit) chunks.
rand_max = 2 ** 24 - 1 rand_bytes = 3
# The highest possible result of the RNG.
rand_max = 2 ** (rand_bytes * 8) - 1
# The range of the RNG places an upper-bound on the size of the list that
# may be shuffled. It is a logic error to supply an oversized list.
assert values_count < rand_max assert values_count < rand_max
output = [x for x in values] output = [x for x in values]
source = seed source = seed
index = 0 index = 0
while index < values_count - 1: while index < values_count - 1:
# Re-hash the source # Re-hash the `source` to obtain a new pattern of bytes.
source = hash(source) source = hash(source)
for position in range(0, 30, 3): # Reads indices 3 bytes at a time # Iterate through the `source` bytes in 3-byte chunks.
# Determine the number of indices remaining and exit once the last for position in range(0, 32 - (32 % rand_bytes), rand_bytes):
# index is reached. # Determine the number of indices remaining in `values` and exit
# once the last index is reached.
remaining = values_count - index remaining = values_count - index
if remaining == 1: if remaining == 1:
break break
# Read 3-bytes of the seed as a 24-bit big-endian integer. # Read 3-bytes of `source` as a 24-bit big-endian integer.
sample_from_source = int.from_bytes(source[position:position + 3], 'big') sample_from_source = int.from_bytes(
source[position:position + rand_bytes], 'big'
)
# Sample values greater than or equal to `sample_max` will cause # Sample values greater than or equal to `sample_max` will cause
# modulo bias when mapped into the `remaining` range. # modulo bias when mapped into the `remaining` range.
@ -350,9 +358,9 @@ def shuffle(values: List[Any],
# Perform a swap if the consumed entropy will not cause modulo bias. # Perform a swap if the consumed entropy will not cause modulo bias.
if sample_from_source < sample_max: if sample_from_source < sample_max:
# Select a replacement index for the present index. # Select a replacement index for the current index.
replacement_position = (sample_from_source % remaining) + index replacement_position = (sample_from_source % remaining) + index
# Swap the present index with the replacement index. # Swap the current index with the replacement index.
output[index], output[replacement_position] = output[replacement_position], output[index] output[index], output[replacement_position] = output[replacement_position], output[index]
index += 1 index += 1
else: else: