    {-# LANGUAGE DataKinds                        #-}
    {-# LANGUAGE KindSignatures                   #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving       #-}
    {-# LANGUAGE ForeignFunctionInterface         #-}
    {-# LANGUAGE FlexibleInstances                #-}
    {-# LANGUAGE MultiParamTypeClasses            #-}
    {-# LANGUAGE TypeFamilies                     #-}

    -- | Internals of AES.
    module Raaz.Cipher.AES.Internal
           (-- * AES cipher.
             AES(..)
           -- ** AES key types.
           , KEY128, KEY192, KEY256
           , EKEY128, EKEY192, EKEY256, IV
           , aes128cbc, aes192cbc, aes256cbc
           , aes128ctr
           ) where

    import Data.String
    import Data.Word

    import Foreign.Ptr      ( castPtr, Ptr )
    import Foreign.Storable (Storable, poke)
    import GHC.TypeLits

    import Raaz.Core
    import Raaz.Random

    import Raaz.Cipher.Internal

    --------------- Basic types associated with AES -------------

    -- | The type associated with AES ciphers. Raaz provides AES variants
    -- with key lengths 128, 192 and 256. The key types for the above
    -- ciphers in cbc mode are given by the types @(`KEY128`, IV)@,
    -- @(`KEY192`, IV)@ @(`KEY256`, IV)@ respectively.
    data AES (n :: Nat) (mode :: CipherMode) = AES

    -- | The basic word used in AES.
    type WORD    = BE Word32

    -- | A tuple of AES words.
    type TUPLE n = Tuple n WORD

    -- | Key used for AES-128
    newtype KEY128  = KEY128  (TUPLE 4)  deriving (Ptr b -> Int -> IO KEY128
    Ptr b -> Int -> KEY128 -> IO ()
    Ptr KEY128 -> IO KEY128
    Ptr KEY128 -> Int -> IO KEY128
    Ptr KEY128 -> Int -> KEY128 -> IO ()
    Ptr KEY128 -> KEY128 -> IO ()
    KEY128 -> Int
    (KEY128 -> Int)
    -> (KEY128 -> Int)
    -> (Ptr KEY128 -> Int -> IO KEY128)
    -> (Ptr KEY128 -> Int -> KEY128 -> IO ())
    -> (forall b. Ptr b -> Int -> IO KEY128)
    -> (forall b. Ptr b -> Int -> KEY128 -> IO ())
    -> (Ptr KEY128 -> IO KEY128)
    -> (Ptr KEY128 -> KEY128 -> IO ())
    -> Storable KEY128
    forall b. Ptr b -> Int -> IO KEY128
    forall b. Ptr b -> Int -> KEY128 -> IO ()
    forall a.
    (a -> Int)
    -> (a -> Int)
    -> (Ptr a -> Int -> IO a)
    -> (Ptr a -> Int -> a -> IO ())
    -> (forall b. Ptr b -> Int -> IO a)
    -> (forall b. Ptr b -> Int -> a -> IO ())
    -> (Ptr a -> IO a)
    -> (Ptr a -> a -> IO ())
    -> Storable a
    poke :: Ptr KEY128 -> KEY128 -> IO ()
    $cpoke :: Ptr KEY128 -> KEY128 -> IO ()
    peek :: Ptr KEY128 -> IO KEY128
    $cpeek :: Ptr KEY128 -> IO KEY128
    pokeByteOff :: Ptr b -> Int -> KEY128 -> IO ()
    $cpokeByteOff :: forall b. Ptr b -> Int -> KEY128 -> IO ()
    peekByteOff :: Ptr b -> Int -> IO KEY128
    $cpeekByteOff :: forall b. Ptr b -> Int -> IO KEY128
    pokeElemOff :: Ptr KEY128 -> Int -> KEY128 -> IO ()
    $cpokeElemOff :: Ptr KEY128 -> Int -> KEY128 -> IO ()
    peekElemOff :: Ptr KEY128 -> Int -> IO KEY128
    $cpeekElemOff :: Ptr KEY128 -> Int -> IO KEY128
    alignment :: KEY128 -> Int
    $calignment :: KEY128 -> Int
    sizeOf :: KEY128 -> Int
    $csizeOf :: KEY128 -> Int
    Storable, Storable KEY128
    Ptr KEY128 -> IO KEY128
    Ptr KEY128 -> Int -> IO ()
    Ptr KEY128 -> KEY128 -> IO ()
    Storable KEY128 =>
    (Ptr KEY128 -> KEY128 -> IO ())
    -> (Ptr KEY128 -> IO KEY128)
    -> (Ptr KEY128 -> Int -> IO ())
    -> EndianStore KEY128
    forall w.
    Storable w =>
    (Ptr w -> w -> IO ())
    -> (Ptr w -> IO w) -> (Ptr w -> Int -> IO ()) -> EndianStore w
    adjustEndian :: Ptr KEY128 -> Int -> IO ()
    $cadjustEndian :: Ptr KEY128 -> Int -> IO ()
    load :: Ptr KEY128 -> IO KEY128
    $cload :: Ptr KEY128 -> IO KEY128
    store :: Ptr KEY128 -> KEY128 -> IO ()
    $cstore :: Ptr KEY128 -> KEY128 -> IO ()
    $cp1EndianStore :: Storable KEY128
    EndianStore)

    -- | Key used for AES-128
    newtype KEY192  = KEY192  (TUPLE 6)  deriving (Ptr b -> Int -> IO KEY192
    Ptr b -> Int -> KEY192 -> IO ()
    Ptr KEY192 -> IO KEY192
    Ptr KEY192 -> Int -> IO KEY192
    Ptr KEY192 -> Int -> KEY192 -> IO ()
    Ptr KEY192 -> KEY192 -> IO ()
    KEY192 -> Int
    (KEY192 -> Int)
    -> (KEY192 -> Int)
    -> (Ptr KEY192 -> Int -> IO KEY192)
    -> (Ptr KEY192 -> Int -> KEY192 -> IO ())
    -> (forall b. Ptr b -> Int -> IO KEY192)
    -> (forall b. Ptr b -> Int -> KEY192 -> IO ())
    -> (Ptr KEY192 -> IO KEY192)
    -> (Ptr KEY192 -> KEY192 -> IO ())
    -> Storable KEY192
    forall b. Ptr b -> Int -> IO KEY192
    forall b. Ptr b -> Int -> KEY192 -> IO ()
    forall a.
    (a -> Int)
    -> (a -> Int)
    -> (Ptr a -> Int -> IO a)
    -> (Ptr a -> Int -> a -> IO ())
    -> (forall b. Ptr b -> Int -> IO a)
    -> (forall b. Ptr b -> Int -> a -> IO ())
    -> (Ptr a -> IO a)
    -> (Ptr a -> a -> IO ())
    -> Storable a
    poke :: Ptr KEY192 -> KEY192 -> IO ()
    $cpoke :: Ptr KEY192 -> KEY192 -> IO ()
    peek :: Ptr KEY192 -> IO KEY192
    $cpeek :: Ptr KEY192 -> IO KEY192
    pokeByteOff :: Ptr b -> Int -> KEY192 -> IO ()
    $cpokeByteOff :: forall b. Ptr b -> Int -> KEY192 -> IO ()
    peekByteOff :: Ptr b -> Int -> IO KEY192
    $cpeekByteOff :: forall b. Ptr b -> Int -> IO KEY192
    pokeElemOff :: Ptr KEY192 -> Int -> KEY192 -> IO ()
    $cpokeElemOff :: Ptr KEY192 -> Int -> KEY192 -> IO ()
    peekElemOff :: Ptr KEY192 -> Int -> IO KEY192
    $cpeekElemOff :: Ptr KEY192 -> Int -> IO KEY192
    alignment :: KEY192 -> Int
    $calignment :: KEY192 -> Int
    sizeOf :: KEY192 -> Int
    $csizeOf :: KEY192 -> Int
    Storable, Storable KEY192
    Ptr KEY192 -> IO KEY192
    Ptr KEY192 -> Int -> IO ()
    Ptr KEY192 -> KEY192 -> IO ()
    Storable KEY192 =>
    (Ptr KEY192 -> KEY192 -> IO ())
    -> (Ptr KEY192 -> IO KEY192)
    -> (Ptr KEY192 -> Int -> IO ())
    -> EndianStore KEY192
    forall w.
    Storable w =>
    (Ptr w -> w -> IO ())
    -> (Ptr w -> IO w) -> (Ptr w -> Int -> IO ()) -> EndianStore w
    adjustEndian :: Ptr KEY192 -> Int -> IO ()
    $cadjustEndian :: Ptr KEY192 -> Int -> IO ()
    load :: Ptr KEY192 -> IO KEY192
    $cload :: Ptr KEY192 -> IO KEY192
    store :: Ptr KEY192 -> KEY192 -> IO ()
    $cstore :: Ptr KEY192 -> KEY192 -> IO ()
    $cp1EndianStore :: Storable KEY192
    EndianStore)

    -- | Key used for AES-128
    newtype KEY256  = KEY256  (TUPLE 8)  deriving (Ptr b -> Int -> IO KEY256
    Ptr b -> Int -> KEY256 -> IO ()
    Ptr KEY256 -> IO KEY256
    Ptr KEY256 -> Int -> IO KEY256
    Ptr KEY256 -> Int -> KEY256 -> IO ()
    Ptr KEY256 -> KEY256 -> IO ()
    KEY256 -> Int
    (KEY256 -> Int)
    -> (KEY256 -> Int)
    -> (Ptr KEY256 -> Int -> IO KEY256)
    -> (Ptr KEY256 -> Int -> KEY256 -> IO ())
    -> (forall b. Ptr b -> Int -> IO KEY256)
    -> (forall b. Ptr b -> Int -> KEY256 -> IO ())
    -> (Ptr KEY256 -> IO KEY256)
    -> (Ptr KEY256 -> KEY256 -> IO ())
    -> Storable KEY256
    forall b. Ptr b -> Int -> IO KEY256
    forall b. Ptr b -> Int -> KEY256 -> IO ()
    forall a.
    (a -> Int)
    -> (a -> Int)
    -> (Ptr a -> Int -> IO a)
    -> (Ptr a -> Int -> a -> IO ())
    -> (forall b. Ptr b -> Int -> IO a)
    -> (forall b. Ptr b -> Int -> a -> IO ())
    -> (Ptr a -> IO a)
    -> (Ptr a -> a -> IO ())
    -> Storable a
    poke :: Ptr KEY256 -> KEY256 -> IO ()
    $cpoke :: Ptr KEY256 -> KEY256 -> IO ()
    peek :: Ptr KEY256 -> IO KEY256
    $cpeek :: Ptr KEY256 -> IO KEY256
    pokeByteOff :: Ptr b -> Int -> KEY256 -> IO ()
    $cpokeByteOff :: forall b. Ptr b -> Int -> KEY256 -> IO ()
    peekByteOff :: Ptr b -> Int -> IO KEY256
    $cpeekByteOff :: forall b. Ptr b -> Int -> IO KEY256
    pokeElemOff :: Ptr KEY256 -> Int -> KEY256 -> IO ()
    $cpokeElemOff :: Ptr KEY256 -> Int -> KEY256 -> IO ()
    peekElemOff :: Ptr KEY256 -> Int -> IO KEY256
    $cpeekElemOff :: Ptr KEY256 -> Int -> IO KEY256
    alignment :: KEY256 -> Int
    $calignment :: KEY256 -> Int
    sizeOf :: KEY256 -> Int
    $csizeOf :: KEY256 -> Int
    Storable, Storable KEY256
    Ptr KEY256 -> IO KEY256
    Ptr KEY256 -> Int -> IO ()
    Ptr KEY256 -> KEY256 -> IO ()
    Storable KEY256 =>
    (Ptr KEY256 -> KEY256 -> IO ())
    -> (Ptr KEY256 -> IO KEY256)
    -> (Ptr KEY256 -> Int -> IO ())
    -> EndianStore KEY256
    forall w.
    Storable w =>
    (Ptr w -> w -> IO ())
    -> (Ptr w -> IO w) -> (Ptr w -> Int -> IO ()) -> EndianStore w
    adjustEndian :: Ptr KEY256 -> Int -> IO ()
    $cadjustEndian :: Ptr KEY256 -> Int -> IO ()
    load :: Ptr KEY256 -> IO KEY256
    $cload :: Ptr KEY256 -> IO KEY256
    store :: Ptr KEY256 -> KEY256 -> IO ()
    $cstore :: Ptr KEY256 -> KEY256 -> IO ()
    $cp1EndianStore :: Storable KEY256
    EndianStore)

    instance Encodable KEY128
    instance Encodable KEY192
    instance Encodable KEY256

    instance RandomStorable KEY128 where
      fillRandomElements :: Int -> Ptr KEY128 -> RT mem ()
    fillRandomElements = Int -> Ptr KEY128 -> RT mem ()
    forall mem a. (Memory mem, Storable a) => Int -> Ptr a -> RT mem ()
    unsafeFillRandomElements

    instance RandomStorable KEY192 where
      fillRandomElements :: Int -> Ptr KEY192 -> RT mem ()
    fillRandomElements = Int -> Ptr KEY192 -> RT mem ()
    forall mem a. (Memory mem, Storable a) => Int -> Ptr a -> RT mem ()
    unsafeFillRandomElements

    instance RandomStorable KEY256 where
      fillRandomElements :: Int -> Ptr KEY256 -> RT mem ()
    fillRandomElements = Int -> Ptr KEY256 -> RT mem ()
    forall mem a. (Memory mem, Storable a) => Int -> Ptr a -> RT mem ()
    unsafeFillRandomElements

    -- | Expects in base 16
    instance IsString KEY128 where
      fromString :: String -> KEY128
    fromString = String -> KEY128
    forall a. Encodable a => String -> a
    fromBase16

    -- | Shows in base 16
    instance Show KEY128 where
      show :: KEY128 -> String
    show = KEY128 -> String
    forall a. Encodable a => a -> String
    showBase16

    -- | Expects in  base 16
    instance IsString KEY192 where
      fromString :: String -> KEY192
    fromString = String -> KEY192
    forall a. Encodable a => String -> a
    fromBase16

    -- | Shows in base 16
    instance Show KEY192 where
      show :: KEY192 -> String
    show = KEY192 -> String
    forall a. Encodable a => a -> String
    showBase16

    -- | Expects in base 16
    instance IsString KEY256 where
      fromString :: String -> KEY256
    fromString = String -> KEY256
    forall a. Encodable a => String -> a
    fromBase16

    -- | Shows in base 16
    instance Show KEY256 where
      show :: KEY256 -> String
    show = KEY256 -> String
    forall a. Encodable a => a -> String
    showBase16

    --------------- AES CBC ---------------------------------

    -- | The IV used by the CBC mode.
    newtype IV  = IV (TUPLE 4) deriving (Ptr b -> Int -> IO IV
    Ptr b -> Int -> IV -> IO ()
    Ptr IV -> IO IV
    Ptr IV -> Int -> IO IV
    Ptr IV -> Int -> IV -> IO ()
    Ptr IV -> IV -> IO ()
    IV -> Int
    (IV -> Int)
    -> (IV -> Int)
    -> (Ptr IV -> Int -> IO IV)
    -> (Ptr IV -> Int -> IV -> IO ())
    -> (forall b. Ptr b -> Int -> IO IV)
    -> (forall b. Ptr b -> Int -> IV -> IO ())
    -> (Ptr IV -> IO IV)
    -> (Ptr IV -> IV -> IO ())
    -> Storable IV
    forall b. Ptr b -> Int -> IO IV
    forall b. Ptr b -> Int -> IV -> IO ()
    forall a.
    (a -> Int)
    -> (a -> Int)
    -> (Ptr a -> Int -> IO a)
    -> (Ptr a -> Int -> a -> IO ())
    -> (forall b. Ptr b -> Int -> IO a)
    -> (forall b. Ptr b -> Int -> a -> IO ())
    -> (Ptr a -> IO a)
    -> (Ptr a -> a -> IO ())
    -> Storable a
    poke :: Ptr IV -> IV -> IO ()
    $cpoke :: Ptr IV -> IV -> IO ()
    peek :: Ptr IV -> IO IV
    $cpeek :: Ptr IV -> IO IV
    pokeByteOff :: Ptr b -> Int -> IV -> IO ()
    $cpokeByteOff :: forall b. Ptr b -> Int -> IV -> IO ()
    peekByteOff :: Ptr b -> Int -> IO IV
    $cpeekByteOff :: forall b. Ptr b -> Int -> IO IV
    pokeElemOff :: Ptr IV -> Int -> IV -> IO ()
    $cpokeElemOff :: Ptr IV -> Int -> IV -> IO ()
    peekElemOff :: Ptr IV -> Int -> IO IV
    $cpeekElemOff :: Ptr IV -> Int -> IO IV
    alignment :: IV -> Int
    $calignment :: IV -> Int
    sizeOf :: IV -> Int
    $csizeOf :: IV -> Int
    Storable, Storable IV
    Ptr IV -> IO IV
    Ptr IV -> Int -> IO ()
    Ptr IV -> IV -> IO ()
    Storable IV =>
    (Ptr IV -> IV -> IO ())
    -> (Ptr IV -> IO IV) -> (Ptr IV -> Int -> IO ()) -> EndianStore IV
    forall w.
    Storable w =>
    (Ptr w -> w -> IO ())
    -> (Ptr w -> IO w) -> (Ptr w -> Int -> IO ()) -> EndianStore w
    adjustEndian :: Ptr IV -> Int -> IO ()
    $cadjustEndian :: Ptr IV -> Int -> IO ()
    load :: Ptr IV -> IO IV
    $cload :: Ptr IV -> IO IV
    store :: Ptr IV -> IV -> IO ()
    $cstore :: Ptr IV -> IV -> IO ()
    $cp1EndianStore :: Storable IV
    EndianStore)

    instance Encodable IV

    instance RandomStorable IV where
      fillRandomElements :: Int -> Ptr IV -> RT mem ()
    fillRandomElements = Int -> Ptr IV -> RT mem ()
    forall mem a. (Memory mem, Storable a) => Int -> Ptr a -> RT mem ()
    unsafeFillRandomElements

    -- | Expects in base16.
    instance IsString IV where
      fromString :: String -> IV
    fromString = String -> IV
    forall a. Encodable a => String -> a
    fromBase16

    -- | Shown as a its base16 encoding.
    instance Show IV where
      show :: IV -> String
    show = IV -> String
    forall a. Encodable a => a -> String
    showBase16

    ----------------- AES 128 CBC ------------------------------

    -- | 128-bit aes cipher in `CBC` mode.
    aes128cbc :: AES 128 'CBC
    aes128cbc :: AES 128 'CBC
    aes128cbc = AES 128 'CBC
    forall (n :: Nat) (mode :: CipherMode). AES n mode
    AES

    -- | The 128-bit aes cipher in cbc mode.
    instance Primitive (AES 128 'CBC) where
      blockSize :: AES 128 'CBC -> BYTES Int
    blockSize _ = Int -> BYTES Int
    forall a. a -> BYTES a
    BYTES 16
      type Implementation (AES 128 'CBC) = SomeCipherI (AES 128 'CBC)

    -- | Key is @(`KEY128`,`IV`)@ pair.
    type instance Key (AES 128 'CBC) = (KEY128,IV)

    instance Describable (AES 128 'CBC) where
      name :: AES 128 'CBC -> String
    name _ = "aes-128-cbc"
      description :: AES 128 'CBC -> String
    description _ = "The AES cipher in CBC mode with 128-bit key"

    instance Cipher (AES 128 'CBC)

    ----------------- AES 192 CBC --------------------------------

    -- | 128-bit aes cipher in `CBC` mode.
    aes192cbc :: AES 192 'CBC
    aes192cbc :: AES 192 'CBC
    aes192cbc = AES 192 'CBC
    forall (n :: Nat) (mode :: CipherMode). AES n mode
    AES

    -- | The 192-bit aes cipher in cbc mode.
    instance Primitive (AES 192 'CBC) where
      blockSize :: AES 192 'CBC -> BYTES Int
    blockSize _ = Int -> BYTES Int
    forall a. a -> BYTES a
    BYTES 16
      type Implementation (AES 192 'CBC) = SomeCipherI (AES 192 'CBC)

    -- | Key is @(`KEY192`,`IV`)@ pair.
    type instance Key (AES 192 'CBC) = (KEY192,IV)

    instance Describable (AES 192 'CBC) where
      name :: AES 192 'CBC -> String
    name _ = "aes-192-cbc"
      description :: AES 192 'CBC -> String
    description _ = "The AES cipher in CBC mode with 192-bit key"

    instance Cipher (AES 192 'CBC)

    ------------------- AES 256 CBC -----------------------------

    -- | 128-bit aes cipher in `CBC` mode.
    aes256cbc :: AES 256 'CBC
    aes256cbc :: AES 256 'CBC
    aes256cbc = AES 256 'CBC
    forall (n :: Nat) (mode :: CipherMode). AES n mode
    AES

    -- | The 256-bit aes cipher in cbc mode.
    instance Primitive (AES 256 'CBC) where
      blockSize :: AES 256 'CBC -> BYTES Int
    blockSize _ = Int -> BYTES Int
    forall a. a -> BYTES a
    BYTES 16
      type Implementation (AES 256 'CBC) = SomeCipherI (AES 256 'CBC)

    -- | Key is @(`KEY256`,`IV`)@ pair.
    type instance Key (AES 256 'CBC) = (KEY256,IV)

    instance Describable (AES 256 'CBC) where
      name :: AES 256 'CBC -> String
    name _ = "aes-256-cbc"
      description :: AES 256 'CBC -> String
    description _ = "The AES cipher in CBC mode with 256-bit key"

    instance Cipher (AES 256 'CBC)

    ------------------- AES CTR mode ---------------------------

    -- | Smart constructors for AES 128 ctr.
    aes128ctr :: AES 128 'CTR
    aes128ctr :: AES 128 'CTR
    aes128ctr = AES 128 'CTR
    forall (n :: Nat) (mode :: CipherMode). AES n mode
    AES

    --------------  Memory for storing extended keys ---------

    -- | Extended key for aes128
    newtype EKEY128 = EKEY128 (TUPLE 44) deriving (Ptr b -> Int -> IO EKEY128
    Ptr b -> Int -> EKEY128 -> IO ()
    Ptr EKEY128 -> IO EKEY128
    Ptr EKEY128 -> Int -> IO EKEY128
    Ptr EKEY128 -> Int -> EKEY128 -> IO ()
    Ptr EKEY128 -> EKEY128 -> IO ()
    EKEY128 -> Int
    (EKEY128 -> Int)
    -> (EKEY128 -> Int)
    -> (Ptr EKEY128 -> Int -> IO EKEY128)
    -> (Ptr EKEY128 -> Int -> EKEY128 -> IO ())
    -> (forall b. Ptr b -> Int -> IO EKEY128)
    -> (forall b. Ptr b -> Int -> EKEY128 -> IO ())
    -> (Ptr EKEY128 -> IO EKEY128)
    -> (Ptr EKEY128 -> EKEY128 -> IO ())
    -> Storable EKEY128
    forall b. Ptr b -> Int -> IO EKEY128
    forall b. Ptr b -> Int -> EKEY128 -> IO ()
    forall a.
    (a -> Int)
    -> (a -> Int)
    -> (Ptr a -> Int -> IO a)
    -> (Ptr a -> Int -> a -> IO ())
    -> (forall b. Ptr b -> Int -> IO a)
    -> (forall b. Ptr b -> Int -> a -> IO ())
    -> (Ptr a -> IO a)
    -> (Ptr a -> a -> IO ())
    -> Storable a
    poke :: Ptr EKEY128 -> EKEY128 -> IO ()
    $cpoke :: Ptr EKEY128 -> EKEY128 -> IO ()
    peek :: Ptr EKEY128 -> IO EKEY128
    $cpeek :: Ptr EKEY128 -> IO EKEY128
    pokeByteOff :: Ptr b -> Int -> EKEY128 -> IO ()
    $cpokeByteOff :: forall b. Ptr b -> Int -> EKEY128 -> IO ()
    peekByteOff :: Ptr b -> Int -> IO EKEY128
    $cpeekByteOff :: forall b. Ptr b -> Int -> IO EKEY128
    pokeElemOff :: Ptr EKEY128 -> Int -> EKEY128 -> IO ()
    $cpokeElemOff :: Ptr EKEY128 -> Int -> EKEY128 -> IO ()
    peekElemOff :: Ptr EKEY128 -> Int -> IO EKEY128
    $cpeekElemOff :: Ptr EKEY128 -> Int -> IO EKEY128
    alignment :: EKEY128 -> Int
    $calignment :: EKEY128 -> Int
    sizeOf :: EKEY128 -> Int
    $csizeOf :: EKEY128 -> Int
    Storable, Storable EKEY128
    Ptr EKEY128 -> IO EKEY128
    Ptr EKEY128 -> Int -> IO ()
    Ptr EKEY128 -> EKEY128 -> IO ()
    Storable EKEY128 =>
    (Ptr EKEY128 -> EKEY128 -> IO ())
    -> (Ptr EKEY128 -> IO EKEY128)
    -> (Ptr EKEY128 -> Int -> IO ())
    -> EndianStore EKEY128
    forall w.
    Storable w =>
    (Ptr w -> w -> IO ())
    -> (Ptr w -> IO w) -> (Ptr w -> Int -> IO ()) -> EndianStore w
    adjustEndian :: Ptr EKEY128 -> Int -> IO ()
    $cadjustEndian :: Ptr EKEY128 -> Int -> IO ()
    load :: Ptr EKEY128 -> IO EKEY128
    $cload :: Ptr EKEY128 -> IO EKEY128
    store :: Ptr EKEY128 -> EKEY128 -> IO ()
    $cstore :: Ptr EKEY128 -> EKEY128 -> IO ()
    $cp1EndianStore :: Storable EKEY128
    EndianStore)
    -- | Extended key for aes192
    newtype EKEY192 = EKEY192 (TUPLE 52) deriving (Ptr b -> Int -> IO EKEY192
    Ptr b -> Int -> EKEY192 -> IO ()
    Ptr EKEY192 -> IO EKEY192
    Ptr EKEY192 -> Int -> IO EKEY192
    Ptr EKEY192 -> Int -> EKEY192 -> IO ()
    Ptr EKEY192 -> EKEY192 -> IO ()
    EKEY192 -> Int
    (EKEY192 -> Int)
    -> (EKEY192 -> Int)
    -> (Ptr EKEY192 -> Int -> IO EKEY192)
    -> (Ptr EKEY192 -> Int -> EKEY192 -> IO ())
    -> (forall b. Ptr b -> Int -> IO EKEY192)
    -> (forall b. Ptr b -> Int -> EKEY192 -> IO ())
    -> (Ptr EKEY192 -> IO EKEY192)
    -> (Ptr EKEY192 -> EKEY192 -> IO ())
    -> Storable EKEY192
    forall b. Ptr b -> Int -> IO EKEY192
    forall b. Ptr b -> Int -> EKEY192 -> IO ()
    forall a.
    (a -> Int)
    -> (a -> Int)
    -> (Ptr a -> Int -> IO a)
    -> (Ptr a -> Int -> a -> IO ())
    -> (forall b. Ptr b -> Int -> IO a)
    -> (forall b. Ptr b -> Int -> a -> IO ())
    -> (Ptr a -> IO a)
    -> (Ptr a -> a -> IO ())
    -> Storable a
    poke :: Ptr EKEY192 -> EKEY192 -> IO ()
    $cpoke :: Ptr EKEY192 -> EKEY192 -> IO ()
    peek :: Ptr EKEY192 -> IO EKEY192
    $cpeek :: Ptr EKEY192 -> IO EKEY192
    pokeByteOff :: Ptr b -> Int -> EKEY192 -> IO ()
    $cpokeByteOff :: forall b. Ptr b -> Int -> EKEY192 -> IO ()
    peekByteOff :: Ptr b -> Int -> IO EKEY192
    $cpeekByteOff :: forall b. Ptr b -> Int -> IO EKEY192
    pokeElemOff :: Ptr EKEY192 -> Int -> EKEY192 -> IO ()
    $cpokeElemOff :: Ptr EKEY192 -> Int -> EKEY192 -> IO ()
    peekElemOff :: Ptr EKEY192 -> Int -> IO EKEY192
    $cpeekElemOff :: Ptr EKEY192 -> Int -> IO EKEY192
    alignment :: EKEY192 -> Int
    $calignment :: EKEY192 -> Int
    sizeOf :: EKEY192 -> Int
    $csizeOf :: EKEY192 -> Int
    Storable, Storable EKEY192
    Ptr EKEY192 -> IO EKEY192
    Ptr EKEY192 -> Int -> IO ()
    Ptr EKEY192 -> EKEY192 -> IO ()
    Storable EKEY192 =>
    (Ptr EKEY192 -> EKEY192 -> IO ())
    -> (Ptr EKEY192 -> IO EKEY192)
    -> (Ptr EKEY192 -> Int -> IO ())
    -> EndianStore EKEY192
    forall w.
    Storable w =>
    (Ptr w -> w -> IO ())
    -> (Ptr w -> IO w) -> (Ptr w -> Int -> IO ()) -> EndianStore w
    adjustEndian :: Ptr EKEY192 -> Int -> IO ()
    $cadjustEndian :: Ptr EKEY192 -> Int -> IO ()
    load :: Ptr EKEY192 -> IO EKEY192
    $cload :: Ptr EKEY192 -> IO EKEY192
    store :: Ptr EKEY192 -> EKEY192 -> IO ()
    $cstore :: Ptr EKEY192 -> EKEY192 -> IO ()
    $cp1EndianStore :: Storable EKEY192
    EndianStore)

    -- | Extended key for aes256
    newtype EKEY256 = EKEY256 (TUPLE 60) deriving (Ptr b -> Int -> IO EKEY256
    Ptr b -> Int -> EKEY256 -> IO ()
    Ptr EKEY256 -> IO EKEY256
    Ptr EKEY256 -> Int -> IO EKEY256
    Ptr EKEY256 -> Int -> EKEY256 -> IO ()
    Ptr EKEY256 -> EKEY256 -> IO ()
    EKEY256 -> Int
    (EKEY256 -> Int)
    -> (EKEY256 -> Int)
    -> (Ptr EKEY256 -> Int -> IO EKEY256)
    -> (Ptr EKEY256 -> Int -> EKEY256 -> IO ())
    -> (forall b. Ptr b -> Int -> IO EKEY256)
    -> (forall b. Ptr b -> Int -> EKEY256 -> IO ())
    -> (Ptr EKEY256 -> IO EKEY256)
    -> (Ptr EKEY256 -> EKEY256 -> IO ())
    -> Storable EKEY256
    forall b. Ptr b -> Int -> IO EKEY256
    forall b. Ptr b -> Int -> EKEY256 -> IO ()
    forall a.
    (a -> Int)
    -> (a -> Int)
    -> (Ptr a -> Int -> IO a)
    -> (Ptr a -> Int -> a -> IO ())
    -> (forall b. Ptr b -> Int -> IO a)
    -> (forall b. Ptr b -> Int -> a -> IO ())
    -> (Ptr a -> IO a)
    -> (Ptr a -> a -> IO ())
    -> Storable a
    poke :: Ptr EKEY256 -> EKEY256 -> IO ()
    $cpoke :: Ptr EKEY256 -> EKEY256 -> IO ()
    peek :: Ptr EKEY256 -> IO EKEY256
    $cpeek :: Ptr EKEY256 -> IO EKEY256
    pokeByteOff :: Ptr b -> Int -> EKEY256 -> IO ()
    $cpokeByteOff :: forall b. Ptr b -> Int -> EKEY256 -> IO ()
    peekByteOff :: Ptr b -> Int -> IO EKEY256
    $cpeekByteOff :: forall b. Ptr b -> Int -> IO EKEY256
    pokeElemOff :: Ptr EKEY256 -> Int -> EKEY256 -> IO ()
    $cpokeElemOff :: Ptr EKEY256 -> Int -> EKEY256 -> IO ()
    peekElemOff :: Ptr EKEY256 -> Int -> IO EKEY256
    $cpeekElemOff :: Ptr EKEY256 -> Int -> IO EKEY256
    alignment :: EKEY256 -> Int
    $calignment :: EKEY256 -> Int
    sizeOf :: EKEY256 -> Int
    $csizeOf :: EKEY256 -> Int
    Storable, Storable EKEY256
    Ptr EKEY256 -> IO EKEY256
    Ptr EKEY256 -> Int -> IO ()
    Ptr EKEY256 -> EKEY256 -> IO ()
    Storable EKEY256 =>
    (Ptr EKEY256 -> EKEY256 -> IO ())
    -> (Ptr EKEY256 -> IO EKEY256)
    -> (Ptr EKEY256 -> Int -> IO ())
    -> EndianStore EKEY256
    forall w.
    Storable w =>
    (Ptr w -> w -> IO ())
    -> (Ptr w -> IO w) -> (Ptr w -> Int -> IO ()) -> EndianStore w
    adjustEndian :: Ptr EKEY256 -> Int -> IO ()
    $cadjustEndian :: Ptr EKEY256 -> Int -> IO ()
    load :: Ptr EKEY256 -> IO EKEY256
    $cload :: Ptr EKEY256 -> IO EKEY256
    store :: Ptr EKEY256 -> EKEY256 -> IO ()
    $cstore :: Ptr EKEY256 -> EKEY256 -> IO ()
    $cp1EndianStore :: Storable EKEY256
    EndianStore)

    instance Initialisable (MemoryCell EKEY128) KEY128 where
      initialise :: KEY128 -> MT (MemoryCell EKEY128) ()
    initialise k :: KEY128
    k = (Ptr EKEY128 -> IO ()) -> MT (MemoryCell EKEY128) ()
    forall (mT :: * -> * -> *) a b.
    (MemoryThread mT, Storable a) =>
    (Ptr a -> IO b) -> mT (MemoryCell a) b
    withCellPointer ((Ptr EKEY128 -> IO ()) -> MT (MemoryCell EKEY128) ())
    -> (Ptr EKEY128 -> IO ()) -> MT (MemoryCell EKEY128) ()
    forall a b. (a -> b) -> a -> b
    $ KEY128 -> (Ptr EKEY128 -> IO ()) -> Ptr EKEY128 -> IO ()
    forall k ekey.
    Storable k =>
    k -> (Ptr ekey -> IO ()) -> Ptr ekey -> IO ()
    pokeAndExpand KEY128
    k (Int -> Ptr EKEY128 -> IO ()
    forall ekey. Int -> Ptr ekey -> IO ()
    c_expand 4)

    instance Initialisable (MemoryCell EKEY192) KEY192 where
      initialise :: KEY192 -> MT (MemoryCell EKEY192) ()
    initialise k :: KEY192
    k = (Ptr EKEY192 -> IO ()) -> MT (MemoryCell EKEY192) ()
    forall (mT :: * -> * -> *) a b.
    (MemoryThread mT, Storable a) =>
    (Ptr a -> IO b) -> mT (MemoryCell a) b
    withCellPointer ((Ptr EKEY192 -> IO ()) -> MT (MemoryCell EKEY192) ())
    -> (Ptr EKEY192 -> IO ()) -> MT (MemoryCell EKEY192) ()
    forall a b. (a -> b) -> a -> b
    $ KEY192 -> (Ptr EKEY192 -> IO ()) -> Ptr EKEY192 -> IO ()
    forall k ekey.
    Storable k =>
    k -> (Ptr ekey -> IO ()) -> Ptr ekey -> IO ()
    pokeAndExpand KEY192
    k (Int -> Ptr EKEY192 -> IO ()
    forall ekey. Int -> Ptr ekey -> IO ()
    c_expand 6)

    instance Initialisable (MemoryCell EKEY256) KEY256 where
      initialise :: KEY256 -> MT (MemoryCell EKEY256) ()
    initialise k :: KEY256
    k = (Ptr EKEY256 -> IO ()) -> MT (MemoryCell EKEY256) ()
    forall (mT :: * -> * -> *) a b.
    (MemoryThread mT, Storable a) =>
    (Ptr a -> IO b) -> mT (MemoryCell a) b
    withCellPointer ((Ptr EKEY256 -> IO ()) -> MT (MemoryCell EKEY256) ())
    -> (Ptr EKEY256 -> IO ()) -> MT (MemoryCell EKEY256) ()
    forall a b. (a -> b) -> a -> b
    $ KEY256 -> (Ptr EKEY256 -> IO ()) -> Ptr EKEY256 -> IO ()
    forall k ekey.
    Storable k =>
    k -> (Ptr ekey -> IO ()) -> Ptr ekey -> IO ()
    pokeAndExpand KEY256
    k (Int -> Ptr EKEY256 -> IO ()
    forall ekey. Int -> Ptr ekey -> IO ()
    c_expand 8)

    foreign import ccall unsafe
      "raaz/cipher/aes/common.h raazAESExpand"
      c_expand :: Int -> Ptr ekey -> IO ()

    -- | Poke a key and expand it with the given routine.
    pokeAndExpand :: Storable k
                  => k                    -- ^ key to poke
                  -> (Ptr ekey -> IO ())  -- ^ expansion algorithm
                  -> Ptr ekey             -- ^ buffer pointer.
                  -> IO ()
    pokeAndExpand :: k -> (Ptr ekey -> IO ()) -> Ptr ekey -> IO ()
    pokeAndExpand k :: k
    k expander :: Ptr ekey -> IO ()
    expander ptr :: Ptr ekey
    ptr = Ptr k -> k -> IO ()
    forall a. Storable a => Ptr a -> a -> IO ()
    poke (Ptr ekey -> Ptr k
    forall a b. Ptr a -> Ptr b
    castPtr Ptr ekey
    ptr) k
    k IO () -> IO () -> IO ()
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> Ptr ekey -> IO ()
    expander Ptr ekey
    ptr