{-# LINE 1 "src/Crypto/Skein/Internal.hsc" #-}
{-# CFILES
{-# LINE 2 "src/Crypto/Skein/Internal.hsc" #-}
      c_impl/reference/skein.c
      c_impl/reference/skein_block.c
 #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Crypto.Skein.Internal
-- Copyright   :  (c) 2011 Felipe A. Lessa
-- License     :  BSD3 (see LICENSE)
--
-- Maintainer  :  felipe.lessa@gmail.com
-- Stability   :  provisional
-- Portability :  portable (needs FFI)
--
-- Basic wrappers around the C library.  You shouldn't need to
-- use these functions.  Instead, use the high-level
-- "Crypto.Skein" module.
--
-----------------------------------------------------------------------------

module Crypto.Skein.Internal
    ( -- * Return codes
      sKEIN_SUCCESS
    , sKEIN_FAIL
    , sKEIN_BAD_HASHLEN
    , check

      -- * Skein-256
    , Skein256Ctx(..)
    , skein256Init
    , skein256Update
    , skein256Final
    , skein256InitExt
    , skein256FinalPad
    , skein256Output

      -- * Skein-512
    , Skein512Ctx(..)
    , skein512Init
    , skein512Update
    , skein512Final
    , skein512InitExt
    , skein512FinalPad
    , skein512Output

      -- * Skein-1024
    , Skein1024Ctx(..)
    , skein1024Init
    , skein1024Update
    , skein1024Final
    , skein1024InitExt
    , skein1024FinalPad
    , skein1024Output

      -- * Misc constants
    , sKEIN_SEQUENTIAL
    ) where

-- from base
import Foreign
import Foreign.C

-- from bytestring
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as BI
import qualified Data.ByteString.Unsafe as BU

-- from this package

{-# LINE 71 "src/Crypto/Skein/Internal.hsc" #-}

sKEIN_SUCCESS, sKEIN_FAIL, sKEIN_BAD_HASHLEN :: CInt
sKEIN_SUCCESS     = 0
{-# LINE 74 "src/Crypto/Skein/Internal.hsc" #-}
sKEIN_FAIL        = 1
{-# LINE 75 "src/Crypto/Skein/Internal.hsc" #-}
sKEIN_BAD_HASHLEN = 2
{-# LINE 76 "src/Crypto/Skein/Internal.hsc" #-}

-- | Throws exception if the function does not return
-- successfully.
check :: IO CInt -> IO ()
check act = do
  x <- act
  case () of
    () | x == sKEIN_SUCCESS     -> return ()
       | x == sKEIN_FAIL        -> fail "Skein returned FAIL."
       | x == sKEIN_BAD_HASHLEN -> fail "Skein returned BAD_HASHLEN."
       | otherwise              -> fail "Skein returned unknown code."

newtype Skein256Ctx  = S256Ctx  {unS256Ctx  :: B.ByteString}
newtype Skein512Ctx  = S512Ctx  {unS512Ctx  :: B.ByteString}
newtype Skein1024Ctx = S1024Ctx {unS1024Ctx :: B.ByteString}

size256Ctx, size512Ctx, size1024Ctx :: Int
size256Ctx  = (88)
{-# LINE 94 "src/Crypto/Skein/Internal.hsc" #-}
size512Ctx  = (152)
{-# LINE 95 "src/Crypto/Skein/Internal.hsc" #-}
size1024Ctx = (280)
{-# LINE 96 "src/Crypto/Skein/Internal.hsc" #-}

instance Storable Skein256Ctx where
    sizeOf    _ = size256Ctx
    alignment _ = 16
    peek ptr =
        fmap S256Ctx $ BI.create size256Ctx $ \bptr ->
            BI.memcpy bptr (castPtr ptr) (fromIntegral size256Ctx)
    poke ptr (S256Ctx bs) =
        BU.unsafeUseAsCString bs $ \bs_ptr ->
            BI.memcpy (castPtr ptr) (castPtr bs_ptr) (fromIntegral size256Ctx)

instance Storable Skein512Ctx where
    sizeOf    _ = size512Ctx
    alignment _ = 16
    peek ptr =
        fmap S512Ctx $ BI.create size512Ctx $ \bptr ->
            BI.memcpy bptr (castPtr ptr) (fromIntegral size512Ctx)
    poke ptr (S512Ctx bs) =
        BU.unsafeUseAsCString bs $ \bs_ptr ->
            BI.memcpy (castPtr ptr) (castPtr bs_ptr) (fromIntegral size512Ctx)

instance Storable Skein1024Ctx where
    sizeOf    _ = size1024Ctx
    alignment _ = 16
    peek ptr =
        fmap S1024Ctx $ BI.create size1024Ctx $ \bptr ->
            BI.memcpy bptr (castPtr ptr) (fromIntegral size1024Ctx)
    poke ptr (S1024Ctx bs) =
        BU.unsafeUseAsCString bs $ \bs_ptr ->
            BI.memcpy (castPtr ptr) (castPtr bs_ptr) (fromIntegral size1024Ctx)

foreign import ccall unsafe "skein.h Skein_256_Init" skein256Init  :: Ptr Skein256Ctx  -> CSize -> IO CInt
foreign import ccall unsafe "skein.h Skein_512_Init" skein512Init  :: Ptr Skein512Ctx  -> CSize -> IO CInt
foreign import ccall unsafe "skein.h Skein1024_Init" skein1024Init :: Ptr Skein1024Ctx -> CSize -> IO CInt

foreign import ccall unsafe "skein.h Skein_256_Update" skein256Update  :: Ptr Skein256Ctx  -> Ptr Word8 -> CSize -> IO CInt
foreign import ccall unsafe "skein.h Skein_512_Update" skein512Update  :: Ptr Skein512Ctx  -> Ptr Word8 -> CSize -> IO CInt
foreign import ccall unsafe "skein.h Skein1024_Update" skein1024Update :: Ptr Skein1024Ctx -> Ptr Word8 -> CSize -> IO CInt

foreign import ccall unsafe "skein.h Skein_256_Final" skein256Final  :: Ptr Skein256Ctx  -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "skein.h Skein_512_Final" skein512Final  :: Ptr Skein512Ctx  -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "skein.h Skein1024_Final" skein1024Final :: Ptr Skein1024Ctx -> Ptr Word8 -> IO CInt

foreign import ccall unsafe "skein.h Skein_256_InitExt" skein256InitExt   :: Ptr Skein256Ctx  -> CSize -> Word64 -> Ptr Word8 -> CSize -> IO CInt
foreign import ccall unsafe "skein.h Skein_512_InitExt" skein512InitExt   :: Ptr Skein512Ctx  -> CSize -> Word64 -> Ptr Word8 -> CSize -> IO CInt
foreign import ccall unsafe "skein.h Skein1024_InitExt" skein1024InitExt  :: Ptr Skein1024Ctx -> CSize -> Word64 -> Ptr Word8 -> CSize -> IO CInt

foreign import ccall unsafe "skein.h Skein_256_Final_Pad" skein256FinalPad  :: Ptr Skein256Ctx  -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "skein.h Skein_512_Final_Pad" skein512FinalPad  :: Ptr Skein512Ctx  -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "skein.h Skein1024_Final_Pad" skein1024FinalPad :: Ptr Skein1024Ctx -> Ptr Word8 -> IO CInt

foreign import ccall unsafe "skein.h Skein_256_Output" skein256Output  :: Ptr Skein256Ctx  -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "skein.h Skein_512_Output" skein512Output  :: Ptr Skein512Ctx  -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "skein.h Skein1024_Output" skein1024Output :: Ptr Skein1024Ctx -> Ptr Word8 -> IO CInt


-- | Pass to @InitExt@ to get sequential processing.
sKEIN_SEQUENTIAL :: Word64
sKEIN_SEQUENTIAL = 0