I have implemented a working prototype of a pluggable RandomState.  The repo is located at https://github.com/bashtage/core-prng

The main design has a small PRNG (currently only SplitMix64 and Xoroshiro128 are implemented) that does not have any public functions available to generate random numbers.  These objects only expose methods to get and set state and to jump the PRNG. 

The random number generator is exposed via an opaque structure wrapped in a PyCapsule.  This structure has two void pointers, one to the state and one to the function that generates the next uint 64.  I think in the long-run it might make sense to expose a few additional interfaces, such as the next random double (makes sense for dSFMT) or the next random uint32 (makes sense for MT19937).  For now, I have deliberately kept it simple.

The user-facing object is called `RandomGenerator` and it can be initialized using the syntax `RandomGenerator` or `RandomGenerator(Xoroshiro128())`.  The object exposes user-facing methods (currently only `random_integer` and `random_double`).

A basic demo:

from core_prng.generator import RandomGenerator
# Splitmix 64 for now

from core_prng.xoroshiro128 import Xoroshiro128

A few questions that have come up:
  1. Should a passed core PRNG be initialized or not. The syntax RandomGenerator(Xoroshiro128) looks nicer than RandomGenerator(Xoroshiro128()) 
  2. Which low-level methods should be part of the core PRNG?  These would all be scalar generators that would be consumed by RandomGenerator and exposed through void *. I could imagine some subset of the following:
    • uint64
    • uint32
    • double
    • float
    • uint53 (applicable to PRNGs that use doubles as default type)
  3. Since RandomState is taken, a new name is needed for the user-facing object.  RandomGenerator is a placeholder but ideally, something meaningful could be chosen.
  4. I can't see how locking can be usefully implemented in the core PRNGs without a large penalty. This means that these are not threadsafe.  This isn't a massive problem but they do access the state (get or set) although with GIL.
  5. Should state be a property -- this isn't Java...

Other feedback is of course also welcome.