cryptonite/Crypto/Hash/Internal/Tiger.hs
Vincent Hanquez b5dbc9caae add internalUpdateUnsafe to process data more efficiently at the expense of threads.
internalUpdateUnsafe, just like internalUpdate update the context, but
does it using the unsafe key word for the ffi binding
2015-02-14 23:39:06 +00:00

114 lines
3.6 KiB
Haskell

{-# LANGUAGE ForeignFunctionInterface, CPP, MultiParamTypeClasses #-}
-- |
-- Module : Crypto.Hash.Internal.Tiger
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : unknown
--
-- A module containing Tiger bindings
--
module Crypto.Hash.Internal.Tiger
( Ctx(..)
-- * Internal values
, digestSize
, sizeCtx
-- * Internal IO hash functions
, internalInit
, internalInitAt
, internalUpdate
, internalUpdateUnsafe
, internalFinalize
-- * Context copy and creation
, withCtxCopy
, withCtxNewThrow
, withCtxThrow
) where
import Foreign.Ptr
import Foreign.ForeignPtr (withForeignPtr)
import Foreign.Storable
import Foreign.Marshal.Alloc
import Data.ByteString (ByteString)
import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
import Data.ByteString.Internal (create, toForeignPtr)
import Data.Word
newtype Ctx = Ctx ByteString
{-# INLINE digestSize #-}
digestSize :: Int
digestSize = 24
{-# INLINE sizeCtx #-}
sizeCtx :: Int
sizeCtx = 96
{-# INLINE withByteStringPtr #-}
withByteStringPtr :: ByteString -> (Ptr Word8 -> IO a) -> IO a
withByteStringPtr b f =
withForeignPtr fptr $ \ptr -> f (ptr `plusPtr` off)
where (fptr, off, _) = toForeignPtr b
{-# INLINE memcopy64 #-}
memcopy64 :: Ptr Word64 -> Ptr Word64 -> IO ()
memcopy64 dst src = mapM_ peekAndPoke [0..(12-1)]
where peekAndPoke i = peekElemOff src i >>= pokeElemOff dst i
withCtxCopy :: Ctx -> (Ptr Ctx -> IO ()) -> IO Ctx
withCtxCopy (Ctx ctxB) f = Ctx `fmap` createCtx
where createCtx = create sizeCtx $ \dstPtr ->
withByteStringPtr ctxB $ \srcPtr -> do
memcopy64 (castPtr dstPtr) (castPtr srcPtr)
f (castPtr dstPtr)
withCtxThrow :: Ctx -> (Ptr Ctx -> IO a) -> IO a
withCtxThrow (Ctx ctxB) f =
allocaBytes sizeCtx $ \dstPtr ->
withByteStringPtr ctxB $ \srcPtr -> do
memcopy64 (castPtr dstPtr) (castPtr srcPtr)
f (castPtr dstPtr)
withCtxNew :: (Ptr Ctx -> IO ()) -> IO Ctx
withCtxNew f = Ctx `fmap` create sizeCtx (f . castPtr)
withCtxNewThrow :: (Ptr Ctx -> IO a) -> IO a
withCtxNewThrow f = allocaBytes sizeCtx (f . castPtr)
foreign import ccall unsafe "cryptonite_tiger.h cryptonite_tiger_init"
c_tiger_init :: Ptr Ctx -> IO ()
foreign import ccall "cryptonite_tiger.h cryptonite_tiger_update"
c_tiger_update :: Ptr Ctx -> Ptr Word8 -> Word32 -> IO ()
foreign import ccall unsafe "cryptonite_tiger.h cryptonite_tiger_update"
c_tiger_update_unsafe :: Ptr Ctx -> Ptr Word8 -> Word32 -> IO ()
foreign import ccall unsafe "cryptonite_tiger.h cryptonite_tiger_finalize"
c_tiger_finalize :: Ptr Ctx -> Ptr Word8 -> IO ()
internalInitAt :: Ptr Ctx -> IO ()
internalInitAt = c_tiger_init
-- | init a context
internalInit :: IO Ctx
internalInit = withCtxNew internalInitAt
-- | Update a context in place
internalUpdate :: Ptr Ctx -> ByteString -> IO ()
internalUpdate ptr d =
unsafeUseAsCStringLen d (\(cs, len) -> c_tiger_update ptr (castPtr cs) (fromIntegral len))
-- | Update a context in place using an unsafe foreign function call.
--
-- It is faster than `internalUpdate`, but will block the haskell runtime.
-- This shouldn't be used if the input data is large.
internalUpdateUnsafe :: Ptr Ctx -> ByteString -> IO ()
internalUpdateUnsafe ptr d =
unsafeUseAsCStringLen d (\(cs, len) -> c_tiger_update_unsafe ptr (castPtr cs) (fromIntegral len))
-- | Finalize a context in place
internalFinalize :: Ptr Ctx -> IO ByteString
internalFinalize ptr = create digestSize (c_tiger_finalize ptr)