Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Provide a way to check if a reseed is needed (Crypto.Random) #13

singpolyma opened this Issue Mar 6, 2013 · 8 comments


None yet
3 participants

singpolyma commented Mar 6, 2013

The discussion at vincenthz/hs-crypto-pubkey#1 has left me thinking it's a good idea to provide a way to check if a reseed is/will be prudent besides just getting an error when you try to gen more bytes. I don't know if this is actually practical to implement, but if it is I think it would be useful to add.


vincenthz commented Mar 6, 2013

You can already do that now:

either (const True) (const False) $ genBytes 1 rng

singpolyma commented Mar 6, 2013

Right, maybe I should have been more clear. What if there are only two bytes of entropy left? The check if there is one left will succeed. Would be nice (if it's practical) to be able to ask "how soon to reseed?" And get given a ceiling.


TomMD commented Mar 6, 2013

A reseedInfo function does seem sensible. Something like:

reseedInfo :: g -> ReseedInfo
data ReseedInfo = NeverReseed | ReseedInXBytes Integer

Something like SystemRandom would use NeverReseed while most other (deterministic) generators will use ReseedInXBytes. The byte count should be an integer because some generators have absurd periods (ex: 2^8000).

While we're fiddling with the API there are two other changes that seem to make sense. 1) SystemRandom should return the proper error when too many bytes are requested (as you reported earlier) 2) SystemRandom should probably silently ignore reseed attempts, particularly now that users will have a way to discover NeverReseed, if that is important to them, where as they didn't have such a solution before.


vincenthz commented Mar 7, 2013

Practically, choosing an integer is just going to slow down the operations for no good reason. a 64bits size is enough and allow for decent performance for - and comparaison. i would be surprise that you could generate 16 exabytes with one instance, but even then if you'ld reach it you can always reseed before the period is exhausted.

Talking about API change, did the Either GenError is being considered with it or not ?


singpolyma commented Mar 7, 2013

The Either return types are necessary to keep library authors like me from needing to do weird documentation-based bookkeeping to make sure entropy is not being reused. If end users are doing similar bookkeeping and reseeding properly they can safely assume a Right.


TomMD commented Mar 7, 2013

Vincenthz: I'll consider the issue of Integer vs Int,but are there really applications that proactively check a reseed count at all let alone often enough that it's a performance concern? I know there are generators of a period longer than 2^64 so we can't just use Word64.

Another complication is that real generators (SP800-90 for example) don't always count bytes but number of calls to the generate function. Perhaps the ADT could be more like:

data ReseedInfo = InXBytes Word64
                         | InXCalls Word64
                         | NotSoonSoRelexDamnIt
                         | Never

As for getting rid of Either GenError - that isn't going to happen. When I use an RNG I would rather get a Left NeedReseed then force the library author to throw NeedReseed forcing me to catch it in the IO monad. Not all RNGs will be willing to break with determinism and feed in a system entropy source or break with security and repeat "random" values.

I will, however, probably add documentation pointing to MonadCryptoRandom (which people should be using if the Either values bother them) as well as functions in the style of:

bytes :: CryptoRandomGen g => ByteLength -> g -> (ByteString, g)
bytes n = throwLeft . genBytes n

mkGen :: CryptoRandomGen g => ByteString -> g
mkGen = throwLeft . newGen

--- obviously I'll need to decide on a naming scheme

And along with these functions perhaps a pointer to the GenAutoReseed as an example of how to practically and safely avoid exceptions but toss determinism.


vincenthz commented Mar 8, 2013

@TomMD: you're missing my point with the Integer/Word64 issue. I know there are generators that would not fit in a W64 but that's irrevelant, you can just consider them as being maxBound on a Word64. that allows for 16 Exabytes of random before it reach 0, which will take a awful long time to reach. Performance would not only be hit in the reseed check, but in the bookkeeping you need to do on the RNG side. Again it depends what do you want to model: the real world (W64 is enough), or the theoratical world (Integer)

I've considered different units too (blocks and call in my case), but doing so make it harder to have a practical value for the user.


TomMD commented Mar 8, 2013

Ok, I have implemented this using a data type and Word64... humm.. should probably make that unboxed...


The function is reseedInfo :: g -> ReseedInfo and the data type is:

data ReseedInfo =
    = InXBytes {-# UNPACK #-} !Word64   -- ^ Generator needs reseeded in X bytes
    | InXCalls {-# UNPACK #-} !Word64   -- ^ Generator needs reseeded in X calls
    | NotSoon           -- ^ The bound is over 2^64 bytes or calls
    | Never             -- ^ This generator never reseeds (ex: 'SystemRandom')
  deriving (Eq, Ord, Show, Read, Typeable)

Comments on this structure are most welcome. I suspect many users will want what Vincent is saying, a simplified scalar value:

simplify :: ReseedInfo -> Word64
simplify (InXBytes x) = x
simplify (InXCalls x) = x*8 -- some approximation of entropy requested per call?
simplicy _ = maxBound

needReseedNow :: CryptoRandomGen g => g -> Bool
needReseedNow = (< 2^20) . simplify . reseedInfo

but I think it's best to leave that to the individual users to implement for their specific cases.

@TomMD TomMD closed this Mar 8, 2013

@singpolyma singpolyma referenced this issue in singpolyma/OpenPGP-CryptoAPI Aug 7, 2013


Updated to build against current interfaces. #4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment