packages feed

cryptohash-sha512 0.11.101.0 → 0.11.102.0

raw patch · 10 files changed

+1637/−316 lines, 10 filesdep ~basedep ~bytestringdep ~tastyPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base, bytestring, tasty, tasty-quickcheck

API changes (from Hackage documentation)

+ Crypto.Hash.SHA384: Ctx :: ByteString -> Ctx
+ Crypto.Hash.SHA384: finalize :: Ctx -> ByteString
+ Crypto.Hash.SHA384: finalizeAndLength :: Ctx -> (ByteString, Word64)
+ Crypto.Hash.SHA384: hash :: ByteString -> ByteString
+ Crypto.Hash.SHA384: hashlazy :: ByteString -> ByteString
+ Crypto.Hash.SHA384: hashlazyAndLength :: ByteString -> (ByteString, Word64)
+ Crypto.Hash.SHA384: hmac :: ByteString -> ByteString -> ByteString
+ Crypto.Hash.SHA384: hmaclazy :: ByteString -> ByteString -> ByteString
+ Crypto.Hash.SHA384: hmaclazyAndLength :: ByteString -> ByteString -> (ByteString, Word64)
+ Crypto.Hash.SHA384: init :: Ctx
+ Crypto.Hash.SHA384: newtype Ctx
+ Crypto.Hash.SHA384: start :: ByteString -> Ctx
+ Crypto.Hash.SHA384: startlazy :: ByteString -> Ctx
+ Crypto.Hash.SHA384: update :: Ctx -> ByteString -> Ctx
+ Crypto.Hash.SHA384: updates :: Ctx -> [ByteString] -> Ctx
+ Crypto.Hash.SHA512t: Ctx :: !Int -> !Ctx -> Ctx
+ Crypto.Hash.SHA512t: data Ctx
+ Crypto.Hash.SHA512t: finalize :: Ctx -> ByteString
+ Crypto.Hash.SHA512t: finalizeAndLength :: Ctx -> (ByteString, Word64)
+ Crypto.Hash.SHA512t: hash :: Int -> ByteString -> ByteString
+ Crypto.Hash.SHA512t: hashlazy :: Int -> ByteString -> ByteString
+ Crypto.Hash.SHA512t: hashlazyAndLength :: Int -> ByteString -> (ByteString, Word64)
+ Crypto.Hash.SHA512t: hmac :: Int -> ByteString -> ByteString -> ByteString
+ Crypto.Hash.SHA512t: hmaclazy :: Int -> ByteString -> ByteString -> ByteString
+ Crypto.Hash.SHA512t: hmaclazyAndLength :: Int -> ByteString -> ByteString -> (ByteString, Word64)
+ Crypto.Hash.SHA512t: init :: Int -> Ctx
+ Crypto.Hash.SHA512t: instance GHC.Classes.Eq Crypto.Hash.SHA512t.Ctx
+ Crypto.Hash.SHA512t: start :: Int -> ByteString -> Ctx
+ Crypto.Hash.SHA512t: startlazy :: Int -> ByteString -> Ctx
+ Crypto.Hash.SHA512t: update :: Ctx -> ByteString -> Ctx
+ Crypto.Hash.SHA512t: updates :: Ctx -> [ByteString] -> Ctx

Files

