From fdd1146c01e3049d55ef90668323fa1a992beee9 Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Thu, 4 Mar 2021 18:55:05 +0000 Subject: [PATCH] implement prgFork, closes #15 --- Crypto/Random.hs | 1 + Crypto/Random/Types.hs | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Crypto/Random.hs b/Crypto/Random.hs index a1f60cc4..cdee60a8 100644 --- a/Crypto/Random.hs +++ b/Crypto/Random.hs @@ -27,6 +27,7 @@ module Crypto.Random , DRG(..) , PRG(..) , prgNew + , prgFork -- * Random abstraction , MonadRandom(..) , MonadPseudoRandom diff --git a/Crypto/Random/Types.hs b/Crypto/Random/Types.hs index 50b6bf93..9faba97c 100644 --- a/Crypto/Random/Types.hs +++ b/Crypto/Random/Types.hs @@ -13,12 +13,14 @@ module Crypto.Random.Types , DRG(..) , PRG(..) , prgNew + , prgFork , withDRG ) where import Crypto.Error import Crypto.Random.Entropy import Crypto.Internal.ByteArray +import Data.ByteString import Data.Proxy -- | A monad constraint that allows to generate random bytes @@ -52,6 +54,33 @@ prgNewEntropy myGetEntropy = prgNew :: (PRG gen, MonadRandom f) => f gen prgNew = throwCryptoError <$> prgNewEntropy getRandomBytes +prgFork :: forall g. PRG g => g -> (g, g) +prgFork gen = + {- + Background: security definition of a PRG is that later values cannot be + predicted from older values and vice versa, *unless* you know the seed or any + of the secret states. + + Therefore, we do not need to do anything fancy like hashing the seed. In more + detail, this algorithm is secure because: + + 1. Given outputs (subsequent to generating the seed) from the old PRG, one + cannot predict values of the new PRG, because that would require somehow + deriving the seed (an old output) from the subsequent outputs, which would + contradict the security definition of a PRG. + + 2. Given outputs from the new PRG, one cannot predict values of the old PRG, + because again this would require deriving the seed, then deriving the + internal secret state of the old PRG, which would again contradict the + security definition of a PRG. + + It *may* be theoretically possible to break the new PRG if you know the state + of the old PRG (to reverse-engineer what the seed was), but we assume the + caller consumes both PRGs and that they are not attacking themselves. + -} + let (seed, gen') = randomBytesGenerate (prgSeedLength (Proxy :: Proxy g)) gen + in (throwCryptoError (prgNewSeed (seed :: ByteString)), gen') + instance MonadRandom IO where getRandomBytes = getEntropy