-- | SHA512 hash: wrapper around Aaron D. Gifford's C implementation. -- {-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls #-} 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 --typedef struct _SHA512_CTX { -- uint64_t state[8]; -- uint64_t bitcount[2]; -- uint8_t buffer[SHA512_BLOCK_LENGTH]; --} 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" -------------------------------------------------------------------------------- -- void SHA512_Init(SHA512_CTX *); foreign import ccall safe "sha2.h SHA512_Init" c_SHA512_Init :: Ptr SHA512_CTX -> IO () -- void SHA512_Update(SHA512_CTX*, const uint8_t*, size_t); foreign import ccall safe "sha2.h SHA512_Update" c_SHA512_Update :: Ptr SHA512_CTX -> Ptr Word8 -> CSize -> IO () -- void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); foreign import ccall safe "sha2.h SHA512_Final" c_SHA512_Final :: Ptr Word8 -> Ptr SHA512_CTX -> IO () -- char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); foreign import ccall safe "sha2.h SHA512_End" c_SHA512_End :: Ptr SHA512_CTX -> Ptr Word8 -> IO (Ptr CChar) -- char* SHA512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); 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) {- sha512String :: String -> HexStringLE sha512String msg = hexEncode' False $ B.unpack $ sha512 $ B.pack $ map char_to_word8 msg -} --------------------------------------------------------------------------------