diff --git a/cardano-crypto-class/cardano-crypto-class.cabal b/cardano-crypto-class/cardano-crypto-class.cabal index ecf28f999..a0a249088 100644 --- a/cardano-crypto-class/cardano-crypto-class.cabal +++ b/cardano-crypto-class/cardano-crypto-class.cabal @@ -80,11 +80,11 @@ library Cardano.Crypto.Libsodium.MLockedBytes Cardano.Crypto.Libsodium.MLockedBytes.Internal Cardano.Crypto.Libsodium.UnsafeC + Cardano.Crypto.MonadMLock + Cardano.Crypto.MonadMLock.Class + Cardano.Crypto.MonadMLock.Alloc Cardano.Crypto.MEqOrd Cardano.Crypto.MLockedSeed - Cardano.Crypto.MonadSodium - Cardano.Crypto.MonadSodium.Class - Cardano.Crypto.MonadSodium.Alloc Cardano.Crypto.PinnedSizedBytes Cardano.Crypto.Seed Cardano.Crypto.Util diff --git a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed25519ML.hs b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed25519ML.hs index 923264a55..28680be42 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed25519ML.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed25519ML.hs @@ -39,11 +39,11 @@ import Control.Monad.ST.Unsafe (unsafeIOToST) import Cardano.Binary (FromCBOR (..), ToCBOR (..)) import Cardano.Foreign -import Cardano.Crypto.PinnedSizedBytes import Cardano.Crypto.Libsodium.C import Cardano.Crypto.Libsodium (MLockedSizedBytes) -import Cardano.Crypto.MonadSodium - ( MonadSodium (..) +import Cardano.Crypto.MonadMLock + ( MonadMLock (..) + , MonadPSB (..) , mlsbToByteString , mlsbFromByteStringCheck , mlsbUseAsSizedPtr @@ -51,6 +51,11 @@ import Cardano.Crypto.MonadSodium , mlsbFinalize , mlsbCopy , MEq (..) + , PinnedSizedBytes + , psbUseAsSizedPtr + , psbToByteString + , psbFromByteStringCheck + , psbCreateSizedResult ) import Cardano.Crypto.DSIGNM.Class @@ -171,7 +176,7 @@ instance DSIGNMAlgorithmBase Ed25519DSIGNM where -- reflects this. -- -- Various libsodium primitives, particularly 'MLockedSizedBytes' primitives, --- are used via the 'MonadSodium' typeclass, which is responsible for +-- are used via the 'MonadMLock' typeclass, which is responsible for -- guaranteeing orderly execution of these actions. We avoid using these -- primitives inside 'unsafeIOToST', as well as any 'IO' actions that would be -- unsafe to use inside 'unsafePerformIO'. @@ -188,12 +193,13 @@ instance DSIGNMAlgorithmBase Ed25519DSIGNM where -- we use 'getErrno', so this is fine. -- - 'BS.useAsCStringLen', which is fine and shouldn't require 'IO' to begin -- with, but unfortunately, for historical reasons, does. -instance (MonadST m, MonadSodium m, MonadThrow m) => DSIGNMAlgorithm m Ed25519DSIGNM where +instance (MonadST m, MonadMLock m, MonadPSB m, MonadThrow m) => DSIGNMAlgorithm m Ed25519DSIGNM where deriveVerKeyDSIGNM (SignKeyEd25519DSIGNM sk) = VerKeyEd25519DSIGNM <$!> do mlsbUseAsSizedPtr sk $ \skPtr -> do - (psb, maybeErrno) <- withLiftST $ \fromST -> fromST $ do - psbCreateSizedResult $ \pkPtr -> + (psb, maybeErrno) <- + psbCreateSizedResult $ \pkPtr -> + withLiftST $ \fromST -> fromST $ do cOrError $ unsafeIOToST $ c_crypto_sign_ed25519_sk_to_pk pkPtr skPtr throwOnErrno "deriveVerKeyDSIGNM @Ed25519DSIGNM" "c_crypto_sign_ed25519_sk_to_pk" maybeErrno @@ -204,8 +210,9 @@ instance (MonadST m, MonadSodium m, MonadThrow m) => DSIGNMAlgorithm m Ed25519DS let bs = getSignableRepresentation a in SigEd25519DSIGNM <$!> do mlsbUseAsSizedPtr sk $ \skPtr -> do - (psb, maybeErrno) <- withLiftST $ \fromST -> fromST $ do - psbCreateSizedResult $ \sigPtr -> do + (psb, maybeErrno) <- + psbCreateSizedResult $ \sigPtr -> do + withLiftST $ \fromST -> fromST $ do cOrError $ unsafeIOToST $ do BS.useAsCStringLen bs $ \(ptr, len) -> c_crypto_sign_ed25519_detached sigPtr nullPtr (castPtr ptr) (fromIntegral len) skPtr @@ -251,9 +258,9 @@ instance (MonadST m, MonadSodium m, MonadThrow m) => DSIGNMAlgorithm m Ed25519DS mlsbFinalize sk deriving via (MLockedSizedBytes (SizeSignKeyDSIGNM Ed25519DSIGNM)) - instance (MonadST m, MonadSodium m) => MEq m (SignKeyDSIGNM Ed25519DSIGNM) + instance (MonadST m, MonadMLock m) => MEq m (SignKeyDSIGNM Ed25519DSIGNM) -instance (MonadST m, MonadSodium m, MonadThrow m) => UnsoundDSIGNMAlgorithm m Ed25519DSIGNM where +instance (MonadST m, MonadMLock m, MonadPSB m, MonadThrow m) => UnsoundDSIGNMAlgorithm m Ed25519DSIGNM where -- -- Ser/deser (dangerous - do not use in production code) -- diff --git a/cardano-crypto-class/src/Cardano/Crypto/KES/CompactSum.hs b/cardano-crypto-class/src/Cardano/Crypto/KES/CompactSum.hs index bb4075ec4..8fa67071e 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/KES/CompactSum.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/KES/CompactSum.hs @@ -98,7 +98,7 @@ import Cardano.Crypto.KES.Class import Cardano.Crypto.KES.CompactSingle (CompactSingleKES) import Cardano.Crypto.Util import Cardano.Crypto.MLockedSeed -import qualified Cardano.Crypto.MonadSodium as NaCl +import Cardano.Crypto.MonadMLock import Control.Monad.Class.MonadST (MonadST) import Control.Monad.Class.MonadThrow (MonadThrow) import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT) @@ -150,7 +150,7 @@ instance (NFData (SignKeyKES d), NFData (VerKeyKES d)) => rnf (sk, r, vk1, vk2) instance ( OptimizedKESAlgorithm d - , NaCl.SodiumHashAlgorithm h -- needed for secure forgetting + , SodiumHashAlgorithm h -- needed for secure forgetting , SizeHash h ~ SeedSizeKES d -- can be relaxed , NoThunks (VerKeyKES (CompactSumKES h d)) , KnownNat (SizeVerKeyKES (CompactSumKES h d)) @@ -250,9 +250,9 @@ instance ( OptimizedKESAlgorithm d instance ( OptimizedKESAlgorithm d , KESSignAlgorithm m d - , NaCl.SodiumHashAlgorithm h -- needed for secure forgetting + , SodiumHashAlgorithm h -- needed for secure forgetting , SizeHash h ~ SeedSizeKES d -- can be relaxed - , NaCl.MonadSodium m + , MonadMLock m , MonadST m -- only needed for unsafe raw ser/deser , MonadThrow m , NoThunks (VerKeyKES (CompactSumKES h d)) @@ -310,7 +310,7 @@ instance ( OptimizedKESAlgorithm d {-# NOINLINE genKeyKES #-} genKeyKES r = do - (r0raw, r1raw) <- NaCl.expandHash (Proxy :: Proxy h) (mlockedSeedMLSB r) + (r0raw, r1raw) <- expandHash (Proxy :: Proxy h) (mlockedSeedMLSB r) let r0 = MLockedSeed r0raw r1 = MLockedSeed r1raw sk_0 <- genKeyKES r0 @@ -330,7 +330,7 @@ instance ( OptimizedKESAlgorithm d instance ( KESSignAlgorithm m (CompactSumKES h d) , UnsoundKESSignAlgorithm m d - , NaCl.MonadSodium m + , MonadMLock m , MonadST m ) => UnsoundKESSignAlgorithm m (CompactSumKES h d) where -- @@ -340,7 +340,7 @@ instance ( KESSignAlgorithm m (CompactSumKES h d) {-# NOINLINE rawSerialiseSignKeyKES #-} rawSerialiseSignKeyKES (SignKeyCompactSumKES sk r_1 vk_0 vk_1) = do ssk <- rawSerialiseSignKeyKES sk - sr1 <- NaCl.mlsbToByteString . mlockedSeedMLSB $ r_1 + sr1 <- mlsbToByteString . mlockedSeedMLSB $ r_1 return $ mconcat [ ssk , sr1 @@ -352,7 +352,7 @@ instance ( KESSignAlgorithm m (CompactSumKES h d) rawDeserialiseSignKeyKES b = runMaybeT $ do guard (BS.length b == fromIntegral size_total) sk <- MaybeT $ rawDeserialiseSignKeyKES b_sk - r <- MaybeT $ NaCl.mlsbFromByteStringCheck b_r + r <- MaybeT $ mlsbFromByteStringCheck b_r vk_0 <- MaybeT . return $ rawDeserialiseVerKeyKES b_vk0 vk_1 <- MaybeT . return $ rawDeserialiseVerKeyKES b_vk1 return (SignKeyCompactSumKES sk (MLockedSeed r) vk_0 vk_1) @@ -406,7 +406,7 @@ deriving via OnlyCheckWhnfNamed "SignKeyKES (CompactSumKES h d)" (SignKeyKES (Co instance (KESAlgorithm d) => NoThunks (VerKeyKES (CompactSumKES h d)) instance ( OptimizedKESAlgorithm d - , NaCl.SodiumHashAlgorithm h + , SodiumHashAlgorithm h , SizeHash h ~ SeedSizeKES d , NoThunks (VerKeyKES (CompactSumKES h d)) , KnownNat (SizeVerKeyKES (CompactSumKES h d)) @@ -418,7 +418,7 @@ instance ( OptimizedKESAlgorithm d encodedSizeExpr _size = encodedVerKeyKESSizeExpr instance ( OptimizedKESAlgorithm d - , NaCl.SodiumHashAlgorithm h + , SodiumHashAlgorithm h , SizeHash h ~ SeedSizeKES d , NoThunks (VerKeyKES (CompactSumKES h d)) , KnownNat (SizeVerKeyKES (CompactSumKES h d)) @@ -458,7 +458,7 @@ deriving instance KESAlgorithm d => Eq (SigKES (CompactSumKES h d)) instance KESAlgorithm d => NoThunks (SigKES (CompactSumKES h d)) instance ( OptimizedKESAlgorithm d - , NaCl.SodiumHashAlgorithm h + , SodiumHashAlgorithm h , SizeHash h ~ SeedSizeKES d , NoThunks (VerKeyKES (CompactSumKES h d)) , KnownNat (SizeVerKeyKES (CompactSumKES h d)) @@ -470,7 +470,7 @@ instance ( OptimizedKESAlgorithm d encodedSizeExpr _size = encodedSigKESSizeExpr instance ( OptimizedKESAlgorithm d - , NaCl.SodiumHashAlgorithm h + , SodiumHashAlgorithm h , SizeHash h ~ SeedSizeKES d , NoThunks (VerKeyKES (CompactSumKES h d)) , KnownNat (SizeVerKeyKES (CompactSumKES h d)) diff --git a/cardano-crypto-class/src/Cardano/Crypto/KES/Mock.hs b/cardano-crypto-class/src/Cardano/Crypto/KES/Mock.hs index 17c8e9cac..0ab6bda6b 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/KES/Mock.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/KES/Mock.hs @@ -34,7 +34,9 @@ import Cardano.Crypto.Seed import Cardano.Crypto.KES.Class import Cardano.Crypto.Util import Cardano.Crypto.MLockedSeed -import Cardano.Crypto.MonadSodium (mlsbAsByteString) +import Cardano.Crypto.MonadMLock + ( mlsbAsByteString + ) data MockKES (t :: Nat) diff --git a/cardano-crypto-class/src/Cardano/Crypto/KES/Simple.hs b/cardano-crypto-class/src/Cardano/Crypto/KES/Simple.hs index 043ddbb31..307263268 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/KES/Simple.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/KES/Simple.hs @@ -40,7 +40,7 @@ import Cardano.Crypto.MLockedSeed import Cardano.Crypto.Libsodium.MLockedBytes import Cardano.Crypto.Util import Data.Unit.Strict (forceElemsToWHNF) -import Cardano.Crypto.MonadSodium (MonadSodium (..), MEq (..)) +import Cardano.Crypto.MonadMLock (MonadMLock (..), MEq (..)) data SimpleKES d (t :: Nat) @@ -143,7 +143,7 @@ instance ( KESAlgorithm (SimpleKES d t) , KnownNat t , KnownNat (SeedSizeDSIGNM d * t) , MonadEvaluate m - , MonadSodium m + , MonadMLock m , MonadST m ) => KESSignAlgorithm m (SimpleKES d t) where diff --git a/cardano-crypto-class/src/Cardano/Crypto/KES/Sum.hs b/cardano-crypto-class/src/Cardano/Crypto/KES/Sum.hs index 50892f750..fa9669a4a 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/KES/Sum.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/KES/Sum.hs @@ -64,13 +64,14 @@ import Cardano.Crypto.KES.Class import Cardano.Crypto.KES.Single (SingleKES) import Cardano.Crypto.Util import Cardano.Crypto.MLockedSeed -import qualified Cardano.Crypto.MonadSodium as NaCl -import Control.Monad.Class.MonadST (MonadST) +import Cardano.Crypto.MonadMLock +import Control.Monad.Class.MonadST (MonadST (..)) import Control.Monad.Class.MonadThrow (MonadThrow) import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT) import Control.DeepSeq (NFData (..)) import GHC.TypeLits (KnownNat, type (+), type (*)) + -- | A 2^0 period KES type Sum0KES d = SingleKES d @@ -115,7 +116,7 @@ instance (NFData (SignKeyKES d), NFData (VerKeyKES d)) => rnf (sk, r, vk1, vk2) instance ( KESAlgorithm d - , NaCl.SodiumHashAlgorithm h -- needed for secure forgetting + , SodiumHashAlgorithm h -- needed for secure forgetting , SizeHash h ~ SeedSizeKES d -- can be relaxed , KnownNat ((SizeSignKeyKES d + SeedSizeKES d) + (2 * SizeVerKeyKES d)) , KnownNat (SizeSigKES d + (SizeVerKeyKES d * 2)) @@ -220,9 +221,9 @@ instance ( KESAlgorithm d off_vk1 = off_vk0 + size_vk instance ( KESSignAlgorithm m d - , NaCl.SodiumHashAlgorithm h -- needed for secure forgetting + , SodiumHashAlgorithm h -- needed for secure forgetting , SizeHash h ~ SeedSizeKES d -- can be relaxed - , NaCl.MonadSodium m + , MonadMLock m , MonadST m -- only needed for unsafe raw ser/deser , MonadThrow m , KnownNat ((SizeSignKeyKES d + SeedSizeKES d) + (2 * SizeVerKeyKES d)) @@ -276,7 +277,7 @@ instance ( KESSignAlgorithm m d {-# NOINLINE genKeyKES #-} genKeyKES r = do - (r0raw, r1raw) <- NaCl.expandHash (Proxy :: Proxy h) (mlockedSeedMLSB r) + (r0raw, r1raw) <- expandHash (Proxy :: Proxy h) (mlockedSeedMLSB r) let r0 = MLockedSeed r0raw r1 = MLockedSeed r1raw sk_0 <- genKeyKES r0 @@ -296,7 +297,7 @@ instance ( KESSignAlgorithm m d instance ( KESSignAlgorithm m (SumKES h d) , UnsoundKESSignAlgorithm m d - , NaCl.MonadSodium m + , MonadMLock m , MonadST m ) => UnsoundKESSignAlgorithm m (SumKES h d) where -- @@ -306,7 +307,7 @@ instance ( KESSignAlgorithm m (SumKES h d) {-# NOINLINE rawSerialiseSignKeyKES #-} rawSerialiseSignKeyKES (SignKeySumKES sk r_1 vk_0 vk_1) = do ssk <- rawSerialiseSignKeyKES sk - sr1 <- NaCl.mlsbToByteString . mlockedSeedMLSB $ r_1 + sr1 <- mlsbToByteString . mlockedSeedMLSB $ r_1 return $ mconcat [ ssk , sr1 @@ -318,7 +319,7 @@ instance ( KESSignAlgorithm m (SumKES h d) rawDeserialiseSignKeyKES b = runMaybeT $ do guard (BS.length b == fromIntegral size_total) sk <- MaybeT $ rawDeserialiseSignKeyKES b_sk - r <- MaybeT $ NaCl.mlsbFromByteStringCheck b_r + r <- MaybeT $ mlsbFromByteStringCheck b_r vk_0 <- MaybeT . return $ rawDeserialiseVerKeyKES b_vk0 vk_1 <- MaybeT . return $ rawDeserialiseVerKeyKES b_vk1 return (SignKeySumKES sk (MLockedSeed r) vk_0 vk_1) @@ -346,12 +347,12 @@ instance ( KESSignAlgorithm m (SumKES h d) deriving instance HashAlgorithm h => Show (VerKeyKES (SumKES h d)) deriving instance Eq (VerKeyKES (SumKES h d)) -instance (KESAlgorithm (SumKES h d), NaCl.SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) +instance (KESAlgorithm (SumKES h d), SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) => ToCBOR (VerKeyKES (SumKES h d)) where toCBOR = encodeVerKeyKES encodedSizeExpr _size = encodedVerKeyKESSizeExpr -instance (KESAlgorithm (SumKES h d), NaCl.SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) +instance (KESAlgorithm (SumKES h d), SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) => FromCBOR (VerKeyKES (SumKES h d)) where fromCBOR = decodeVerKeyKES @@ -385,11 +386,11 @@ deriving instance (KESAlgorithm d, KESAlgorithm (SumKES h d)) => Eq (SigKES (Sum instance KESAlgorithm d => NoThunks (SigKES (SumKES h d)) -instance (KESAlgorithm (SumKES h d), NaCl.SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) +instance (KESAlgorithm (SumKES h d), SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) => ToCBOR (SigKES (SumKES h d)) where toCBOR = encodeSigKES encodedSizeExpr _size = encodedSigKESSizeExpr -instance (KESAlgorithm (SumKES h d), NaCl.SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) +instance (KESAlgorithm (SumKES h d), SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) => FromCBOR (SigKES (SumKES h d)) where fromCBOR = decodeSigKES diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium.hs index 0201f7fc7..cd9b930fe 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium.hs @@ -23,4 +23,4 @@ module Cardano.Crypto.Libsodium ( ) where import Cardano.Crypto.Libsodium.Init -import Cardano.Crypto.MonadSodium +import Cardano.Crypto.MonadMLock diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Hash.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Hash.hs index fc9bd8073..c483dd0c0 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Hash.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Hash.hs @@ -21,8 +21,8 @@ import GHC.TypeLits import Cardano.Crypto.Hash (HashAlgorithm(SizeHash)) import Cardano.Crypto.Libsodium.Hash.Class import Cardano.Crypto.Libsodium.MLockedBytes.Internal -import Cardano.Crypto.MonadSodium.Class -import Cardano.Crypto.MonadSodium.Alloc +import Cardano.Crypto.MonadMLock.Class +import Cardano.Crypto.MonadMLock.Alloc import Control.Monad.Class.MonadST (MonadST (..)) import Control.Monad.Class.MonadThrow (MonadThrow) import Control.Monad.ST.Unsafe (unsafeIOToST) @@ -33,7 +33,7 @@ import Control.Monad.ST.Unsafe (unsafeIOToST) expandHash :: forall h m proxy. - (SodiumHashAlgorithm h, MonadSodium m, MonadST m, MonadThrow m) + (SodiumHashAlgorithm h, MonadMLock m, MonadST m, MonadThrow m) => proxy h -> MLockedSizedBytes (SizeHash h) -> m (MLockedSizedBytes (SizeHash h), MLockedSizedBytes (SizeHash h)) diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedBytes/Internal.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedBytes/Internal.hs index 69c03f2c6..723693950 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedBytes/Internal.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedBytes/Internal.hs @@ -45,8 +45,8 @@ import GHC.TypeLits (KnownNat, Nat, natVal) import NoThunks.Class (NoThunks) import Cardano.Foreign -import Cardano.Crypto.MonadSodium.Class -import Cardano.Crypto.MonadSodium.Alloc +import Cardano.Crypto.MonadMLock.Class +import Cardano.Crypto.MonadMLock.Alloc import Cardano.Crypto.Libsodium.Memory.Internal (MLockedForeignPtr (..)) import Cardano.Crypto.Libsodium.C import Cardano.Crypto.MEqOrd @@ -78,7 +78,7 @@ instance KnownNat n => Show (MLockedSizedBytes n) where -- hexstr = concatMap (printf "%02x") bytes -- in "MLSB " ++ hexstr -instance (MonadSodium m, MonadST m, KnownNat n) => MEq m (MLockedSizedBytes n) where +instance (MonadMLock m, MonadST m, KnownNat n) => MEq m (MLockedSizedBytes n) where equalsM = mlsbEq nextPowerOf2 :: forall n. (Num n, Ord n, Bits n) => n -> n @@ -94,11 +94,11 @@ traceMLSB :: KnownNat n => MLockedSizedBytes n -> IO () traceMLSB = print {-# DEPRECATED traceMLSB "Don't leave traceMLockedForeignPtr in production" #-} -withMLSB :: forall b n m. (MonadSodium m) => MLockedSizedBytes n -> (Ptr (SizedVoid n) -> m b) -> m b +withMLSB :: forall b n m. (MonadMLock m) => MLockedSizedBytes n -> (Ptr (SizedVoid n) -> m b) -> m b withMLSB (MLSB fptr) action = withMLockedForeignPtr fptr action withMLSBChunk :: forall b n n' m. - (MonadSodium m, MonadST m, KnownNat n, KnownNat n') + (MonadMLock m, MonadST m, KnownNat n, KnownNat n') => MLockedSizedBytes n -> Int -> (MLockedSizedBytes n' -> m b) @@ -123,7 +123,7 @@ mlsbSize mlsb = fromInteger (natVal mlsb) -- | Allocate a new 'MLockedSizedBytes'. The caller is responsible for -- deallocating it ('mlsbFinalize') when done with it. The contents of the -- memory block is undefined. -mlsbNew :: forall n m. (KnownNat n, MonadSodium m) => m (MLockedSizedBytes n) +mlsbNew :: forall n m. (KnownNat n, MonadMLock m) => m (MLockedSizedBytes n) mlsbNew = MLSB <$> mlockedAllocForeignPtrBytes size align where @@ -133,19 +133,19 @@ mlsbNew = -- | Allocate a new 'MLockedSizedBytes', and pre-fill it with zeroes. -- The caller is responsible for deallocating it ('mlsbFinalize') when done -- with it. (See also 'mlsbNew'). -mlsbNewZero :: forall n m. (KnownNat n, MonadSodium m) => m (MLockedSizedBytes n) +mlsbNewZero :: forall n m. (KnownNat n, MonadMLock m) => m (MLockedSizedBytes n) mlsbNewZero = do mlsb <- mlsbNew mlsbZero mlsb return mlsb -- | Overwrite an existing 'MLockedSizedBytes' with zeroes. -mlsbZero :: forall n m. (KnownNat n, MonadSodium m) => MLockedSizedBytes n -> m () +mlsbZero :: forall n m. (KnownNat n, MonadMLock m) => MLockedSizedBytes n -> m () mlsbZero mlsb = do withMLSB mlsb $ \ptr -> zeroMem ptr (mlsbSize mlsb) -- | Create a deep mlocked copy of an 'MLockedSizedBytes'. -mlsbCopy :: forall n m. (KnownNat n, MonadSodium m) => MLockedSizedBytes n -> m (MLockedSizedBytes n) +mlsbCopy :: forall n m. (KnownNat n, MonadMLock m) => MLockedSizedBytes n -> m (MLockedSizedBytes n) mlsbCopy src = mlsbUseAsCPtr src $ \ptrSrc -> do dst <- mlsbNew withMLSB dst $ \ptrDst -> do @@ -160,7 +160,7 @@ mlsbCopy src = mlsbUseAsCPtr src $ \ptrSrc -> do -- 'mlsbNew' or 'mlsbNewZero' to create 'MLockedSizedBytes' values, and -- manipulate them through 'withMLSB', 'mlsbUseAsCPtr', or 'mlsbUseAsSizedPtr'. -- (See also 'mlsbFromByteStringCheck') -mlsbFromByteString :: forall n m. (KnownNat n, MonadSodium m, MonadST m) +mlsbFromByteString :: forall n m. (KnownNat n, MonadMLock m, MonadST m) => BS.ByteString -> m (MLockedSizedBytes n) mlsbFromByteString bs = do dst <- mlsbNew @@ -178,7 +178,7 @@ mlsbFromByteString bs = do -- 'mlsbNew' or 'mlsbNewZero' to create 'MLockedSizedBytes' values, and -- manipulate them through 'withMLSB', 'mlsbUseAsCPtr', or 'mlsbUseAsSizedPtr'. -- (See also 'mlsbFromByteString') -mlsbFromByteStringCheck :: forall n m. (KnownNat n, MonadSodium m, MonadST m) => BS.ByteString -> m (Maybe (MLockedSizedBytes n)) +mlsbFromByteStringCheck :: forall n m. (KnownNat n, MonadMLock m, MonadST m) => BS.ByteString -> m (Maybe (MLockedSizedBytes n)) mlsbFromByteStringCheck bs | BS.length bs /= size = return Nothing | otherwise = Just <$> mlsbFromByteString bs @@ -200,7 +200,7 @@ mlsbAsByteString mlsb@(MLSB (SFP fptr)) = BSI.PS (castForeignPtr fptr) 0 size -- | /Note:/ this function will leak mlocked memory to the Haskell heap -- and should not be used in production code. -mlsbToByteString :: forall n m. (KnownNat n, MonadSodium m, MonadST m) => MLockedSizedBytes n -> m BS.ByteString +mlsbToByteString :: forall n m. (KnownNat n, MonadMLock m, MonadST m) => MLockedSizedBytes n -> m BS.ByteString mlsbToByteString mlsb = withMLSB mlsb $ \ptr -> withLiftST $ \liftST -> liftST . unsafeIOToST $ BS.packCStringLen (castPtr ptr, size) @@ -212,7 +212,7 @@ mlsbToByteString mlsb = -- to never copy the contents of the 'MLockedSizedBytes' value into managed -- memory through the raw pointer, because that would violate the -- secure-forgetting property of mlocked memory. -mlsbUseAsCPtr :: MonadSodium m => MLockedSizedBytes n -> (Ptr Word8 -> m r) -> m r +mlsbUseAsCPtr :: MonadMLock m => MLockedSizedBytes n -> (Ptr Word8 -> m r) -> m r mlsbUseAsCPtr (MLSB x) k = withMLockedForeignPtr x (k . castPtr) @@ -220,18 +220,18 @@ mlsbUseAsCPtr (MLSB x) k = -- should be taken to never copy the contents of the 'MLockedSizedBytes' value -- into managed memory through the sized pointer, because that would violate -- the secure-forgetting property of mlocked memory. -mlsbUseAsSizedPtr :: forall n r m. (MonadSodium m) => MLockedSizedBytes n -> (SizedPtr n -> m r) -> m r +mlsbUseAsSizedPtr :: forall n r m. (MonadMLock m) => MLockedSizedBytes n -> (SizedPtr n -> m r) -> m r mlsbUseAsSizedPtr (MLSB x) k = withMLockedForeignPtr x (k . SizedPtr . castPtr) -- | Calls 'finalizeMLockedForeignPtr' on underlying pointer. -- This function invalidates argument. -- -mlsbFinalize :: MonadSodium m => MLockedSizedBytes n -> m () +mlsbFinalize :: MonadMLock m => MLockedSizedBytes n -> m () mlsbFinalize (MLSB ptr) = finalizeMLockedForeignPtr ptr -- | 'compareM' on 'MLockedSizedBytes' -mlsbCompare :: forall n m. (MonadSodium m, MonadST m, KnownNat n) => MLockedSizedBytes n -> MLockedSizedBytes n -> m Ordering +mlsbCompare :: forall n m. (MonadMLock m, MonadST m, KnownNat n) => MLockedSizedBytes n -> MLockedSizedBytes n -> m Ordering mlsbCompare (MLSB x) (MLSB y) = withMLockedForeignPtr x $ \x' -> withMLockedForeignPtr y $ \y' -> do @@ -241,5 +241,5 @@ mlsbCompare (MLSB x) (MLSB y) = size = fromInteger $ natVal (Proxy @n) -- | 'equalsM' on 'MLockedSizedBytes' -mlsbEq :: forall n m. (MonadSodium m, MonadST m, KnownNat n) => MLockedSizedBytes n -> MLockedSizedBytes n -> m Bool +mlsbEq :: forall n m. (MonadMLock m, MonadST m, KnownNat n) => MLockedSizedBytes n -> MLockedSizedBytes n -> m Bool mlsbEq a b = (== EQ) <$> mlsbCompare a b diff --git a/cardano-crypto-class/src/Cardano/Crypto/MLockedSeed.hs b/cardano-crypto-class/src/Cardano/Crypto/MLockedSeed.hs index e5f9fc9ce..f12829f22 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/MLockedSeed.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/MLockedSeed.hs @@ -6,9 +6,9 @@ module Cardano.Crypto.MLockedSeed where -import Cardano.Crypto.MonadSodium +import Cardano.Crypto.MonadMLock ( MLockedSizedBytes - , MonadSodium (..) + , MonadMLock (..) , mlsbCopy , mlsbNew , mlsbNewZero @@ -33,7 +33,7 @@ newtype MLockedSeed n = deriving (NFData, NoThunks) deriving via (MLockedSizedBytes n) - instance (MonadSodium m, MonadST m, KnownNat n) => MEq m (MLockedSeed n) + instance (MonadMLock m, MonadST m, KnownNat n) => MEq m (MLockedSeed n) withMLockedSeedAsMLSB :: Functor m => (MLockedSizedBytes n -> m (MLockedSizedBytes n)) @@ -42,23 +42,23 @@ withMLockedSeedAsMLSB :: Functor m withMLockedSeedAsMLSB action = fmap MLockedSeed . action . mlockedSeedMLSB -mlockedSeedCopy :: (KnownNat n, MonadSodium m) => MLockedSeed n -> m (MLockedSeed n) +mlockedSeedCopy :: (KnownNat n, MonadMLock m) => MLockedSeed n -> m (MLockedSeed n) mlockedSeedCopy = withMLockedSeedAsMLSB mlsbCopy -mlockedSeedNew :: (KnownNat n, MonadSodium m) => m (MLockedSeed n) +mlockedSeedNew :: (KnownNat n, MonadMLock m) => m (MLockedSeed n) mlockedSeedNew = MLockedSeed <$> mlsbNew -mlockedSeedNewZero :: (KnownNat n, MonadSodium m) => m (MLockedSeed n) +mlockedSeedNewZero :: (KnownNat n, MonadMLock m) => m (MLockedSeed n) mlockedSeedNewZero = MLockedSeed <$> mlsbNewZero -mlockedSeedFinalize :: (MonadSodium m) => MLockedSeed n -> m () +mlockedSeedFinalize :: (MonadMLock m) => MLockedSeed n -> m () mlockedSeedFinalize = mlsbFinalize . mlockedSeedMLSB -mlockedSeedUseAsCPtr :: (MonadSodium m) => MLockedSeed n -> (Ptr Word8 -> m b) -> m b +mlockedSeedUseAsCPtr :: (MonadMLock m) => MLockedSeed n -> (Ptr Word8 -> m b) -> m b mlockedSeedUseAsCPtr seed = mlsbUseAsCPtr (mlockedSeedMLSB seed) -mlockedSeedUseAsSizedPtr :: (MonadSodium m) => MLockedSeed n -> (SizedPtr n -> m b) -> m b +mlockedSeedUseAsSizedPtr :: (MonadMLock m) => MLockedSeed n -> (SizedPtr n -> m b) -> m b mlockedSeedUseAsSizedPtr seed = mlsbUseAsSizedPtr (mlockedSeedMLSB seed) diff --git a/cardano-crypto-class/src/Cardano/Crypto/MonadSodium.hs b/cardano-crypto-class/src/Cardano/Crypto/MonadMLock.hs similarity index 74% rename from cardano-crypto-class/src/Cardano/Crypto/MonadSodium.hs rename to cardano-crypto-class/src/Cardano/Crypto/MonadMLock.hs index 0085fdb7c..8ff9cbfe4 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/MonadSodium.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/MonadMLock.hs @@ -1,6 +1,5 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications #-} -- We need this so that we can forward the deprecated traceMLockedForeignPtr {-# OPTIONS_GHC -Wno-deprecations #-} @@ -14,10 +13,13 @@ -- It may also be used to provide Libsodium functionality in monad stacks that -- have IO at the bottom, but decorate certain Libsodium operations with -- additional effects, e.g. logging mlocked memory access. -module Cardano.Crypto.MonadSodium +module Cardano.Crypto.MonadMLock ( - -- * MonadSodium class - MonadSodium (..), + -- * MonadMLock class + MonadMLock (..), + MonadUnmanagedMemory (..), + MonadByteStringMemory (..), + MonadPSB (..), -- * Re-exported types MLockedForeignPtr, @@ -34,6 +36,22 @@ module Cardano.Crypto.MonadSodium mlockedAllocForeignPtr, mlockedAllocForeignPtrBytes, + -- * Generalized foreign memory access + packByteStringCStringLen, + + -- * PinnedSizedBytes operations + PinnedSizedBytes, + + psbUseAsCPtr, + psbUseAsSizedPtr, + + psbCreate, + psbCreateLen, + psbCreateSizedResult, + + psbToByteString, + psbFromByteStringCheck, + -- * MLockedSizedBytes operations mlsbNew, mlsbZero, @@ -57,8 +75,8 @@ module Cardano.Crypto.MonadSodium ) where -import Cardano.Crypto.MonadSodium.Class -import Cardano.Crypto.MonadSodium.Alloc +import Cardano.Crypto.MonadMLock.Class +import Cardano.Crypto.MonadMLock.Alloc import Cardano.Crypto.Libsodium.Hash import Cardano.Crypto.Libsodium.MLockedBytes import Cardano.Crypto.MEqOrd diff --git a/cardano-crypto-class/src/Cardano/Crypto/MonadSodium/Alloc.hs b/cardano-crypto-class/src/Cardano/Crypto/MonadMLock/Alloc.hs similarity index 80% rename from cardano-crypto-class/src/Cardano/Crypto/MonadSodium/Alloc.hs rename to cardano-crypto-class/src/Cardano/Crypto/MonadMLock/Alloc.hs index 5eecbafb5..1f05b13a8 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/MonadSodium/Alloc.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/MonadMLock/Alloc.hs @@ -14,9 +14,9 @@ -- It may also be used to provide Libsodium functionality in monad stacks that -- have IO at the bottom, but decorate certain Libsodium operations with -- additional effects, e.g. logging mlocked memory access. -module Cardano.Crypto.MonadSodium.Alloc +module Cardano.Crypto.MonadMLock.Alloc ( - MonadSodium (..), + MonadMLock (..), mlockedAlloca, mlockedAllocaSized, mlockedAllocForeignPtr, @@ -27,7 +27,7 @@ module Cardano.Crypto.MonadSodium.Alloc ) where -import Cardano.Crypto.MonadSodium.Class +import Cardano.Crypto.MonadMLock.Class import Control.Monad.Class.MonadThrow (MonadThrow, bracket) import qualified Cardano.Crypto.Libsodium.Memory as NaCl @@ -40,12 +40,12 @@ import Foreign.C.Types (CSize) import Foreign.Ptr (Ptr) import Data.Proxy (Proxy (..)) -mlockedAllocaSized :: forall m n b. (MonadSodium m, MonadThrow m, KnownNat n) => (SizedPtr n -> m b) -> m b +mlockedAllocaSized :: forall m n b. (MonadMLock m, MonadThrow m, KnownNat n) => (SizedPtr n -> m b) -> m b mlockedAllocaSized k = mlockedAlloca size (k . SizedPtr) where size :: CSize size = fromInteger (natVal (Proxy @n)) -mlockedAllocForeignPtrBytes :: (MonadSodium m) => CSize -> CSize -> m (MLockedForeignPtr a) +mlockedAllocForeignPtrBytes :: (MonadMLock m) => CSize -> CSize -> m (MLockedForeignPtr a) mlockedAllocForeignPtrBytes size align = do mlockedMalloc size' where @@ -56,7 +56,7 @@ mlockedAllocForeignPtrBytes size align = do where (q,m) = size `quotRem` align -mlockedAllocForeignPtr :: forall a m . (MonadSodium m, Storable a) => m (MLockedForeignPtr a) +mlockedAllocForeignPtr :: forall a m . (MonadMLock m, Storable a) => m (MLockedForeignPtr a) mlockedAllocForeignPtr = mlockedAllocForeignPtrBytes size align where @@ -69,7 +69,7 @@ mlockedAllocForeignPtr = align :: CSize align = fromIntegral $ alignment dummy -mlockedAlloca :: forall a b m. (MonadSodium m, MonadThrow m) => CSize -> (Ptr a -> m b) -> m b +mlockedAlloca :: forall a b m. (MonadMLock m, MonadThrow m) => CSize -> (Ptr a -> m b) -> m b mlockedAlloca size = bracket alloc free . flip withMLockedForeignPtr where diff --git a/cardano-crypto-class/src/Cardano/Crypto/MonadMLock/Class.hs b/cardano-crypto-class/src/Cardano/Crypto/MonadMLock/Class.hs new file mode 100644 index 000000000..0687d45c9 --- /dev/null +++ b/cardano-crypto-class/src/Cardano/Crypto/MonadMLock/Class.hs @@ -0,0 +1,198 @@ +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleInstances #-} + +-- We need this so that we can forward the deprecated traceMLockedForeignPtr +{-# OPTIONS_GHC -Wno-deprecations #-} + +-- | The Libsodium API generalized to fit arbitrary-ish Monads. +-- +-- The purpose of this module is to provide a drop-in replacement for the plain +-- 'Cardano.Crypto.Libsodium' module, but such that the Monad in which some +-- essential actions run can be mocked, rather than forcing it to be 'IO'. +-- +-- It may also be used to provide Libsodium functionality in monad stacks that +-- have IO at the bottom, but decorate certain Libsodium operations with +-- additional effects, e.g. logging mlocked memory access. +module Cardano.Crypto.MonadMLock.Class +( + MonadMLock (..), + MonadUnmanagedMemory (..), + MonadByteStringMemory (..), + MonadPSB (..), + + module PSB_Export, + + psbUseAsCPtr, + psbUseAsSizedPtr, + + psbCreate, + psbCreateLen, + psbCreateSized, + psbCreateSizedResult, + + packByteStringCStringLen, + + -- * Re-exports from plain Libsodium module + NaCl.MLockedForeignPtr, +) +where + +import Cardano.Crypto.Libsodium.Memory.Internal (MLockedForeignPtr (..)) + +import qualified Cardano.Crypto.Libsodium.Memory as NaCl +import Control.Monad (void) +import Control.Monad.Class.MonadST (MonadST (..)) +import Control.Monad.ST.Unsafe + +import Cardano.Foreign (c_memset, c_memcpy, SizedPtr (..)) + +import Foreign.Ptr (Ptr, castPtr) +import Foreign.Storable (Storable) +import Foreign.C.Types (CSize) +import Foreign.C.String (CStringLen) +import qualified Foreign.Marshal.Alloc as Foreign +import Data.ByteString (ByteString) +import qualified Data.ByteString as BS +import qualified Cardano.Crypto.PinnedSizedBytes as PSB +import Cardano.Crypto.PinnedSizedBytes as PSB_Export + ( PinnedSizedBytes + , psbToByteString + , psbFromByteStringCheck + ) +import Data.Word (Word8) +import GHC.TypeLits (KnownNat) + +{-# DEPRECATED traceMLockedForeignPtr "Do not use traceMLockedForeignPtr in production" #-} + +-- | Primitive operations on unmanaged mlocked memory. +-- These are all implemented in 'IO' underneath, but should morally be in 'ST'. +-- There are two use cases for this: +-- - Running mlocked-memory operations in a mocking context (e.g. 'IOSim') for +-- testing purposes. +-- - Running mlocked-memory operations directly on some monad stack with 'IO' +-- at the bottom. +class MonadUnmanagedMemory m => MonadMLock m where + withMLockedForeignPtr :: forall a b. MLockedForeignPtr a -> (Ptr a -> m b) -> m b + finalizeMLockedForeignPtr :: forall a. MLockedForeignPtr a -> m () + traceMLockedForeignPtr :: (Storable a, Show a) => MLockedForeignPtr a -> m () + mlockedMalloc :: CSize -> m (MLockedForeignPtr a) + +class Monad m => MonadUnmanagedMemory m where + zeroMem :: Ptr a -> CSize -> m () + copyMem :: Ptr a -> Ptr a -> CSize -> m () + allocaBytes :: Int -> (Ptr a -> m b) -> m b + +class Monad m => MonadByteStringMemory m where + useByteStringAsCStringLen :: ByteString -> (CStringLen -> m a) -> m a + +class Monad m => MonadPSB m where + psbUseAsCPtrLen :: forall n r. + KnownNat n + => PSB.PinnedSizedBytes n + -> (Ptr Word8 -> CSize -> m r) + -> m r + psbCreateResultLen :: forall n r. + KnownNat n + => (Ptr Word8 -> CSize -> m r) + -> m (PSB.PinnedSizedBytes n, r) + +instance MonadMLock IO where + withMLockedForeignPtr = NaCl.withMLockedForeignPtr + finalizeMLockedForeignPtr = NaCl.finalizeMLockedForeignPtr + traceMLockedForeignPtr = NaCl.traceMLockedForeignPtr + mlockedMalloc = NaCl.mlockedMalloc + +instance MonadUnmanagedMemory IO where + zeroMem ptr size = void $ c_memset (castPtr ptr) 0 size + copyMem dst src size = void $ c_memcpy (castPtr dst) (castPtr src) size + allocaBytes = Foreign.allocaBytes + +instance MonadByteStringMemory IO where + useByteStringAsCStringLen = BS.useAsCStringLen + +instance MonadPSB IO where + psbUseAsCPtrLen = PSB.psbUseAsCPtrLen + psbCreateResultLen = PSB.psbCreateResultLen + +psbUseAsCPtr :: forall n r m. + MonadPSB m + => KnownNat n + => PinnedSizedBytes n + -> (Ptr Word8 -> m r) + -> m r +psbUseAsCPtr psb action = + psbUseAsCPtrLen psb $ \ptr _ -> action ptr + +psbUseAsSizedPtr :: forall n r m. + MonadPSB m + => KnownNat n + => PinnedSizedBytes n + -> (SizedPtr n -> m r) + -> m r +psbUseAsSizedPtr psb action = + psbUseAsCPtrLen psb $ \ptr _len -> + action (SizedPtr $ castPtr ptr) + +psbCreateSized :: + forall n m. + (KnownNat n, MonadPSB m) => + (SizedPtr n -> m ()) -> + m (PinnedSizedBytes n) +psbCreateSized k = psbCreate (k . SizedPtr . castPtr) + +-- | As 'psbCreateResult', but presumes that no useful value is produced: that +-- is, the function argument is run only for its side effects. +psbCreate :: + forall n m. + (KnownNat n, MonadPSB m) => + (Ptr Word8 -> m ()) -> + m (PinnedSizedBytes n) +psbCreate f = fst <$> psbCreateResult f + +-- | As 'psbCreateResultLen', but presumes that no useful value is produced: +-- that is, the function argument is run only for its side effects. +psbCreateLen :: + forall n m. + (KnownNat n, MonadPSB m) => + (Ptr Word8 -> CSize -> m ()) -> + m (PinnedSizedBytes n) +psbCreateLen f = fst <$> psbCreateResultLen f + +-- | Given an \'initialization action\', which also produces some result, allocate +-- new pinned memory of the specified size, perform the action, then return the +-- result together with the initialized pinned memory (as a 'PinnedSizedBytes'). +-- +-- = Note +-- +-- It is essential that @r@ is not the 'Ptr' given to the function argument. +-- Returning this 'Ptr' is /extremely/ unsafe: +-- +-- * It breaks referential transparency guarantees by aliasing supposedly +-- immutable memory; and +-- * This 'Ptr' could refer to memory which has already been garbage collected, +-- which can lead to segfaults or out-of-bounds reads. +-- +-- This poses both correctness /and/ security risks, so please don't do it. +psbCreateResult :: + forall n r m. + (KnownNat n, MonadPSB m) => + (Ptr Word8 -> m r) -> + m (PinnedSizedBytes n, r) +psbCreateResult f = psbCreateResultLen (\p _ -> f p) + +-- | As 'psbCreateResult', but gives a 'SizedPtr' to the function argument. The +-- same caveats apply to this function as to 'psbCreateResult': the 'SizedPtr' +-- given to the function argument /must not/ be resulted as @r@. +psbCreateSizedResult :: + forall n r m. + (KnownNat n, MonadPSB m) => + (SizedPtr n -> m r) -> + m (PinnedSizedBytes n, r) +psbCreateSizedResult f = psbCreateResult (f . SizedPtr . castPtr) + + +packByteStringCStringLen :: MonadST m => CStringLen -> m ByteString +packByteStringCStringLen (ptr, len) = + withLiftST $ \lift -> lift . unsafeIOToST $ BS.packCStringLen (ptr, len) diff --git a/cardano-crypto-class/src/Cardano/Crypto/MonadSodium/Class.hs b/cardano-crypto-class/src/Cardano/Crypto/MonadSodium/Class.hs deleted file mode 100644 index b9a0cde56..000000000 --- a/cardano-crypto-class/src/Cardano/Crypto/MonadSodium/Class.hs +++ /dev/null @@ -1,62 +0,0 @@ -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE FlexibleInstances #-} - --- We need this so that we can forward the deprecated traceMLockedForeignPtr -{-# OPTIONS_GHC -Wno-deprecations #-} - --- | The Libsodium API generalized to fit arbitrary-ish Monads. --- --- The purpose of this module is to provide a drop-in replacement for the plain --- 'Cardano.Crypto.Libsodium' module, but such that the Monad in which some --- essential actions run can be mocked, rather than forcing it to be 'IO'. --- --- It may also be used to provide Libsodium functionality in monad stacks that --- have IO at the bottom, but decorate certain Libsodium operations with --- additional effects, e.g. logging mlocked memory access. -module Cardano.Crypto.MonadSodium.Class -( - MonadSodium (..), - - -- * Re-exports from plain Libsodium module - NaCl.MLockedForeignPtr, -) -where - -import Cardano.Crypto.Libsodium.Memory.Internal (MLockedForeignPtr (..)) - -import qualified Cardano.Crypto.Libsodium.Memory as NaCl -import Control.Monad (void) - -import Cardano.Foreign (c_memset, c_memcpy) - -import Foreign.Ptr (Ptr, castPtr) -import Foreign.Storable (Storable) -import Foreign.C.Types (CSize) - -{-# DEPRECATED traceMLockedForeignPtr "Do not use traceMLockedForeignPtr in production" #-} - --- | Primitive operations on unmanaged mlocked memory. --- These are all implemented in 'IO' underneath, but should morally be in 'ST'. --- There are two use cases for this: --- - Running mlocked-memory operations in a mocking context (e.g. 'IOSim') for --- testing purposes. --- - Running mlocked-memory operations directly on some monad stack with 'IO' --- at the bottom. -class Monad m => MonadSodium m where - withMLockedForeignPtr :: forall a b. MLockedForeignPtr a -> (Ptr a -> m b) -> m b - finalizeMLockedForeignPtr :: forall a. MLockedForeignPtr a -> m () - traceMLockedForeignPtr :: (Storable a, Show a) => MLockedForeignPtr a -> m () - mlockedMalloc :: CSize -> m (MLockedForeignPtr a) - zeroMem :: Ptr a -> CSize -> m () - copyMem :: Ptr a -> Ptr a -> CSize -> m () - -instance MonadSodium IO where - withMLockedForeignPtr = NaCl.withMLockedForeignPtr - finalizeMLockedForeignPtr = NaCl.finalizeMLockedForeignPtr - traceMLockedForeignPtr = NaCl.traceMLockedForeignPtr - mlockedMalloc = NaCl.mlockedMalloc - zeroMem ptr size = void $ c_memset (castPtr ptr) 0 size - copyMem dst src size = void $ c_memcpy (castPtr dst) (castPtr src) size diff --git a/cardano-crypto-tests/src/Cardano/Crypto/KES/ForgetMock.hs b/cardano-crypto-tests/src/Cardano/Crypto/KES/ForgetMock.hs index 9a0536a76..cc245136c 100644 --- a/cardano-crypto-tests/src/Cardano/Crypto/KES/ForgetMock.hs +++ b/cardano-crypto-tests/src/Cardano/Crypto/KES/ForgetMock.hs @@ -43,7 +43,7 @@ import Control.Monad ((<$!>)) -- The wrapped KES behaves exactly like its unwrapped payload, except that -- invocations of 'genKeyKES', 'updateKES' and 'forgetSignKeyKES' are logged -- as 'GenericEvent' 'ForgetMockEvent' values. (We use 'GenericEvent' in order --- to use the generic 'MonadSodium' instance of 'LogT'; otherwise we would +-- to use the generic 'MonadMLock' instance of 'LogT'; otherwise we would -- have to provide a boilerplate instance here). data ForgetMockKES k diff --git a/cardano-crypto-tests/src/Test/Crypto/AllocLog.hs b/cardano-crypto-tests/src/Test/Crypto/AllocLog.hs index 7c2c755df..b452bfa7a 100644 --- a/cardano-crypto-tests/src/Test/Crypto/AllocLog.hs +++ b/cardano-crypto-tests/src/Test/Crypto/AllocLog.hs @@ -6,7 +6,7 @@ {-# OPTIONS_GHC -Wno-deprecations #-} module Test.Crypto.AllocLog where -import Cardano.Crypto.MonadSodium +import Cardano.Crypto.MonadMLock import Cardano.Crypto.Libsodium.Memory.Internal (MLockedForeignPtr (..)) import Control.Tracer import Control.Monad.Reader @@ -56,10 +56,8 @@ pushLogEvent event = do pushAllocLogEvent :: Monad m => AllocEvent -> LogT AllocEvent m () pushAllocLogEvent = pushLogEvent --- | Automatically log all mlocked allocation events (allocate and free) via --- 'mlockedAlloca', 'mlockedMalloc', and associated finalizers. -instance (MonadIO m, MonadThrow m, MonadSodium m, MonadST m, RunIO m) - => MonadSodium (LogT AllocEvent m) where +instance (MonadIO m, MonadThrow m, MonadMLock m, MonadST m, RunIO m) + => MonadMLock (LogT AllocEvent m) where withMLockedForeignPtr fptr action = LogT $ do tracer <- ask lift $ withMLockedForeignPtr fptr (\ptr -> (runReaderT . unLogT) (action ptr) tracer) @@ -79,17 +77,40 @@ instance (MonadIO m, MonadThrow m, MonadSodium m, MonadST m, RunIO m) (io . runLogT tracer . pushAllocLogEvent $ FreeEv addr) return fptr +instance (MonadIO m, MonadMLock m) + => MonadUnmanagedMemory (LogT AllocEvent m) where zeroMem addr size = lift $ zeroMem addr size copyMem dst src size = lift $ copyMem dst src size + allocaBytes len action = LogT $ do + tracer <- ask + lift $ allocaBytes len (\ptr -> (runReaderT . unLogT) (action ptr) tracer) + +instance (MonadIO m, MonadByteStringMemory m) + => MonadByteStringMemory (LogT AllocEvent m) where + useByteStringAsCStringLen b action = LogT $ do + tracer <- ask + lift $ useByteStringAsCStringLen b (\csl -> (runReaderT . unLogT) (action csl) tracer) + +instance (MonadIO m, MonadPSB m) + => MonadPSB (LogT AllocEvent m) where + psbUseAsCPtrLen psb action = LogT $ do + tracer <- ask + lift $ psbUseAsCPtrLen psb (\ptr len -> (runReaderT . unLogT) (action ptr len) tracer) + + psbCreateResultLen action = LogT $ do + tracer <- ask + lift $ psbCreateResultLen (\ptr len -> (runReaderT . unLogT) (action ptr len) tracer) + + -- | Newtype wrapper over an arbitrary event; we use this to write the generic --- 'MonadSodium' instance below while avoiding overlapping instances. +-- 'MonadMLock' instance below while avoiding overlapping instances. newtype GenericEvent e = GenericEvent { concreteEvent :: e } -- | Generic instance, log nothing automatically. Log entries can be triggered -- manually using 'pushLogEvent'. -instance MonadSodium m => MonadSodium (LogT (GenericEvent e) m) where - withMLockedForeignPtr fptr (action) = LogT $ do +instance MonadMLock m => MonadMLock (LogT (GenericEvent e) m) where + withMLockedForeignPtr fptr action = LogT $ do tracer <- ask lift $ withMLockedForeignPtr fptr (\ptr -> (runReaderT . unLogT) (action ptr) tracer) @@ -97,5 +118,23 @@ instance MonadSodium m => MonadSodium (LogT (GenericEvent e) m) where traceMLockedForeignPtr = lift . traceMLockedForeignPtr mlockedMalloc size = lift (mlockedMalloc size) +instance MonadUnmanagedMemory m => MonadUnmanagedMemory (LogT (GenericEvent e) m) where zeroMem addr size = lift $ zeroMem addr size copyMem dst src size = lift $ copyMem dst src size + allocaBytes len action = LogT $ do + tracer <- ask + lift $ allocaBytes len (\ptr -> (runReaderT . unLogT) (action ptr) tracer) + +instance MonadByteStringMemory m => MonadByteStringMemory (LogT (GenericEvent e) m) where + useByteStringAsCStringLen b action = LogT $ do + tracer <- ask + lift $ useByteStringAsCStringLen b (\csl -> (runReaderT . unLogT) (action csl) tracer) + +instance MonadPSB m => MonadPSB (LogT (GenericEvent e) m) where + psbUseAsCPtrLen psb action = LogT $ do + tracer <- ask + lift $ psbUseAsCPtrLen psb (\ptr len -> (runReaderT . unLogT) (action ptr len) tracer) + + psbCreateResultLen action = LogT $ do + tracer <- ask + lift $ psbCreateResultLen (\ptr len -> (runReaderT . unLogT) (action ptr len) tracer) diff --git a/cardano-crypto-tests/src/Test/Crypto/DSIGN.hs b/cardano-crypto-tests/src/Test/Crypto/DSIGN.hs index e369ab422..358490d40 100644 --- a/cardano-crypto-tests/src/Test/Crypto/DSIGN.hs +++ b/cardano-crypto-tests/src/Test/Crypto/DSIGN.hs @@ -32,7 +32,7 @@ import Test.Tasty.QuickCheck (testProperty, QuickCheckTests) import qualified Data.ByteString as BS import qualified Cardano.Crypto.Libsodium as NaCl -import Cardano.Crypto.MonadSodium (MEq (..), (==!)) +import Cardano.Crypto.MonadMLock (MEq (..), (==!)) import Text.Show.Pretty (ppShow) @@ -431,37 +431,37 @@ testDSIGNMAlgorithm lock _ n = , testGroup "To/FromCBOR class" [ testProperty "VerKey" $ - ioPropertyWithSK lock $ \sk -> do + ioPropertyWithSK @v lock $ \sk -> do vk :: VerKeyDSIGNM v <- deriveVerKeyDSIGNM sk return $ prop_cbor vk -- No To/FromCBOR for 'SignKeyDSIGNM', see above. , testProperty "Sig" $ \(msg :: Message) -> - ioPropertyWithSK lock $ \sk -> do + ioPropertyWithSK @v lock $ \sk -> do sig :: SigDSIGNM v <- signDSIGNM () msg sk return $ prop_cbor sig ] , testGroup "ToCBOR size" [ testProperty "VerKey" $ - ioPropertyWithSK lock $ \sk -> do + ioPropertyWithSK @v lock $ \sk -> do vk :: VerKeyDSIGNM v <- deriveVerKeyDSIGNM sk return $ prop_cbor_size vk -- No To/FromCBOR for 'SignKeyDSIGNM', see above. , testProperty "Sig" $ \(msg :: Message) -> - ioPropertyWithSK lock $ \sk -> do + ioPropertyWithSK @v lock $ \sk -> do sig :: SigDSIGNM v <- signDSIGNM () msg sk return $ prop_cbor_size sig ] , testGroup "direct matches class" [ testProperty "VerKey" $ - ioPropertyWithSK lock $ \sk -> do + ioPropertyWithSK @v lock $ \sk -> do vk :: VerKeyDSIGNM v <- deriveVerKeyDSIGNM sk return $ prop_cbor_direct_vs_class encodeVerKeyDSIGNM vk -- No CBOR testing for SignKey: sign keys are stored in MLocked memory -- and require IO for access. , testProperty "Sig" $ \(msg :: Message) -> - ioPropertyWithSK lock $ \sk -> do + ioPropertyWithSK @v lock $ \sk -> do sig :: SigDSIGNM v <- signDSIGNM () msg sk return $ prop_cbor_direct_vs_class encodeSigDSIGNM sig ] diff --git a/cardano-crypto-tests/src/Test/Crypto/Instances.hs b/cardano-crypto-tests/src/Test/Crypto/Instances.hs index f295d99ee..ec10a5ceb 100644 --- a/cardano-crypto-tests/src/Test/Crypto/Instances.hs +++ b/cardano-crypto-tests/src/Test/Crypto/Instances.hs @@ -12,13 +12,8 @@ import Data.Proxy (Proxy (Proxy)) import GHC.TypeLits (KnownNat, natVal) import Test.QuickCheck (Arbitrary (..)) import qualified Test.QuickCheck.Gen as Gen -import Cardano.Crypto.MonadSodium +import Cardano.Crypto.MonadMLock import Cardano.Crypto.MLockedSeed -import Cardano.Crypto.PinnedSizedBytes ( - PinnedSizedBytes, - psbFromByteStringCheck, - psbToByteString, - ) import Control.Monad.Class.MonadThrow import Control.Monad.Class.MonadST @@ -37,19 +32,19 @@ import Control.Monad.Class.MonadST -- size :: Int -- size = fromInteger (natVal (Proxy :: Proxy n)) -mlsbFromPSB :: (MonadSodium m, MonadST m, KnownNat n) => PinnedSizedBytes n -> m (MLockedSizedBytes n) +mlsbFromPSB :: (MonadMLock m, MonadST m, KnownNat n) => PinnedSizedBytes n -> m (MLockedSizedBytes n) mlsbFromPSB = mlsbFromByteString . psbToByteString -withMLSBFromPSB :: (MonadSodium m, MonadST m, MonadThrow m, KnownNat n) => PinnedSizedBytes n -> (MLockedSizedBytes n -> m a) -> m a +withMLSBFromPSB :: (MonadMLock m, MonadST m, MonadThrow m, KnownNat n) => PinnedSizedBytes n -> (MLockedSizedBytes n -> m a) -> m a withMLSBFromPSB psb = bracket (mlsbFromPSB psb) mlsbFinalize -mlockedSeedFromPSB :: (MonadSodium m, MonadST m, KnownNat n) => PinnedSizedBytes n -> m (MLockedSeed n) +mlockedSeedFromPSB :: (MonadMLock m, MonadST m, KnownNat n) => PinnedSizedBytes n -> m (MLockedSeed n) mlockedSeedFromPSB = fmap MLockedSeed . mlsbFromPSB -withMLockedSeedFromPSB :: (MonadSodium m, MonadST m, MonadThrow m, KnownNat n) => PinnedSizedBytes n -> (MLockedSeed n -> m a) -> m a +withMLockedSeedFromPSB :: (MonadMLock m, MonadST m, MonadThrow m, KnownNat n) => PinnedSizedBytes n -> (MLockedSeed n -> m a) -> m a withMLockedSeedFromPSB psb = bracket (mlockedSeedFromPSB psb) diff --git a/cardano-crypto-tests/src/Test/Crypto/KES.hs b/cardano-crypto-tests/src/Test/Crypto/KES.hs index b4c554e69..7ab96ff9b 100644 --- a/cardano-crypto-tests/src/Test/Crypto/KES.hs +++ b/cardano-crypto-tests/src/Test/Crypto/KES.hs @@ -33,10 +33,10 @@ import Data.Foldable (traverse_) import GHC.TypeNats (KnownNat) import Control.Tracer -import Control.Monad (void) -import Control.Monad.IO.Class (MonadIO, liftIO) -import Control.Monad.Class.MonadThrow import Control.Monad.Class.MonadST +import Control.Monad.Class.MonadThrow +import Control.Monad.IO.Class (MonadIO, liftIO) +import Control.Monad (void) import Cardano.Crypto.DSIGN hiding (Signable) import Cardano.Crypto.Hash @@ -45,8 +45,7 @@ import Cardano.Crypto.KES.ForgetMock import Cardano.Crypto.Util (SignableRepresentation(..)) import Cardano.Crypto.MLockedSeed import qualified Cardano.Crypto.Libsodium as NaCl -import Cardano.Crypto.PinnedSizedBytes (PinnedSizedBytes) -import Cardano.Crypto.MonadSodium +import Cardano.Crypto.MonadMLock import Test.QuickCheck import Test.Tasty (TestTree, testGroup, adjustOption) @@ -75,6 +74,7 @@ import Test.Crypto.Instances (withMLockedSeedFromPSB) import Test.Crypto.AllocLog {- HLINT ignore "Reduce duplication" -} +{- HLINT ignore "Use head" -} -- -- The list of all tests @@ -122,7 +122,7 @@ deriving via (PureMEq (SignKeyKES (MockKES t))) instance Applicative m => MEq m deriving newtype instance (MEq m (SignKeyDSIGNM d)) => MEq m (SignKeyKES (SingleKES d)) -instance ( MonadSodium m +instance ( MonadMLock m , MonadST m , MEq m (SignKeyKES d) , Eq (VerKeyKES d) @@ -133,7 +133,7 @@ instance ( MonadSodium m deriving newtype instance (MEq m (SignKeyDSIGNM d)) => MEq m (SignKeyKES (CompactSingleKES d)) -instance ( MonadSodium m +instance ( MonadMLock m , MonadST m , MEq m (SignKeyKES d) , Eq (VerKeyKES d) @@ -144,7 +144,7 @@ instance ( MonadSodium m testKESAlloc :: forall v. - ( (forall m. (MonadSodium m, MonadThrow m, MonadST m) => KESSignAlgorithm m v) + ( (forall m. (MonadMLock m, MonadThrow m, MonadST m, MonadPSB m) => KESSignAlgorithm m v) , ContextKES v ~ () ) => Proxy v @@ -405,7 +405,7 @@ testKESAlgorithm lock _pm _pv n = -- timely forgetting. Special care must be taken to not leak the key outside of -- the wrapped action (be particularly mindful of thunks and unsafe key access -- here). -withSK :: ( MonadSodium m +withSK :: ( MonadMLock m , MonadST m , MonadThrow m , KESSignAlgorithm m v @@ -472,7 +472,7 @@ prop_oneUpdateSignKeyKES ( ContextKES v ~ () , RunIO m , MonadFail m - , MonadSodium m + , MonadMLock m , MonadST m , MonadThrow m , KESSignAlgorithm m v @@ -491,7 +491,7 @@ prop_allUpdatesSignKeyKES ( ContextKES v ~ () , RunIO m , MonadIO m - , MonadSodium m + , MonadMLock m , MonadST m , MonadThrow m , KESSignAlgorithm m v @@ -510,7 +510,7 @@ prop_totalPeriodsKES ( ContextKES v ~ () , RunIO m , MonadIO m - , MonadSodium m + , MonadMLock m , MonadST m , MonadThrow m , KESSignAlgorithm m v @@ -537,7 +537,7 @@ prop_deriveVerKeyKES ( ContextKES v ~ () , RunIO m , MonadIO m - , MonadSodium m + , MonadMLock m , MonadST m , MonadThrow m , KESSignAlgorithm m v @@ -567,7 +567,7 @@ prop_verifyKES_positive , Signable v ~ SignableRepresentation , RunIO m , MonadIO m - , MonadSodium m + , MonadMLock m , MonadST m , MonadThrow m , KESSignAlgorithm m v @@ -604,7 +604,7 @@ prop_verifyKES_negative_key , Signable v ~ SignableRepresentation , RunIO m , MonadIO m - , MonadSodium m + , MonadMLock m , MonadST m , MonadThrow m , KESSignAlgorithm m v @@ -636,7 +636,7 @@ prop_verifyKES_negative_message , Signable v ~ SignableRepresentation , RunIO m , MonadIO m - , MonadSodium m + , MonadMLock m , MonadST m , MonadThrow m , KESSignAlgorithm m v @@ -668,7 +668,7 @@ prop_verifyKES_negative_period , Signable v ~ SignableRepresentation , RunIO m , MonadIO m - , MonadSodium m + , MonadMLock m , MonadST m , MonadThrow m , KESSignAlgorithm m v @@ -703,7 +703,7 @@ prop_serialise_VerKeyKES ( ContextKES v ~ () , RunIO m , MonadIO m - , MonadSodium m + , MonadMLock m , MonadST m , MonadThrow m , KESSignAlgorithm m v @@ -735,7 +735,7 @@ prop_serialise_SigKES , Show (SignKeyKES v) , RunIO m , MonadIO m - , MonadSodium m + , MonadMLock m , MonadST m , MonadThrow m , KESSignAlgorithm m v @@ -766,7 +766,7 @@ prop_serialise_SigKES _ _ seedPSB x = withAllUpdatesKES_ :: forall m v a. ( KESSignAlgorithm m v , ContextKES v ~ () - , MonadSodium m + , MonadMLock m , MonadST m , MonadThrow m ) @@ -779,7 +779,7 @@ withAllUpdatesKES_ seedPSB f = do withAllUpdatesKES :: forall m v a. ( KESSignAlgorithm m v , ContextKES v ~ () - , MonadSodium m + , MonadMLock m , MonadST m , MonadThrow m ) diff --git a/cardano-crypto-tests/src/Test/Crypto/Util.hs b/cardano-crypto-tests/src/Test/Crypto/Util.hs index 9ee41496a..d28600b38 100644 --- a/cardano-crypto-tests/src/Test/Crypto/Util.hs +++ b/cardano-crypto-tests/src/Test/Crypto/Util.hs @@ -126,7 +126,7 @@ import qualified Test.QuickCheck.Gen as Gen import Control.Monad (guard, when) import GHC.TypeLits (Nat, KnownNat, natVal) import Formatting.Buildable (Buildable (..), build) -import Control.Concurrent.MVar (MVar, withMVar, newMVar) +import Control.Monad.Class.MonadMVar -------------------------------------------------------------------------------- -- Connecting MonadRandom to Gen @@ -359,7 +359,7 @@ noExceptionsThrown = pure (property True) doesNotThrow :: Applicative m => m a -> m Property doesNotThrow = (*> noExceptionsThrown) -newtype Lock = Lock (MVar ()) +newtype Lock = Lock (MVar IO ()) withLock :: Lock -> IO a -> IO a withLock (Lock v) = withMVar v . const