module Bitcoin.Crypto.Hash.SHA512
( SHA512(..)
, sha512
)
where
import Data.Char
import Data.Int
import Data.Word
import Data.Bits
import qualified Data.ByteString as B
import Control.Monad
import Foreign
import Foreign.C
import System.IO.Unsafe as Unsafe
import Bitcoin.Misc.OctetStream
import Bitcoin.Misc.HexString
data SHA512_CTX
instance Storable SHA512_CTX where
alignment _ = 8
sizeOf _ = 8*8 + 16 + 128
peek = error "SHA512_CTX/peek: not implemented"
poke = error "SHA512_CTX/poke: not implemented"
foreign import ccall safe "sha2.h SHA512_Init" c_SHA512_Init :: Ptr SHA512_CTX -> IO ()
foreign import ccall safe "sha2.h SHA512_Update" c_SHA512_Update :: Ptr SHA512_CTX -> Ptr Word8 -> CSize -> IO ()
foreign import ccall safe "sha2.h SHA512_Final" c_SHA512_Final :: Ptr Word8 -> Ptr SHA512_CTX -> IO ()
foreign import ccall safe "sha2.h SHA512_End" c_SHA512_End :: Ptr SHA512_CTX -> Ptr Word8 -> IO (Ptr CChar)
foreign import ccall safe "sha2.h SHA512_Data" c_SHA512_Data :: Ptr Word8 -> CSize -> Ptr SHA512_CTX -> IO (Ptr CChar)
newtype SHA512 = SHA512 { unSHA512 :: B.ByteString } deriving (Eq,Ord)
instance Show SHA512 where show (SHA512 bs) = "SHA512<" ++ toHexStringChars bs ++ ">"
instance OctetStream SHA512 where
toByteString = unSHA512
fromByteString bs = case B.length bs of
64 -> SHA512 bs
_ -> error "SHA512/fromByteString: SHA512 is expected to be 64 bytes"
sha512 :: OctetStream a => a -> SHA512
sha512 x = SHA512 $ Unsafe.unsafePerformIO (sha512_IO $ toByteString x)
sha512_IO :: B.ByteString -> IO B.ByteString
sha512_IO msg = do
alloca $ \ctx -> do
c_SHA512_Init ctx
B.useAsCStringLen msg $ \(cstr,len) -> c_SHA512_Update ctx (castPtr cstr) (fromIntegral len)
allocaBytes 64 $ \pdigest -> do
c_SHA512_Final pdigest ctx
B.packCStringLen (castPtr pdigest,64)