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

    -- | The internals of ChaCha20 ciphers.
    module Raaz.Cipher.ChaCha20.Internal
           ( ChaCha20(..), WORD, Counter(..), IV(..), KEY(..), ChaCha20Mem(..)
           ) where

    import Control.Applicative
    import Data.Word
    import Data.String
    import Foreign.Storable
    import Prelude

    import Raaz.Core
    import Raaz.Cipher.Internal

    -- | The chacha20 stream cipher.

    -- | The word type
    type WORD     = LE Word32

    -- | The IV for the chacha20
    newtype IV       = IV (Tuple 3 (LE Word32))     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 Show IV where
      show :: IV -> String
    show = IV -> String
    forall a. Encodable a => a -> String
    showBase16
    instance IsString IV where
      fromString :: String -> IV
    fromString = String -> IV
    forall a. Encodable a => String -> a
    fromBase16

    -- | The counter type for chacha20
    newtype Counter  = Counter (LE Word32) deriving (Integer -> Counter
    Counter -> Counter
    Counter -> Counter -> Counter
    (Counter -> Counter -> Counter)
    -> (Counter -> Counter -> Counter)
    -> (Counter -> Counter -> Counter)
    -> (Counter -> Counter)
    -> (Counter -> Counter)
    -> (Counter -> Counter)
    -> (Integer -> Counter)
    -> Num Counter
    forall a.
    (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (Integer -> a)
    -> Num a
    fromInteger :: Integer -> Counter
    $cfromInteger :: Integer -> Counter
    signum :: Counter -> Counter
    $csignum :: Counter -> Counter
    abs :: Counter -> Counter
    $cabs :: Counter -> Counter
    negate :: Counter -> Counter
    $cnegate :: Counter -> Counter
    * :: Counter -> Counter -> Counter
    $c* :: Counter -> Counter -> Counter
    - :: Counter -> Counter -> Counter
    $c- :: Counter -> Counter -> Counter
    + :: Counter -> Counter -> Counter
    $c+ :: Counter -> Counter -> Counter
    Num, Ptr b -> Int -> IO Counter
    Ptr b -> Int -> Counter -> IO ()
    Ptr Counter -> IO Counter
    Ptr Counter -> Int -> IO Counter
    Ptr Counter -> Int -> Counter -> IO ()
    Ptr Counter -> Counter -> IO ()
    Counter -> Int
    (Counter -> Int)
    -> (Counter -> Int)
    -> (Ptr Counter -> Int -> IO Counter)
    -> (Ptr Counter -> Int -> Counter -> IO ())
    -> (forall b. Ptr b -> Int -> IO Counter)
    -> (forall b. Ptr b -> Int -> Counter -> IO ())
    -> (Ptr Counter -> IO Counter)
    -> (Ptr Counter -> Counter -> IO ())
    -> Storable Counter
    forall b. Ptr b -> Int -> IO Counter
    forall b. Ptr b -> Int -> Counter -> 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 Counter -> Counter -> IO ()
    $cpoke :: Ptr Counter -> Counter -> IO ()
    peek :: Ptr Counter -> IO Counter
    $cpeek :: Ptr Counter -> IO Counter
    pokeByteOff :: Ptr b -> Int -> Counter -> IO ()
    $cpokeByteOff :: forall b. Ptr b -> Int -> Counter -> IO ()
    peekByteOff :: Ptr b -> Int -> IO Counter
    $cpeekByteOff :: forall b. Ptr b -> Int -> IO Counter
    pokeElemOff :: Ptr Counter -> Int -> Counter -> IO ()
    $cpokeElemOff :: Ptr Counter -> Int -> Counter -> IO ()
    peekElemOff :: Ptr Counter -> Int -> IO Counter
    $cpeekElemOff :: Ptr Counter -> Int -> IO Counter
    alignment :: Counter -> Int
    $calignment :: Counter -> Int
    sizeOf :: Counter -> Int
    $csizeOf :: Counter -> Int
    Storable, Storable Counter
    Ptr Counter -> IO Counter
    Ptr Counter -> Int -> IO ()
    Ptr Counter -> Counter -> IO ()
    Storable Counter =>
    (Ptr Counter -> Counter -> IO ())
    -> (Ptr Counter -> IO Counter)
    -> (Ptr Counter -> Int -> IO ())
    -> EndianStore Counter
    forall w.
    Storable w =>
    (Ptr w -> w -> IO ())
    -> (Ptr w -> IO w) -> (Ptr w -> Int -> IO ()) -> EndianStore w
    adjustEndian :: Ptr Counter -> Int -> IO ()
    $cadjustEndian :: Ptr Counter -> Int -> IO ()
    load :: Ptr Counter -> IO Counter
    $cload :: Ptr Counter -> IO Counter
    store :: Ptr Counter -> Counter -> IO ()
    $cstore :: Ptr Counter -> Counter -> IO ()
    $cp1EndianStore :: Storable Counter
    EndianStore, Int -> Counter -> ShowS
    [Counter] -> ShowS
    Counter -> String
    (Int -> Counter -> ShowS)
    -> (Counter -> String) -> ([Counter] -> ShowS) -> Show Counter
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [Counter] -> ShowS
    $cshowList :: [Counter] -> ShowS
    show :: Counter -> String
    $cshow :: Counter -> String
    showsPrec :: Int -> Counter -> ShowS
    $cshowsPrec :: Int -> Counter -> ShowS
    Show, Counter -> Counter -> Bool
    (Counter -> Counter -> Bool)
    -> (Counter -> Counter -> Bool) -> Eq Counter
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Counter -> Counter -> Bool
    $c/= :: Counter -> Counter -> Bool
    == :: Counter -> Counter -> Bool
    $c== :: Counter -> Counter -> Bool
    Eq, Eq Counter
    Eq Counter =>
    (Counter -> Counter -> Ordering)
    -> (Counter -> Counter -> Bool)
    -> (Counter -> Counter -> Bool)
    -> (Counter -> Counter -> Bool)
    -> (Counter -> Counter -> Bool)
    -> (Counter -> Counter -> Counter)
    -> (Counter -> Counter -> Counter)
    -> Ord Counter
    Counter -> Counter -> Bool
    Counter -> Counter -> Ordering
    Counter -> Counter -> Counter
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    min :: Counter -> Counter -> Counter
    $cmin :: Counter -> Counter -> Counter
    max :: Counter -> Counter -> Counter
    $cmax :: Counter -> Counter -> Counter
    >= :: Counter -> Counter -> Bool
    $c>= :: Counter -> Counter -> Bool
    > :: Counter -> Counter -> Bool
    $c> :: Counter -> Counter -> Bool
    <= :: Counter -> Counter -> Bool
    $c<= :: Counter -> Counter -> Bool
    < :: Counter -> Counter -> Bool
    $c< :: Counter -> Counter -> Bool
    compare :: Counter -> Counter -> Ordering
    $ccompare :: Counter -> Counter -> Ordering
    $cp1Ord :: Eq Counter
    Ord)

    -- | The key type.
    newtype KEY      = ChaCha20Key (Tuple 8 WORD) deriving (Ptr b -> Int -> IO KEY
    Ptr b -> Int -> KEY -> IO ()
    Ptr KEY -> IO KEY
    Ptr KEY -> Int -> IO KEY
    Ptr KEY -> Int -> KEY -> IO ()
    Ptr KEY -> KEY -> IO ()
    KEY -> Int
    (KEY -> Int)
    -> (KEY -> Int)
    -> (Ptr KEY -> Int -> IO KEY)
    -> (Ptr KEY -> Int -> KEY -> IO ())
    -> (forall b. Ptr b -> Int -> IO KEY)
    -> (forall b. Ptr b -> Int -> KEY -> IO ())
    -> (Ptr KEY -> IO KEY)
    -> (Ptr KEY -> KEY -> IO ())
    -> Storable KEY
    forall b. Ptr b -> Int -> IO KEY
    forall b. Ptr b -> Int -> KEY -> 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 KEY -> KEY -> IO ()
    $cpoke :: Ptr KEY -> KEY -> IO ()
    peek :: Ptr KEY -> IO KEY
    $cpeek :: Ptr KEY -> IO KEY
    pokeByteOff :: Ptr b -> Int -> KEY -> IO ()
    $cpokeByteOff :: forall b. Ptr b -> Int -> KEY -> IO ()
    peekByteOff :: Ptr b -> Int -> IO KEY
    $cpeekByteOff :: forall b. Ptr b -> Int -> IO KEY
    pokeElemOff :: Ptr KEY -> Int -> KEY -> IO ()
    $cpokeElemOff :: Ptr KEY -> Int -> KEY -> IO ()
    peekElemOff :: Ptr KEY -> Int -> IO KEY
    $cpeekElemOff :: Ptr KEY -> Int -> IO KEY
    alignment :: KEY -> Int
    $calignment :: KEY -> Int
    sizeOf :: KEY -> Int
    $csizeOf :: KEY -> Int
    Storable, Storable KEY
    Ptr KEY -> IO KEY
    Ptr KEY -> Int -> IO ()
    Ptr KEY -> KEY -> IO ()
    Storable KEY =>
    (Ptr KEY -> KEY -> IO ())
    -> (Ptr KEY -> IO KEY)
    -> (Ptr KEY -> Int -> IO ())
    -> EndianStore KEY
    forall w.
    Storable w =>
    (Ptr w -> w -> IO ())
    -> (Ptr w -> IO w) -> (Ptr w -> Int -> IO ()) -> EndianStore w
    adjustEndian :: Ptr KEY -> Int -> IO ()
    $cadjustEndian :: Ptr KEY -> Int -> IO ()
    load :: Ptr KEY -> IO KEY
    $cload :: Ptr KEY -> IO KEY
    store :: Ptr KEY -> KEY -> IO ()
    $cstore :: Ptr KEY -> KEY -> IO ()
    $cp1EndianStore :: Storable KEY
    EndianStore)

    instance Encodable KEY

    instance Show KEY where
      show :: KEY -> String
    show = KEY -> String
    forall a. Encodable a => a -> String
    showBase16

    instance IsString KEY where
      fromString :: String -> KEY
    fromString = String -> KEY
    forall a. Encodable a => String -> a
    fromBase16

    -- | The type associated with the ChaCha20 cipher.
    data ChaCha20 = ChaCha20

    instance Primitive ChaCha20 where
      blockSize :: ChaCha20 -> BYTES Int
    blockSize _ = Int -> BYTES Int
    forall a. a -> BYTES a
    BYTES 64
      type Implementation ChaCha20 = SomeCipherI ChaCha20

    -- | The key for ChaCha20.
    type instance Key ChaCha20 = (KEY, IV, Counter)

    instance Describable ChaCha20 where
      name :: ChaCha20 -> String
    name        _ = "chacha20"
      description :: ChaCha20 -> String
    description _ = "The ChaCha20 cipher"

    instance Cipher ChaCha20

    instance StreamCipher ChaCha20

    ---------- Memory for ChaCha20 implementations  ------------------
    -- | chacha20 memory
    data ChaCha20Mem = ChaCha20Mem { ChaCha20Mem -> MemoryCell KEY
    keyCell      :: MemoryCell KEY
                                   , ChaCha20Mem -> MemoryCell IV
    ivCell       :: MemoryCell IV
                                   , ChaCha20Mem -> MemoryCell Counter
    counterCell  :: MemoryCell Counter
                                   }

    instance Memory ChaCha20Mem where
      memoryAlloc :: Alloc ChaCha20Mem
    memoryAlloc     = MemoryCell KEY
    -> MemoryCell IV -> MemoryCell Counter -> ChaCha20Mem
    ChaCha20Mem (MemoryCell KEY
     -> MemoryCell IV -> MemoryCell Counter -> ChaCha20Mem)
    -> TwistRF AllocField (BYTES Int) (MemoryCell KEY)
    -> TwistRF
         AllocField
         (BYTES Int)
         (MemoryCell IV -> MemoryCell Counter -> ChaCha20Mem)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> TwistRF AllocField (BYTES Int) (MemoryCell KEY)
    forall m. Memory m => Alloc m
    memoryAlloc TwistRF
      AllocField
      (BYTES Int)
      (MemoryCell IV -> MemoryCell Counter -> ChaCha20Mem)
    -> TwistRF AllocField (BYTES Int) (MemoryCell IV)
    -> TwistRF
         AllocField (BYTES Int) (MemoryCell Counter -> ChaCha20Mem)
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> TwistRF AllocField (BYTES Int) (MemoryCell IV)
    forall m. Memory m => Alloc m
    memoryAlloc TwistRF AllocField (BYTES Int) (MemoryCell Counter -> ChaCha20Mem)
    -> TwistRF AllocField (BYTES Int) (MemoryCell Counter)
    -> Alloc ChaCha20Mem
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> TwistRF AllocField (BYTES Int) (MemoryCell Counter)
    forall m. Memory m => Alloc m
    memoryAlloc
      unsafeToPointer :: ChaCha20Mem -> Pointer
    unsafeToPointer = MemoryCell KEY -> Pointer
    forall m. Memory m => m -> Pointer
    unsafeToPointer (MemoryCell KEY -> Pointer)
    -> (ChaCha20Mem -> MemoryCell KEY) -> ChaCha20Mem -> Pointer
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ChaCha20Mem -> MemoryCell KEY
    keyCell

    instance Initialisable ChaCha20Mem (KEY, IV, Counter) where
      initialise :: (KEY, IV, Counter) -> MT ChaCha20Mem ()
    initialise (k :: KEY
    k,iv :: IV
    iv,ctr :: Counter
    ctr) = do (ChaCha20Mem -> MemoryCell KEY)
    -> MT (MemoryCell KEY) () -> MT ChaCha20Mem ()
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory ChaCha20Mem -> MemoryCell KEY
    keyCell     (MT (MemoryCell KEY) () -> MT ChaCha20Mem ())
    -> MT (MemoryCell KEY) () -> MT ChaCha20Mem ()
    forall a b. (a -> b) -> a -> b
    $ KEY -> MT (MemoryCell KEY) ()
    forall m v. Initialisable m v => v -> MT m ()
    initialise KEY
    k
                                 (ChaCha20Mem -> MemoryCell IV)
    -> MT (MemoryCell IV) () -> MT ChaCha20Mem ()
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory ChaCha20Mem -> MemoryCell IV
    ivCell      (MT (MemoryCell IV) () -> MT ChaCha20Mem ())
    -> MT (MemoryCell IV) () -> MT ChaCha20Mem ()
    forall a b. (a -> b) -> a -> b
    $ IV -> MT (MemoryCell IV) ()
    forall m v. Initialisable m v => v -> MT m ()
    initialise IV
    iv
                                 (ChaCha20Mem -> MemoryCell Counter)
    -> MT (MemoryCell Counter) () -> MT ChaCha20Mem ()
    forall (mT :: * -> * -> *) mem submem a.
    MemoryThread mT =>
    (mem -> submem) -> mT submem a -> mT mem a
    onSubMemory ChaCha20Mem -> MemoryCell Counter
    counterCell (MT (MemoryCell Counter) () -> MT ChaCha20Mem ())
    -> MT (MemoryCell Counter) () -> MT ChaCha20Mem ()
    forall a b. (a -> b) -> a -> b
    $ Counter -> MT (MemoryCell Counter) ()
    forall m v. Initialisable m v => v -> MT m ()
    initialise Counter
    ctr

    instance Initialisable ChaCha20Mem (KEY, IV) where
      initialise :: (KEY, IV) -> MT ChaCha20Mem ()
    initialise (k :: KEY
    k, iv :: IV
    iv) = (KEY, IV, Counter) -> MT ChaCha20Mem ()
    forall m v. Initialisable m v => v -> MT m ()
    initialise (KEY
    k, IV
    iv, 0 :: Counter)