davidbau / seedrandom

seeded random number generator for Javascript
2.04k stars 160 forks source link

Saved state doesn't work #33

Closed Lomacar closed 8 years ago

Lomacar commented 8 years ago

I can't even run the example in the documentation:

var seedrandom = Math.seedrandom;
var saveable = seedrandom("secret-seed", {state: true});
for (var j = 0; j < 1e5; ++j) saveable();
var saved = saveable.state();
var replica = seedrandom("", {state: saved});
assert(replica() == saveable());

I get an error: Uncaught TypeError: saveable.state is not a function(…)

tmedwards commented 8 years ago

The example is erroneous (explained at the bottom). If requested, the state() method is always on the PRNG itself.

If you replace Math.random with Math.seedrandom, then you need to call sate() on Math.random. For example:

// Initially...
Math.seedrandom('secret-seed', { state : true }); // replaces `Math.random`, returns seed
for (var j = 0; j < 1e5; ++j) Math.random();
var savedState = Math.random.state();

// Later, to restore the state...
Math.seedrandom('', { state : savedState }); // replace `Math.random`, using state

On the other hand, if you create a separate instance for seedrandom, then you'll need to call sate() on that instance. For example:

// Initially...
var myRandom = new Math.seedrandom('secret-seed', { state : true }); // returns PRNG
for (var j = 0; j < 1e5; ++j) myRandom();
var savedState = myRandom.state();

// Later, to restore the state...
var myRandom = new Math.seedrandom('', { state : savedState }); // returns PRNG, using state

The problem with the example is that it's clearly written assuming you'll have seedrandom return a new instance, rather than overwriting Math.random, but whoever wrote it forgot to use the new operator. So, instead, as written it replaces Math.random and returns the seed, rather than returning the new instance and leaving Math.random alone. The seed is just a string, which is why you can't call state() on it.

The seedrandom invocations in the example:

var saveable = seedrandom("secret-seed", {state: true});

var replica = seedrandom("", {state: saved});

Should have been written using new, like so:

var saveable = new seedrandom("secret-seed", {state: true});

var replica = new seedrandom("", {state: saved});
Lomacar commented 8 years ago

@tmedwards None of your examples work. I still always get same error that XYZ.state is not a function(…).

In fact .state is undefined.

tmedwards commented 8 years ago

Both of my examples were tested (against the latest release) and do, in fact, work. I don't know what you're doing wrong.

davidbau commented 8 years ago

Although the API is slightly confusing, it does work. The purpose of the slightly design is to make sure that prng instances are perfectly opaque (e.g., if made available to adversarial code) unless you have explicitly asked for the state to be transparent.

Closing as by-design.