module Bitcoin.Crypto.Hash.SHA256
( SHA256(..)
, sha256
)
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 SHA256_CTX
instance Storable SHA256_CTX where
alignment _ = 8
sizeOf _ = 4*8 + 8 + 64
peek = error "SHA256_CTX/peek: not implemented"
poke = error "SHA256_CTX/poke: not implemented"
foreign import ccall safe "sha2.h SHA256_Init" c_SHA256_Init :: Ptr SHA256_CTX -> IO ()
foreign import ccall safe "sha2.h SHA256_Update" c_SHA256_Update :: Ptr SHA256_CTX -> Ptr Word8 -> CSize -> IO ()
foreign import ccall safe "sha2.h SHA256_Final" c_SHA256_Final :: Ptr Word8 -> Ptr SHA256_CTX -> IO ()
foreign import ccall safe "sha2.h SHA256_End" c_SHA256_End :: Ptr SHA256_CTX -> Ptr Word8 -> IO (Ptr CChar)
foreign import ccall safe "sha2.h SHA256_Data" c_SHA256_Data :: Ptr Word8 -> CSize -> Ptr SHA256_CTX -> IO (Ptr CChar)
newtype SHA256 = SHA256 { unSHA256 :: B.ByteString } deriving (Eq,Ord)
instance Show SHA256 where show (SHA256 bs) = "SHA256<" ++ toHexStringChars bs ++ ">"
instance OctetStream SHA256 where
toByteString = unSHA256
fromByteString bs = case B.length bs of
32 -> SHA256 bs
_ -> error "SHA256/fromByteString: SHA256 is expected to be 32 bytes"
sha256 :: OctetStream a => a -> SHA256
sha256 x = SHA256 $ Unsafe.unsafePerformIO (sha256_IO $ toByteString x)
sha256_IO :: B.ByteString -> IO B.ByteString
sha256_IO msg = do
alloca $ \ctx -> do
c_SHA256_Init ctx
B.useAsCStringLen msg $ \(cstr,len) -> c_SHA256_Update ctx (castPtr cstr) (fromIntegral len)
allocaBytes 32 $ \pdigest -> do
c_SHA256_Final pdigest ctx
B.packCStringLen (castPtr pdigest,32)