content: {-# LANGUAGE DataKinds                  #-}
  
  -- | The portable C-implementation of Blake2b.
  module ChaCha20.CPortable where
  
  import           Foreign.Ptr                ( castPtr )
  import qualified Data.Vector.Unboxed as V
  
  import           Raaz.Core
  import           Raaz.Core.Types.Internal
  import           Raaz.Primitive.ChaCha20.Internal
  import           Raaz.Verse.ChaCha20.C.Portable
  
  name :: String
  name = "libverse-c"
  
  primName :: String
  primName = "chacha20"
  
  description :: String
  description = "ChaCha20 Implementation in C exposed by libverse"
  
  type Prim                    = ChaCha20
  type Internals               = ChaCha20Mem
  type BufferAlignment         = 32
  type BufferPtr               = AlignedBlockPtr BufferAlignment Prim
  
  additionalBlocks :: BlockCount ChaCha20
  additionalBlocks = blocksOf 1 Proxy
  
  processBlocks :: BufferPtr
                -> BlockCount Prim
                -> Internals
                -> IO ()
  
  processBlocks = runBlockProcess verse_chacha20_c_portable
  
  
  -- | Process the last bytes.
  processLast :: BufferPtr
              -> BYTES Int
              -> Internals
              -> IO ()
  processLast buf = processBlocks buf . atLeast
  
  
  -- | The xchacha20Setup  does the following to the internal state
  --
  -- 1. Replaces the key stored in the keyCell using the hchacah20 hashing function
  --
  -- 2. Initialises the ivcell with the last two words in the xiv value.
  --
  -- As a result the internal state is ready to start encrypting using
  -- the xchacha20 variant.
  --
  xchacha20Setup :: Nounce XChaCha20 -> Internals -> IO ()
  xchacha20Setup (XNounce tup) mem = do
    verse_hchacha20_c_portable keyPtr h0 h1 h2 h3
    -- In the above step, the key gets replaced by the subkey obtained
    -- from the hchacha20 hash.  Note that verse_hchacha expects a
    -- Word32 for h0 .. , h3 and hence the match LE h0 ... LE h3 in the
    -- where clause below.
    initialise iv $ ivCell mem
    -- The associated chacha 20 iv is just the rest of the words from
    -- the XChacha20 IV. When building the iv we need them as LE Word32
    -- and hence we do a simple h4, h4 match below.
    where keyPtr = castPtr $ keyCellPtr mem
          [LE h0,LE h1,LE h2, LE h3, h4, h5] = V.toList $ unsafeToVector tup
          iv  = Nounce $ unsafeFromList [0, h4, h5] :: Nounce ChaCha20
  
  
  -- | Copy the key from the memory cell chacha20Mem.
  copyKey :: Dest ChaCha20Mem -> Src (MemoryCell (Key ChaCha20)) -> IO ()
  copyKey = copyCell . fmap keyCell
  
  -------------- Helper function for running an iterator -----------
  runBlockProcess :: ( Ptr buf ->
                       Word64  ->
                       Ptr a   ->
                       Ptr b   ->
                       Ptr c   ->
                       IO ()
                     )
                  -> BufferPtr
                  -> BlockCount Prim
                  -> Internals
                  -> IO ()
  runBlockProcess func buf blks mem =
    let keyPtr     = castPtr $ keyCellPtr mem
        ivPtr      = castPtr $ ivCellPtr mem
        counterPtr = castPtr $ counterCellPtr mem
        blkPtr     = castPtr $ forgetAlignment buf
        wBlks      = toEnum  $ fromEnum blks
    in func blkPtr wBlks keyPtr ivPtr counterPtr
  