{-# LANGUAGE ForeignFunctionInterface   #-}
{-# LANGUAGE DataKinds                  #-}


-- | The portable C-implementation of Blake2b.
module Blake2b.CHandWritten where

import Raaz.Core
import Raaz.Core.Transfer.Unsafe
import Raaz.Core.Types.Internal
import Raaz.Primitive.HashMemory
import Raaz.Primitive.Blake2.Internal


name :: String
name :: String
name = String
"blake2b-c-handwritten"

description :: String
description :: String
description = String
"Hand written Blake2b Implementation in portable C and Haskell FFI"

type Prim                    = Blake2b
type Internals               = Blake2bMem
type BufferAlignment         = 32
type BufferPtr               = AlignedBlockPtr BufferAlignment Prim

additionalBlocks :: BlockCount Blake2b
additionalBlocks :: BlockCount Blake2b
additionalBlocks = Int -> Proxy Blake2b -> BlockCount Blake2b
forall p. Int -> Proxy p -> BlockCount p
blocksOf Int
1 Proxy Blake2b
forall k (t :: k). Proxy t
Proxy


------------------------ The foreign function calls  ---------------------

foreign import ccall unsafe
  "raaz/hash/blake2/common.h raazHashBlake2bPortableBlockCompress"
  c_blake2b_compress  :: BufferPtr
                      -> BlockCount Prim
                      -> Ptr (BYTES Word64)
                      -> Ptr (BYTES Word64)
                      -> Ptr Blake2b
                      -> IO ()

foreign import ccall unsafe
  "raaz/hash/blake2/common.h raazHashBlake2bPortableLastBlock"
  c_blake2b_last   :: BlockPtr Prim
                   -> BYTES Int
                   -> BYTES Word64
                   -> BYTES Word64
                   -> Word64
                   -> Word64
                   -> Ptr Blake2b
                   -> IO ()

--
processBlocks :: BufferPtr
              -> BlockCount Blake2b
              -> Blake2bMem
              -> IO ()

processBlocks :: BufferPtr -> BlockCount Blake2b -> Blake2bMem -> IO ()
processBlocks BufferPtr
buf BlockCount Blake2b
blks Blake2bMem
b2bmem =
  let uPtr :: Ptr (BYTES Word64)
uPtr = Blake2bMem -> Ptr (BYTES Word64)
forall h. Storable h => HashMemory128 h -> Ptr (BYTES Word64)
uLengthCellPointer Blake2bMem
b2bmem
      lPtr :: Ptr (BYTES Word64)
lPtr = Blake2bMem -> Ptr (BYTES Word64)
forall h. Storable h => HashMemory128 h -> Ptr (BYTES Word64)
lLengthCellPointer Blake2bMem
b2bmem
      hshPtr :: Ptr Blake2b
hshPtr = Blake2bMem -> Ptr Blake2b
forall h. Storable h => HashMemory128 h -> Ptr h
hashCell128Pointer Blake2bMem
b2bmem
  in BufferPtr
-> BlockCount Blake2b
-> Ptr (BYTES Word64)
-> Ptr (BYTES Word64)
-> Ptr Blake2b
-> IO ()
c_blake2b_compress BufferPtr
buf BlockCount Blake2b
blks Ptr (BYTES Word64)
uPtr Ptr (BYTES Word64)
lPtr Ptr Blake2b
hshPtr

-- | Process the last bytes.
processLast :: BufferPtr
            -> BYTES Int
            -> Blake2bMem
            -> IO ()
processLast :: BufferPtr -> BYTES Int -> Blake2bMem -> IO ()
processLast BufferPtr
buf BYTES Int
nbytes Blake2bMem
b2bmem  = do
  Transfer 'WriteToBuffer
-> AlignedPtr BufferAlignment (Tuple 16 (LE Word64)) -> IO ()
forall (ptr :: * -> *) (t :: Mode) a.
Pointer ptr =>
Transfer t -> ptr a -> IO ()
unsafeTransfer Transfer 'WriteToBuffer
padding AlignedPtr BufferAlignment (Tuple 16 (LE Word64))
BufferPtr
buf         -- pad the message
  BufferPtr -> BlockCount Blake2b -> Blake2bMem -> IO ()
processBlocks BufferPtr
buf BlockCount Blake2b
nBlocks Blake2bMem
b2bmem   -- process all but the last block
  --
  -- Handle the last block
  --
  let
      hshPtr :: Ptr Blake2b
hshPtr = Blake2bMem -> Ptr Blake2b
forall h. Storable h => HashMemory128 h -> Ptr h
hashCell128Pointer Blake2bMem
b2bmem
    in  do BYTES Word64
u <- Blake2bMem -> IO (BYTES Word64)
forall h. HashMemory128 h -> IO (BYTES Word64)
getULength Blake2bMem
b2bmem
           BYTES Word64
l <- Blake2bMem -> IO (BYTES Word64)
forall h. HashMemory128 h -> IO (BYTES Word64)
getLLength Blake2bMem
b2bmem
           BlockPtr Blake2b
-> BYTES Int
-> BYTES Word64
-> BYTES Word64
-> Word64
-> Word64
-> Ptr Blake2b
-> IO ()
c_blake2b_last Ptr (Tuple 16 (LE Word64))
BlockPtr Blake2b
lastBlockPtr BYTES Int
remBytes BYTES Word64
u BYTES Word64
l Word64
f0 Word64
f1 Ptr Blake2b
hshPtr

  where padding :: Transfer 'WriteToBuffer
padding      = Proxy Blake2b -> BYTES Int -> Transfer 'WriteToBuffer
forall prim.
Primitive prim =>
Proxy prim -> BYTES Int -> Transfer 'WriteToBuffer
blake2Pad (Proxy Blake2b
forall k (t :: k). Proxy t
Proxy :: Proxy Blake2b) BYTES Int
nbytes
        nBlocks :: BlockCount Blake2b
nBlocks      = BYTES Int -> BlockCount Blake2b
forall src dest. (LengthUnit src, LengthUnit dest) => src -> dest
atMost (Transfer 'WriteToBuffer -> BYTES Int
forall (t :: Mode). Transfer t -> BYTES Int
transferSize Transfer 'WriteToBuffer
padding) BlockCount Blake2b -> BlockCount Blake2b -> BlockCount Blake2b
forall a. Monoid a => a -> a -> a
`mappend` Int -> BlockCount Blake2b
forall a. Enum a => Int -> a
toEnum (-Int
1)
                                           -- all but the last block
        remBytes :: BYTES Int
remBytes     = BYTES Int
nbytes BYTES Int -> BYTES Int -> BYTES Int
forall a. Num a => a -> a -> a
- BlockCount Blake2b -> BYTES Int
forall u. LengthUnit u => u -> BYTES Int
inBytes BlockCount Blake2b
nBlocks
                                           -- Actual bytes in the last block.
        lastBlockPtr :: Ptr (Tuple 16 (LE Word64))
lastBlockPtr = AlignedPtr BufferAlignment (Tuple 16 (LE Word64))
-> Ptr (Tuple 16 (LE Word64))
forall (n :: Nat) a. AlignedPtr n a -> Ptr a
forgetAlignment AlignedPtr BufferAlignment (Tuple 16 (LE Word64))
BufferPtr
buf Ptr (Tuple 16 (LE Word64))
-> BlockCount Blake2b -> Ptr (Tuple 16 (LE Word64))
forall l a. LengthUnit l => Ptr a -> l -> Ptr a
`movePtr` BlockCount Blake2b
nBlocks
        --
        -- Finalisation FLAGS
        --
        f0 :: Word64
f0 = Word64 -> Word64
forall a. Bits a => a -> a
complement Word64
0
        f1 :: Word64
f1 = Word64
0