packages feed

cryptohash-sha256 0.11.7.1 → 0.11.7.2

raw patch · 12 files changed

+492/−625 lines, 12 filesdep +SHAdep +base16-bytestringdep ~basedep ~bytestringPVP ok

version bump matches the API change (PVP)

Dependencies added: SHA, base16-bytestring

Dependency ranges changed: base, bytestring

API changes (from Hackage documentation)

Files

− Bench/Bench.hs
@@ -1,33 +0,0 @@-{-# LANGUAGE BangPatterns #-}-import Criterion.Main-import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as L-import qualified Crypto.Hash.SHA256 as SHA256--hashmany (i,u,f) = f . foldl u i--allHashs =-    [ ("SHA2-256",SHA256.hash, hashmany (SHA256.init,SHA256.update,SHA256.finalize))-    ]--benchHash :: a -> (a -> B.ByteString) -> Benchmarkable-benchHash bs f = whnf f bs--withHashesFilter out f = map f $ filter (\(n,_,_) -> not (n `elem` out)) allHashs-withHashes f = map f allHashs--main = do-    let !bs32     = B.replicate 32 0-        !bs256    = B.replicate 256 0-        !bs4096   = B.replicate 4096 0-        !bs1M     = B.replicate (1*1024*1024) 0-    let !lbs64x256 = (map (const (B.replicate 64 0)) [0..3])-        !lbs64x4096 = (map (const (B.replicate 64 0)) [0..63])-    defaultMain-        [ bgroup "hash-32b" (withHashes (\(name, f,_) -> bench name $ benchHash bs32 f))-        , bgroup "hash-256b" (withHashes (\(name, f,_) -> bench name $ benchHash bs256 f))-        , bgroup "hash-4Kb" (withHashes (\(name, f,_) -> bench name $ benchHash bs4096 f))-        , bgroup "hash-1Mb" (withHashesFilter ["MD2"] (\(name, f,_) -> bench name $ benchHash bs1M f))-        , bgroup "iuf-64x256" (withHashes (\(name, _,f) -> bench name $ benchHash lbs64x256 f))-        , bgroup "iuf-64x4096" (withHashes (\(name, _,f) -> bench name $ benchHash lbs64x4096 f))-        ]
− Bench/BenchAPI.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE BangPatterns #-}-import Criterion.Main-import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as L-import qualified Crypto.Hash.SHA256 as SHA256--sha256F = ( "SHA256"-        , SHA256.hash-        , SHA256.finalize . SHA256.update SHA256.init-        )--main = do-    let !bs32     = B.replicate 32 0-        !bs256    = B.replicate 256 0-        !bs4096   = B.replicate 4096 0-        !bs1M     = B.replicate (1*1024*1024) 0-    let !lbs64x256 = (map (const (B.replicate 64 0)) [0..3])-        !lbs64x4096 = (map (const (B.replicate 64 0)) [0..63])--    let (fname, fHash, fIncr) = sha256F-    let benchName ty z = fname ++ "." ++ ty -- ++ " " ++ show z-    defaultMain-        [ bgroup "hash-0b"-            [ bench (benchName "hash" 0) $ whnf fHash B.empty-            , bench (benchName "incr" 0) $ whnf fIncr B.empty-            ]-        , bgroup "hash-32b"-            [ bench (benchName "hash" 32) $ whnf fHash bs32-            , bench (benchName "incr" 32) $ whnf fIncr bs32-            ]-        , bgroup "hash-256b"-            [ bench (benchName "hash" 256) $ whnf fHash bs256-            , bench (benchName "incr" 256) $ whnf fIncr bs256-            ]-        , bgroup "hash-4Kb"-            [ bench (benchName "hash" 4096) $ whnf fHash bs4096-            , bench (benchName "incr" 4096) $ whnf fIncr bs4096-            ]-        ]
− Crypto/Hash/SHA256.hs
@@ -1,184 +0,0 @@--- |--- Module      : Crypto.Hash.SHA256--- License     : BSD-style--- Maintainer  : Herbert Valerio Riedel <hvr@gnu.org>--- Stability   : stable--- Portability : unknown------ A module containing <https://en.wikipedia.org/wiki/SHA-2 SHA-256> bindings----module Crypto.Hash.SHA256-    (--    -- * Incremental API-    ---    -- | This API is based on 4 different functions, similar to the-    -- lowlevel operations of a typical hash:-    ---    --  - 'init': create a new hash context-    --  - 'update': update non-destructively a new hash context with a strict bytestring-    --  - 'updates': same as update, except that it takes a list of strict bytestring-    --  - 'finalize': finalize the context and returns a digest bytestring.-    ---    -- all those operations are completely pure, and instead of-    -- changing the context as usual in others language, it-    -- re-allocates a new context each time.-    ---    -- Example:-    ---    -- > import qualified Data.ByteString-    -- > import qualified Crypto.Hash.SHA256 as SHA256-    -- >-    -- > main = print digest-    -- >   where-    -- >     digest = SHA256.finalize ctx-    -- >     ctx    = foldl SHA256.update ctx0 (map Data.ByteString.pack [ [1,2,3], [4,5,6] ])-    -- >     ctx0   = SHA256.init--      Ctx(..)-    , init     -- :: Ctx-    , update   -- :: Ctx -> ByteString -> Ctx-    , updates  -- :: Ctx -> [ByteString] -> Ctx-    , finalize -- :: Ctx -> ByteString--    -- * Single Pass API-    ---    -- | This API use the incremental API under the hood to provide-    -- the common all-in-one operations to create digests out of a-    -- 'ByteString' and lazy 'L.ByteString'.-    ---    --  - 'hash': create a digest ('init' + 'update' + 'finalize') from a strict 'ByteString'-    --  - 'hashlazy': create a digest ('init' + 'update' + 'finalize') from a lazy 'L.ByteString'-    ---    -- Example:-    ---    -- > import qualified Data.ByteString-    -- > import qualified Crypto.Hash.SHA256 as SHA256-    -- >-    -- > main = print $ SHA256.hash (Data.ByteString.pack [0..255])-    ---    -- __NOTE__: The returned digest is a binary 'ByteString'. For-    -- converting to a base16/hex encoded digest the-    -- <https://hackage.haskell.org/package/base16-bytestring base16-bytestring>-    -- package is recommended.--    , hash     -- :: ByteString -> ByteString-    , hashlazy -- :: ByteString -> ByteString-    ) where--import Prelude hiding (init)-import Foreign.Ptr-import Foreign.ForeignPtr (withForeignPtr)-import Foreign.Storable-import Foreign.Marshal.Alloc-import qualified Data.ByteString.Lazy as L-import qualified Data.ByteString as B-import Data.ByteString (ByteString)-import Data.ByteString.Unsafe (unsafeUseAsCStringLen)-import Data.ByteString.Internal (create, toForeignPtr)-import Data.Word-import System.IO.Unsafe (unsafeDupablePerformIO)---- | perform IO for hashes that do allocation and ffi.--- unsafeDupablePerformIO is used when possible as the--- computation is pure and the output is directly linked--- to the input. we also do not modify anything after it has--- been returned to the user.-unsafeDoIO :: IO a -> a-unsafeDoIO = unsafeDupablePerformIO---- | SHA-256 Context-newtype Ctx = Ctx ByteString--{-# INLINE digestSize #-}-digestSize :: Int-digestSize = 32--{-# INLINE sizeCtx #-}-sizeCtx :: Int-sizeCtx = 192--{-# RULES "digestSize" B.length (finalize init) = digestSize #-}-{-# RULES "hash" forall b. finalize (update init b) = hash b #-}-{-# RULES "hash.list1" forall b. finalize (updates init [b]) = hash b #-}-{-# RULES "hashmany" forall b. finalize (foldl update init b) = hashlazy (L.fromChunks b) #-}-{-# RULES "hashlazy" forall b. finalize (foldl update init $ L.toChunks b) = hashlazy b #-}--{-# 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..(24-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 "sha256.h hs_cryptohash_sha256_init"-    c_sha256_init :: Ptr Ctx -> IO ()--foreign import ccall unsafe "sha256.h hs_cryptohash_sha256_update"-    c_sha256_update :: Ptr Ctx -> Ptr Word8 -> Word32 -> IO ()--foreign import ccall unsafe "sha256.h hs_cryptohash_sha256_finalize"-    c_sha256_finalize :: Ptr Ctx -> Ptr Word8 -> IO ()--updateInternalIO :: Ptr Ctx -> ByteString -> IO ()-updateInternalIO ptr d =-    unsafeUseAsCStringLen d (\(cs, len) -> c_sha256_update ptr (castPtr cs) (fromIntegral len))--finalizeInternalIO :: Ptr Ctx -> IO ByteString-finalizeInternalIO ptr = create digestSize (c_sha256_finalize ptr)--{-# NOINLINE init #-}--- | init a context-init :: Ctx-init = unsafeDoIO $ withCtxNew $ c_sha256_init--{-# NOINLINE update #-}--- | update a context with a bytestring-update :: Ctx -> ByteString -> Ctx-update ctx d = unsafeDoIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d--{-# NOINLINE updates #-}--- | updates a context with multiples bytestring-updates :: Ctx -> [ByteString] -> Ctx-updates ctx d = unsafeDoIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d--{-# NOINLINE finalize #-}--- | finalize the context into a digest bytestring-finalize :: Ctx -> ByteString-finalize ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO--{-# NOINLINE hash #-}--- | hash a strict bytestring into a digest bytestring-hash :: ByteString -> ByteString-hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do-    c_sha256_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr--{-# NOINLINE hashlazy #-}--- | hash a lazy bytestring into a digest bytestring-hashlazy :: L.ByteString -> ByteString-hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do-    c_sha256_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr
− Tests/KAT.hs
@@ -1,92 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ViewPatterns #-}-import Data.Char-import Data.Bits-import Data.Word-import Data.ByteString (ByteString)-import Data.Foldable (foldl')-import Data.Monoid (mconcat)-import qualified Data.ByteString as B-import qualified Data.ByteString.Char8 as BC-import qualified Crypto.Hash.SHA256 as SHA256--import Test.Tasty-import Test.Tasty.QuickCheck-import Test.Tasty.HUnit--v0,v1,v2 :: ByteString-v0 = ""-v1 = "The quick brown fox jumps over the lazy dog"-v2 = "The quick brown fox jumps over the lazy cog"-vectors = [ v0, v1, v2 ]--instance Arbitrary ByteString where-    arbitrary = B.pack `fmap` arbitrary--data HashFct = HashFct-    { fctHash   :: (B.ByteString -> B.ByteString)-    , fctInc    :: ([B.ByteString] -> B.ByteString) }--hashinc i u f = f . foldl u i--sha256Hash = HashFct { fctHash = SHA256.hash, fctInc = hashinc SHA256.init SHA256.update SHA256.finalize }---results :: [ (String, HashFct, [String]) ]-results = [-    ("SHA256", sha256Hash, [-        "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",-        "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",-        "e4c4d8f3bf76b692de791a173e05321150f7a345b46484fe427f6acc7ecc81be" ])-    ]--hexalise s = concatMap (\c -> [ hex $ c `div` 16, hex $ c `mod` 16 ]) s-        where hex i-                | i >= 0 && i <= 9   = fromIntegral (ord '0') + i-                | i >= 10 && i <= 15 = fromIntegral (ord 'a') + i - 10-                | otherwise          = 0--hexaliseB :: B.ByteString -> B.ByteString-hexaliseB = B.pack . hexalise . B.unpack--splitB :: Int -> ByteString -> [ByteString]-splitB l b =-    if B.length b > l-        then-            let (b1, b2) = B.splitAt l b in-            b1 : splitB l b2-        else-            [ b ]--showHash :: B.ByteString -> String-showHash = map (toEnum.fromEnum) . hexalise . B.unpack--runhash hash v = showHash $ (fctHash hash) $ v-runhashinc hash v = showHash $ (fctInc hash) $ v--makeTestAlg (name, hash, results) = testGroup name $ concatMap maketest (zip3 [0..] vectors results)-    where-        runtest :: ByteString -> String-        runtest v = runhash hash v--        runtestinc :: Int -> ByteString -> String-        runtestinc i v = runhashinc hash $ splitB i v--        maketest (i, v, r) =-            [ testCase (show i ++ " one-pass") (r @=? runtest v)-            , testCase (show i ++ " inc 1") (r @=? runtestinc 1 v)-            , testCase (show i ++ " inc 2") (r @=? runtestinc 2 v)-            , testCase (show i ++ " inc 3") (r @=? runtestinc 3 v)-            , testCase (show i ++ " inc 4") (r @=? runtestinc 4 v)-            , testCase (show i ++ " inc 5") (r @=? runtestinc 5 v)-            , testCase (show i ++ " inc 9") (r @=? runtestinc 9 v)-            , testCase (show i ++ " inc 16") (r @=? runtestinc 16 v)-            ]--katTests :: [TestTree]-katTests = map makeTestAlg results---main = defaultMain $ testGroup "cryptohash"-    [ testGroup "KATs" katTests-    ]
− cbits/bitfn.h
@@ -1,240 +0,0 @@-/*- * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- *    notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- *    notice, this list of conditions and the following disclaimer in the- *    documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#ifndef BITFN_H-#define BITFN_H-#include <stdint.h>--#ifndef NO_INLINE_ASM-/**********************************************************/-# if (defined(__i386__))-#  define ARCH_HAS_SWAP32-static inline uint32_t bitfn_swap32(uint32_t a)-{-	asm ("bswap %0" : "=r" (a) : "0" (a));-	return a;-}-/**********************************************************/-# elif (defined(__arm__))-#  define ARCH_HAS_SWAP32-static inline uint32_t bitfn_swap32(uint32_t a)-{-	uint32_t tmp = a;-	asm volatile ("eor %1, %0, %0, ror #16\n"-	              "bic %1, %1, #0xff0000\n"-	              "mov %0, %0, ror #8\n"-	              "eor %0, %0, %1, lsr #8\n"-	             : "=r" (a), "=r" (tmp) : "0" (a), "1" (tmp));-	return a;-}-/**********************************************************/-# elif defined(__x86_64__)-#  define ARCH_HAS_SWAP32-#  define ARCH_HAS_SWAP64-static inline uint32_t bitfn_swap32(uint32_t a)-{-	asm ("bswap %0" : "=r" (a) : "0" (a));-	return a;-}--static inline uint64_t bitfn_swap64(uint64_t a)-{-	asm ("bswap %0" : "=r" (a) : "0" (a));-	return a;-}--# endif-#endif /* NO_INLINE_ASM */-/**********************************************************/--#ifndef ARCH_HAS_ROL32-static inline uint32_t rol32(uint32_t word, uint32_t shift)-{-	return (word << shift) | (word >> (32 - shift));-}-#endif--#ifndef ARCH_HAS_ROR32-static inline uint32_t ror32(uint32_t word, uint32_t shift)-{-	return (word >> shift) | (word << (32 - shift));-}-#endif--#ifndef ARCH_HAS_ROL64-static inline uint64_t rol64(uint64_t word, uint32_t shift)-{-	return (word << shift) | (word >> (64 - shift));-}-#endif--#ifndef ARCH_HAS_ROR64-static inline uint64_t ror64(uint64_t word, uint32_t shift)-{-	return (word >> shift) | (word << (64 - shift));-}-#endif--#ifndef ARCH_HAS_SWAP32-static inline uint32_t bitfn_swap32(uint32_t a)-{-	return (a << 24) | ((a & 0xff00) << 8) | ((a >> 8) & 0xff00) | (a >> 24);-}-#endif--#ifndef ARCH_HAS_ARRAY_SWAP32-static inline void array_swap32(uint32_t *d, uint32_t *s, uint32_t nb)-{-	while (nb--)-		*d++ = bitfn_swap32(*s++);-}-#endif--#ifndef ARCH_HAS_SWAP64-static inline uint64_t bitfn_swap64(uint64_t a)-{-	return ((uint64_t) bitfn_swap32((uint32_t) (a >> 32))) |-	       (((uint64_t) bitfn_swap32((uint32_t) a)) << 32);-}-#endif--#ifndef ARCH_HAS_ARRAY_SWAP64-static inline void array_swap64(uint64_t *d, uint64_t *s, uint32_t nb)-{-	while (nb--)-		*d++ = bitfn_swap64(*s++);-}-#endif--#ifndef ARCH_HAS_MEMORY_ZERO-static inline void memory_zero(void *ptr, uint32_t len)-{-	uint32_t *ptr32 = ptr;-	uint8_t *ptr8;-	int i;--	for (i = 0; i < len / 4; i++)-		*ptr32++ = 0;-	if (len % 4) {-		ptr8 = (uint8_t *) ptr32;-		for (i = len % 4; i >= 0; i--)-			ptr8[i] = 0;-	}-}-#endif--#ifndef ARCH_HAS_ARRAY_COPY32-static inline void array_copy32(uint32_t *d, uint32_t *s, uint32_t nb)-{-	while (nb--) *d++ = *s++;-}-#endif--#ifndef ARCH_HAS_ARRAY_COPY64-static inline void array_copy64(uint64_t *d, uint64_t *s, uint32_t nb)-{-	while (nb--) *d++ = *s++;-}-#endif--#ifdef __MINGW32__-  # define LITTLE_ENDIAN 1234-  # define BYTE_ORDER    LITTLE_ENDIAN-#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)-  # include <sys/endian.h>-#elif defined(__OpenBSD__) || defined(__SVR4)-  # include <sys/types.h>-#elif defined(__APPLE__)-  # include <machine/endian.h>-#elif defined( BSD ) && ( BSD >= 199103 )-  # include <machine/endian.h>-#elif defined( __QNXNTO__ ) && defined( __LITTLEENDIAN__ )-  # define LITTLE_ENDIAN 1234-  # define BYTE_ORDER    LITTLE_ENDIAN-#elif defined( __QNXNTO__ ) && defined( __BIGENDIAN__ )-  # define BIG_ENDIAN 1234-  # define BYTE_ORDER    BIG_ENDIAN-#elif defined( _AIX )-  # include <sys/machine.h>-#else-  # include <endian.h>-#endif-/* big endian to cpu */-#if LITTLE_ENDIAN == BYTE_ORDER--# define be32_to_cpu(a) bitfn_swap32(a)-# define cpu_to_be32(a) bitfn_swap32(a)-# define le32_to_cpu(a) (a)-# define cpu_to_le32(a) (a)-# define be64_to_cpu(a) bitfn_swap64(a)-# define cpu_to_be64(a) bitfn_swap64(a)-# define le64_to_cpu(a) (a)-# define cpu_to_le64(a) (a)--# define cpu_to_le32_array(d, s, l) array_copy32(d, s, l)-# define le32_to_cpu_array(d, s, l) array_copy32(d, s, l)-# define cpu_to_be32_array(d, s, l) array_swap32(d, s, l)-# define be32_to_cpu_array(d, s, l) array_swap32(d, s, l)--# define cpu_to_le64_array(d, s, l) array_copy64(d, s, l)-# define le64_to_cpu_array(d, s, l) array_copy64(d, s, l)-# define cpu_to_be64_array(d, s, l) array_swap64(d, s, l)-# define be64_to_cpu_array(d, s, l) array_swap64(d, s, l)--# define ror32_be(a, s) rol32(a, s)-# define rol32_be(a, s) ror32(a, s)--# define ARCH_IS_LITTLE_ENDIAN--#elif BIG_ENDIAN == BYTE_ORDER--# define be32_to_cpu(a) (a)-# define cpu_to_be32(a) (a)-# define be64_to_cpu(a) (a)-# define cpu_to_be64(a) (a)-# define le64_to_cpu(a) bitfn_swap64(a)-# define cpu_to_le64(a) bitfn_swap64(a)-# define le32_to_cpu(a) bitfn_swap32(a)-# define cpu_to_le32(a) bitfn_swap32(a)--# define cpu_to_le32_array(d, s, l) array_swap32(d, s, l)-# define le32_to_cpu_array(d, s, l) array_swap32(d, s, l)-# define cpu_to_be32_array(d, s, l) array_copy32(d, s, l)-# define be32_to_cpu_array(d, s, l) array_copy32(d, s, l)--# define cpu_to_le64_array(d, s, l) array_swap64(d, s, l)-# define le64_to_cpu_array(d, s, l) array_swap64(d, s, l)-# define cpu_to_be64_array(d, s, l) array_copy64(d, s, l)-# define be64_to_cpu_array(d, s, l) array_copy64(d, s, l)--# define ror32_be(a, s) ror32(a, s)-# define rol32_be(a, s) rol32(a, s)--# define ARCH_IS_BIG_ENDIAN--#else-# error "endian not supported"-#endif--#endif /* !BITFN_H */
cbits/sha256.c view
@@ -23,15 +23,67 @@  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */ -#include <string.h> #include "sha256.h"-#include "bitfn.h" +#include <assert.h>+#include <string.h>+#include <ghcautoconf.h>++#if defined(static_assert)+static_assert(sizeof(struct sha256_ctx) == SHA256_CTX_SIZE, "unexpected sha256_ctx size");+#else+// poor man's pre-C11 _Static_assert+typedef char static_assertion__unexpected_sha256_ctx_size[(sizeof(struct sha256_ctx) == SHA256_CTX_SIZE)?1:-1];+#endif++static inline uint32_t+ror32(uint32_t word, uint32_t shift)+{+  // GCC usually transforms this into a 'ror'-insn+  return (word >> shift) | (word << (32 - shift));+}++static inline uint32_t+hs_htonl(uint32_t hl)+{+#if WORDS_BIGENDIAN+  return hl;+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)+  return __builtin_bswap32(hl);+#else+  // GCC usually transforms this into a bswap insn+  return ((hl & 0xff000000) >> 24) |+         ((hl & 0x00ff0000) >> 8)  |+         ((hl & 0x0000ff00) << 8)  |+         ( hl               << 24);+#endif+}++static inline void+hs_htonl_array(uint32_t *dest, const uint32_t *src, unsigned wordcnt)+{+  while (wordcnt--)+    *dest++ = hs_htonl(*src++);+}++static inline uint64_t+hs_htonll(uint64_t hll)+{+#if WORDS_BIGENDIAN+  return hll;+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)+  return __builtin_bswap64(hll);+#else+  return ((uint64_t)hs_htonl(hll & 0xFFFFFFFF) << 32LL) | hs_htonl(hll >> 32);+#endif+}++ void hs_cryptohash_sha256_init (struct sha256_ctx *ctx) { 	memset(ctx, 0, sizeof(*ctx));-+         	ctx->h[0] = 0x6a09e667; 	ctx->h[1] = 0xbb67ae85; 	ctx->h[2] = 0x3c6ef372;@@ -69,7 +121,7 @@ 	int i; 	uint32_t w[64]; -	cpu_to_be32_array(w, buf, 16);+	hs_htonl_array(w, buf, 16); 	for (i = 16; i < 64; i++) 		w[i] = s1(w[i - 2]) + w[i - 7] + s0(w[i - 15]) + w[i - 16]; @@ -100,12 +152,12 @@ }  void-hs_cryptohash_sha256_update (struct sha256_ctx *ctx, const uint8_t *data, uint32_t len)+hs_cryptohash_sha256_update (struct sha256_ctx *ctx, const uint8_t *data, size_t len) {-	uint32_t index, to_fill;+	size_t index, to_fill;  	/* check for partial buffer */-	index = (uint32_t) (ctx->sz & 0x3f);+	index = (size_t) (ctx->sz & 0x3f); 	to_fill = 64 - index;  	ctx->sz += len;@@ -133,11 +185,10 @@ { 	static uint8_t padding[64] = { 0x80, }; 	uint64_t bits;-	uint32_t i, index, padlen;-	uint32_t *p = (uint32_t *) out;+	uint32_t index, padlen;  	/* cpu -> big endian */-	bits = cpu_to_be64(ctx->sz << 3);+	bits = hs_htonll(ctx->sz << 3);  	/* pad out to 56 */ 	index = (uint32_t) (ctx->sz & 0x3f);@@ -148,6 +199,5 @@ 	hs_cryptohash_sha256_update(ctx, (uint8_t *) &bits, sizeof(bits));  	/* store to digest */-	for (i = 0; i < 8; i++)-		p[i] = cpu_to_be32(ctx->h[i]);+        hs_htonl_array((uint32_t *) out, ctx->h, 8); }
cbits/sha256.h view
@@ -27,19 +27,21 @@ #define CRYPTOHASH_SHA256_H  #include <stdint.h>+#include <stddef.h>  struct sha256_ctx { 	uint64_t sz;-	uint8_t  buf[128];+	uint8_t  buf[64]; 	uint32_t h[8]; }; +/* keep this synchronised with 'digestSize'/'sizeCtx' in SHA256.hs */ #define SHA256_DIGEST_SIZE	32-#define SHA256_CTX_SIZE		sizeof(struct sha256_ctx)+#define SHA256_CTX_SIZE		104  void hs_cryptohash_sha256_init (struct sha256_ctx *ctx);-void hs_cryptohash_sha256_update (struct sha256_ctx *ctx, const uint8_t *data, uint32_t len);+void hs_cryptohash_sha256_update (struct sha256_ctx *ctx, const uint8_t *data, size_t len); void hs_cryptohash_sha256_finalize (struct sha256_ctx *ctx, uint8_t *out);  #endif
+ changelog.md view
@@ -0,0 +1,11 @@+## 0.11.7.2++ - switch to 'safe' FFI for calls where overhead becomes neglible+ - removed inline assembly in favour of portable C constructs+ - fix 32bit length overflow bug in `hash` function+ - fix inaccurate context-size+ - add context-size verification to incremental API operations++## 0.11.7.1++ - first version forked off `cryptohash-0.11.7` release
cryptohash-sha256.cabal view
@@ -1,5 +1,5 @@ name:                cryptohash-sha256-version:             0.11.7.1+version:             0.11.7.2 description:     A practical incremental and one-pass, pure API to the     <https://en.wikipedia.org/wiki/SHA-2 SHA-256 hash algorithm>@@ -7,7 +7,7 @@     .     The implementation is made in C with a haskell FFI wrapper that hides the C implementation.     .-    NOTE: This package has been forked off @cryptohash-0.11.7@ because the @cryptohash@ has been+    NOTE: This package has been forked off @cryptohash-0.11.7@ because the @cryptohash@ package has been     deprecated and so this package continues to satisfy the need for a lightweight package     providing the SHA256 hash algorithm without any dependencies on packages other than     @base@ and @bytestring@.@@ -31,8 +31,8 @@                    , GHC == 7.10.3                    , GHC == 8.0.1 -extra-source-files:  cbits/bitfn.h-                     cbits/sha256.h+extra-source-files:  cbits/sha256.h+                     changelog.md  source-repository head   type:     git@@ -43,39 +43,34 @@   build-depends:     base             >= 4.5   && < 4.10                    , bytestring       >= 0.9.2 && < 0.11 +  hs-source-dirs:    src   exposed-modules:   Crypto.Hash.SHA256   ghc-options:       -Wall -fno-cse -O2   cc-options:        -O3   c-sources:         cbits/sha256.c   include-dirs:      cbits -test-suite test-kat+test-suite test-sha256   default-language:  Haskell2010   type:              exitcode-stdio-1.0-  hs-source-dirs:    Tests-  main-is:           KAT.hs+  hs-source-dirs:    src-tests+  main-is:           test-sha256.hs+  ghc-options:       -Wall -threaded   build-depends:     cryptohash-sha256                    , base                    , bytestring-                   , tasty            == 0.11.*-                   , tasty-quickcheck == 0.8.*-                   , tasty-hunit      == 0.9.* -benchmark bench-hashes-  default-language:  Haskell2010-  type:              exitcode-stdio-1.0-  main-is:           Bench.hs-  hs-source-dirs:    Bench-  build-depends:     cryptohash-sha256-                   , base-                   , bytestring-                   , criterion        == 1.1.*+                   , base16-bytestring >= 0.1.1  && < 0.2+                   , SHA               >= 1.6.4  && < 1.7+                   , tasty             == 0.11.*+                   , tasty-quickcheck  == 0.8.*+                   , tasty-hunit       == 0.9.* -benchmark bench-api+benchmark bench-sha256   default-language:  Haskell2010   type:              exitcode-stdio-1.0-  main-is:           BenchAPI.hs-  hs-source-dirs:    Bench+  main-is:           bench-sha256.hs+  hs-source-dirs:    src-bench   build-depends:     cryptohash-sha256                    , base                    , bytestring
+ src-bench/bench-sha256.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE BangPatterns #-}++import           Criterion.Main+import qualified Crypto.Hash.SHA256   as SHA256+import qualified Data.ByteString      as B+import qualified Data.ByteString.Lazy as L++benchSize :: Int -> Benchmark+benchSize sz = bs `seq` bench msg (whnf SHA256.hash bs)+  where+    bs = B.replicate sz 0+    msg = "bs-" ++ show sz++main :: IO ()+main = do+    let !lbs64x256  = L.fromChunks $ replicate 4  (B.replicate 64 0)+        !lbs64x4096 = L.fromChunks $ replicate 64 (B.replicate 64 0)+    defaultMain+        [ bgroup "cryptohash-sha256"+          [ benchSize 0+          , benchSize 8+          , benchSize 32+          , benchSize 64+          , benchSize 128+          , benchSize 256+          , benchSize 1024+          , benchSize 4096+          , benchSize (128*1024)+          , benchSize (1024*1024)+          , benchSize (2*1024*1024)+          , benchSize (4*1024*1024)++          , L.length lbs64x256  `seq` bench "lbs64x256"  (whnf SHA256.hashlazy lbs64x256)+          , L.length lbs64x4096 `seq` bench "lbs64x4096" (whnf SHA256.hashlazy lbs64x4096)+          ]+        ]
+ src-tests/test-sha256.hs view
@@ -0,0 +1,146 @@+{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++import           Data.ByteString        (ByteString)+import qualified Data.ByteString        as B+import qualified Data.ByteString.Lazy   as BL+import qualified Data.ByteString.Base16 as B16++-- reference implementation+import qualified Data.Digest.Pure.SHA as REF++-- implementation under test+import qualified Crypto.Hash.SHA256     as IUT++import           Test.Tasty+import           Test.Tasty.HUnit+import           Test.Tasty.QuickCheck as QC++vectors :: [ByteString]+vectors =+    [ ""+    , "The quick brown fox jumps over the lazy dog"+    , "The quick brown fox jumps over the lazy cog"+    , "abc"+    , "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"+    , "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"+    , B.replicate 1000000 0x61+    ]++answers :: [ByteString]+answers = map (B.filter (/= 0x20))+    [ "e3b0c442 98fc1c14 9afbf4c8 996fb924 27ae41e4 649b934c a495991b 7852b855"+    , "d7a8fbb3 07d78094 69ca9abc b0082e4f 8d5651e4 6d3cdb76 2d02d0bf 37c9e592"+    , "e4c4d8f3 bf76b692 de791a17 3e053211 50f7a345 b46484fe 427f6acc 7ecc81be"+    , "ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad"+    , "248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1"+    , "cf5b16a7 78af8380 036ce59e 7b049237 0b249b11 e8f07a51 afac4503 7afee9d1"+    , "cdc76e5c 9914fb92 81a1c7e2 84d73e67 f1809a48 a497200e 046d39cc c7112cd0"+    ]++ansXLTest :: ByteString+ansXLTest = B.filter (/= 0x20)+    "50e72a0e 26442fe2 552dc393 8ac58658 228c0cbf b1d2ca87 2ae43526 6fcd055e"++katTests :: [TestTree]+katTests+  | length vectors == length answers = map makeTest (zip3 [1::Int ..] vectors answers) ++ [xltest]+  | otherwise = error "vectors/answers length mismatch"+  where+    makeTest (i, v, r) = testGroup ("vec"++show i) $+        [ testCase "one-pass" (r @=? runTest v)+        , testCase "inc-1"    (r @=? runTestInc 1 v)+        , testCase "inc-2"    (r @=? runTestInc 2 v)+        , testCase "inc-3"    (r @=? runTestInc 3 v)+        , testCase "inc-4"    (r @=? runTestInc 4 v)+        , testCase "inc-5"    (r @=? runTestInc 5 v)+        , testCase "inc-7"    (r @=? runTestInc 7 v)+        , testCase "inc-8"    (r @=? runTestInc 8 v)+        , testCase "inc-9"    (r @=? runTestInc 9 v)+        , testCase "inc-16"   (r @=? runTestInc 16 v)+        , testCase "lazy-1"   (r @=? runTestLazy 1 v)+        , testCase "lazy-2"   (r @=? runTestLazy 2 v)+        , testCase "lazy-7"   (r @=? runTestLazy 7 v)+        , testCase "lazy-8"   (r @=? runTestLazy 8 v)+        , testCase "lazy-16"  (r @=? runTestLazy 16 v)+        ]++    runTest :: ByteString -> ByteString+    runTest = B16.encode . IUT.hash++    runTestInc :: Int -> ByteString -> ByteString+    runTestInc i = B16.encode . IUT.finalize . myfoldl' IUT.update IUT.init . splitB i++    runTestLazy :: Int -> ByteString -> ByteString+    runTestLazy i = B16.encode . IUT.hashlazy . BL.fromChunks . splitB i++    ----++    xltest = testGroup "XL-vec"+        [ testCase "inc" (ansXLTest @=? (B16.encode . IUT.hashlazy) vecXL) ]+      where+        vecXL = BL.fromChunks (replicate 16777216 "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno")++    splitB :: Int -> ByteString -> [ByteString]+    splitB l b+      | B.length b > l = b1 : splitB l b2+      | otherwise = [b]+      where+        (b1, b2) = B.splitAt l b+++-- define own 'foldl' here to avoid RULE rewriting to 'hashlazy'+myfoldl' :: (b -> a -> b) -> b -> [a] -> b+myfoldl' f z0 xs0 = lgo z0 xs0+  where+    lgo z []     = z+    lgo z (x:xs) = let z' = f z x+                   in z' `seq` lgo z' xs++newtype RandBS = RandBS { unRandBS :: ByteString }+newtype RandLBS = RandLBS BL.ByteString++instance Arbitrary RandBS where+    arbitrary = fmap (RandBS . B.pack) arbitrary+    shrink (RandBS x) = fmap RandBS (go x)+      where+        go bs = zipWith B.append (B.inits bs) (tail $ B.tails bs)++instance Show RandBS where+    show (RandBS x) = "RandBS {len=" ++ show (B.length x)++"}"++instance Arbitrary RandLBS where+    arbitrary = fmap (RandLBS . BL.fromChunks . map unRandBS) arbitrary++instance Show RandLBS where+    show (RandLBS x) = "RandLBS {len=" ++ show (BL.length x) ++ ", chunks=" ++ show (length $ BL.toChunks x)++"}"+++refImplTests :: [TestTree]+refImplTests =+    [ testProperty "hash" prop_hash+    , testProperty "hashlazy" prop_hashlazy+    ]+  where+    prop_hash (RandBS bs)+        = ref_hash bs == IUT.hash bs++    prop_hashlazy (RandLBS bs)+        = ref_hashlazy bs == IUT.hashlazy bs++    ref_hash :: ByteString -> ByteString+    ref_hash = toStrict . REF.bytestringDigest . REF.sha256 . fromStrict++    ref_hashlazy :: BL.ByteString -> ByteString+    ref_hashlazy = toStrict . REF.bytestringDigest . REF.sha256++    -- toStrict/fromStrict only available with bytestring-0.10 and later+    toStrict = B.concat . BL.toChunks+    fromStrict = BL.fromChunks . (:[])++main :: IO ()+main = defaultMain $ testGroup "cryptohash-sha256"+    [ testGroup "KATs" katTests+    , testGroup "REF" refImplTests+    ]
+ src/Crypto/Hash/SHA256.hs view
@@ -0,0 +1,215 @@+-- |+-- Module      : Crypto.Hash.SHA256+-- License     : BSD-style+-- Maintainer  : Herbert Valerio Riedel <hvr@gnu.org>+-- Stability   : stable+-- Portability : unknown+--+-- A module containing <https://en.wikipedia.org/wiki/SHA-2 SHA-256> bindings+--+module Crypto.Hash.SHA256+    (++    -- * Incremental API+    --+    -- | This API is based on 4 different functions, similar to the+    -- lowlevel operations of a typical hash:+    --+    --  - 'init': create a new hash context+    --  - 'update': update non-destructively a new hash context with a strict bytestring+    --  - 'updates': same as update, except that it takes a list of strict bytestrings+    --  - 'finalize': finalize the context and returns a digest bytestring.+    --+    -- all those operations are completely pure, and instead of+    -- changing the context as usual in others language, it+    -- re-allocates a new context each time.+    --+    -- Example:+    --+    -- > import qualified Data.ByteString+    -- > import qualified Crypto.Hash.SHA256 as SHA256+    -- >+    -- > main = print digest+    -- >   where+    -- >     digest = SHA256.finalize ctx+    -- >     ctx    = foldl SHA256.update ctx0 (map Data.ByteString.pack [ [1,2,3], [4,5,6] ])+    -- >     ctx0   = SHA256.init++      Ctx(..)+    , init     -- :: Ctx+    , update   -- :: Ctx -> ByteString -> Ctx+    , updates  -- :: Ctx -> [ByteString] -> Ctx+    , finalize -- :: Ctx -> ByteString++    -- * Single Pass API+    --+    -- | This API use the incremental API under the hood to provide+    -- the common all-in-one operations to create digests out of a+    -- 'ByteString' and lazy 'L.ByteString'.+    --+    --  - 'hash': create a digest ('init' + 'update' + 'finalize') from a strict 'ByteString'+    --  - 'hashlazy': create a digest ('init' + 'update' + 'finalize') from a lazy 'L.ByteString'+    --+    -- Example:+    --+    -- > import qualified Data.ByteString+    -- > import qualified Crypto.Hash.SHA256 as SHA256+    -- >+    -- > main = print $ SHA256.hash (Data.ByteString.pack [0..255])+    --+    -- __NOTE__: The returned digest is a binary 'ByteString'. For+    -- converting to a base16/hex encoded digest the+    -- <https://hackage.haskell.org/package/base16-bytestring base16-bytestring>+    -- package is recommended.++    , hash     -- :: ByteString -> ByteString+    , hashlazy -- :: ByteString -> ByteString+    ) where++import Prelude hiding (init)+import Foreign.C.Types+import Foreign.Ptr+import Foreign.ForeignPtr (withForeignPtr)+import Foreign.Marshal.Alloc+import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString as B+import Data.ByteString (ByteString)+import Data.ByteString.Unsafe (unsafeUseAsCStringLen)+import Data.ByteString.Internal (create, toForeignPtr, memcpy)+import Data.Word+import System.IO.Unsafe (unsafeDupablePerformIO)++-- | perform IO for hashes that do allocation and ffi.+-- unsafeDupablePerformIO is used when possible as the+-- computation is pure and the output is directly linked+-- to the input. we also do not modify anything after it has+-- been returned to the user.+unsafeDoIO :: IO a -> a+unsafeDoIO = unsafeDupablePerformIO++-- | SHA-256 Context+--+-- The context data is exactly 104 bytes long, however+-- the data in the context is stored in host-endianness.+--+-- The context data is made up of+--+--  * a 'Word64' representing the number of bytes already feed to hash algorithm so far,+--+--  * a 64-element 'Word8' buffer holding partial input-chunks, and finally+--+--  * a 8-element 'Word32' array holding the current work-in-progress digest-value.+--+-- Consequently, a SHA-256 digest as produced by 'hash', 'hashlazy', or 'finalize' is 32 bytes long.+newtype Ctx = Ctx ByteString++-- keep this synchronised with cbits/sha256.h+{-# INLINE digestSize #-}+digestSize :: Int+digestSize = 32++{-# INLINE sizeCtx #-}+sizeCtx :: Int+sizeCtx = 104++{-# RULES "digestSize" B.length (finalize init) = digestSize #-}+{-# RULES "hash" forall b. finalize (update init b) = hash b #-}+{-# RULES "hash.list1" forall b. finalize (updates init [b]) = hash b #-}+{-# RULES "hashmany" forall b. finalize (foldl update init b) = hashlazy (L.fromChunks b) #-}+{-# RULES "hashlazy" forall b. finalize (foldl update init $ L.toChunks b) = hashlazy b #-}++{-# 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++copyCtx :: Ptr Ctx -> Ptr Ctx -> IO ()+copyCtx dst src = memcpy (castPtr dst) (castPtr src) (fromIntegral sizeCtx)++withCtxCopy :: Ctx -> (Ptr Ctx -> IO ()) -> IO Ctx+withCtxCopy (Ctx ctxB) f = Ctx `fmap` createCtx+  where+    createCtx = create sizeCtx $ \dstPtr ->+                withByteStringPtr ctxB $ \srcPtr -> do+                    copyCtx (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+        copyCtx (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 "sha256.h hs_cryptohash_sha256_init"+    c_sha256_init :: Ptr Ctx -> IO ()++foreign import ccall unsafe "sha256.h hs_cryptohash_sha256_update"+    c_sha256_update_unsafe :: Ptr Ctx -> Ptr Word8 -> CSize -> IO ()++foreign import ccall safe "sha256.h hs_cryptohash_sha256_update"+    c_sha256_update_safe :: Ptr Ctx -> Ptr Word8 -> CSize -> IO ()++-- 'safe' call overhead neglible for 4KiB and more+c_sha256_update :: Ptr Ctx -> Ptr Word8 -> CSize -> IO ()+c_sha256_update pctx pbuf sz+  | sz < 4096 = c_sha256_update_unsafe pctx pbuf sz+  | otherwise = c_sha256_update_safe   pctx pbuf sz++foreign import ccall unsafe "sha256.h hs_cryptohash_sha256_finalize"+    c_sha256_finalize :: Ptr Ctx -> Ptr Word8 -> IO ()++updateInternalIO :: Ptr Ctx -> ByteString -> IO ()+updateInternalIO ptr d =+    unsafeUseAsCStringLen d (\(cs, len) -> c_sha256_update ptr (castPtr cs) (fromIntegral len))++finalizeInternalIO :: Ptr Ctx -> IO ByteString+finalizeInternalIO ptr = create digestSize (c_sha256_finalize ptr)++{-# NOINLINE init #-}+-- | create a new hash context+init :: Ctx+init = unsafeDoIO $ withCtxNew $ c_sha256_init++validCtx :: Ctx -> Bool+validCtx (Ctx b) = B.length b == sizeCtx++{-# NOINLINE update #-}+-- | update a context with a bytestring+update :: Ctx -> ByteString -> Ctx+update ctx d+  | validCtx ctx = unsafeDoIO $ withCtxCopy ctx $ \ptr -> updateInternalIO ptr d+  | otherwise    = error "SHA256.update: invalid Ctx"++{-# NOINLINE updates #-}+-- | updates a context with multiple bytestrings+updates :: Ctx -> [ByteString] -> Ctx+updates ctx d+  | validCtx ctx = unsafeDoIO $ withCtxCopy ctx $ \ptr -> mapM_ (updateInternalIO ptr) d+  | otherwise    = error "SHA256.updates: invalid Ctx"++{-# NOINLINE finalize #-}+-- | finalize the context into a digest bytestring (32 bytes)+finalize :: Ctx -> ByteString+finalize ctx+  | validCtx ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO+  | otherwise    = error "SHA256.finalize: invalid Ctx"++{-# NOINLINE hash #-}+-- | hash a strict bytestring into a digest bytestring (32 bytes)+hash :: ByteString -> ByteString+hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do+    c_sha256_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr++{-# NOINLINE hashlazy #-}+-- | hash a lazy bytestring into a digest bytestring (32 bytes)+hashlazy :: L.ByteString -> ByteString+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do+    c_sha256_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr