summaryrefslogtreecommitdiff
path: root/numpy/random
diff options
context:
space:
mode:
authorRobert Kern <robert.kern@gmail.com>2020-06-09 11:58:49 -0400
committerCharles Harris <charlesr.harris@gmail.com>2020-06-10 12:10:10 -0600
commit9bdcfec980eb8b5b01fd72b6ded283fcf0b8e240 (patch)
tree1f93dcf54a4bb511772de817dc4aed8549d59470 /numpy/random
parent41da5ea9ec14b6aa62e1b446853d34f0159108e4 (diff)
downloadnumpy-9bdcfec980eb8b5b01fd72b6ded283fcf0b8e240.tar.gz
BUG: Ensure SeedSequence 0-padding does not collide with spawn keys
Fixes #16539 The implicit 0-padding that is done to small entropy inputs to make them the size of the internal pool conflicts with the spawn keys, which start with an appended 0. In order to maintain stream compatibility with unspawned `SeedSequence`s, we explicitly 0-pad short inputs out to the pool size only if the spawn key is provided, and thus would trigger the bug. This should minimize the impact on users that were not encountering the bug.
Diffstat (limited to 'numpy/random')
-rw-r--r--numpy/random/bit_generator.pyx11
-rw-r--r--numpy/random/tests/test_seed_sequence.py28
2 files changed, 37 insertions, 2 deletions
diff --git a/numpy/random/bit_generator.pyx b/numpy/random/bit_generator.pyx
index f145ec13d..3c52a9933 100644
--- a/numpy/random/bit_generator.pyx
+++ b/numpy/random/bit_generator.pyx
@@ -382,13 +382,22 @@ cdef class SeedSequence():
-------
entropy_array : 1D uint32 array
"""
- # Convert run-entropy, program-entropy, and the spawn key into uint32
+ # Convert run-entropy and the spawn key into uint32
# arrays and concatenate them.
# We MUST have at least some run-entropy. The others are optional.
assert self.entropy is not None
run_entropy = _coerce_to_uint32_array(self.entropy)
spawn_entropy = _coerce_to_uint32_array(self.spawn_key)
+ if len(spawn_entropy) > 0 and len(run_entropy) < self.pool_size:
+ # Explicitly fill out the entropy with 0s to the pool size to avoid
+ # conflict with spawn keys. We changed this in 1.19.0 to fix
+ # gh-16539. In order to preserve stream-compatibility with
+ # unspawned SeedSequences with small entropy inputs, we only do
+ # this when a spawn_key is specified.
+ diff = self.pool_size - len(run_entropy)
+ run_entropy = np.concatenate(
+ [run_entropy, np.zeros(diff, dtype=np.uint32)])
entropy_array = np.concatenate([run_entropy, spawn_entropy])
return entropy_array
diff --git a/numpy/random/tests/test_seed_sequence.py b/numpy/random/tests/test_seed_sequence.py
index fe23680ed..f08cf80fa 100644
--- a/numpy/random/tests/test_seed_sequence.py
+++ b/numpy/random/tests/test_seed_sequence.py
@@ -1,5 +1,5 @@
import numpy as np
-from numpy.testing import assert_array_equal
+from numpy.testing import assert_array_equal, assert_array_compare
from numpy.random import SeedSequence
@@ -52,3 +52,29 @@ def test_reference_data():
assert_array_equal(state, expected)
state64 = ss.generate_state(len(expected64), dtype=np.uint64)
assert_array_equal(state64, expected64)
+
+
+def test_zero_padding():
+ """ Ensure that the implicit zero-padding does not cause problems.
+ """
+ # Ensure that large integers are inserted in little-endian fashion to avoid
+ # trailing 0s.
+ ss0 = SeedSequence(42)
+ ss1 = SeedSequence(42 << 32)
+ assert_array_compare(
+ np.not_equal,
+ ss0.generate_state(4),
+ ss1.generate_state(4))
+
+ # Ensure backwards compatibility with the original 0.17 release for small
+ # integers and no spawn key.
+ expected42 = np.array([3444837047, 2669555309, 2046530742, 3581440988],
+ dtype=np.uint32)
+ assert_array_equal(SeedSequence(42).generate_state(4), expected42)
+
+ # Regression test for gh-16539 to ensure that the implicit 0s don't
+ # conflict with spawn keys.
+ assert_array_compare(
+ np.not_equal,
+ SeedSequence(42, spawn_key=(0,)).generate_state(4),
+ expected42)