{-# LANGUAGE ForeignFunctionInterface         #-}
{-# LANGUAGE MultiParamTypeClasses            #-}
{-# LANGUAGE FlexibleInstances                #-}
{-# LANGUAGE DataKinds                        #-}

-- | Portable C implementation of ChaCha20.
module Raaz.Cipher.ChaCha20.Implementation.CPortable
       ( implementation, chacha20Random
       ) where

import Control.Monad.IO.Class   ( liftIO )
import Foreign.Ptr              ( Ptr    )

import Raaz.Core
import Raaz.Cipher.Internal
import Raaz.Cipher.ChaCha20.Internal

-- | The portable c implementation of chacha20 cipher.
implementation :: SomeCipherI ChaCha20
implementation :: SomeCipherI ChaCha20
implementation  = CipherI ChaCha20 ChaCha20Mem ChaCha20Mem -> SomeCipherI ChaCha20
forall cipher encMem decMem.
CipherM cipher encMem decMem =>
CipherI cipher encMem decMem -> SomeCipherI cipher
SomeCipherI CipherI ChaCha20 ChaCha20Mem ChaCha20Mem
chacha20Portable

-- | Chacha20 block transformation.
foreign import ccall unsafe
  "raaz/cipher/chacha20/cportable.h raazChaCha20Block"
  c_chacha20_block :: Pointer      -- Message
                   -> Int          -- number of blocks
                   -> Ptr KEY      -- key
                   -> Ptr IV       -- iv
                   -> Ptr Counter  -- Counter value
                   -> IO ()




-- | Encrypting/Decrypting a block of chacha20.
chacha20Block :: Pointer -> BLOCKS ChaCha20 -> MT ChaCha20Mem ()
chacha20Block :: Pointer -> BLOCKS ChaCha20 -> MT ChaCha20Mem ()
chacha20Block Pointer
msgPtr BLOCKS ChaCha20
nblocks = do Ptr KEY
keyPtr <- (ChaCha20Mem -> MemoryCell KEY)
-> MT (MemoryCell KEY) (Ptr KEY) -> MT ChaCha20Mem (Ptr KEY)
forall (mT :: * -> * -> *) mem submem a.
MemoryThread mT =>
(mem -> submem) -> mT submem a -> mT mem a
onSubMemory ChaCha20Mem -> MemoryCell KEY
keyCell     MT (MemoryCell KEY) (Ptr KEY)
forall (mT :: * -> * -> *) a.
(MemoryThread mT, Storable a) =>
mT (MemoryCell a) (Ptr a)
getCellPointer
                                  Ptr IV
ivPtr  <- (ChaCha20Mem -> MemoryCell IV)
-> MT (MemoryCell IV) (Ptr IV) -> MT ChaCha20Mem (Ptr IV)
forall (mT :: * -> * -> *) mem submem a.
MemoryThread mT =>
(mem -> submem) -> mT submem a -> mT mem a
onSubMemory ChaCha20Mem -> MemoryCell IV
ivCell      MT (MemoryCell IV) (Ptr IV)
forall (mT :: * -> * -> *) a.
(MemoryThread mT, Storable a) =>
mT (MemoryCell a) (Ptr a)
getCellPointer
                                  Ptr Counter
ctrPtr <- (ChaCha20Mem -> MemoryCell Counter)
-> MT (MemoryCell Counter) (Ptr Counter)
-> MT ChaCha20Mem (Ptr Counter)
forall (mT :: * -> * -> *) mem submem a.
MemoryThread mT =>
(mem -> submem) -> mT submem a -> mT mem a
onSubMemory ChaCha20Mem -> MemoryCell Counter
counterCell MT (MemoryCell Counter) (Ptr Counter)
forall (mT :: * -> * -> *) a.
(MemoryThread mT, Storable a) =>
mT (MemoryCell a) (Ptr a)
getCellPointer
                                  IO () -> MT ChaCha20Mem ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> MT ChaCha20Mem ()) -> IO () -> MT ChaCha20Mem ()
forall a b. (a -> b) -> a -> b
$ Pointer -> Int -> Ptr KEY -> Ptr IV -> Ptr Counter -> IO ()
c_chacha20_block Pointer
msgPtr (BLOCKS ChaCha20 -> Int
forall a. Enum a => a -> Int
fromEnum BLOCKS ChaCha20
nblocks) Ptr KEY
keyPtr Ptr IV
ivPtr Ptr Counter
ctrPtr

-- | The chacha20 randomness generator.
chacha20Random :: Pointer -> BLOCKS ChaCha20 -> MT ChaCha20Mem ()
chacha20Random :: Pointer -> BLOCKS ChaCha20 -> MT ChaCha20Mem ()
chacha20Random = Pointer -> BLOCKS ChaCha20 -> MT ChaCha20Mem ()
chacha20Block

---------------------- DANGEROUS CODE --------------------------------------

-- | The chacha20 randomness generator. We have set the alignment to
-- 32 because this allows gcc to further optimise the implementation.
chacha20Portable :: CipherI ChaCha20 ChaCha20Mem ChaCha20Mem
chacha20Portable :: CipherI ChaCha20 ChaCha20Mem ChaCha20Mem
chacha20Portable = String
-> String
-> (Pointer -> BLOCKS ChaCha20 -> MT ChaCha20Mem ())
-> Alignment
-> CipherI ChaCha20 ChaCha20Mem ChaCha20Mem
forall prim mem.
String
-> String
-> (Pointer -> BLOCKS prim -> MT mem ())
-> Alignment
-> CipherI prim mem mem
makeCipherI
                   String
"chacha20-cportable"
                   String
"Implementation of the chacha20 stream cipher (RFC7539)"
                   Pointer -> BLOCKS ChaCha20 -> MT ChaCha20Mem ()
chacha20Block
                   Alignment
32