+ cbits/hs_sha512.h view
@@ -0,0 +1,415 @@+/*+ * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>+ *               2016      Herbert Valerio Riedel <hvr@gnu.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 CRYPTOHASH_SHA512_H+#define CRYPTOHASH_SHA512_H++#include <stdbool.h>+#include <stdint.h>+#include <stdio.h>+#include <stddef.h>+#include <assert.h>+#include <string.h>+#include <ghcautoconf.h>++struct sha512_ctx+{+  uint64_t sz;+  uint64_t sz_hi;+  uint8_t  buf[128];+  uint64_t h[8];+};++/* keep this synchronised with 'digestSize'/'sizeCtx' in SHA512.hs */+#define SHA512_DIGEST_SIZE	64+#define SHA512t_DIGEST_SIZE(t)	(((t)+7)/8)+#define SHA384_DIGEST_SIZE	48+#define SHA512_CTX_SIZE		208++/* NB: SHA384 and SHA512/t are essentially the same algorithm as SHA512 and+ * therefore share the same data structures and most of the codepaths+ * except for different initialization data and truncating the 512bit+ * digest down to the respective digest bit-length.+ */+static inline void hs_cryptohash_sha384_init(struct sha512_ctx *ctx);+static inline void hs_cryptohash_sha512_init (struct sha512_ctx *ctx);+static inline void hs_cryptohash_sha512t_init(struct sha512_ctx *ctx, const uint16_t t);++static inline void hs_cryptohash_sha512_update (struct sha512_ctx *ctx, const uint8_t *data, size_t len);++static inline uint64_t hs_cryptohash_sha512t_finalize (struct sha512_ctx *ctx, uint16_t outbits, uint8_t *out);++#if defined(static_assert)+static_assert(sizeof(struct sha512_ctx) == SHA512_CTX_SIZE, "unexpected sha512_ctx size");+#else+/* poor man's pre-C11 _Static_assert */+typedef char static_assertion__unexpected_sha512_ctx_size[(sizeof(struct sha512_ctx) == SHA512_CTX_SIZE)?1:-1];+#endif++#define ptr_uint64_aligned(ptr) (!((uintptr_t)(ptr) & 0x7))++static inline uint64_t+ror64(const uint64_t word, const unsigned shift)+{+  /* GCC usually transforms this into a 'ror'-insn */+  return (word >> shift) | (word << (64 - shift));+}++static inline uint64_t+cpu_to_be64(const uint64_t hll)+{+#if WORDS_BIGENDIAN+  return hll;+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)+  return __builtin_bswap64(hll);+#else+  /* GCC & Clang usually transforms this into a bswap insn */+  return ((hll & 0xff00000000000000) >> 56) |+         ((hll & 0x00ff000000000000) >> 40) |+         ((hll & 0x0000ff0000000000) >> 24) |+         ((hll & 0x000000ff00000000) >>  8) |+         ((hll & 0x00000000ff000000) <<  8) |+         ((hll & 0x0000000000ff0000) << 24) |+         ((hll & 0x000000000000ff00) << 40) |+         ((hll & 0x00000000000000ff) << 56);+#endif+}++static inline void+cpu_to_be64_array(uint64_t *dest, const uint64_t *src, unsigned wordcnt)+{+  while (wordcnt--)+    *dest++ = cpu_to_be64(*src++);+}++static inline void+hs_cryptohash_sha512_init (struct sha512_ctx *ctx)+{+  memset(ctx, 0, SHA512_CTX_SIZE);++  ctx->h[0] = 0x6a09e667f3bcc908ULL;+  ctx->h[1] = 0xbb67ae8584caa73bULL;+  ctx->h[2] = 0x3c6ef372fe94f82bULL;+  ctx->h[3] = 0xa54ff53a5f1d36f1ULL;+  ctx->h[4] = 0x510e527fade682d1ULL;+  ctx->h[5] = 0x9b05688c2b3e6c1fULL;+  ctx->h[6] = 0x1f83d9abfb41bd6bULL;+  ctx->h[7] = 0x5be0cd19137e2179ULL;+}++static inline void+hs_cryptohash_sha384_init (struct sha512_ctx *ctx)+{+  memset(ctx, 0, SHA512_CTX_SIZE);++  ctx->h[0] = 0xcbbb9d5dc1059ed8ULL;+  ctx->h[1] = 0x629a292a367cd507ULL;+  ctx->h[2] = 0x9159015a3070dd17ULL;+  ctx->h[3] = 0x152fecd8f70e5939ULL;+  ctx->h[4] = 0x67332667ffc00b31ULL;+  ctx->h[5] = 0x8eb44a8768581511ULL;+  ctx->h[6] = 0xdb0c2e0d64f98fa7ULL;+  ctx->h[7] = 0x47b5481dbefa4fa4ULL;+}++static inline void+hs_cryptohash_sha512t_init(struct sha512_ctx *ctx, const uint16_t t)+{+  memset(ctx, 0, SHA512_CTX_SIZE);++  if (!((0 < t) && (t < 512)))+    return;++  /* shortcuts for the currently two FIPS 180-4 "approved" parameters */+  switch (t) {+  case 224:+    ctx->h[0] = 0x8c3d37c819544da2ULL;+    ctx->h[1] = 0x73e1996689dcd4d6ULL;+    ctx->h[2] = 0x1dfab7ae32ff9c82ULL;+    ctx->h[3] = 0x679dd514582f9fcfULL;+    ctx->h[4] = 0x0f6d2b697bd44da8ULL;+    ctx->h[5] = 0x77e36f7304c48942ULL;+    ctx->h[6] = 0x3f9d85a86a1d36c8ULL;+    ctx->h[7] = 0x1112e6ad91d692a1ULL;+    return;++  case 256:+    ctx->h[0] = 0x22312194fc2bf72cULL;+    ctx->h[1] = 0x9f555fa3c84c64c2ULL;+    ctx->h[2] = 0x2393b86b6f53b151ULL;+    ctx->h[3] = 0x963877195940eabdULL;+    ctx->h[4] = 0x96283ee2a88effe3ULL;+    ctx->h[5] = 0xbe5e1e2553863992ULL;+    ctx->h[6] = 0x2b0199fc2c85b8aaULL;+    ctx->h[7] = 0x0eb72ddc81c52ca2ULL;+    return;+  }++  /* slow path */+  hs_cryptohash_sha512_init(ctx);+  for (int i = 0; i < 8; i++)+    ctx->h[i] ^= 0xa5a5a5a5a5a5a5a5ULL;++  uint64_t out[8] = { 0, };++  {+    char buf[16] = { 0, };+    const int bufsz = snprintf(buf, 16, "SHA-512/%d", t);+    hs_cryptohash_sha512_update(ctx, (uint8_t*)buf, bufsz);+    hs_cryptohash_sha512t_finalize(ctx, 512, (uint8_t*)out);+  }++  /* re-init the context, otherwise len is changed */+  memset(ctx, 0, SHA512_CTX_SIZE);+  for (int i = 0; i < 8; i++)+    ctx->h[i] = cpu_to_be64(out[i]);++}+++/* 232 times the cube root of the first 64 primes 2..311 */+static const uint64_t k[] = {+  0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,+  0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,+  0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,+  0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,+  0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,+  0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,+  0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,+  0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,+  0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,+  0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,+  0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,+  0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,+  0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,+  0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,+  0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,+  0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,+  0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,+  0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,+  0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,+  0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,+  0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,+  0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,+  0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,+  0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,+  0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,+  0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,+  0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL+};++#define e0(x)       (ror64(x, 28) ^ ror64(x, 34) ^ ror64(x, 39))+#define e1(x)       (ror64(x, 14) ^ ror64(x, 18) ^ ror64(x, 41))+#define s0(x)       (ror64(x,  1) ^ ror64(x,  8) ^ (x >> 7))+#define s1(x)       (ror64(x, 19) ^ ror64(x, 61) ^ (x >> 6))++static void+sha512_do_chunk_aligned(struct sha512_ctx *ctx, uint64_t w[])+{+  int i;++  for (i = 16; i < 80; i++)+    w[i] = s1(w[i - 2]) + w[i - 7] + s0(w[i - 15]) + w[i - 16];++  uint64_t a = ctx->h[0];+  uint64_t b = ctx->h[1];+  uint64_t c = ctx->h[2];+  uint64_t d = ctx->h[3];+  uint64_t e = ctx->h[4];+  uint64_t f = ctx->h[5];+  uint64_t g = ctx->h[6];+  uint64_t h = ctx->h[7];++#define R(a, b, c, d, e, f, g, h, k, w)             \+    t1 = h + e1(e) + (g ^ (e & (f ^ g))) + k + w;   \+    t2 = e0(a) + ((a & b) | (c & (a | b)));         \+    d += t1;                                        \+    h = t1 + t2++  for (i = 0; i < 80; i += 8) {+    uint64_t t1, t2;++    R(a, b, c, d, e, f, g, h, k[i + 0], w[i + 0]);+    R(h, a, b, c, d, e, f, g, k[i + 1], w[i + 1]);+    R(g, h, a, b, c, d, e, f, k[i + 2], w[i + 2]);+    R(f, g, h, a, b, c, d, e, k[i + 3], w[i + 3]);+    R(e, f, g, h, a, b, c, d, k[i + 4], w[i + 4]);+    R(d, e, f, g, h, a, b, c, k[i + 5], w[i + 5]);+    R(c, d, e, f, g, h, a, b, k[i + 6], w[i + 6]);+    R(b, c, d, e, f, g, h, a, k[i + 7], w[i + 7]);+  }++#undef R++  ctx->h[0] += a;+  ctx->h[1] += b;+  ctx->h[2] += c;+  ctx->h[3] += d;+  ctx->h[4] += e;+  ctx->h[5] += f;+  ctx->h[6] += g;+  ctx->h[7] += h;+}++static void+sha512_do_chunk(struct sha512_ctx *ctx, const uint8_t buf[])+{+  uint64_t w[80]; /* only first 16 words are filled in */+  if (ptr_uint64_aligned(buf)) { /* aligned buf */+    cpu_to_be64_array(w, (const uint64_t *)buf, 16);+  } else { /* unaligned buf */+    memcpy(w, buf, 128);+#if !WORDS_BIGENDIAN+    cpu_to_be64_array(w, w, 16);+#endif+  }+  sha512_do_chunk_aligned(ctx, w);+}++static inline void+hs_cryptohash_sha512_update(struct sha512_ctx *ctx, const uint8_t *data, size_t len)+{+  size_t index = ctx->sz & 0x7f;+  const size_t to_fill = 128 - index;++  ctx->sz += len;+  // handle overflow+  if (ctx->sz < len)+    ctx->sz_hi++;++  /* process partial buffer if there's enough data to make a block */+  if (index && len >= to_fill) {+    memcpy(ctx->buf + index, data, to_fill);+    sha512_do_chunk(ctx, ctx->buf);+    /* memset(ctx->buf, 0, 128); */+    len -= to_fill;+    data += to_fill;+    index = 0;+  }++  /* process as many 128b-blocks as possible */+  while (len >= 128) {+    sha512_do_chunk(ctx, data);+    len -= 128;+    data += 128;+  }++  /* append data into buf */+  if (len)+    memcpy(ctx->buf + index, data, len);+}++static inline uint64_t+hs_cryptohash_sha512t_finalize (struct sha512_ctx *ctx, uint16_t outbits, uint8_t *out)+{+  static const uint8_t padding[128] = { 0x80, };+  const uint64_t sz = ctx->sz;++  /* add padding and update data with it */+  uint64_t bits[2];+  bits[0] = cpu_to_be64((ctx->sz_hi << 3) | (ctx->sz >> 61));+  bits[1] = cpu_to_be64(ctx->sz << 3);++  /* pad out to 112 */+  const size_t index = ctx->sz & 0x7f;+  const size_t padlen = (index < 112) ? (112 - index) : ((128 + 112) - index);+  hs_cryptohash_sha512_update(ctx, padding, padlen);++  /* append length */+  hs_cryptohash_sha512_update(ctx, (uint8_t *) bits, sizeof(bits));++  /* output hash */+  if (outbits > 512)+    outbits = 512; /* clamp to <= 512; better safe than sorry */++  if(outbits % 64 == 0) {+    /* fast path for 0,64,128,192,256,320,384,448,512 */+    cpu_to_be64_array((uint64_t *) out, ctx->h, outbits/64);+  } else {+    /* slow-path */+    uint8_t buf[SHA512_DIGEST_SIZE] = { 0x00, };+    cpu_to_be64_array((uint64_t *) buf, ctx->h, 8);++    const unsigned outbytes = SHA512t_DIGEST_SIZE(outbits);+    assert(outbytes > 0);+    assert(outbytes <= SHA512_DIGEST_SIZE);++    /* Handle case of t parameter not being an integral amount of+     * octects.  FIPS 180-4 states that "the resulting message digest+     * is truncated by selecting an appropriate number of the leftmost+     * bits". Hence in such a case we apply a mask to retain the+     * appropriate number of leftmost bits in the rightmost retained+     * octet.+     */+    const uint8_t outmask = ~(((uint8_t)0xff) >> (outbits % 8));+    if (outmask)+      buf[outbytes-1] &= outmask;++    memcpy(out, buf, outbytes);+  }++  return sz;+}++static inline void+hs_cryptohash_sha512_hash (const uint8_t *data, size_t len, uint8_t *out)+{+  struct sha512_ctx ctx;++  hs_cryptohash_sha512_init(&ctx);++  hs_cryptohash_sha512_update(&ctx, data, len);++  hs_cryptohash_sha512t_finalize(&ctx, 512, out);+}++static inline void+hs_cryptohash_sha384_hash (const uint8_t *data, size_t len, uint8_t *out)+{+  struct sha512_ctx ctx;++  hs_cryptohash_sha384_init(&ctx);++  hs_cryptohash_sha512_update(&ctx, data, len);++  hs_cryptohash_sha512t_finalize(&ctx, 384, out);+}++static inline void+hs_cryptohash_sha512t_hash (const uint8_t *data, size_t len, uint8_t *out, const uint16_t outbits)+{+  struct sha512_ctx ctx;++  if (!(0 < outbits && outbits < 512)) return;++  hs_cryptohash_sha512t_init(&ctx, outbits);++  hs_cryptohash_sha512_update(&ctx, data, len);++  hs_cryptohash_sha512t_finalize(&ctx, outbits, out);+}+++#endif
− cbits/sha512.h
@@ -1,278 +0,0 @@-/*- * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>- *               2016      Herbert Valerio Riedel <hvr@gnu.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 CRYPTOHASH_SHA512_H-#define CRYPTOHASH_SHA512_H--#include <stdint.h>-#include <stddef.h>-#include <assert.h>-#include <string.h>-#include <ghcautoconf.h>--struct sha512_ctx-{-  uint64_t sz;-  uint64_t sz_hi;-  uint8_t  buf[128];-  uint64_t h[8];-};--/* keep this synchronised with 'digestSize'/'sizeCtx' in SHA512.hs */-#define SHA512_DIGEST_SIZE	64-#define SHA512_CTX_SIZE		208--static inline void hs_cryptohash_sha512_init (struct sha512_ctx *ctx);-static inline void hs_cryptohash_sha512_update (struct sha512_ctx *ctx, const uint8_t *data, size_t len);-static inline uint64_t hs_cryptohash_sha512_finalize (struct sha512_ctx *ctx, uint8_t *out);--#if defined(static_assert)-static_assert(sizeof(struct sha512_ctx) == SHA512_CTX_SIZE, "unexpected sha512_ctx size");-#else-/* poor man's pre-C11 _Static_assert */-typedef char static_assertion__unexpected_sha512_ctx_size[(sizeof(struct sha512_ctx) == SHA512_CTX_SIZE)?1:-1];-#endif--#define ptr_uint64_aligned(ptr) (!((uintptr_t)(ptr) & 0x7))--static inline uint64_t-ror64(const uint64_t word, const unsigned shift)-{-  /* GCC usually transforms this into a 'ror'-insn */-  return (word >> shift) | (word << (64 - shift));-}--static inline uint64_t-cpu_to_be64(const uint64_t hll)-{-#if WORDS_BIGENDIAN-  return hll;-#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)-  return __builtin_bswap64(hll);-#else-  /* GCC & Clang usually transforms this into a bswap insn */-  return ((hll & 0xff00000000000000) >> 56) |-         ((hll & 0x00ff000000000000) >> 40) |-         ((hll & 0x0000ff0000000000) >> 24) |-         ((hll & 0x000000ff00000000) >>  8) |-         ((hll & 0x00000000ff000000) <<  8) |-         ((hll & 0x0000000000ff0000) << 24) |-         ((hll & 0x000000000000ff00) << 40) |-         ((hll & 0x00000000000000ff) << 56);-#endif-}--static inline void-cpu_to_be64_array(uint64_t *dest, const uint64_t *src, unsigned wordcnt)-{-  while (wordcnt--)-    *dest++ = cpu_to_be64(*src++);-}--static inline void-hs_cryptohash_sha512_init (struct sha512_ctx *ctx)-{-  memset(ctx, 0, SHA512_CTX_SIZE);-  -  ctx->h[0] = 0x6a09e667f3bcc908ULL;-  ctx->h[1] = 0xbb67ae8584caa73bULL;-  ctx->h[2] = 0x3c6ef372fe94f82bULL;-  ctx->h[3] = 0xa54ff53a5f1d36f1ULL;-  ctx->h[4] = 0x510e527fade682d1ULL;-  ctx->h[5] = 0x9b05688c2b3e6c1fULL;-  ctx->h[6] = 0x1f83d9abfb41bd6bULL;-  ctx->h[7] = 0x5be0cd19137e2179ULL;-}--/* 232 times the cube root of the first 64 primes 2..311 */-static const uint64_t k[] = {-  0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,-  0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,-  0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,-  0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,-  0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,-  0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,-  0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,-  0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,-  0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,-  0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,-  0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,-  0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,-  0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,-  0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,-  0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,-  0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,-  0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,-  0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,-  0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,-  0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,-  0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,-  0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,-  0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,-  0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,-  0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,-  0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,-  0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL-};--#define e0(x)       (ror64(x, 28) ^ ror64(x, 34) ^ ror64(x, 39))-#define e1(x)       (ror64(x, 14) ^ ror64(x, 18) ^ ror64(x, 41))-#define s0(x)       (ror64(x,  1) ^ ror64(x,  8) ^ (x >> 7))-#define s1(x)       (ror64(x, 19) ^ ror64(x, 61) ^ (x >> 6))--static void-sha512_do_chunk_aligned(struct sha512_ctx *ctx, uint64_t w[])-{-  int i;-  -  for (i = 16; i < 80; i++)-    w[i] = s1(w[i - 2]) + w[i - 7] + s0(w[i - 15]) + w[i - 16];--  uint64_t a = ctx->h[0];-  uint64_t b = ctx->h[1];-  uint64_t c = ctx->h[2];-  uint64_t d = ctx->h[3];-  uint64_t e = ctx->h[4];-  uint64_t f = ctx->h[5];-  uint64_t g = ctx->h[6];-  uint64_t h = ctx->h[7];--#define R(a, b, c, d, e, f, g, h, k, w)             \-    t1 = h + e1(e) + (g ^ (e & (f ^ g))) + k + w;   \-    t2 = e0(a) + ((a & b) | (c & (a | b)));         \-    d += t1;                                        \-    h = t1 + t2--  for (i = 0; i < 80; i += 8) {-    uint64_t t1, t2;--    R(a, b, c, d, e, f, g, h, k[i + 0], w[i + 0]);-    R(h, a, b, c, d, e, f, g, k[i + 1], w[i + 1]);-    R(g, h, a, b, c, d, e, f, k[i + 2], w[i + 2]);-    R(f, g, h, a, b, c, d, e, k[i + 3], w[i + 3]);-    R(e, f, g, h, a, b, c, d, k[i + 4], w[i + 4]);-    R(d, e, f, g, h, a, b, c, k[i + 5], w[i + 5]);-    R(c, d, e, f, g, h, a, b, k[i + 6], w[i + 6]);-    R(b, c, d, e, f, g, h, a, k[i + 7], w[i + 7]);-  }--#undef R--  ctx->h[0] += a;-  ctx->h[1] += b;-  ctx->h[2] += c;-  ctx->h[3] += d;-  ctx->h[4] += e;-  ctx->h[5] += f;-  ctx->h[6] += g;-  ctx->h[7] += h;-}--static void-sha512_do_chunk(struct sha512_ctx *ctx, const uint8_t buf[])-{-  uint64_t w[80]; /* only first 16 words are filled in */-  if (ptr_uint64_aligned(buf)) { /* aligned buf */-    cpu_to_be64_array(w, (const uint64_t *)buf, 16);-  } else { /* unaligned buf */-    memcpy(w, buf, 128);-#if !WORDS_BIGENDIAN-    cpu_to_be64_array(w, w, 16);-#endif-  }-  sha512_do_chunk_aligned(ctx, w);-}--static inline void-hs_cryptohash_sha512_update(struct sha512_ctx *ctx, const uint8_t *data, size_t len)-{-  size_t index = ctx->sz & 0x7f;-  const size_t to_fill = 128 - index;--  ctx->sz += len;-  // handle overflow-  if (ctx->sz < len)-    ctx->sz_hi++;--  /* process partial buffer if there's enough data to make a block */-  if (index && len >= to_fill) {-    memcpy(ctx->buf + index, data, to_fill);-    sha512_do_chunk(ctx, ctx->buf);-    /* memset(ctx->buf, 0, 128); */-    len -= to_fill;-    data += to_fill;-    index = 0;-  }--  /* process as many 128b-blocks as possible */-  while (len >= 128) {-    sha512_do_chunk(ctx, data);-    len -= 128;-    data += 128;-  }--  /* append data into buf */-  if (len)-    memcpy(ctx->buf + index, data, len);-}--static inline uint64_t-hs_cryptohash_sha512_finalize (struct sha512_ctx *ctx, uint8_t *out)-{-  static const uint8_t padding[128] = { 0x80, };-  const uint64_t sz = ctx->sz;--  /* add padding and update data with it */-  uint64_t bits[2];-  bits[0] = cpu_to_be64((ctx->sz_hi << 3) | (ctx->sz >> 61));-  bits[1] = cpu_to_be64(ctx->sz << 3);--  /* pad out to 112 */-  const size_t index = ctx->sz & 0x7f;-  const size_t padlen = (index < 112) ? (112 - index) : ((128 + 112) - index);-  hs_cryptohash_sha512_update(ctx, padding, padlen);--  /* append length */-  hs_cryptohash_sha512_update(ctx, (uint8_t *) bits, sizeof(bits));--  /* output hash */-  cpu_to_be64_array((uint64_t *) out, ctx->h, 8);--  return sz;-}--static inline void-hs_cryptohash_sha512_hash (const uint8_t *data, size_t len, uint8_t *out)-{-  struct sha512_ctx ctx;--  hs_cryptohash_sha512_init(&ctx);--  hs_cryptohash_sha512_update(&ctx, data, len);--  hs_cryptohash_sha512_finalize(&ctx, out);-}--#endif
changelog.md view
@@ -1,3 +1,8 @@+## 0.11.102.0++ - Expose SHA512/t variant via new `Crypto.Hash.SHA512t` module+ - Expose SHA384 variant via new `Crypto.Hash.SHA384` module+ ## 0.11.101.0   - Add Eq instance for Ctx
cryptohash-sha512.cabal view
@@ -1,31 +1,56 @@+cabal-version:       2.0 name:                cryptohash-sha512-version:             0.11.101.0-description:-    A practical incremental and one-pass, pure API to the-    <https://en.wikipedia.org/wiki/SHA-2 SHA-512 hash algorithm>-    (including <https://en.wikipedia.org/wiki/HMAC HMAC> support)-    with performance close to the fastest implementations available in other languages.-    .-    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@ package has been-    deprecated and so this package continues to satisfy the need for a lightweight package-    providing the SHA512 hash algorithm without any dependencies on packages other than-    @base@ and @bytestring@.-    .-    Consequently, this package can be used as a drop-in replacement for @cryptohash@'s-    "Crypto.Hash.SHA512" module, though with a clearly smaller footprint.+version:             0.11.102.0 +synopsis:            Fast, pure and practical SHA-512 implementation+description: {++A practical incremental and one-pass, pure API to+the [SHA-512, SHA512/t and SHA-384 cryptographic hash algorithms](https://en.wikipedia.org/wiki/SHA-2) according+to [FIPS 180-4](http://dx.doi.org/10.6028/NIST.FIPS.180-4)+with performance close to the fastest implementations available in other languages.+.+The core SHA-512 algorithm is implemented in C and is thus expected+to be as fast as the standard [sha512sum(1) tool](https://linux.die.net/man/1/sha512sum).+(If, instead, you require a pure Haskell implementation and performance is secondary, please refer to the [SHA package](https://hackage.haskell.org/package/SHA).)+.+Additionally, this package provides support for+.+- HMAC-SHA-384: SHA-384-based [Hashed Message Authentication Codes](https://en.wikipedia.org/wiki/HMAC) (HMAC)+- HMAC-SHA-512: SHA-512-based [Hashed Message Authentication Codes](https://en.wikipedia.org/wiki/HMAC) (HMAC)+- HMAC-SHA-512\/t: SHA-512\/t-based [Hashed Message Authentication Codes](https://en.wikipedia.org/wiki/HMAC) (HMAC)+.+conforming to [RFC6234](https://tools.ietf.org/html/rfc6234), [RFC4231](https://tools.ietf.org/html/rfc4231), [RFC5869](https://tools.ietf.org/html/rfc5869), et al..+.+=== Packages in the @cryptohash-*@ family+.+- <https://hackage.haskell.org/package/cryptohash-md5    cryptohash-md5>+- <https://hackage.haskell.org/package/cryptohash-sha1   cryptohash-sha1>+- <https://hackage.haskell.org/package/cryptohash-sha256 cryptohash-sha256>+- <https://hackage.haskell.org/package/cryptohash-sha512 cryptohash-sha512>+.+=== Relationship to the @cryptohash@ package and its API+.+This package has been originally a fork of @cryptohash-0.11.7@ because the @cryptohash@+package had been deprecated and so this package continues to satisfy the need for a+lightweight package providing the SHA-512 hash algorithms without any dependencies on packages+other than @base@ and @bytestring@. The API exposed by @cryptohash-sha512-0.11.*@'s+"Crypto.Hash.SHA512", "Crypto.Hash.SHA512t", and "Crypto.Hash.SHA384" module is guaranteed to remain a compatible superset of the API provided+by the @cryptohash-0.11.7@'s module of the same name.+.+Consequently, this package is designed to be used as a drop-in replacement for the @cryptohash-0.11.7@ modules mentioned above, though with+a [clearly smaller footprint by almost 3 orders of magnitude](https://www.reddit.com/r/haskell/comments/5lxv75/psa_please_use_unique_module_names_when_uploading/dbzegx3/).++}+ license:             BSD3 license-file:        LICENSE copyright:           Vincent Hanquez, Herbert Valerio Riedel maintainer:          Herbert Valerio Riedel <hvr@gnu.org> homepage:            https://github.com/hvr/cryptohash-sha512 bug-reports:         https://github.com/hvr/cryptohash-sha512/issues-synopsis:            Fast, pure and practical SHA-512 implementation category:            Data, Cryptography build-type:          Simple-cabal-version:       >=1.10 tested-with:         GHC == 7.4.2                    , GHC == 7.6.3                    , GHC == 7.8.4@@ -35,11 +60,12 @@                    , GHC == 8.4.4                    , GHC == 8.6.5                    , GHC == 8.8.4-                   , GHC == 8.10.4-                   , GHC == 9.0.1-                   , GHC == 9.2.1+                   , GHC == 8.10.7+                   , GHC == 9.0.2+                   , GHC == 9.2.4+                   , GHC == 9.4.1 -extra-source-files:  cbits/sha512.h+extra-source-files:  cbits/hs_sha512.h                      changelog.md  source-repository head@@ -48,11 +74,11 @@  library   default-language:  Haskell2010-  build-depends:     base             >= 4.5   && < 4.17+  build-depends:     base             >= 4.5   && < 4.18                    , bytestring       >= 0.9.2 && < 0.12    hs-source-dirs:    src-  exposed-modules:   Crypto.Hash.SHA512+  exposed-modules:   Crypto.Hash.SHA512 Crypto.Hash.SHA512t Crypto.Hash.SHA384   other-modules:     Crypto.Hash.SHA512.FFI Compat   ghc-options:       -Wall -fno-cse -O2   cc-options:        -Wall@@ -74,6 +100,38 @@                    , tasty-quickcheck  >= 0.10     && < 0.11                    , tasty-hunit       >= 0.10     && < 0.11 +test-suite test-sha512t+  default-language:  Haskell2010+  type:              exitcode-stdio-1.0+  hs-source-dirs:    src-tests+  main-is:           test-sha512t.hs+  ghc-options:       -Wall -threaded+  build-depends:     cryptohash-sha512+                   , base+                   , bytestring++                   , base16-bytestring >= 1.0.1.0  && < 1.1+                   , SHA               >= 1.6.4    && < 1.7+                   , tasty             >= 1.4      && < 1.5+                   , tasty-quickcheck  >= 0.10     && < 0.11+                   , tasty-hunit       >= 0.10     && < 0.11++test-suite test-sha384+  default-language:  Haskell2010+  type:              exitcode-stdio-1.0+  hs-source-dirs:    src-tests+  main-is:           test-sha384.hs+  ghc-options:       -Wall -threaded+  build-depends:     cryptohash-sha512+                   , base+                   , bytestring++                   , base16-bytestring >= 1.0.1.0  && < 1.1+                   , SHA               >= 1.6.4    && < 1.7+                   , tasty             >= 1.4      && < 1.5+                   , tasty-quickcheck  >= 0.10     && < 0.11+                   , tasty-hunit       >= 0.10     && < 0.11+ benchmark bench-sha512   default-language:  Haskell2010   type:              exitcode-stdio-1.0@@ -82,4 +140,4 @@   build-depends:     cryptohash-sha512                    , base                    , bytestring-                   , criterion        >= 1.5 && <1.6+                   , criterion        >= 1.5 && <1.7
+ src-tests/test-sha384.hs view
@@ -0,0 +1,244 @@+{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++import           Data.Word              (Word64)+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.SHA384     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))+    [ "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"+    , "ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1"+    , "098cea620b0978caa5f0befba6ddcf22764bea977e1c70b3483edfdf1de25f4b40d6cea3cadf00f809d422feb1f0161b"+    , "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"+    , "3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b"+    , "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039"+    , "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985"+    ]++ansXLTest :: ByteString+ansXLTest = B.filter (/= 0x20)+    "5441235cc0235341ed806a64fb354742b5e5c02a3c5cb71b5f63fb793458d8fdae599c8cd8884943c04f11b31b89f023"++katTests :: [TestTree]+katTests+  | length vectors == length answers = map makeTest (zip3 [1::Int ..] vectors answers) ++ [xltest,xltest']+  | otherwise = error "vectors/answers length mismatch"+  where+    makeTest (i, v, r) = testGroup ("vec"++show i) $+        [ testCase "one-pass" (r @=? runTest v)+        , 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)+        , 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)+        ] +++        [ testCase "lazy-63u"  (r @=? runTestLazyU 63 v) | B.length v > 63 ] +++        [ testCase "lazy-65u"  (r @=? runTestLazyU 65 v) | B.length v > 65 ] +++        [ testCase "lazy-97u"  (r @=? runTestLazyU 97 v) | B.length v > 97 ] +++        [ testCase "lazy-131u" (r @=? runTestLazyU 131 v) | B.length v > 131 ] +++        [ testCase "lazy-63u'"  (r @=? runTestLazyU' 63 v) | B.length v > 63 ] +++        [ testCase "lazy-65u'"  (r @=? runTestLazyU' 65 v) | B.length v > 65 ] +++        [ testCase "lazy-97u'"  (r @=? runTestLazyU' 97 v) | B.length v > 97 ] +++        [ testCase "lazy-131u'" (r @=? runTestLazyU' 131 v) | B.length v > 131 ]++    runTest :: ByteString -> ByteString+    runTest = B16.encode . IUT.hash++    runTest' :: ByteString -> ByteString+    runTest' = B16.encode . IUT.finalize . IUT.start++    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++    runTestLazy' :: Int -> ByteString -> ByteString+    runTestLazy' i = B16.encode . IUT.finalize . IUT.startlazy . BL.fromChunks . splitB i++    -- force unaligned md5-blocks+    runTestLazyU :: Int -> ByteString -> ByteString+    runTestLazyU i = B16.encode . IUT.hashlazy . BL.fromChunks . map B.copy . splitB i++    runTestLazyU' :: Int -> ByteString -> ByteString+    runTestLazyU' i = B16.encode . IUT.finalize . IUT.startlazy . BL.fromChunks . map B.copy . splitB i+++    ----++    xltest = testGroup "XL-vec"+        [ testCase "inc" (ansXLTest @=? (B16.encode . IUT.hashlazy) vecXL) ]+      where+        vecXL = BL.fromChunks (replicate 16777216 "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno")++    xltest' = testGroup "XL-vec'"+        [ testCase "inc" (ansXLTest @=? (B16.encode . IUT.finalize . IUT.startlazy) 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+++rfc4231Vectors :: [(ByteString,ByteString,ByteString)]+rfc4231Vectors = -- (secrect,msg,mac)+    [ (rep 20 0x0b, "Hi There", x"afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6")+    , ("Jefe", "what do ya want for nothing?", x"af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649")+    , (rep 20 0xaa, rep 50 0xdd, x"88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27")+    , (B.pack [1..25], rep 50 0xcd, x"3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb")+    , (rep 20 0x0c, "Test With Truncation", x"3abf34c3503b2a23a46efc619baef897f4c8e42c934ce55ccbae9740fcbc1af4ca62269e2a37cd88ba926341efe4aeea")+    , (rep 131 0xaa, "Test Using Larger Than Block-Size Key - Hash Key First", x"4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952")+    , (rep 131 0xaa, "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.", x"6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e")+    ]+  where+    x = B16.decodeLenient+    rep n c = B.replicate n c++rfc4231Tests :: [TestTree]+rfc4231Tests = zipWith makeTest [1::Int ..] rfc4231Vectors+  where+    makeTest i (key, msg, mac) = testGroup ("vec"++show i) $+        [ testCase "hmac" (hex mac  @=? hex (IUT.hmac key msg))+        , testCase "hmaclazy" (hex mac  @=? hex (IUT.hmaclazy key lazymsg))+        ]+      where+        lazymsg = BL.fromChunks . splitB 1 $ msg++    hex = B16.encode++-- 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 "start" prop_start+    , testProperty "hashlazy" prop_hashlazy+    , testProperty "startlazy" prop_startlazy+    , testProperty "hashlazyAndLength" prop_hashlazyAndLength+    , testProperty "hmac" prop_hmac+    , testProperty "hmaclazy" prop_hmaclazy+    , testProperty "hmaclazyAndLength" prop_hmaclazyAndLength+    ]+  where+    prop_hash (RandBS bs)+        = ref_hash bs == IUT.hash bs++    prop_start (RandBS bs)+        = ref_hash bs == (IUT.finalize $ IUT.start bs)++    prop_hashlazy (RandLBS bs)+        = ref_hashlazy bs == IUT.hashlazy bs++    prop_hashlazyAndLength (RandLBS bs)+        = ref_hashlazyAndLength bs == IUT.hashlazyAndLength bs++    prop_startlazy (RandLBS bs)+        = ref_hashlazy bs == (IUT.finalize $ IUT.startlazy bs)++    prop_hmac (RandBS k) (RandBS bs)+        = ref_hmac k bs == IUT.hmac k bs++    prop_hmaclazy (RandBS k) (RandLBS bs)+        = ref_hmaclazy k bs == IUT.hmaclazy k bs++    prop_hmaclazyAndLength (RandBS k) (RandLBS bs)+        = ref_hmaclazyAndLength k bs == IUT.hmaclazyAndLength k bs++    ref_hash :: ByteString -> ByteString+    ref_hash = ref_hashlazy . fromStrict++    ref_hashlazy :: BL.ByteString -> ByteString+    ref_hashlazy = toStrict . REF.bytestringDigest . REF.sha384++    ref_hashlazyAndLength :: BL.ByteString -> (ByteString,Word64)+    ref_hashlazyAndLength x = (ref_hashlazy x, fromIntegral (BL.length x))++    ref_hmac :: ByteString -> ByteString -> ByteString+    ref_hmac secret = ref_hmaclazy secret . fromStrict++    ref_hmaclazy :: ByteString -> BL.ByteString -> ByteString+    ref_hmaclazy secret = toStrict . REF.bytestringDigest . REF.hmacSha384 (fromStrict secret)++    ref_hmaclazyAndLength :: ByteString -> BL.ByteString -> (ByteString,Word64)+    ref_hmaclazyAndLength secret msg = (ref_hmaclazy secret msg, fromIntegral (BL.length msg))++    -- toStrict/fromStrict only available with bytestring-0.10 and later+    toStrict = B.concat . BL.toChunks+    fromStrict = BL.fromChunks . (:[])++main :: IO ()+main = defaultMain $ testGroup "cryptohash-sha384"+    [ testGroup "KATs" katTests+    , testGroup "RFC4231" rfc4231Tests+    , testGroup "REF" refImplTests+    ]
+ src-tests/test-sha512t.hs view
@@ -0,0 +1,237 @@+{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++import           Data.ByteString        (ByteString)+import qualified Data.ByteString        as B+import qualified Data.ByteString.Base16 as B16+import qualified Data.ByteString.Lazy   as BL++-- implementation under test+import qualified Crypto.Hash.SHA512t    as IUT++import           Test.Tasty+import           Test.Tasty.HUnit+import           Test.Tasty.QuickCheck  as QC++vectors :: Int -> [ByteString]+vectors 224 =+    [ ""+    , "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+    ]+vectors 256 = vectors 224++vectors 100 = [ "", "a" ]+vectors 128 = [ "", "a" ]+vectors 160 = [ "", "a" ]+vectors 192 = [ "", "a" ]+vectors _ = undefined++answers :: Int -> [ByteString]+answers 224 = map (B.filter (/= 0x20))+    [ "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4"+    , "944cd2847fb54558d4775db0485a50003111c8e5daa63fe722c6aa37"+    , "2b9d6565a7e40f780ba8ab7c8dcf41e3ed3b77997f4c55aa987eede5"+    , "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa"+    , "e5302d6d54bb242275d1e7622d68df6eb02dedd13f564c13dbda2174"+    , "23fec5bb94d60b23308192640b0c453335d664734fe40e7268674af9"+    , "37ab331d76f0d36de422bd0edeb22a28accd487b7a8453ae965dd287"+    ]+answers 256 = map (B.filter (/= 0x20))+    [ "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"+    , "dd9d67b371519c339ed8dbd25af90e976a1eeefd4ad3d889005e532fc5bef04d"+    , "cc8d255a7f2f38fd50388fd1f65ea7910835c5c1e73da46fba01ea50d5dd76fb"+    , "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"+    , "bde8e1f9f19bb9fd3406c90ec6bc47bd36d8ada9f11880dbc8a22a7078b6a461"+    , "3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a"+    , "9a59a052930187a97038cae692f30708aa6491923ef5194394dc68d56c74fb21"+    ]+answers 100 = map (B.filter (/= 0x20))+    [ "c00f7e9998dd8ee623557a8490"+    , "12ed51ef9eec8c369a200b6c50"+    ]+answers 128 = map (B.filter (/= 0x20))+    [ "deca5d803a5cfcbf4191e9fc4bc065e3"+    , "81dc223475633e08da618cca7053d145"+    ]+answers 160 = map (B.filter (/= 0x20))+    [ "4cc04bc7087617e98d7da7443d79fb481cf169bf"+    , "ffa50d50f314aa7f53e3a215e5789508c2342135"+    ]+answers 192 = map (B.filter (/= 0x20))+    [ "9896f27c73cdc4ecc8eca3e16f6eeb63afe04b6c0d39276c"+    , "08ce8ab4f3bbc3acc1959cd62527b63b4359a54012e167a5"+    ]+answers _ = undefined++ansXLTest :: Int -> ByteString+ansXLTest 224 = B.filter (/= 0x20) "9a7f86727c3be1403d6702617646b15589b8c5a92c70f1703cd25b52"+ansXLTest 256 = B.filter (/= 0x20) "b5855a6179802ce567cbf43888284c6ac7c3f6c48b08c5bc1e8ad75d12782c9e"+ansXLTest _   = ""++katTests :: Int -> [TestTree]+katTests t+  | length (vectors t) == length (answers t) = map makeTest (zip3 [1::Int ..] (vectors t) (answers t)) +++                                               (if B.null (ansXLTest t) then [] else [xltest,xltest'])+  | otherwise = error "vectors/answers length mismatch"+  where+    makeTest (i, v, r) = testGroup ("vec"++show i) $+        [ testCase "one-pass" (r @=? runTest v)+        , 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)+        , 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)+        ] +++        [ testCase "lazy-63u"  (r @=? runTestLazyU 63 v) | B.length v > 63 ] +++        [ testCase "lazy-65u"  (r @=? runTestLazyU 65 v) | B.length v > 65 ] +++        [ testCase "lazy-97u"  (r @=? runTestLazyU 97 v) | B.length v > 97 ] +++        [ testCase "lazy-131u" (r @=? runTestLazyU 131 v) | B.length v > 131 ] +++        [ testCase "lazy-63u'"  (r @=? runTestLazyU' 63 v) | B.length v > 63 ] +++        [ testCase "lazy-65u'"  (r @=? runTestLazyU' 65 v) | B.length v > 65 ] +++        [ testCase "lazy-97u'"  (r @=? runTestLazyU' 97 v) | B.length v > 97 ] +++        [ testCase "lazy-131u'" (r @=? runTestLazyU' 131 v) | B.length v > 131 ]++    runTest :: ByteString -> ByteString+    runTest = B16.encode . IUT.hash t++    runTest' :: ByteString -> ByteString+    runTest' = B16.encode . IUT.finalize . IUT.start t++    runTestInc :: Int -> ByteString -> ByteString+    runTestInc i = B16.encode . IUT.finalize . myfoldl' IUT.update (IUT.init t) . splitB i++    runTestLazy :: Int -> ByteString -> ByteString+    runTestLazy i = B16.encode . IUT.hashlazy t . BL.fromChunks . splitB i++    runTestLazy' :: Int -> ByteString -> ByteString+    runTestLazy' i = B16.encode . IUT.finalize . IUT.startlazy t . BL.fromChunks . splitB i++    -- force unaligned md5-blocks+    runTestLazyU :: Int -> ByteString -> ByteString+    runTestLazyU i = B16.encode . IUT.hashlazy t . BL.fromChunks . map B.copy . splitB i++    runTestLazyU' :: Int -> ByteString -> ByteString+    runTestLazyU' i = B16.encode . IUT.finalize . IUT.startlazy t . BL.fromChunks . map B.copy . splitB i+++    ----++    xltest = testGroup "XL-vec"+        [ testCase "inc" (ansXLTest t @=? (B16.encode . IUT.hashlazy t) vecXL) ]+      where+        vecXL = BL.fromChunks (replicate 16777216 "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno")++    xltest' = testGroup "XL-vec'"+        [ testCase "inc" (ansXLTest t @=? (B16.encode . IUT.finalize . IUT.startlazy t) 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+++rfc4231Vectors :: Int -> [(ByteString,ByteString,ByteString)]+rfc4231Vectors t = case t of   -- (secrect,msg,mac)+    224 -> [ (rep 20 0x0b, "Hi There", x"b244ba01307c0e7a8ccaad13b1067a4cf6b961fe0c6a20bda3d92039")+           , ("Jefe", "what do ya want for nothing?", x"4a530b31a79ebcce36916546317c45f247d83241dfb818fd37254bde")+           , (rep 20 0xaa, rep 50 0xdd, x"db34ea525c2c216ee5a6ccb6608bea870bbef12fd9b96a5109e2b6fc")+           , (B.pack [1..25], rep 50 0xcd, x"c2391863cda465c6828af06ac5d4b72d0b792109952da530e11a0d26")+           , (rep 20 0x0c, "Test With Truncation", x"1df8eae8baeedd4eddfb555ec0ba768f4b5ba29e9e3d55f08303120f")+           , (rep 131 0xaa, "Test Using Larger Than Block-Size Key - Hash Key First", x"29bef8ce88b54d4226c3c7718ea9e32ace2429026f089e38cea9aeda")+           , (rep 131 0xaa, "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.", x"82a9619b47af0cea73a8b9741355ce902d807ad87ee9078522a246e1")+           ]++    256 -> [ (rep 20 0x0b, "Hi There", x"9f9126c3d9c3c330d760425ca8a217e31feae31bfe70196ff81642b868402eab")+           , ("Jefe", "what do ya want for nothing?", x"6df7b24630d5ccb2ee335407081a87188c221489768fa2020513b2d593359456")+           , (rep 20 0xaa, rep 50 0xdd, x"229006391d66c8ecddf43ba5cf8f83530ef221a4e9401840d1bead5137c8a2ea")+           , (B.pack [1..25], rep 50 0xcd, x"36d60c8aa1d0be856e10804cf836e821e8733cbafeae87630589fd0b9b0a2f4c")+           , (rep 20 0x0c, "Test With Truncation", x"337f526924766971bf72b82ad19c2c825301791e3ae2d8bb4ec03817dd821f46")+           , (rep 131 0xaa, "Test Using Larger Than Block-Size Key - Hash Key First", x"87123c45f7c537a404f8f47cdbedda1fc9bec60eeb971982ce7ef10e774e6539")+           , (rep 131 0xaa, "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.", x"6ea83f8e7315072c0bdaa33b93a26fc1659974637a9db8a887d06c05a7f35a66")+           ]++    _ -> []+  where+    x = B16.decodeLenient+    rep n c = B.replicate n c++rfc4231Tests :: Int -> [TestTree]+rfc4231Tests t = zipWith makeTest [1::Int ..] (rfc4231Vectors t)+  where+    makeTest i (key, msg, mac) = testGroup ("vec"++show i) $+        [ testCase "hmac" (hex mac  @=? hex (IUT.hmac t key msg))+        , testCase "hmaclazy" (hex mac  @=? hex (IUT.hmaclazy t key lazymsg))+        ]+      where+        lazymsg = BL.fromChunks . splitB 1 $ msg++    hex = B16.encode++-- 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)++"}"+++main :: IO ()+main = defaultMain $ testGroup "cryptohash-sha512t"+    [ testGroup "SHA512/224"+      [ testGroup "KATs" (katTests 224)+      , testGroup "RFC4231" (rfc4231Tests 224)+      ]+    , testGroup "SHA512/256"+      [ testGroup "KATs" (katTests 256)+      , testGroup "RFC4231" (rfc4231Tests 256)+      ]+    , testGroup "SHA512/100" [ testGroup "KATs" (katTests 100) ]+    , testGroup "SHA512/128" [ testGroup "KATs" (katTests 128) ]+    , testGroup "SHA512/160" [ testGroup "KATs" (katTests 160) ]+    , testGroup "SHA512/192" [ testGroup "KATs" (katTests 192) ]+    ]
+ src/Crypto/Hash/SHA384.hs view
@@ -0,0 +1,292 @@+{-# LANGUAGE Trustworthy #-}+-- |+-- Module      : Crypto.Hash.SHA384+-- 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-384> bindings+--+-- @since 0.11.102.0+module Crypto.Hash.SHA384+    (++    -- * 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.SHA384 as SHA384+    -- >+    -- > main = print digest+    -- >   where+    -- >     digest = SHA384.finalize ctx+    -- >     ctx    = foldl SHA384.update ctx0 (map Data.ByteString.pack [ [1,2,3], [4,5,6] ])+    -- >     ctx0   = SHA384.init++      Ctx(..)+    , init     -- :: Ctx+    , update   -- :: Ctx -> ByteString -> Ctx+    , updates  -- :: Ctx -> [ByteString] -> Ctx+    , finalize -- :: Ctx -> ByteString+    , finalizeAndLength -- :: Ctx -> (ByteString,Word64)+    , start    -- :: ByteString -> Ct+    , startlazy -- :: L.ByteString -> Ctx+++    -- * 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.SHA384 as SHA384+    -- >+    -- > main = print $ SHA384.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 -- :: L.ByteString -> ByteString+    , hashlazyAndLength -- :: L.ByteString -> (ByteString,Word64)++    -- ** HMAC-SHA-384+    --+    -- | <https://tools.ietf.org/html/rfc2104 RFC2104>-compatible+    -- <https://en.wikipedia.org/wiki/HMAC HMAC>-SHA-384 digests++    , hmac     -- :: ByteString -> ByteString -> ByteString+    , hmaclazy -- :: ByteString -> L.ByteString -> ByteString+    , hmaclazyAndLength -- :: ByteString -> L.ByteString -> (ByteString,Word64)+    ) 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, mallocByteString)+import Data.Bits (xor)+import Data.Word+import System.IO.Unsafe (unsafeDupablePerformIO)++import Compat (constructBS)+import Crypto.Hash.SHA512.FFI++-- | 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++-- keep this synchronised with cbits/sha512.h+{-# INLINE digestSize #-}+digestSize :: Int+digestSize = 48++{-# INLINE sizeCtx #-}+sizeCtx :: Int+sizeCtx = 208++{-# 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 create' #-}+-- | Variant of 'create' which allows to return an argument+create' :: Int -> (Ptr Word8 -> IO a) -> IO (ByteString,a)+create' l f = do+    fp <- mallocByteString l+    x <- withForeignPtr fp $ \p -> f p+    let bs = constructBS fp l+    return $! x `seq` bs `seq` (bs,x)++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)++-- 'safe' call overhead neglible for 4KiB and more+c_sha512_update :: Ptr Ctx -> Ptr Word8 -> CSize -> IO ()+c_sha512_update pctx pbuf sz+  | sz < 4096 = c_sha512_update_unsafe pctx pbuf sz+  | otherwise = c_sha512_update_safe   pctx pbuf sz++-- 'safe' call overhead neglible for 4KiB and more+c_sha384_hash :: Ptr Word8 -> CSize -> Ptr Word8 -> IO ()+c_sha384_hash pbuf sz pout+  | sz < 4096 = c_sha384_hash_unsafe pbuf sz pout+  | otherwise = c_sha384_hash_safe   pbuf sz pout++updateInternalIO :: Ptr Ctx -> ByteString -> IO ()+updateInternalIO ptr d =+    unsafeUseAsCStringLen d (\(cs, len) -> c_sha512_update ptr (castPtr cs) (fromIntegral len))++finalizeInternalIO :: Ptr Ctx -> IO ByteString+finalizeInternalIO ptr = create digestSize (c_sha512t_finalize ptr 384)++finalizeInternalIO' :: Ptr Ctx -> IO (ByteString,Word64)+finalizeInternalIO' ptr = create' digestSize (c_sha512t_finalize_len ptr 384)++{-# NOINLINE init #-}+-- | create a new hash context+init :: Ctx+init = unsafeDoIO $ withCtxNew $ c_sha384_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 "SHA384.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 "SHA384.updates: invalid Ctx"++{-# NOINLINE finalize #-}+-- | finalize the context into a digest bytestring (48 bytes)+finalize :: Ctx -> ByteString+finalize ctx+  | validCtx ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO+  | otherwise    = error "SHA384.finalize: invalid Ctx"++{-# NOINLINE finalizeAndLength #-}+-- | Variant of 'finalize' also returning length of hashed content+finalizeAndLength :: Ctx -> (ByteString,Word64)+finalizeAndLength ctx+  | validCtx ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO'+  | otherwise    = error "SHA384.finalize: invalid Ctx"++{-# NOINLINE hash #-}+-- | hash a strict bytestring into a digest bytestring (48 bytes)+hash :: ByteString -> ByteString+-- hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do c_sha384_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr+hash d = unsafeDoIO $ unsafeUseAsCStringLen d $ \(cs, len) -> create digestSize (c_sha384_hash (castPtr cs) (fromIntegral len))++{-# NOINLINE start #-}+-- | hash a strict bytestring into a Ctx+start :: ByteString -> Ctx+start d = unsafeDoIO $ withCtxNew $ \ptr -> do+    c_sha384_init ptr >> updateInternalIO ptr d++{-# NOINLINE hashlazy #-}+-- | hash a lazy bytestring into a digest bytestring (48 bytes)+hashlazy :: L.ByteString -> ByteString+hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do+    c_sha384_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO ptr++{-# NOINLINE hashlazyAndLength #-}+-- | Variant of 'hashlazy' which simultaneously computes the hash and length of a lazy bytestring.+hashlazyAndLength :: L.ByteString -> (ByteString,Word64)+hashlazyAndLength l = unsafeDoIO $ withCtxNewThrow $ \ptr ->+    c_sha384_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO' ptr++{-# NOINLINE startlazy #-}+-- | hash a lazy bytestring into a Ctx+startlazy :: L.ByteString -> Ctx+startlazy l = unsafeDoIO $ withCtxNew $ \ptr -> do+    c_sha384_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l)++{-# NOINLINE hmac #-}+-- | Compute 48-byte <https://tools.ietf.org/html/rfc2104 RFC2104>-compatible+-- HMAC-SHA-384 digest for a strict bytestring message+hmac :: ByteString -- ^ secret+     -> ByteString -- ^ message+     -> ByteString+hmac secret msg = hash $ B.append opad (hash $ B.append ipad msg)+  where+    opad = B.map (xor 0x5c) k'+    ipad = B.map (xor 0x36) k'++    k'  = B.append kt pad+    kt  = if B.length secret > 128 then hash secret else secret+    pad = B.replicate (128 - B.length kt) 0+++{-# NOINLINE hmaclazy #-}+-- | Compute 48-byte <https://tools.ietf.org/html/rfc2104 RFC2104>-compatible+-- HMAC-SHA-384 digest for a lazy bytestring message+hmaclazy :: ByteString   -- ^ secret+         -> L.ByteString -- ^ message+         -> ByteString+hmaclazy secret msg = hash $ B.append opad (hashlazy $ L.append ipad msg)+  where+    opad = B.map (xor 0x5c) k'+    ipad = L.fromChunks [B.map (xor 0x36) k']++    k'  = B.append kt pad+    kt  = if B.length secret > 128 then hash secret else secret+    pad = B.replicate (128 - B.length kt) 0++-- | Variant of 'hmaclazy' which also returns length of message+hmaclazyAndLength :: ByteString   -- ^ secret+                  -> L.ByteString -- ^ message+                  -> (ByteString,Word64) -- ^ digest (48 bytes) and length of message+hmaclazyAndLength secret msg =+    (hash (B.append opad htmp), sz' - fromIntegral ipadLen)+  where+    (htmp, sz') = hashlazyAndLength (L.append ipad msg)++    opad = B.map (xor 0x5c) k'+    ipad = L.fromChunks [B.map (xor 0x36) k']+    ipadLen = B.length k'++    k'  = B.append kt pad+    kt  = if B.length secret > 128 then hash secret else secret+    pad = B.replicate (128 - B.length kt) 0
src/Crypto/Hash/SHA512.hs view
@@ -171,10 +171,10 @@     unsafeUseAsCStringLen d (\(cs, len) -> c_sha512_update ptr (castPtr cs) (fromIntegral len))  finalizeInternalIO :: Ptr Ctx -> IO ByteString-finalizeInternalIO ptr = create digestSize (c_sha512_finalize ptr)+finalizeInternalIO ptr = create digestSize (c_sha512t_finalize ptr 512)  finalizeInternalIO' :: Ptr Ctx -> IO (ByteString,Word64)-finalizeInternalIO' ptr = create' digestSize (c_sha512_finalize_len ptr)+finalizeInternalIO' ptr = create' digestSize (c_sha512t_finalize_len ptr 512)  {-# NOINLINE init #-} -- | create a new hash context@@ -212,7 +212,7 @@ finalizeAndLength :: Ctx -> (ByteString,Word64) finalizeAndLength ctx   | validCtx ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO'-  | otherwise    = error "SHA256.finalize: invalid Ctx"+  | otherwise    = error "SHA512.finalize: invalid Ctx"  {-# NOINLINE hash #-} -- | hash a strict bytestring into a digest bytestring (64 bytes)
src/Crypto/Hash/SHA512/FFI.hs view
@@ -35,27 +35,47 @@ -- --  * a 8-element 'Word64' array holding the current work-in-progress digest-value. ----- Consequently, a SHA-512 digest as produced by 'hash', 'hashlazy', or 'finalize' is 64 bytes long. newtype Ctx = Ctx ByteString   deriving (Eq) -foreign import capi unsafe "sha512.h hs_cryptohash_sha512_init"+foreign import capi unsafe "hs_sha512.h hs_cryptohash_sha384_init"+    c_sha384_init :: Ptr Ctx -> IO ()++foreign import capi unsafe "hs_sha512.h hs_cryptohash_sha512_init"     c_sha512_init :: Ptr Ctx -> IO () -foreign import capi unsafe "sha512.h hs_cryptohash_sha512_update"+foreign import capi unsafe "hs_sha512.h hs_cryptohash_sha512t_init"+    c_sha512t_init :: Ptr Ctx -> Word16 -> IO ()+++foreign import capi unsafe "hs_sha512.h hs_cryptohash_sha512_update"     c_sha512_update_unsafe :: Ptr Ctx -> Ptr Word8 -> CSize -> IO () -foreign import capi safe "sha512.h hs_cryptohash_sha512_update"+foreign import capi safe "hs_sha512.h hs_cryptohash_sha512_update"     c_sha512_update_safe :: Ptr Ctx -> Ptr Word8 -> CSize -> IO () -foreign import capi unsafe "sha512.h hs_cryptohash_sha512_finalize"-    c_sha512_finalize :: Ptr Ctx -> Ptr Word8 -> IO () -foreign import capi unsafe "sha512.h hs_cryptohash_sha512_finalize"-    c_sha512_finalize_len :: Ptr Ctx -> Ptr Word8 -> IO Word64+foreign import capi unsafe "hs_sha512.h hs_cryptohash_sha512t_finalize"+    c_sha512t_finalize :: Ptr Ctx -> Word16 -> Ptr Word8 -> IO () -foreign import capi unsafe "sha512.h hs_cryptohash_sha512_hash"+foreign import capi unsafe "hs_sha512.h hs_cryptohash_sha512t_finalize"+    c_sha512t_finalize_len :: Ptr Ctx -> Word16 -> Ptr Word8 -> IO Word64+++foreign import capi unsafe "hs_sha512.h hs_cryptohash_sha384_hash"+    c_sha384_hash_unsafe :: Ptr Word8 -> CSize -> Ptr Word8 -> IO ()++foreign import capi safe "hs_sha512.h hs_cryptohash_sha384_hash"+    c_sha384_hash_safe :: Ptr Word8 -> CSize -> Ptr Word8 -> IO ()++foreign import capi unsafe "hs_sha512.h hs_cryptohash_sha512_hash"     c_sha512_hash_unsafe :: Ptr Word8 -> CSize -> Ptr Word8 -> IO () -foreign import capi safe "sha512.h hs_cryptohash_sha512_hash"+foreign import capi safe "hs_sha512.h hs_cryptohash_sha512_hash"     c_sha512_hash_safe :: Ptr Word8 -> CSize -> Ptr Word8 -> IO ()++foreign import capi unsafe "hs_sha512.h hs_cryptohash_sha512t_hash"+    c_sha512t_hash_unsafe :: Ptr Word8 -> CSize -> Ptr Word8 -> Word16 -> IO ()++foreign import capi safe "hs_sha512.h hs_cryptohash_sha512t_hash"+    c_sha512t_hash_safe :: Ptr Word8 -> CSize -> Ptr Word8 -> Word16 -> IO ()
+ src/Crypto/Hash/SHA512t.hs view
@@ -0,0 +1,328 @@+{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE BangPatterns #-}+-- |+-- Module      : Crypto.Hash.SHA512t+-- 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-512/t> bindings+--+-- @since 0.11.102.0+module Crypto.Hash.SHA512t+    (++    -- * 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.SHA512t as SHA512t+    -- >+    -- > main = print digest+    -- >   where+    -- >     digest = SHA512t.finalize ctx+    -- >     ctx    = foldl SHA512t.update ctx0 (map Data.ByteString.pack [ [1,2,3], [4,5,6] ])+    -- >     ctx0   = SHA512t.init 224++      Ctx(..)+    , init     -- :: Int -> Ctx+    , update   -- :: Ctx -> ByteString -> Ctx+    , updates  -- :: Ctx -> [ByteString] -> Ctx+    , finalize -- :: Ctx -> ByteString+    , finalizeAndLength -- :: Ctx -> (ByteString,Word64)+    , start    -- :: Int -> ByteString -> Ctx+    , startlazy -- :: Int -> L.ByteString -> Ctx+++    -- * 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.SHA512t as SHA512t+    -- >+    -- > main = print $ SHA512t.hash 224 (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     -- :: Int -> ByteString -> ByteString+    , hashlazy -- :: Int -> L.ByteString -> ByteString+    , hashlazyAndLength -- :: Int -> L.ByteString -> (ByteString,Word64)++    -- ** HMAC-SHA-512/t+    --+    -- | <https://tools.ietf.org/html/rfc2104 RFC2104>-compatible+    -- <https://en.wikipedia.org/wiki/HMAC HMAC>-SHA-512/t digests++    , hmac     -- :: Int -> ByteString -> ByteString -> ByteString+    , hmaclazy -- :: Int -> ByteString -> L.ByteString -> ByteString+    , hmaclazyAndLength -- :: Int -> ByteString -> L.ByteString -> (ByteString,Word64)+    ) 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, mallocByteString)+import Data.Bits (xor)+import Data.Word+import System.IO.Unsafe (unsafeDupablePerformIO)++import Compat (constructBS)+import Crypto.Hash.SHA512.FFI hiding (Ctx(..))+import qualified Crypto.Hash.SHA512.FFI as FFI (Ctx(..))++-- | SHA-512/t Context+--+-- This extends the non-truncated SHA-512 Context (see 'FFI.Ctx')+-- with the value of the /t/ parameter which must be within the+-- range @[1..511]@ excluding the value @384@ as per FIPS-180-4+-- section 5.3.6.+data Ctx = Ctx !Int !FFI.Ctx+  deriving (Eq)++-- | 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++{-# INLINE digestSize #-}+digestSize :: Int -> Int+digestSize t = (t+7) `div` 8++{-# INLINE sizeCtx #-}+sizeCtx :: Int+sizeCtx = 208++{-# 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 create' #-}+-- | Variant of 'create' which allows to return an argument+create' :: Int -> (Ptr Word8 -> IO a) -> IO (ByteString,a)+create' l f = do+    fp <- mallocByteString l+    x <- withForeignPtr fp $ \p -> f p+    let bs = constructBS fp l+    return $! x `seq` bs `seq` (bs,x)++copyCtx :: Ptr FFI.Ctx -> Ptr FFI.Ctx -> IO ()+copyCtx dst src = memcpy (castPtr dst) (castPtr src) (fromIntegral sizeCtx)++withCtxCopy :: Ctx -> (Ptr FFI.Ctx -> IO ()) -> IO Ctx+withCtxCopy (Ctx tbits (FFI.Ctx ctxB)) f = (Ctx tbits . FFI.Ctx) `fmap` createCtx+  where+    createCtx = create sizeCtx $ \dstPtr ->+                withByteStringPtr ctxB $ \srcPtr -> do+                    copyCtx (castPtr dstPtr) (castPtr srcPtr)+                    f (castPtr dstPtr)++withCtxThrow :: Ctx -> (Ptr FFI.Ctx -> IO a) -> IO a+withCtxThrow (Ctx _ (FFI.Ctx ctxB)) f =+    allocaBytes sizeCtx $ \dstPtr ->+    withByteStringPtr ctxB $ \srcPtr -> do+        copyCtx (castPtr dstPtr) (castPtr srcPtr)+        f (castPtr dstPtr)++withCtxNew :: Int -> (Ptr FFI.Ctx -> IO ()) -> IO Ctx+withCtxNew t f = (Ctx t . FFI.Ctx) `fmap` create sizeCtx (f . castPtr)++withCtxNewThrow :: (Ptr FFI.Ctx -> IO a) -> IO a+withCtxNewThrow f = allocaBytes sizeCtx (f . castPtr)++-- 'safe' call overhead neglible for 4KiB and more+c_sha512_update :: Ptr FFI.Ctx -> Ptr Word8 -> CSize -> IO ()+c_sha512_update pctx pbuf sz+  | sz < 4096 = c_sha512_update_unsafe pctx pbuf sz+  | otherwise = c_sha512_update_safe   pctx pbuf sz++-- 'safe' call overhead neglible for 4KiB and more+c_sha512t_hash :: Word16 -> Ptr Word8 -> CSize -> Ptr Word8 -> IO ()+c_sha512t_hash t pbuf sz pout+  | sz < 4096 = c_sha512t_hash_unsafe pbuf sz pout t+  | otherwise = c_sha512t_hash_safe   pbuf sz pout t++updateInternalIO :: Ptr FFI.Ctx -> ByteString -> IO ()+updateInternalIO ptr d =+    unsafeUseAsCStringLen d (\(cs, len) -> c_sha512_update ptr (castPtr cs) (fromIntegral len))++finalizeInternalIO :: Int -> Ptr FFI.Ctx -> IO ByteString+finalizeInternalIO t ptr = create (digestSize t) (c_sha512t_finalize ptr (fromIntegral t))++finalizeInternalIO' :: Int -> Ptr FFI.Ctx -> IO (ByteString,Word64)+finalizeInternalIO' t ptr = create' (digestSize t) (c_sha512t_finalize_len ptr (fromIntegral t))++{-# NOINLINE init #-}+-- | create a new hash context+init :: Int -> Ctx+init 224 = unsafeDoIO $ withCtxNew 224 $ flip c_sha512t_init 224+init 256 = unsafeDoIO $ withCtxNew 256 $ flip c_sha512t_init 256+init t   = unsafeDoIO $ withCtxNew t $ flip c_sha512t_init t'+  where+    !t' = tFromInt t -- will 'error' for invalid values++tFromInt :: Int -> Word16+tFromInt t+  | isValidT t = fromIntegral t+  | otherwise  = error ("invalid SHA512/t (with t=" ++ show t ++ ") requested")++-- see FIPS 180-4 section 5.3.6.+isValidT :: Int -> Bool+isValidT t = t > 0 && t < 512 && t /= 384++validCtx :: Ctx -> Bool+validCtx (Ctx t (FFI.Ctx b)) = isValidT t && 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 "SHA512t.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 "SHA512t.updates: invalid Ctx"++{-# NOINLINE finalize #-}+-- | finalize the context into a digest bytestring (/t/ bits)+finalize :: Ctx -> ByteString+finalize ctx@(Ctx t _)+  | validCtx ctx = unsafeDoIO $ withCtxThrow ctx (finalizeInternalIO t)+  | otherwise    = error "SHA512t.finalize: invalid Ctx"++{-# NOINLINE finalizeAndLength #-}+-- | Variant of 'finalize' also returning length of hashed content+finalizeAndLength :: Ctx -> (ByteString,Word64)+finalizeAndLength ctx@(Ctx t _)+  | validCtx ctx = unsafeDoIO $ withCtxThrow ctx (finalizeInternalIO' t)+  | otherwise    = error "SHA512t.finalize: invalid Ctx"++{-# NOINLINE hash #-}+-- | hash a strict bytestring into a digest bytestring (/t/ bits)+hash :: Int -> ByteString -> ByteString+hash t d = unsafeDoIO $ unsafeUseAsCStringLen d $ \(cs, len) ->+    create (digestSize t) (c_sha512t_hash t' (castPtr cs) (fromIntegral len))+  where+    !t' = tFromInt t++{-# NOINLINE start #-}+-- | hash a strict bytestring into a Ctx+start :: Int -> ByteString -> Ctx+start t d = unsafeDoIO $ withCtxNew t $ \ptr -> do+    c_sha512t_init ptr t' >> updateInternalIO ptr d+  where+    !t' = tFromInt t++{-# NOINLINE hashlazy #-}+-- | hash a lazy bytestring into a digest bytestring (/t/ bits)+hashlazy :: Int -> L.ByteString -> ByteString+hashlazy t l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do+    c_sha512t_init ptr t' >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO t ptr+  where+    !t' = tFromInt t++{-# NOINLINE hashlazyAndLength #-}+-- | Variant of 'hashlazy' which simultaneously computes the hash and length of a lazy bytestring.+hashlazyAndLength :: Int -> L.ByteString -> (ByteString,Word64)+hashlazyAndLength t l = unsafeDoIO $ withCtxNewThrow $ \ptr ->+    c_sha512t_init ptr t' >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> finalizeInternalIO' t ptr+  where+    !t' = tFromInt t++{-# NOINLINE startlazy #-}+-- | hash a lazy bytestring into a Ctx+startlazy :: Int -> L.ByteString -> Ctx+startlazy t l = unsafeDoIO $ withCtxNew t $ \ptr -> do+    c_sha512t_init ptr t' >> mapM_ (updateInternalIO ptr) (L.toChunks l)+  where+    t' = tFromInt t++{-# NOINLINE hmac #-}+-- | Compute /t/-bit <https://tools.ietf.org/html/rfc2104 RFC2104>-compatible+-- HMAC-SHA-512/t digest for a strict bytestring message+hmac :: Int        -- ^ digest length /t/ in bits+     -> ByteString -- ^ secret+     -> ByteString -- ^ message+     -> ByteString+hmac t secret msg = hash t $ B.append opad (hash t $ B.append ipad msg)+  where+    opad = B.map (xor 0x5c) k'+    ipad = B.map (xor 0x36) k'++    k'  = B.append kt pad+    kt  = if B.length secret > 128 then hash t secret else secret+    pad = B.replicate (128 - B.length kt) 0+++{-# NOINLINE hmaclazy #-}+-- | Compute4 /t/-bit <https://tools.ietf.org/html/rfc2104 RFC2104>-compatible+-- HMAC-SHA-512/t digest for a lazy bytestring message+hmaclazy :: Int          -- ^ digest length /t/ in bits+         -> ByteString   -- ^ secret+         -> L.ByteString -- ^ message+         -> ByteString+hmaclazy t secret msg = hash t $ B.append opad (hashlazy t $ L.append ipad msg)+  where+    opad = B.map (xor 0x5c) k'+    ipad = L.fromChunks [B.map (xor 0x36) k']++    k'  = B.append kt pad+    kt  = if B.length secret > 128 then hash t secret else secret+    pad = B.replicate (128 - B.length kt) 0++-- | Variant of 'hmaclazy' which also returns length of message+hmaclazyAndLength :: Int          -- ^ digest length /t/ in bits+                  -> ByteString   -- ^ secret+                  -> L.ByteString -- ^ message+                  -> (ByteString,Word64) -- ^ digest (/t/ bits) and length of message+hmaclazyAndLength t secret msg =+    (hash t (B.append opad htmp), sz' - fromIntegral ipadLen)+  where+    (htmp, sz') = hashlazyAndLength t (L.append ipad msg)++    opad = B.map (xor 0x5c) k'+    ipad = L.fromChunks [B.map (xor 0x36) k']+    ipadLen = B.length k'++    k'  = B.append kt pad+    kt  = if B.length secret > 128 then hash t secret else secret+    pad = B.replicate (128 - B.length kt) 0