Skip to content

Commit 434e3da

Browse files
authored
Merge pull request #373 from bashtage/clean-up-seeding
CLN: Remove random_entropy seeding
2 parents eabbc99 + c9d3ea4 commit 434e3da

24 files changed

+31
-605
lines changed

doc/source/bit_generators/chacha.rst

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,6 @@ Seeding and State
1616
~ChaCha.seed
1717
~ChaCha.state
1818

19-
Parallel generation
20-
===================
21-
.. autosummary::
22-
:toctree: generated/
23-
24-
~ChaCha.advance
25-
~ChaCha.jump
26-
~ChaCha.jumped
27-
2819
Extending
2920
=========
3021
.. autosummary::

randomgen/aes.pyx

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import numpy as np
33

44
from randomgen.common cimport *
5-
from randomgen.entropy import random_entropy, seed_by_array
5+
66

77
__all__ = ["AESCounter"]
88

@@ -226,26 +226,11 @@ cdef class AESCounter(BitGenerator):
226226
raise ValueError("seed and key cannot be both used")
227227
if key is None:
228228
BitGenerator._seed_with_seed_sequence(self, seed, counter=counter)
229-
try:
230-
if self.seed_seq is not None:
231-
return
232-
except AttributeError:
233-
if self._seed_seq is not None:
234-
return
235-
236-
seed = object_to_int(seed, 128, "seed")
229+
return
230+
237231
key = object_to_int(key, 128, "key")
238232
counter = object_to_int(counter, 128, "counter")
239-
if seed is not None and key is not None:
240-
raise ValueError("seed and key cannot be both used")
241-
if key is None:
242-
if seed is None:
243-
_seed = random_entropy(4, "auto")
244-
_seed = _seed.view(np.uint64)
245-
else:
246-
_seed = seed_by_array(int_to_array(seed, "seed", None, 64), 2)
247-
else:
248-
_seed = int_to_array(key, "key", 128, 64)
233+
_seed = int_to_array(key, "key", 128, 64)
249234
# TODO: We have swapped here, but should we always use native in Python?
250235
aesctr_seed(self.rng_state, <uint64_t*>np.PyArray_DATA(_seed))
251236
_counter = np.empty(8, dtype=np.uint64)

randomgen/chacha.pxd

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,3 @@ cdef extern from "src/chacha/chacha.h":
3232
cdef class ChaCha(BitGenerator):
3333

3434
cdef chacha_state_t *rng_state
35-
cdef jump_inplace(self, object iter)

randomgen/chacha.pyi

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,3 @@ class ChaCha(BitGenerator):
2929
def state(self) -> dict[str, str | dict[str, ndarray | int]]: ...
3030
@state.setter
3131
def state(self, value: dict[str, str | dict[str, ndarray | int]]) -> None: ...
32-
def jump(self, iter: int = ...) -> ChaCha: ...
33-
def jumped(self, iter: int = ...) -> ChaCha: ...
34-
def advance(self, delta: int) -> ChaCha: ...

randomgen/chacha.pyx

Lines changed: 4 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import numpy as np
33

44
from randomgen.common cimport *
5-
from randomgen.entropy import random_entropy, seed_by_array
65

76
__all__ = ["ChaCha"]
87

