hashes 0.2.1.1 → 0.2.2.0
raw patch · 8 files changed
+185/−142 lines, 8 filesdep +sha-validationdep +vectorPVP ok
version bump matches the API change (PVP)
Dependencies added: sha-validation, vector
API changes (from Hackage documentation)
Files
- CHANGELOG.md +5/−0
- cbits/keccak.c +60/−110
- cbits/keccak.h +1/−11
- hashes.cabal +11/−4
- src/Data/Hash/Class/Mutable.hs +15/−15
- test/Main.hs +8/−0
- test/Test/Data/Hash/FNV1.hs +0/−2
- test/Test/Data/Hash/SHA3.hs +85/−0
CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for the hashes package +## 0.2.2.0 -- 2022-08-20++* Test suite for SHA hash functions+* Fix openssl-3.0 support+ ## 0.2.1.1 -- 2021-10-23 * Fixes for building with GHC-9.2
cbits/keccak.c view
@@ -26,119 +26,77 @@ printf("expected : %s\n", expected); finally:- if (ctx) keccak256_freectx(ctx);+ if (ctx) EVP_MD_CTX_free(ctx); return ! ok; } */ -#if OPENSSL_VERSION_NUMBER >= 0x30000000L /* *************************************************************************** */-/* KECCAK-256 for OpenSSL 3.0 */--extern const OSSL_DISPATCH ossl_sha3_256_functions[];-extern const OSSL_DISPATCH ossl_sha3_512_functions[];-extern int ossl_sha3_init(KECCAK1600_CTX *ctx, unsigned char pad, size_t bitlen);--typedef void (*VoidFunPtr) (void);--VoidFunPtr dispatch(const OSSL_DISPATCH *fns, int fn_id) {- for (; fns->function_id != 0; fns++) {- if (fns->function_id == fn_id) {- return fns->function;- }- }- return NULL;-}--VoidFunPtr dispatch256(int fn_id) {- return dispatch(ossl_sha3_256_functions, fn_id);-}--VoidFunPtr dispatch512(int fn_id) {- return dispatch(ossl_sha3_512_functions, fn_id);-}--KECCAK256_CTX *keccak256_newctx()-{- KECCAK256_CTX * ctx = ((OSSL_FUNC_digest_newctx_fn *) dispatch256(OSSL_FUNC_DIGEST_NEWCTX))(NULL);-- // this has already be called once by the dispatch function. Here we update the pad character- if (ctx) ossl_sha3_init(ctx, '\x01', 256);- return ctx;-}--KECCAK512_CTX *keccak512_newctx()-{- KECCAK512_CTX * ctx = ((OSSL_FUNC_digest_newctx_fn *) dispatch512(OSSL_FUNC_DIGEST_NEWCTX))(NULL);-- // this has already be called once by the dispatch function. Here we update the pad character- if (ctx) ossl_sha3_init(ctx, '\x01', 512);- return ctx;-}--int keccak256_init(KECCAK256_CTX *ctx) {- return ((OSSL_FUNC_digest_init_fn *) dispatch256(OSSL_FUNC_DIGEST_INIT))(ctx, NULL);-}--int keccak512_init(KECCAK256_CTX *ctx) {- return ((OSSL_FUNC_digest_init_fn *) dispatch512(OSSL_FUNC_DIGEST_INIT))(ctx, NULL);-}--int keccak256_update(KECCAK256_CTX *ctx, const void *p, size_t l)-{- return ((OSSL_FUNC_digest_update_fn *) dispatch256(OSSL_FUNC_DIGEST_UPDATE))(ctx, p, l);-}--int keccak512_update(KECCAK512_CTX *ctx, const void *p, size_t l)-{- return ((OSSL_FUNC_digest_update_fn *) dispatch512(OSSL_FUNC_DIGEST_UPDATE))(ctx, p, l);-}--int keccak256_final(KECCAK256_CTX *ctx, unsigned char *md)-{- size_t l;- return ((OSSL_FUNC_digest_final_fn *) dispatch256(OSSL_FUNC_DIGEST_FINAL))(ctx, md, &l, 32);-}--int keccak512_final(KECCAK512_CTX *ctx, unsigned char *md)-{- size_t l;- return ((OSSL_FUNC_digest_final_fn *) dispatch512(OSSL_FUNC_DIGEST_FINAL))(ctx, md, &l, 64);-}--void keccak256_freectx(KECCAK256_CTX *ctx)-{- return ((OSSL_FUNC_digest_freectx_fn *) dispatch256(OSSL_FUNC_DIGEST_FREECTX))(ctx);-}--void keccak512_freectx(KECCAK512_CTX *ctx)-{- return ((OSSL_FUNC_digest_freectx_fn *) dispatch512(OSSL_FUNC_DIGEST_FREECTX))(ctx);-}--#elif OPENSSL_VERSION_NUMBER >= 0x10100000L-/* *************************************************************************** */-/* OpenSSL 1.1 */+/* OpenSSL 1.1 and OpenSSL 3.0 */ /* The computation of the magic offset is base on the keccak_st structure in- * OpenSSL-1.1.+ * OpenSSL-1.1 and OpenSSL-3.0 * * Assuming conventional alignment, the bytes offset is *- * sizeof(uint64_t) * 40 + size_of(size_t) * 3 + (1600 / 8 - 32)+ * sizeof(uint64_t) * 25 + size_of(size_t) * 3 + (1600 / 8 - 32) * * On a 64bit platform this number is 392+ *+ * // struct keccak_st {+ * // uint64_t A[5][5];+ * // size_t block_size;+ * // size_t md_size;+ * // size_t bufsz;+ * // unsigned char buf[KECCAK1600_WIDTH / 8 - 32];+ * // unsigned char pad;+ * // };+ *+ * For OpenSSL 1.1 this context is stored in EVP_MD_CTX as data and is accessed+ * via EVP_CTX_MD_md_data().+ *+ * For OpenSSL 3.0 it is stored in EVP_MD_CTX in the algctx field. The structure+ * is a field of pointers and algctx is the 8th pointer.+ *+ * // struct evp_md_ctx_st {+ * // const EVP_MD *reqdigest;+ * // const EVP_MD *digest;+ * // ENGINE *engine;+ * // unsigned long flags;+ * // void *md_data;+ * // EVP_PKEY_CTX *pctx;+ * // int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count);+ * //+ * // // Opaque ctx returned from a providers digest algorithm implementation+ * // // OSSL_FUNC_digest_newctx()+ * // //+ * // void *algctx;+ * // EVP_MD *fetched_digest;+ * // } */ -// struct keccak_st {-// uint64_t A[5][5];-// size_t block_size; /* cached ctx->digest->block_size */-// size_t md_size; /* output length, variable in XOF */-// size_t bufsz; /* used bytes in below buffer */-// unsigned char buf[KECCAK1600_WIDTH / 8 - 32];-// unsigned char pad;-// };+#define PAD_BYTE_OFFSET (25 * sizeof(uint64_t) + 3 * sizeof(size_t) + 1600/8 - 32) +/* OPENSSL 3.1 */+#if OPENSSL_VERSION_NUMBER >= 0x31000000L+#define SET_PAD_BYTE ++/* OPENSSL 3.0 */+#elif OPENSSL_VERSION_NUMBER >= 0x30000000L+#define GET_CTX(ctx) (*(((uint8_t **) ctx) + 7))+#define SET_PAD_BYTE (((uint8_t *) GET_CTX(ctx))[PAD_BYTE_OFFSET] = 0x01)++/* OPENSSL 1.1 */+#elif OPENSSL_VERSION_NUMBER >= 0x10100000L+#define GET_CTX(ctx) ((uint8_t *) EVP_MD_CTX_md_data(ctx))+#define SET_PAD_BYTE (GET_CTX(ctx)[PAD_BYTE_OFFSET] = 0x01)++#endif++/* *************************************************************************** */+/* Implementation */++ KECCAK256_CTX *keccak256_newctx() { return EVP_MD_CTX_new();@@ -152,12 +110,9 @@ int keccak256_init(KECCAK256_CTX *ctx) { int ok = 1; const EVP_MD *md = NULL;- int padByteOffset = 25 * sizeof(uint64_t) + 3 * sizeof(size_t) + 1600/8 - 32;- CHECKED(md = EVP_sha3_256());+ CHECKED(md = EVP_get_digestbyname("SHA3-256")); CHECKED(EVP_DigestInit(ctx, md));-- // MAGIC (set padding char to 0x1)- ((uint8_t *) EVP_MD_CTX_md_data(ctx))[padByteOffset] = 0x01;+ SET_PAD_BYTE; finally: return ok; }@@ -165,12 +120,9 @@ int keccak512_init(KECCAK512_CTX *ctx) { int ok = 1; const EVP_MD *md = NULL;- int padByteOffset = 25 * sizeof(uint64_t) + 3 * sizeof(size_t) + 1600/8 - 32;- CHECKED(md = EVP_sha3_512());+ CHECKED(md = EVP_get_digestbyname("SHA3-512")); CHECKED(EVP_DigestInit(ctx, md));-- // MAGIC (set padding char to 0x1)- ((uint8_t *) EVP_MD_CTX_md_data(ctx))[padByteOffset] = 0x01;+ SET_PAD_BYTE; finally: return ok; }@@ -206,6 +158,4 @@ { return EVP_MD_CTX_free(ctx); }--#endif
cbits/keccak.h view
@@ -9,20 +9,10 @@ } /* *************************************************************************** */-/* Keccak-256 */--#if OPENSSL_VERSION_NUMBER >= 0x31000000L--#elif OPENSSL_VERSION_NUMBER >= 0x30000000L-typedef struct keccak1600_ctx_st KECCAK1600_CTX;-typedef KECCAK1600_CTX KECCAK256_CTX;-typedef KECCAK1600_CTX KECCAK512_CTX;+/* Keccak */ -#elif OPENSSL_VERSION_NUMBER >= 0x10100000L typedef EVP_MD_CTX KECCAK256_CTX; typedef EVP_MD_CTX KECCAK512_CTX;--#endif // KECCAK-256 KECCAK256_CTX *keccak256_newctx();
hashes.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: hashes-version: 0.2.1.1+version: 0.2.2.0 synopsis: Hash functions Description: Efficient implementations of hash functions homepage: https://github.com/larskuhtz/hs-hashes@@ -12,9 +12,9 @@ copyright: Copyright (c) 2019-2021 Lars Kuhtz <lakuhtz@gmail.com> category: Data tested-with:+ GHC==9.2 GHC==9.0.1 GHC==8.10.7- GHC==8.8.4 extra-source-files: README.md CHANGELOG.md@@ -51,13 +51,13 @@ common openssl-common if flag(with-openssl) c-sources:- cbits/keccak.h cbits/keccak.c cpp-options: -DWITH_OPENSSL=1 if flag(openssl-use-pkg-config) pkgconfig-depends: libcrypto else- extra-Libraries: crypto+ extra-libraries: crypto+ include-dirs: cbits library import: openssl-common@@ -110,6 +110,13 @@ , base >=4.11 && <5 , bytestring >=0.10 , sydtest >=0.4+ , vector >=0.12++ if flag(with-openssl)+ build-depends:+ , sha-validation >=0.1+ other-modules:+ Test.Data.Hash.SHA3 if flag(test-cryptonite) build-depends:
src/Data/Hash/Class/Mutable.hs view
@@ -64,36 +64,36 @@ hashByteString :: forall a . Hash a => B.ByteString -> a hashByteString b = unsafeDupablePerformIO $ do- ctx <- initialize @a- updateByteString @a ctx b- finalize ctx+ ctx <- initialize @a+ updateByteString @a ctx b+ finalize ctx {-# INLINE hashByteString #-} hashByteStringLazy :: forall a . Hash a => BL.ByteString -> a hashByteStringLazy b = unsafeDupablePerformIO $ do- ctx <- initialize @a- updateByteStringLazy @a ctx b- finalize ctx+ ctx <- initialize @a+ updateByteStringLazy @a ctx b+ finalize ctx {-# INLINE hashByteStringLazy #-} hashShortByteString :: forall a . Hash a => BS.ShortByteString -> IO a hashShortByteString b = do- ctx <- initialize @a- updateShortByteString @a ctx b- finalize ctx+ ctx <- initialize @a+ updateShortByteString @a ctx b+ finalize ctx {-# INLINE hashShortByteString #-} hashStorable :: forall a b . Hash a => Storable b => b -> IO a hashStorable b = do- ctx <- initialize @a- updateStorable @a ctx b- finalize ctx+ ctx <- initialize @a+ updateStorable @a ctx b+ finalize ctx {-# INLINE hashStorable #-} hashByteArray :: forall a . Hash a => ByteArray# -> IO a hashByteArray b = do- ctx <- initialize @a- updateByteArray @a ctx b- finalize ctx+ ctx <- initialize @a+ updateByteArray @a ctx b+ finalize ctx {-# INLINE hashByteArray #-}
test/Main.hs view
@@ -15,6 +15,10 @@ import qualified Test.Data.Hash.SipHash import qualified Test.Data.Hash.Class.Pure +#if defined(WITH_OPENSSL)+import qualified Test.Data.Hash.SHA3+#endif+ #if defined(TEST_CRYPTONITE) import qualified Cryptonite #endif@@ -29,6 +33,10 @@ describe "Test.Data.Hash.FNV1.tests" Test.Data.Hash.FNV1.tests describe "Test.Data.Hash.SipHash.tests" Test.Data.Hash.SipHash.tests describe "Test.Data.Hash.Class.Pure" Test.Data.Hash.Class.Pure.tests++#if defined(WITH_OPENSSL)+ describe "Test.Data.Hash.SHA3" Test.Data.Hash.SHA3.tests+#endif #if defined(TEST_CRYPTONITE) describe "Cryptonite" Cryptonite.tests
test/Test/Data/Hash/FNV1.hs view
@@ -1,6 +1,4 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MagicHash #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-}
+ test/Test/Data/Hash/SHA3.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++-- |+-- Module: Test.Data.Hash.SHA3+-- Copyright: Copyright © 2022 Kadena LLC.+-- License: MIT+-- Maintainer: Lars Kuhtz <lars@kadena.io>+-- Stability: experimental+--+-- TODO+--+module Test.Data.Hash.SHA3+( tests+) where++import qualified Data.ByteString.Short as BS+import Data.Coerce++import Test.Syd+import Test.Hash.SHA3++-- internal modules++import Data.Hash.SHA3++-- -------------------------------------------------------------------------- --+--++tests :: Spec+tests = describe "SHA3 Test Vectors" $ do+ shortMsgTests+ longMsgTests+ monteTests++-- -------------------------------------------------------------------------- --+-- Msg Tests++shortMsgTests :: Spec+shortMsgTests = describe "ShortMsg" $ do+ describe "224" $ runMsgTest @Sha3_224 sha3_224ShortMsg+ describe "256" $ runMsgTest @Sha3_256 sha3_256ShortMsg+ describe "384" $ runMsgTest @Sha3_384 sha3_384ShortMsg+ describe "512" $ runMsgTest @Sha3_512 sha3_512ShortMsg++longMsgTests :: Spec+longMsgTests = describe "LongMsg" $ do+ describe "224" $ runMsgTest @Sha3_224 sha3_224LongMsg+ describe "256" $ runMsgTest @Sha3_256 sha3_256LongMsg+ describe "384" $ runMsgTest @Sha3_384 sha3_384LongMsg+ describe "512" $ runMsgTest @Sha3_512 sha3_512LongMsg++runMsgTest+ :: forall a+ . Hash a+ => Coercible a BS.ShortByteString+ => MsgFile+ -> Spec+runMsgTest = msgAssert+ (\l a b -> it l (a == b))+ (BS.fromShort . coerce . hashByteString @a)++-- -------------------------------------------------------------------------- --+-- Monte Tests++monteTests :: Spec+monteTests = describe "Monte" $ do+ describe "224" $ runMonteTest @Sha3_224 sha3_224Monte+ describe "256" $ runMonteTest @Sha3_256 sha3_256Monte+ describe "384" $ runMonteTest @Sha3_384 sha3_384Monte+ describe "512" $ runMonteTest @Sha3_512 sha3_512Monte++runMonteTest+ :: forall a+ . Hash a+ => Coercible a BS.ShortByteString+ => MonteFile+ -> Spec+runMonteTest = monteAssert+ (\l a b -> it l (a == b))+ (BS.fromShort . coerce . hashByteString @a)+