mlkem-0.1.0.0: src/Marking.hs
-- |
-- Module : Marking
-- License : BSD-3-Clause
-- Copyright : (c) 2025 Olivier Chéron
--
-- Infrastructure that associates a security marking at type level to all
-- buffers created by the library. This determines which buffers need the
-- scrubbed (Sec) or regular (Pub) variants.
--
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilyDependencies #-}
module Marking
( SecurityMarking(..), Classified(..), Leak(..)
) where
import Basement.Monad
import Basement.NormalForm
import Basement.PrimType
import Basement.Types.OffsetSize
#ifdef ML_KEM_TESTING
import qualified Basement.Compat.IsList
#endif
import Control.Monad.ST
import Data.ByteArray (Bytes, ScrubbedBytes)
import qualified Data.ByteArray as B
import Data.Kind
import Foreign.Ptr (Ptr)
import Unsafe.Coerce
import Block (Block, MutableBlock, blockIndex)
import ScrubbedBlock (ScrubbedBlock)
import qualified Block
import qualified ByteArrayST as ST
import qualified ScrubbedBlock
data SecurityMarking = Sec | Pub -- secret or public information
-- Transformation called only at expected location in the LWE problem, after
-- adding noise to secret information.
--
-- Block and ScrubbedBlock have the same representation, we can force coercion
-- from Sec to Pub even though the block will be actually scrubbed. This is
-- simpler than copying to a real non-scrubbed block.
class Leak t where
leak :: t Sec -> t Pub
leak = unsafeCoerce
class Classified (marking :: SecurityMarking) where
type SecureBlock marking = (block :: Type -> Type) | block -> marking
create :: PrimType ty => CountOf ty -> (Offset ty -> ty) -> SecureBlock marking ty
index :: PrimType ty => SecureBlock marking ty -> Offset ty -> ty
map :: (PrimType a, PrimType b) => (a -> b) -> SecureBlock marking a -> SecureBlock marking b
new :: (PrimType ty, PrimMonad prim) => proxy marking -> CountOf ty -> prim (MutableBlock ty (PrimState prim))
thaw :: (PrimType ty, PrimMonad m) => SecureBlock marking ty -> m (MutableBlock ty (PrimState m))
unsafeCast :: PrimType b => SecureBlock marking a -> SecureBlock marking b
unsafeFreeze :: PrimMonad prim => MutableBlock ty (PrimState prim) -> prim (SecureBlock marking ty)
toNormalForm :: SecureBlock marking ty -> ()
#ifdef ML_KEM_TESTING
eq :: PrimType ty => SecureBlock marking ty -> SecureBlock marking ty -> Bool
showsPrec :: (PrimType ty, Show ty) => Int -> SecureBlock marking ty -> ShowS
fromList :: PrimType ty => [ty] -> SecureBlock marking ty
replicate :: PrimType ty => CountOf ty -> ty -> SecureBlock marking ty
toList :: PrimType ty => SecureBlock marking ty -> [ty]
lengthBlock :: PrimType ty => SecureBlock marking ty -> CountOf ty
#endif
type SecureBytes marking = bytes | bytes -> marking
unsafeCreate :: Int -> (forall s. Ptr a -> ST s ()) -> SecureBytes marking
lengthBytes :: SecureBytes marking -> Int
copyByteArrayToPtr :: SecureBytes marking -> Ptr a -> IO ()
instance Classified Pub where
type SecureBlock Pub = Block
create = Block.create
{-# INLINE create #-}
index = blockIndex
map = Block.map
{-# INLINE map #-}
new _ = Block.new
thaw = Block.thaw
unsafeCast = Block.unsafeCast
unsafeFreeze = Block.unsafeFreeze
toNormalForm = Basement.NormalForm.toNormalForm
#ifdef ML_KEM_TESTING
eq = (==)
showsPrec = Prelude.showsPrec
fromList = Basement.Compat.IsList.fromList
replicate = Block.replicate
toList = Basement.Compat.IsList.toList
lengthBlock = Block.length
#endif
type SecureBytes Pub = Bytes
unsafeCreate = ST.unsafeCreate
{-# INLINE unsafeCreate #-}
lengthBytes = B.length
copyByteArrayToPtr = B.copyByteArrayToPtr
instance Classified Sec where
type SecureBlock Sec = ScrubbedBlock
create = ScrubbedBlock.create
{-# INLINE create #-}
index = ScrubbedBlock.index
map = ScrubbedBlock.map
{-# INLINE map #-}
new _ = ScrubbedBlock.new
thaw = ScrubbedBlock.thaw
unsafeCast = ScrubbedBlock.unsafeCast
unsafeFreeze = ScrubbedBlock.unsafeFreeze
toNormalForm = Basement.NormalForm.toNormalForm
#ifdef ML_KEM_TESTING
eq = (==)
showsPrec = Prelude.showsPrec
fromList = ScrubbedBlock.fromList
replicate = ScrubbedBlock.replicate
toList = ScrubbedBlock.toList
lengthBlock = ScrubbedBlock.length
#endif
type SecureBytes Sec = ScrubbedBytes
unsafeCreate = ST.unsafeCreate
{-# INLINE unsafeCreate #-}
lengthBytes = B.length
copyByteArrayToPtr = B.copyByteArrayToPtr