@@ -222,27 +221,14 @@ cdef class ChaCha(BitGenerator):
222221
array[i] = (value // 2**(64*i)) % 2**64.
223222
"""
224223
if seed is not None and key is not None:
225-
raise ValueError("seed and key cannot be both used")
224+
raise ValueError("seed and key cannot be simultaneously used")
226225
if key is None:
227226
BitGenerator._seed_with_seed_sequence(self, seed, counter=counter)
228-
try:
229-
if self.seed_seq is not None:
230-
return
231-
except AttributeError:
232-
if self._seed_seq is not None:
233-
return
234-
235-
seed = object_to_int(seed, 256, "seed")
227+
return
228+
236229
key = object_to_int(key, 256, "key")
237230
counter = object_to_int(counter, 128, "counter")
238-
if seed is not None and key is not None:
239-
raise ValueError("seed and key cannot be simultaneously used")
240-
if key is not None:
241-
seed = int_to_array(key, "key", 256, 32)
242-
elif seed is not None:
243-
seed = seed_by_array(int_to_array(seed, "seed", None, 64), 4)
244-
else:
245-
seed = random_entropy(8, "auto")
231+
seed = int_to_array(key, "key", 256, 32)
246232
_seed = seed
247233
if _seed.dtype != np.uint64:
248234
_seed = view_little_endian(_seed, np.uint64)
@@ -301,112 +287,3 @@ cdef class ChaCha(BitGenerator):
301287
for i in range(2):
302288
self.rng_state.ctr[i] = ctr[i]
303289
self.rng_state.rounds = state["rounds"]
304-
305-
cdef jump_inplace(self, object iter):
306-
"""
307-
Jump state in-place
308-
309-
Not part of public API
310-
311-
Parameters
312-
----------
313-
iter : integer, positive
314-
Number of times to jump the state of the rng.
315-
"""
316-
self.advance(iter * int(2 ** 64))
317-
318-
def jump(self, iter=1):
319-
"""
320-
jump(iter=1)
321-
322-
Jumps the state as-if 2**64 random numbers have been generated.
323-
324-
Parameters
325-
----------
326-
iter : integer, positive
327-
Number of times to jump the state of the rng.
328-
329-
Returns
330-
-------
331-
self : ChaCha
332-
PRNG jumped iter times
333-
334-
Notes
335-
-----
336-
Jumping the rng state resets any pre-computed random numbers. This is
337-
required to ensure exact reproducibility.
338-
"""
339-
import warnings
340-
warnings.warn("jump (in-place) has been deprecated in favor of jumped"
341-
", which returns a new instance", DeprecationWarning)
342-
self.jump_inplace(iter)
343-
return self
344-
345-
def jumped(self, iter=1):
346-
"""
347-
jumped(iter=1)
348-
349-
Returns a new bit generator with the state jumped
350-
351-
The state of the returned big generator is jumped as-if
352-
2**(64 * iter) random numbers have been generated.
353-
354-
Parameters
355-
----------
356-
iter : integer, positive
357-
Number of times to jump the state of the bit generator returned
358-
359-
Returns
360-
-------
361-
bit_generator : ChaCha
362-
New instance of generator jumped iter times
363-
"""
364-
cdef ChaCha bit_generator
365-
366-
bit_generator = self.__class__(seed=self._copy_seed())
367-
bit_generator.state = self.state
368-
bit_generator.jump_inplace(iter)
369-
370-
return bit_generator
371-
372-
def advance(self, delta):
373-
"""
374-
advance(delta)
375-
376-
Advance the underlying RNG as-if delta draws have occurred.
377-
378-
Parameters
379-
----------
380-
delta : integer, positive
381-
Number of draws to advance the RNG.
382-
383-
Returns
384-
-------
385-
self : ChaCha
386-
RNG advanced delta steps
387-
388-
Notes
389-
-----
390-
Advancing a RNG updates the underlying RNG state as-if a given
391-
number of calls to the underlying RNG have been made. In general
392-
there is not a one-to-one relationship between the number output
393-
random values from a particular distribution and the number of
394-
draws from the core RNG. This occurs for two reasons:
395-
396-
* The random values are simulated using a rejection-based method
397-
and so, on average, more than one value from the underlying
398-
RNG is required to generate an single draw.
399-
* The number of bits required to generate a simulated value
400-
differs from the number of bits generated by the underlying
401-
RNG. For example, two 16-bit integer values can be simulated
402-
from a single draw of a 32-bit RNG.
403-
404-
Advancing the RNG state resets any pre-computed random numbers.
405-
This is required to ensure exact reproducibility.
406-
"""
407-
cdef np.ndarray step
408-
409-
delta = wrap_int(delta, 128)
410-
step = int_to_array(delta, "delta", 128, 64)
411-
chacha_advance(self.rng_state, <uint64_t *>np.PyArray_DATA(step))
412-
return self

randomgen/common.pyx

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,15 @@ cdef class BitGenerator(_BitGenerator):
6868
return copy.deepcopy(self._seed_seq)
6969

7070
def _seed_with_seed_sequence(self, seed, **kwargs):
71-
from randomgen.seed_sequence import SeedSequence
72-
DefaultSeedSequence = SeedSequence
73-
try:
74-
from numpy.random import SeedSequence as DefaultSeedSequence
75-
except ImportError:
76-
pass
71+
from numpy.random import SeedSequence
7772
if isinstance(seed, ISEED_SEQUENCES):
7873
self._seed_seq = seed
7974
else:
80-
self._seed_seq = DefaultSeedSequence(seed)
81-
if self._seed_seq is not None:
82-
if self.mode == "sequence":
83-
self._seed_from_seq(**kwargs)
84-
else: # numpy
85-
self._seed_from_seq_numpy_compat(**kwargs)
75+
self._seed_seq = SeedSequence(seed)
76+
if self.mode == "sequence":
77+
self._seed_from_seq(**kwargs)
78+
else: # numpy
79+
self._seed_from_seq_numpy_compat(**kwargs)
8680
return
8781

8882
@property

randomgen/dsfmt.pyx

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import numpy as np
55
cimport numpy as np
66

77
from randomgen.common cimport *
8-
from randomgen.entropy import random_entropy
98

109
__all__ = ["DSFMT"]
1110

@@ -168,39 +167,7 @@ cdef class DSFMT(BitGenerator):
168167
ValueError
169168
If seed values are out of range for the PRNG.
170169
"""
171-
cdef np.ndarray obj, seed_arr
172-
173170
BitGenerator._seed_with_seed_sequence(self, seed)
174-
try:
175-
if self.seed_seq is not None:
176-
return
177-
except AttributeError:
178-
if self._seed_seq is not None:
179-
return
180-
try:
181-
if seed is None:
182-
seed_arr = random_entropy(2 * DSFMT_N64, "auto")
183-
dsfmt_init_by_array(self.rng_state.state,
184-
<uint32_t *>np.PyArray_DATA(seed_arr),
185-
2 * DSFMT_N64)
186-
187-
else:
188-
if hasattr(seed, "squeeze"):
189-
seed = seed.squeeze()
190-
idx = operator.index(seed)
191-
if idx > int(2**32 - 1) or idx < 0:
192-
raise ValueError("Seed must be between 0 and 2**32 - 1")
193-
dsfmt_init_gen_rand(self.rng_state.state, seed)
194-
except TypeError:
195-
obj = np.asarray(seed).astype(np.int64, casting="safe").ravel()
196-
if ((obj > int(2**32 - 1)) | (obj < 0)).any():
197-
raise ValueError("Seed must be between 0 and 2**32 - 1")
198-
seed_arr = obj.astype(np.uint32, casting="unsafe", order="C")
199-
dsfmt_init_by_array(self.rng_state.state,
200-
<uint32_t *>np.PyArray_DATA(seed_arr),
201-
<int>np.PyArray_DIM(seed_arr, 0))
202-
# Clear the buffer
203-
self._reset_state_variables()
204171

205172
cdef jump_inplace(self, object iter):
206173
"""

randomgen/hc128.pyx

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import numpy as np
44
cimport numpy as np
55

66
from randomgen.common cimport *
7-
from randomgen.entropy import random_entropy, seed_by_array
87

98
__all__ = ["HC128"]
109

@@ -156,23 +155,11 @@ cdef class HC128(BitGenerator):
156155
raise ValueError("seed and key cannot be simultaneously used")
157156
if key is None:
158157
BitGenerator._seed_with_seed_sequence(self, seed)
159-
try:
160-
if self.seed_seq is not None:
161-
return
162-
except AttributeError:
163-
if self._seed_seq is not None:
164-
return
165-
166-
seed = object_to_int(seed, 256, "seed")
158+
return
159+
167160
key = object_to_int(key, 256, "key")
168-
if key is not None:
169-
state = int_to_array(key, "key", 256, 64)
170-
elif seed is not None:
171-
state = seed_by_array(int_to_array(seed, "seed", None, 64), 4)
172-
else:
173-
state = random_entropy(8, "auto")
174-
# Ensure state uint32 values are the same in LE and BE
175-
# and in the same order
161+
state = int_to_array(key, "key", 256, 64)
162+
# Ensure state uint32 values are the same in LE and BE and in the same order
176163
state = view_little_endian(state, np.uint32)
177164
hc128_seed(&self.rng_state, <uint32_t *>np.PyArray_DATA(state))
178165

randomgen/jsf.pyx

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import numpy as np
55
cimport numpy as np
66

77
from randomgen.common cimport *
8-
from randomgen.entropy import random_entropy, seed_by_array
98

109
__all__ = ["JSF"]
1110

@@ -266,26 +265,6 @@ cdef class JSF(BitGenerator):
266265
If seed values are out of range for the PRNG.
267266
"""
268267
BitGenerator._seed_with_seed_sequence(self, seed)
269-
try:
270-
if self.seed_seq is not None:
271-
return
272-
except AttributeError:
273-
if self._seed_seq is not None:
274-
return
275-
276-
if seed is None:
277-
state = random_entropy(3 * self.size // 32, "auto")
278-
else:
279-
state = seed_by_array(seed, 3)
280-
dtype = np.uint64 if self.size==64 else np.uint32
281-
state = view_little_endian(state, dtype)
282-
if self.size == 64:
283-
jsf64_seed(&self.rng_state, <uint64_t*>np.PyArray_DATA(state),
284-
self.seed_size)
285-
else:
286-
jsf32_seed(&self.rng_state, <uint32_t*>np.PyArray_DATA(state),
287-
self.seed_size)
288-
self._reset_state_variables()
289268

290269
@property
291270
def state(self):

0 commit comments

Comments
 (0)