Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package ghc-cryptohash-md5 for 
openSUSE:Factory checked in at 2021-11-11 21:36:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-cryptohash-md5 (Old)
 and      /work/SRC/openSUSE:Factory/.ghc-cryptohash-md5.new.1890 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ghc-cryptohash-md5"

Thu Nov 11 21:36:23 2021 rev:6 rq:930321 version:0.11.101.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-cryptohash-md5/ghc-cryptohash-md5.changes    
2021-06-23 17:38:24.576486144 +0200
+++ 
/work/SRC/openSUSE:Factory/.ghc-cryptohash-md5.new.1890/ghc-cryptohash-md5.changes
  2021-11-11 21:36:36.960897141 +0100
@@ -1,0 +2,19 @@
+Mon Nov  1 08:22:10 UTC 2021 - [email protected]
+
+- Update cryptohash-md5 to version 0.11.101.0.
+  ## 0.11.101.0
+
+   - Add `Eq` instance for `Ctx`
+   - Add `start` and `startlazy` producing `Ctx`
+   - Remove ineffective RULES
+   - Declare `Crypto.Hash.MD5` module `-XTrustworthy`
+   - Convert to `CApiFFI`
+   - Added `...AndLength` variants of hashing functions:
+
+        - `finalizeAndLength`
+        - `hashlazyAndLength`
+        - `hmaclazyAndLength`
+
+   - Minor optimizations in `hmac` and `hash`
+
+-------------------------------------------------------------------

Old:
----
  cryptohash-md5-0.11.100.1.tar.gz
  cryptohash-md5.cabal

New:
----
  cryptohash-md5-0.11.101.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ghc-cryptohash-md5.spec ++++++
--- /var/tmp/diff_new_pack.qOaKqf/_old  2021-11-11 21:36:37.460897506 +0100
+++ /var/tmp/diff_new_pack.qOaKqf/_new  2021-11-11 21:36:37.464897509 +0100
@@ -19,13 +19,12 @@
 %global pkg_name cryptohash-md5
 %bcond_with tests
 Name:           ghc-%{pkg_name}
-Version:        0.11.100.1
+Version:        0.11.101.0
 Release:        0
 Summary:        Fast, pure and practical MD5 implementation
 License:        BSD-3-Clause
 URL:            https://hackage.haskell.org/package/%{pkg_name}
 Source0:        
https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{version}.tar.gz
-Source1:        
https://hackage.haskell.org/package/%{pkg_name}-%{version}/revision/6.cabal#/%{pkg_name}.cabal
 BuildRequires:  ghc-Cabal-devel
 BuildRequires:  ghc-bytestring-devel
 BuildRequires:  ghc-rpm-macros
@@ -47,31 +46,14 @@
 The implementation is made in C with a haskell FFI wrapper that hides the C
 implementation.
 
-If, instead, you require a pure Haskell implementation and performance is
-secondary, please refer to the [pureMD5
-package](https://hackage.haskell.org/package/pureMD5).
-
-=== 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
+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 MD5 hash algorithm
 without any dependencies on packages other than 'base' and 'bytestring'.
-The API exposed by 'cryptohash-md5-0.11.*''s "Crypto.Hash.MD5" 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
-'cryptohash-0.11.7''s "Crypto.Hash.MD5" module, 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/).
+
+Consequently, this package can be used as a drop-in replacement for
+'cryptohash''s "Crypto.Hash.MD5" module, though with a clearly smaller
+footprint.
 
 %package devel
 Summary:        Haskell %{pkg_name} library development files
@@ -85,7 +67,6 @@
 
 %prep
 %autosetup -n %{pkg_name}-%{version}
-cp -p %{SOURCE1} %{pkg_name}.cabal
 
 %build
 %ghc_lib_build

++++++ cryptohash-md5-0.11.100.1.tar.gz -> cryptohash-md5-0.11.101.0.tar.gz 
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cryptohash-md5-0.11.100.1/cbits/md5.c 
new/cryptohash-md5-0.11.101.0/cbits/md5.c
--- old/cryptohash-md5-0.11.100.1/cbits/md5.c   2016-06-28 09:14:08.000000000 
+0200
+++ new/cryptohash-md5-0.11.101.0/cbits/md5.c   1970-01-01 01:00:00.000000000 
+0100
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2006-2009 Vincent Hanquez <[email protected]>
- *               2016      Herbert Valerio Riedel <[email protected]>
- *
- * 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.
- */
-
-#include "md5.h"
-
-#include <assert.h>
-#include <string.h>
-#include <ghcautoconf.h>
-
-#if defined(static_assert)
-static_assert(sizeof(struct md5_ctx) == MD5_CTX_SIZE, "unexpected md5_ctx 
size");
-#else
-/* poor man's pre-C11 _Static_assert */
-typedef char static_assertion__unexpected_md5_ctx_size[(sizeof(struct md5_ctx) 
== MD5_CTX_SIZE)?1:-1];
-#endif
-
-#define ptr_uint32_aligned(ptr) (!((uintptr_t)(ptr) & 0x3))
-
-static inline uint32_t
-rol32(const uint32_t word, const unsigned shift)
-{
-  /* GCC usually transforms this into a 'rol'-insn */
-  return (word << shift) | (word >> (32 - shift));
-}
-
-static inline uint32_t
-cpu_to_le32(const uint32_t hl)
-{
-#if !WORDS_BIGENDIAN
-  return hl;
-#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
-  return __builtin_bswap32(hl);
-#else
-  /* GCC usually transforms this into a bswap insn */
-  return ((hl & 0xff000000) >> 24) |
-         ((hl & 0x00ff0000) >> 8)  |
-         ((hl & 0x0000ff00) << 8)  |
-         ( hl               << 24);
-#endif
-}
-
-static inline void
-cpu_to_le32_array(uint32_t *dest, const uint32_t *src, unsigned wordcnt)
-{
-  while (wordcnt--)
-    *dest++ = cpu_to_le32(*src++);
-}
-
-static inline uint64_t
-cpu_to_le64(const uint64_t hll)
-{
-#if !WORDS_BIGENDIAN
-  return hll;
-#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
-  return __builtin_bswap64(hll);
-#else
-  return ((uint64_t)cpu_to_le32(hll & 0xffffffff) << 32LL) | cpu_to_le32(hll 
>> 32);
-#endif
-}
-
-
-void
-hs_cryptohash_md5_init(struct md5_ctx *ctx)
-{
-  memset(ctx, 0, sizeof(*ctx));
-
-  ctx->h[0] = 0x67452301;
-  ctx->h[1] = 0xefcdab89;
-  ctx->h[2] = 0x98badcfe;
-  ctx->h[3] = 0x10325476;
-}
-
-#define f1(x, y, z)     (z ^ (x & (y ^ z)))
-#define f2(x, y, z)     f1(z, x, y)
-#define f3(x, y, z)     (x ^ y ^ z)
-#define f4(x, y, z)     (y ^ (x | ~z))
-#define R(f, a, b, c, d, i, k, s) a += f(b, c, d) + w[i] + k; a = rol32(a, s); 
a += b
-
-static void
-md5_do_chunk_aligned(struct md5_ctx *ctx, const uint32_t w[])
-{
-  uint32_t a = ctx->h[0];
-  uint32_t b = ctx->h[1];
-  uint32_t c = ctx->h[2];
-  uint32_t d = ctx->h[3];
-
-  R(f1, a, b, c, d,  0, 0xd76aa478,  7);
-  R(f1, d, a, b, c,  1, 0xe8c7b756, 12);
-  R(f1, c, d, a, b,  2, 0x242070db, 17);
-  R(f1, b, c, d, a,  3, 0xc1bdceee, 22);
-  R(f1, a, b, c, d,  4, 0xf57c0faf,  7);
-  R(f1, d, a, b, c,  5, 0x4787c62a, 12);
-  R(f1, c, d, a, b,  6, 0xa8304613, 17);
-  R(f1, b, c, d, a,  7, 0xfd469501, 22);
-  R(f1, a, b, c, d,  8, 0x698098d8,  7);
-  R(f1, d, a, b, c,  9, 0x8b44f7af, 12);
-  R(f1, c, d, a, b, 10, 0xffff5bb1, 17);
-  R(f1, b, c, d, a, 11, 0x895cd7be, 22);
-  R(f1, a, b, c, d, 12, 0x6b901122,  7);
-  R(f1, d, a, b, c, 13, 0xfd987193, 12);
-  R(f1, c, d, a, b, 14, 0xa679438e, 17);
-  R(f1, b, c, d, a, 15, 0x49b40821, 22);
-
-  R(f2, a, b, c, d,  1, 0xf61e2562,  5);
-  R(f2, d, a, b, c,  6, 0xc040b340,  9);
-  R(f2, c, d, a, b, 11, 0x265e5a51, 14);
-  R(f2, b, c, d, a,  0, 0xe9b6c7aa, 20);
-  R(f2, a, b, c, d,  5, 0xd62f105d,  5);
-  R(f2, d, a, b, c, 10, 0x02441453,  9);
-  R(f2, c, d, a, b, 15, 0xd8a1e681, 14);
-  R(f2, b, c, d, a,  4, 0xe7d3fbc8, 20);
-  R(f2, a, b, c, d,  9, 0x21e1cde6,  5);
-  R(f2, d, a, b, c, 14, 0xc33707d6,  9);
-  R(f2, c, d, a, b,  3, 0xf4d50d87, 14);
-  R(f2, b, c, d, a,  8, 0x455a14ed, 20);
-  R(f2, a, b, c, d, 13, 0xa9e3e905,  5);
-  R(f2, d, a, b, c,  2, 0xfcefa3f8,  9);
-  R(f2, c, d, a, b,  7, 0x676f02d9, 14);
-  R(f2, b, c, d, a, 12, 0x8d2a4c8a, 20);
-
-  R(f3, a, b, c, d,  5, 0xfffa3942,  4);
-  R(f3, d, a, b, c,  8, 0x8771f681, 11);
-  R(f3, c, d, a, b, 11, 0x6d9d6122, 16);
-  R(f3, b, c, d, a, 14, 0xfde5380c, 23);
-  R(f3, a, b, c, d,  1, 0xa4beea44,  4);
-  R(f3, d, a, b, c,  4, 0x4bdecfa9, 11);
-  R(f3, c, d, a, b,  7, 0xf6bb4b60, 16);
-  R(f3, b, c, d, a, 10, 0xbebfbc70, 23);
-  R(f3, a, b, c, d, 13, 0x289b7ec6,  4);
-  R(f3, d, a, b, c,  0, 0xeaa127fa, 11);
-  R(f3, c, d, a, b,  3, 0xd4ef3085, 16);
-  R(f3, b, c, d, a,  6, 0x04881d05, 23);
-  R(f3, a, b, c, d,  9, 0xd9d4d039,  4);
-  R(f3, d, a, b, c, 12, 0xe6db99e5, 11);
-  R(f3, c, d, a, b, 15, 0x1fa27cf8, 16);
-  R(f3, b, c, d, a,  2, 0xc4ac5665, 23);
-
-  R(f4, a, b, c, d,  0, 0xf4292244,  6);
-  R(f4, d, a, b, c,  7, 0x432aff97, 10);
-  R(f4, c, d, a, b, 14, 0xab9423a7, 15);
-  R(f4, b, c, d, a,  5, 0xfc93a039, 21);
-  R(f4, a, b, c, d, 12, 0x655b59c3,  6);
-  R(f4, d, a, b, c,  3, 0x8f0ccc92, 10);
-  R(f4, c, d, a, b, 10, 0xffeff47d, 15);
-  R(f4, b, c, d, a,  1, 0x85845dd1, 21);
-  R(f4, a, b, c, d,  8, 0x6fa87e4f,  6);
-  R(f4, d, a, b, c, 15, 0xfe2ce6e0, 10);
-  R(f4, c, d, a, b,  6, 0xa3014314, 15);
-  R(f4, b, c, d, a, 13, 0x4e0811a1, 21);
-  R(f4, a, b, c, d,  4, 0xf7537e82,  6);
-  R(f4, d, a, b, c, 11, 0xbd3af235, 10);
-  R(f4, c, d, a, b,  2, 0x2ad7d2bb, 15);
-  R(f4, b, c, d, a,  9, 0xeb86d391, 21);
-
-  ctx->h[0] += a;
-  ctx->h[1] += b;
-  ctx->h[2] += c;
-  ctx->h[3] += d;
-}
-
-static void
-md5_do_chunk(struct md5_ctx *ctx, const uint8_t buf[])
-{
-  if (ptr_uint32_aligned(buf)) { /* aligned buf */
-#if WORDS_BIGENDIAN
-    uint32_t w[16]; cpu_to_le32_array(w, (const uint32_t *)buf, 16);
-#else
-    const uint32_t *w = (const uint32_t *)buf;
-#endif
-    md5_do_chunk_aligned(ctx, w);
-  } else { /* unaligned buf */
-    uint32_t w[16]; memcpy(w, buf, 64);
-#if WORDS_BIGENDIAN
-    cpu_to_le32_array(w, w, 16);
-#endif
-    md5_do_chunk_aligned(ctx, w);
-  }
-}
-
-void
-hs_cryptohash_md5_update(struct md5_ctx *ctx, const uint8_t *data, size_t len)
-{
-  size_t index = ctx->sz & 0x3f;
-  const size_t to_fill = 64 - index;
-
-  ctx->sz += len;
-
-  /* process partial buffer if there's enough data to make a block */
-  if (index && len >= to_fill) {
-    memcpy(ctx->buf + index, data, to_fill);
-    md5_do_chunk(ctx, ctx->buf);
-    /* memset(ctx->buf, 0, 64); */
-    len -= to_fill;
-    data += to_fill;
-    index = 0;
-  }
-
-  /* process as many 64-blocks as possible */
-  while (len >= 64) {
-    md5_do_chunk(ctx, data);
-    len -= 64;
-    data += 64;
-  }
-
-  /* append data into buf */
-  if (len)
-    memcpy(ctx->buf + index, data, len);
-}
-
-void
-hs_cryptohash_md5_finalize(struct md5_ctx *ctx, uint8_t *out)
-{
-  static const uint8_t padding[64] = { 0x80, };
-
-  /* add padding and update data with it */
-  const uint64_t bits = cpu_to_le64(ctx->sz << 3);
-
-  /* pad out to 56 */
-  const size_t index = (ctx->sz & 0x3f);
-  const size_t padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
-  hs_cryptohash_md5_update(ctx, padding, padlen);
-
-  /* append length */
-  hs_cryptohash_md5_update(ctx, (const uint8_t *) &bits, sizeof(bits));
-
-  /* output hash */
-  cpu_to_le32_array((uint32_t *) out, ctx->h, 4);
-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cryptohash-md5-0.11.100.1/cbits/md5.h 
new/cryptohash-md5-0.11.101.0/cbits/md5.h
--- old/cryptohash-md5-0.11.100.1/cbits/md5.h   2016-06-28 09:14:08.000000000 
+0200
+++ new/cryptohash-md5-0.11.101.0/cbits/md5.h   2001-09-09 03:46:40.000000000 
+0200
@@ -28,6 +28,9 @@
 
 #include <stdint.h>
 #include <stddef.h>
+#include <assert.h>
+#include <string.h>
+#include <ghcautoconf.h>
 
 struct md5_ctx
 {
@@ -39,8 +42,243 @@
 #define MD5_DIGEST_SIZE                16
 #define MD5_CTX_SIZE           88
 
-void hs_cryptohash_md5_init(struct md5_ctx *ctx);
-void hs_cryptohash_md5_update(struct md5_ctx *ctx, const uint8_t *data, size_t 
len);
-void hs_cryptohash_md5_finalize(struct md5_ctx *ctx, uint8_t *out);
+static inline void hs_cryptohash_md5_init(struct md5_ctx *ctx);
+static inline void hs_cryptohash_md5_update(struct md5_ctx *ctx, const uint8_t 
*data, size_t len);
+static inline uint64_t hs_cryptohash_md5_finalize(struct md5_ctx *ctx, uint8_t 
*out);
+
+#if defined(static_assert)
+static_assert(sizeof(struct md5_ctx) == MD5_CTX_SIZE, "unexpected md5_ctx 
size");
+#else
+/* poor man's pre-C11 _Static_assert */
+typedef char static_assertion__unexpected_md5_ctx_size[(sizeof(struct md5_ctx) 
== MD5_CTX_SIZE)?1:-1];
+#endif
+
+#define ptr_uint32_aligned(ptr) (!((uintptr_t)(ptr) & 0x3))
+
+static inline uint32_t
+rol32(const uint32_t word, const unsigned shift)
+{
+  /* GCC usually transforms this into a 'rol'-insn */
+  return (word << shift) | (word >> (32 - shift));
+}
+
+static inline uint32_t
+cpu_to_le32(const uint32_t hl)
+{
+#if !WORDS_BIGENDIAN
+  return hl;
+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+  return __builtin_bswap32(hl);
+#else
+  /* GCC usually transforms this into a bswap insn */
+  return ((hl & 0xff000000) >> 24) |
+         ((hl & 0x00ff0000) >> 8)  |
+         ((hl & 0x0000ff00) << 8)  |
+         ( hl               << 24);
+#endif
+}
+
+static inline void
+cpu_to_le32_array(uint32_t *dest, const uint32_t *src, unsigned wordcnt)
+{
+  while (wordcnt--)
+    *dest++ = cpu_to_le32(*src++);
+}
+
+static inline uint64_t
+cpu_to_le64(const uint64_t hll)
+{
+#if !WORDS_BIGENDIAN
+  return hll;
+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+  return __builtin_bswap64(hll);
+#else
+  return ((uint64_t)cpu_to_le32(hll & 0xffffffff) << 32LL) | cpu_to_le32(hll 
>> 32);
+#endif
+}
+
+
+static inline void
+hs_cryptohash_md5_init(struct md5_ctx *ctx)
+{
+  memset(ctx, 0, sizeof(*ctx));
+
+  ctx->h[0] = 0x67452301;
+  ctx->h[1] = 0xefcdab89;
+  ctx->h[2] = 0x98badcfe;
+  ctx->h[3] = 0x10325476;
+}
+
+#define f1(x, y, z)     (z ^ (x & (y ^ z)))
+#define f2(x, y, z)     f1(z, x, y)
+#define f3(x, y, z)     (x ^ y ^ z)
+#define f4(x, y, z)     (y ^ (x | ~z))
+#define R(f, a, b, c, d, i, k, s) a += f(b, c, d) + w[i] + k; a = rol32(a, s); 
a += b
+
+static void
+md5_do_chunk_aligned(struct md5_ctx *ctx, const uint32_t w[])
+{
+  uint32_t a = ctx->h[0];
+  uint32_t b = ctx->h[1];
+  uint32_t c = ctx->h[2];
+  uint32_t d = ctx->h[3];
+
+  R(f1, a, b, c, d,  0, 0xd76aa478,  7);
+  R(f1, d, a, b, c,  1, 0xe8c7b756, 12);
+  R(f1, c, d, a, b,  2, 0x242070db, 17);
+  R(f1, b, c, d, a,  3, 0xc1bdceee, 22);
+  R(f1, a, b, c, d,  4, 0xf57c0faf,  7);
+  R(f1, d, a, b, c,  5, 0x4787c62a, 12);
+  R(f1, c, d, a, b,  6, 0xa8304613, 17);
+  R(f1, b, c, d, a,  7, 0xfd469501, 22);
+  R(f1, a, b, c, d,  8, 0x698098d8,  7);
+  R(f1, d, a, b, c,  9, 0x8b44f7af, 12);
+  R(f1, c, d, a, b, 10, 0xffff5bb1, 17);
+  R(f1, b, c, d, a, 11, 0x895cd7be, 22);
+  R(f1, a, b, c, d, 12, 0x6b901122,  7);
+  R(f1, d, a, b, c, 13, 0xfd987193, 12);
+  R(f1, c, d, a, b, 14, 0xa679438e, 17);
+  R(f1, b, c, d, a, 15, 0x49b40821, 22);
+
+  R(f2, a, b, c, d,  1, 0xf61e2562,  5);
+  R(f2, d, a, b, c,  6, 0xc040b340,  9);
+  R(f2, c, d, a, b, 11, 0x265e5a51, 14);
+  R(f2, b, c, d, a,  0, 0xe9b6c7aa, 20);
+  R(f2, a, b, c, d,  5, 0xd62f105d,  5);
+  R(f2, d, a, b, c, 10, 0x02441453,  9);
+  R(f2, c, d, a, b, 15, 0xd8a1e681, 14);
+  R(f2, b, c, d, a,  4, 0xe7d3fbc8, 20);
+  R(f2, a, b, c, d,  9, 0x21e1cde6,  5);
+  R(f2, d, a, b, c, 14, 0xc33707d6,  9);
+  R(f2, c, d, a, b,  3, 0xf4d50d87, 14);
+  R(f2, b, c, d, a,  8, 0x455a14ed, 20);
+  R(f2, a, b, c, d, 13, 0xa9e3e905,  5);
+  R(f2, d, a, b, c,  2, 0xfcefa3f8,  9);
+  R(f2, c, d, a, b,  7, 0x676f02d9, 14);
+  R(f2, b, c, d, a, 12, 0x8d2a4c8a, 20);
+
+  R(f3, a, b, c, d,  5, 0xfffa3942,  4);
+  R(f3, d, a, b, c,  8, 0x8771f681, 11);
+  R(f3, c, d, a, b, 11, 0x6d9d6122, 16);
+  R(f3, b, c, d, a, 14, 0xfde5380c, 23);
+  R(f3, a, b, c, d,  1, 0xa4beea44,  4);
+  R(f3, d, a, b, c,  4, 0x4bdecfa9, 11);
+  R(f3, c, d, a, b,  7, 0xf6bb4b60, 16);
+  R(f3, b, c, d, a, 10, 0xbebfbc70, 23);
+  R(f3, a, b, c, d, 13, 0x289b7ec6,  4);
+  R(f3, d, a, b, c,  0, 0xeaa127fa, 11);
+  R(f3, c, d, a, b,  3, 0xd4ef3085, 16);
+  R(f3, b, c, d, a,  6, 0x04881d05, 23);
+  R(f3, a, b, c, d,  9, 0xd9d4d039,  4);
+  R(f3, d, a, b, c, 12, 0xe6db99e5, 11);
+  R(f3, c, d, a, b, 15, 0x1fa27cf8, 16);
+  R(f3, b, c, d, a,  2, 0xc4ac5665, 23);
+
+  R(f4, a, b, c, d,  0, 0xf4292244,  6);
+  R(f4, d, a, b, c,  7, 0x432aff97, 10);
+  R(f4, c, d, a, b, 14, 0xab9423a7, 15);
+  R(f4, b, c, d, a,  5, 0xfc93a039, 21);
+  R(f4, a, b, c, d, 12, 0x655b59c3,  6);
+  R(f4, d, a, b, c,  3, 0x8f0ccc92, 10);
+  R(f4, c, d, a, b, 10, 0xffeff47d, 15);
+  R(f4, b, c, d, a,  1, 0x85845dd1, 21);
+  R(f4, a, b, c, d,  8, 0x6fa87e4f,  6);
+  R(f4, d, a, b, c, 15, 0xfe2ce6e0, 10);
+  R(f4, c, d, a, b,  6, 0xa3014314, 15);
+  R(f4, b, c, d, a, 13, 0x4e0811a1, 21);
+  R(f4, a, b, c, d,  4, 0xf7537e82,  6);
+  R(f4, d, a, b, c, 11, 0xbd3af235, 10);
+  R(f4, c, d, a, b,  2, 0x2ad7d2bb, 15);
+  R(f4, b, c, d, a,  9, 0xeb86d391, 21);
+
+  ctx->h[0] += a;
+  ctx->h[1] += b;
+  ctx->h[2] += c;
+  ctx->h[3] += d;
+}
+
+static void
+md5_do_chunk(struct md5_ctx *ctx, const uint8_t buf[])
+{
+  if (ptr_uint32_aligned(buf)) { /* aligned buf */
+#if WORDS_BIGENDIAN
+    uint32_t w[16]; cpu_to_le32_array(w, (const uint32_t *)buf, 16);
+#else
+    const uint32_t *w = (const uint32_t *)buf;
+#endif
+    md5_do_chunk_aligned(ctx, w);
+  } else { /* unaligned buf */
+    uint32_t w[16]; memcpy(w, buf, 64);
+#if WORDS_BIGENDIAN
+    cpu_to_le32_array(w, w, 16);
+#endif
+    md5_do_chunk_aligned(ctx, w);
+  }
+}
+
+static inline void
+hs_cryptohash_md5_update(struct md5_ctx *ctx, const uint8_t *data, size_t len)
+{
+  size_t index = ctx->sz & 0x3f;
+  const size_t to_fill = 64 - index;
+
+  ctx->sz += len;
+
+  /* process partial buffer if there's enough data to make a block */
+  if (index && len >= to_fill) {
+    memcpy(ctx->buf + index, data, to_fill);
+    md5_do_chunk(ctx, ctx->buf);
+    /* memset(ctx->buf, 0, 64); */
+    len -= to_fill;
+    data += to_fill;
+    index = 0;
+  }
+
+  /* process as many 64-blocks as possible */
+  while (len >= 64) {
+    md5_do_chunk(ctx, data);
+    len -= 64;
+    data += 64;
+  }
+
+  /* append data into buf */
+  if (len)
+    memcpy(ctx->buf + index, data, len);
+}
+
+static inline uint64_t
+hs_cryptohash_md5_finalize(struct md5_ctx *ctx, uint8_t *out)
+{
+  static const uint8_t padding[64] = { 0x80, };
+  const uint64_t sz = ctx->sz;
+
+  /* add padding and update data with it */
+  const uint64_t bits = cpu_to_le64(ctx->sz << 3);
+
+  /* pad out to 56 */
+  const size_t index = (ctx->sz & 0x3f);
+  const size_t padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
+  hs_cryptohash_md5_update(ctx, padding, padlen);
+
+  /* append length */
+  hs_cryptohash_md5_update(ctx, (const uint8_t *) &bits, sizeof(bits));
+
+  /* output hash */
+  cpu_to_le32_array((uint32_t *) out, ctx->h, 4);
+
+  return sz;
+}
+
+static inline void
+hs_cryptohash_md5_hash (const uint8_t *data, size_t len, uint8_t *out)
+{
+  struct md5_ctx ctx;
+
+  hs_cryptohash_md5_init(&ctx);
+
+  hs_cryptohash_md5_update(&ctx, data, len);
+
+  hs_cryptohash_md5_finalize(&ctx, out);
+}
 
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cryptohash-md5-0.11.100.1/changelog.md 
new/cryptohash-md5-0.11.101.0/changelog.md
--- old/cryptohash-md5-0.11.100.1/changelog.md  2016-06-28 09:14:08.000000000 
+0200
+++ new/cryptohash-md5-0.11.101.0/changelog.md  2001-09-09 03:46:40.000000000 
+0200
@@ -1,3 +1,18 @@
+## 0.11.101.0
+
+ - Add `Eq` instance for `Ctx`
+ - Add `start` and `startlazy` producing `Ctx`
+ - Remove ineffective RULES
+ - Declare `Crypto.Hash.MD5` module `-XTrustworthy`
+ - Convert to `CApiFFI`
+ - Added `...AndLength` variants of hashing functions:
+
+      - `finalizeAndLength`
+      - `hashlazyAndLength`
+      - `hmaclazyAndLength`
+
+ - Minor optimizations in `hmac` and `hash`
+
 ## 0.11.100.1
 
  - Use `__builtin_bswap{32,64}` only with GCC >= 4.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cryptohash-md5-0.11.100.1/cryptohash-md5.cabal 
new/cryptohash-md5-0.11.101.0/cryptohash-md5.cabal
--- old/cryptohash-md5-0.11.100.1/cryptohash-md5.cabal  2016-06-28 
09:14:08.000000000 +0200
+++ new/cryptohash-md5-0.11.101.0/cryptohash-md5.cabal  2001-09-09 
03:46:40.000000000 +0200
@@ -1,5 +1,5 @@
 name:                cryptohash-md5
-version:             0.11.100.1
+version:             0.11.101.0
 description:
     A practical incremental and one-pass, pure API to the
     <https://en.wikipedia.org/wiki/MD5 MD5 hash algorithm>
@@ -30,7 +30,14 @@
                    , GHC == 7.6.3
                    , GHC == 7.8.4
                    , GHC == 7.10.3
-                   , GHC == 8.0.1
+                   , GHC == 8.0.2
+                   , GHC == 8.2.2
+                   , GHC == 8.4.4
+                   , GHC == 8.6.5
+                   , GHC == 8.8.4
+                   , GHC == 8.10.4
+                   , GHC == 9.0.1
+                   , GHC == 9.2.0.20210821
 
 extra-source-files:  cbits/md5.h
                      changelog.md
@@ -41,14 +48,14 @@
 
 library
   default-language:  Haskell2010
-  build-depends:     base             >= 4.5   && < 4.10
-                   , bytestring       >= 0.9.2 && < 0.11
+  build-depends:     base             >= 4.5   && < 4.17
+                   , bytestring       >= 0.9.2 && < 0.12
 
   hs-source-dirs:    src
   exposed-modules:   Crypto.Hash.MD5
+  other-modules:     Crypto.Hash.MD5.FFI Compat
   ghc-options:       -Wall -fno-cse -O2
-  cc-options:        -Wall -O3
-  c-sources:         cbits/md5.c
+  cc-options:        -Wall
   include-dirs:      cbits
 
 test-suite test-md5
@@ -62,11 +69,11 @@
                    , base
                    , bytestring
 
-                   , base16-bytestring >= 0.1.1  && < 0.2
+                   , base16-bytestring >= 1.0.1.0 && < 1.1
                    , pureMD5           >= 2.1.3  && < 2.2
-                   , tasty             == 0.11.*
-                   , tasty-quickcheck  == 0.8.*
-                   , tasty-hunit       == 0.9.*
+                   , tasty             >= 1.4 && <1.5
+                   , tasty-quickcheck  == 0.10.*
+                   , tasty-hunit       == 0.10.*
 
 benchmark bench-md5
   default-language:  Haskell2010
@@ -76,4 +83,4 @@
   build-depends:     cryptohash-md5
                    , base
                    , bytestring
-                   , criterion        == 1.1.*
+                   , criterion        == 1.5.*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cryptohash-md5-0.11.100.1/src/Compat.hs 
new/cryptohash-md5-0.11.101.0/src/Compat.hs
--- old/cryptohash-md5-0.11.100.1/src/Compat.hs 1970-01-01 01:00:00.000000000 
+0100
+++ new/cryptohash-md5-0.11.101.0/src/Compat.hs 2001-09-09 03:46:40.000000000 
+0200
@@ -0,0 +1,24 @@
+{-# LANGUAGE CPP          #-}
+{-# LANGUAGE Trustworthy  #-}
+
+-- |
+-- Module      : Compat
+-- License     : BSD-3
+-- Maintainer  : Herbert Valerio Riedel <[email protected]>
+-- Stability   : stable
+--
+-- Compat layer to reduce code exposure to CPP to a bare minimum
+--
+module Compat (constructBS) where
+
+import Foreign.ForeignPtr (ForeignPtr)
+import Data.Word (Word8)
+import Data.ByteString.Internal (ByteString (..))
+
+-- | Directly construct a 'ByteString', unsafely
+constructBS :: ForeignPtr Word8 -> Int -> ByteString
+#if MIN_VERSION_bytestring(0,11,0)
+constructBS = BS
+#else
+constructBS = \fp -> PS fp 0
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cryptohash-md5-0.11.100.1/src/Crypto/Hash/MD5/FFI.hs 
new/cryptohash-md5-0.11.101.0/src/Crypto/Hash/MD5/FFI.hs
--- old/cryptohash-md5-0.11.100.1/src/Crypto/Hash/MD5/FFI.hs    1970-01-01 
01:00:00.000000000 +0100
+++ new/cryptohash-md5-0.11.101.0/src/Crypto/Hash/MD5/FFI.hs    2001-09-09 
03:46:40.000000000 +0200
@@ -0,0 +1,61 @@
+{-# LANGUAGE CApiFFI #-}
+{-# LANGUAGE Unsafe  #-}
+
+-- Ugly hack to workaround https://ghc.haskell.org/trac/ghc/ticket/14452
+{-# OPTIONS_GHC -O0
+                -fdo-lambda-eta-expansion
+                -fcase-merge
+                -fstrictness
+                -fno-omit-interface-pragmas
+                -fno-ignore-interface-pragmas #-}
+
+{-# OPTIONS_GHC -optc-Wall -optc-O3 #-}
+
+-- |
+-- Module      : Crypto.Hash.MD5.FFI
+-- License     : BSD-3
+--
+module Crypto.Hash.MD5.FFI where
+
+import           Data.ByteString (ByteString)
+import           Data.Word
+import           Foreign.C.Types
+import           Foreign.Ptr
+
+-- | MD5 Context
+--
+-- The context data is exactly 88 bytes long, however
+-- the data in the context is stored in host-endianness.
+--
+-- The context data is made up of
+--
+--  * a 'Word64' representing the number of bytes already feed to hash 
algorithm so far,
+--
+--  * a 64-element 'Word8' buffer holding partial input-chunks, and finally
+--
+--  * a 4-element 'Word32' array holding the current work-in-progress 
digest-value.
+--
+-- Consequently, a MD5 digest as produced by 'hash', 'hashlazy', or 'finalize' 
is 16 bytes long.
+newtype Ctx = Ctx ByteString
+  deriving (Eq)
+
+foreign import capi unsafe "md5.h hs_cryptohash_md5_init"
+    c_md5_init :: Ptr Ctx -> IO ()
+
+foreign import capi unsafe "md5.h hs_cryptohash_md5_update"
+    c_md5_update_unsafe :: Ptr Ctx -> Ptr Word8 -> CSize -> IO ()
+
+foreign import capi safe "md5.h hs_cryptohash_md5_update"
+    c_md5_update_safe :: Ptr Ctx -> Ptr Word8 -> CSize -> IO ()
+
+foreign import capi unsafe "md5.h hs_cryptohash_md5_finalize"
+    c_md5_finalize :: Ptr Ctx -> Ptr Word8 -> IO ()
+
+foreign import capi unsafe "md5.h hs_cryptohash_md5_finalize"
+    c_md5_finalize_len :: Ptr Ctx -> Ptr Word8 -> IO Word64
+
+foreign import capi unsafe "md5.h hs_cryptohash_md5_hash"
+    c_md5_hash_unsafe :: Ptr Word8 -> CSize -> Ptr Word8 -> IO ()
+
+foreign import capi safe "md5.h hs_cryptohash_md5_hash"
+    c_md5_hash_safe :: Ptr Word8 -> CSize -> Ptr Word8 -> IO ()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cryptohash-md5-0.11.100.1/src/Crypto/Hash/MD5.hs 
new/cryptohash-md5-0.11.101.0/src/Crypto/Hash/MD5.hs
--- old/cryptohash-md5-0.11.100.1/src/Crypto/Hash/MD5.hs        2016-06-28 
09:14:08.000000000 +0200
+++ new/cryptohash-md5-0.11.101.0/src/Crypto/Hash/MD5.hs        2001-09-09 
03:46:40.000000000 +0200
@@ -1,3 +1,4 @@
+{-# LANGUAGE Trustworthy #-}
 -- |
 -- Module      : Crypto.Hash.MD5
 -- License     : BSD-style
@@ -40,6 +41,9 @@
     , update   -- :: Ctx -> ByteString -> Ctx
     , updates  -- :: Ctx -> [ByteString] -> Ctx
     , finalize -- :: Ctx -> ByteString
+    , finalizeAndLength -- :: Ctx -> (ByteString,Word64)
+    , start    -- :: ByteString -> Ctx
+    , startlazy-- :: L.ByteString -> Ctx
 
     -- * Single Pass API
     --
@@ -49,6 +53,7 @@
     --
     --  - 'hash': create a digest ('init' + 'update' + 'finalize') from a 
strict 'ByteString'
     --  - 'hashlazy': create a digest ('init' + 'update' + 'finalize') from a 
lazy 'L.ByteString'
+    --  - 'hashlazyAndLength': create a digest ('init' + 'update' + 
'finalizeAndLength') from a lazy 'L.ByteString'
     --
     -- Example:
     --
@@ -64,6 +69,7 @@
 
     , hash     -- :: ByteString -> ByteString
     , hashlazy -- :: L.ByteString -> ByteString
+    , hashlazyAndLength -- :: L.ByteString -> (ByteString,Word64)
 
     -- ** HMAC-MD5
     --
@@ -72,6 +78,7 @@
 
     , hmac     -- :: ByteString -> ByteString -> ByteString
     , hmaclazy -- :: ByteString -> L.ByteString -> ByteString
+    , hmaclazyAndLength -- :: ByteString -> L.ByteString -> (ByteString,Word64)
     ) where
 
 import Prelude hiding (init)
@@ -83,11 +90,14 @@
 import qualified Data.ByteString as B
 import Data.ByteString (ByteString)
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
-import Data.ByteString.Internal (create, toForeignPtr, memcpy)
+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.MD5.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
@@ -96,22 +106,6 @@
 unsafeDoIO :: IO a -> a
 unsafeDoIO = unsafeDupablePerformIO
 
--- | MD5 Context
---
--- The context data is exactly 88 bytes long, however
--- the data in the context is stored in host-endianness.
---
--- The context data is made up of
---
---  * a 'Word64' representing the number of bytes already feed to hash 
algorithm so far,
---
---  * a 64-element 'Word8' buffer holding partial input-chunks, and finally
---
---  * a 4-element 'Word32' array holding the current work-in-progress 
digest-value.
---
--- Consequently, a MD5 digest as produced by 'hash', 'hashlazy', or 'finalize' 
is 16 bytes long.
-newtype Ctx = Ctx ByteString
-
 -- keep this synchronised with cbits/md5.h
 {-# INLINE digestSize #-}
 digestSize :: Int
@@ -121,18 +115,21 @@
 sizeCtx :: Int
 sizeCtx = 88
 
-{-# RULES "digestSize" B.length (finalize init) = digestSize #-}
-{-# RULES "hash" forall b. finalize (update init b) = hash b #-}
-{-# RULES "hash.list1" forall b. finalize (updates init [b]) = hash b #-}
-{-# RULES "hashmany" forall b. finalize (foldl update init b) = hashlazy 
(L.fromChunks b) #-}
-{-# RULES "hashlazy" forall b. finalize (foldl update init $ L.toChunks b) = 
hashlazy b #-}
-
 {-# INLINE withByteStringPtr #-}
 withByteStringPtr :: ByteString -> (Ptr Word8 -> IO a) -> IO a
 withByteStringPtr b f =
     withForeignPtr fptr $ \ptr -> f (ptr `plusPtr` off)
     where (fptr, off, _) = toForeignPtr b
 
+{-# INLINE 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)
 
@@ -157,14 +154,7 @@
 withCtxNewThrow :: (Ptr Ctx -> IO a) -> IO a
 withCtxNewThrow f = allocaBytes sizeCtx (f . castPtr)
 
-foreign import ccall unsafe "md5.h hs_cryptohash_md5_init"
-    c_md5_init :: Ptr Ctx -> IO ()
 
-foreign import ccall unsafe "md5.h hs_cryptohash_md5_update"
-    c_md5_update_unsafe :: Ptr Ctx -> Ptr Word8 -> CSize -> IO ()
-
-foreign import ccall safe "md5.h hs_cryptohash_md5_update"
-    c_md5_update_safe :: Ptr Ctx -> Ptr Word8 -> CSize -> IO ()
 
 -- 'safe' call overhead neglible for 16KiB and more
 c_md5_update :: Ptr Ctx -> Ptr Word8 -> CSize -> IO ()
@@ -172,8 +162,11 @@
   | sz < 16384 = c_md5_update_unsafe pctx pbuf sz
   | otherwise  = c_md5_update_safe   pctx pbuf sz
 
-foreign import ccall unsafe "md5.h hs_cryptohash_md5_finalize"
-    c_md5_finalize :: Ptr Ctx -> Ptr Word8 -> IO ()
+-- 'safe' call overhead neglible for 4KiB and more
+c_md5_hash :: Ptr Word8 -> CSize -> Ptr Word8 -> IO ()
+c_md5_hash pbuf sz pout
+  | sz < 4096 = c_md5_hash_unsafe pbuf sz pout
+  | otherwise = c_md5_hash_safe   pbuf sz pout
 
 updateInternalIO :: Ptr Ctx -> ByteString -> IO ()
 updateInternalIO ptr d =
@@ -182,6 +175,9 @@
 finalizeInternalIO :: Ptr Ctx -> IO ByteString
 finalizeInternalIO ptr = create digestSize (c_md5_finalize ptr)
 
+finalizeInternalIO' :: Ptr Ctx -> IO (ByteString,Word64)
+finalizeInternalIO' ptr = create' digestSize (c_md5_finalize_len ptr)
+
 {-# NOINLINE init #-}
 -- | create a new hash context
 init :: Ctx
@@ -211,11 +207,28 @@
   | validCtx ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO
   | otherwise    = error "MD5.finalize: invalid Ctx"
 
+{-# NOINLINE finalizeAndLength #-}
+-- | Variant of 'finalize' also returning length of hashed content
+--
+-- @since 0.11.101.0
+finalizeAndLength :: Ctx -> (ByteString,Word64)
+finalizeAndLength ctx
+  | validCtx ctx = unsafeDoIO $ withCtxThrow ctx finalizeInternalIO'
+  | otherwise    = error "SHA256.finalize: invalid Ctx"
+
 {-# NOINLINE hash #-}
 -- | hash a strict bytestring into a digest bytestring (16 bytes)
 hash :: ByteString -> ByteString
-hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
-    c_md5_init ptr >> updateInternalIO ptr d >> finalizeInternalIO ptr
+-- hash d = unsafeDoIO $ withCtxNewThrow $ \ptr -> do c_md5_init ptr >> 
updateInternalIO ptr d >> finalizeInternalIO ptr
+hash d = unsafeDoIO $ unsafeUseAsCStringLen d $ \(cs, len) -> create 
digestSize (c_md5_hash (castPtr cs) (fromIntegral len))
+
+{-# NOINLINE start #-}
+-- | hash a strict bytestring into a 'Ctx'
+--
+-- @since 0.11.101.0
+start :: ByteString -> Ctx
+start d = unsafeDoIO $ withCtxNew $ \ptr -> do
+    c_md5_init ptr >> updateInternalIO ptr d
 
 {-# NOINLINE hashlazy #-}
 -- | hash a lazy bytestring into a digest bytestring (16 bytes)
@@ -223,6 +236,21 @@
 hashlazy l = unsafeDoIO $ withCtxNewThrow $ \ptr -> do
     c_md5_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.
+--
+-- @since 0.11.101.0
+hashlazyAndLength :: L.ByteString -> (ByteString,Word64)
+hashlazyAndLength l = unsafeDoIO $ withCtxNewThrow $ \ptr ->
+    c_md5_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l) >> 
finalizeInternalIO' ptr
+
+{-# NOINLINE startlazy #-}
+-- | hash a lazy bytestring into a 'Ctx'
+--
+-- @since 0.11.101.0
+startlazy :: L.ByteString -> Ctx
+startlazy l = unsafeDoIO $ withCtxNew $ \ptr -> do
+    c_md5_init ptr >> mapM_ (updateInternalIO ptr) (L.toChunks l)
 
 {-# NOINLINE hmac #-}
 -- | Compute 16-byte <https://tools.ietf.org/html/rfc2104 RFC2104>-compatible
@@ -257,4 +285,23 @@
 
     k'  = B.append kt pad
     kt  = if B.length secret > 64 then hash secret else secret
+    pad = B.replicate (64 - B.length kt) 0
+
+-- | Variant of 'hmaclazy' which also returns length of message
+--
+-- @since 0.11.101.0
+hmaclazyAndLength :: ByteString   -- ^ secret
+                  -> L.ByteString -- ^ message
+                  -> (ByteString,Word64) -- ^ digest (32 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 > 64 then hash secret else secret
     pad = B.replicate (64 - B.length kt) 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cryptohash-md5-0.11.100.1/src-tests/test-md5.hs 
new/cryptohash-md5-0.11.101.0/src-tests/test-md5.hs
--- old/cryptohash-md5-0.11.100.1/src-tests/test-md5.hs 2016-06-28 
09:14:08.000000000 +0200
+++ new/cryptohash-md5-0.11.101.0/src-tests/test-md5.hs 2001-09-09 
03:46:40.000000000 +0200
@@ -3,6 +3,7 @@
 module Main (main) where
 
 import           Data.Bits              (xor)
+import           Data.Word              (Word64)
 import           Data.ByteString        (ByteString)
 import qualified Data.ByteString        as B
 import qualified Data.ByteString.Lazy   as BL
@@ -46,11 +47,12 @@
 
 katTests :: [TestTree]
 katTests
-  | length vectors == length answers = map makeTest (zip3 [1::Int ..] vectors 
answers) ++ [xltest]
+  | 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)
@@ -65,25 +67,43 @@
         , 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-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"
@@ -91,6 +111,11 @@
       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
@@ -110,7 +135,7 @@
     , (rep 80 0xaa, "Test Using Larger Than Block-Size Key and Larger Than One 
Block-Size Data", x"6f630fad67cda0ee1fb1f562db3aa53e")
     ]
   where
-    x = fst.B16.decode
+    x = B16.decodeLenient
     rep n c = B.replicate n c
 
 rfc2202Tests :: [TestTree]
@@ -125,7 +150,7 @@
 
     hex = B16.encode
 
--- define own 'foldl' here to avoid RULE rewriting to 'hashlazy'
+-- define own 'foldl' here to avoid RULE rewriting to 'startlazy
 myfoldl' :: (b -> a -> b) -> b -> [a] -> b
 myfoldl' f z0 xs0 = lgo z0 xs0
   where
@@ -154,29 +179,48 @@
 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 = REF.md5DigestBytes . REF.md5
 
+    ref_hashlazyAndLength :: BL.ByteString -> (ByteString,Word64)
+    ref_hashlazyAndLength x = (ref_hashlazy x, fromIntegral (BL.length x))
+
     -- stolen & adapted from SHA package
     ref_hmac :: ByteString -> ByteString -> ByteString
     ref_hmac k m = ref_hash (B.append opad (ref_hash (B.append ipad m)))
@@ -195,6 +239,9 @@
     ref_hmaclazy :: ByteString -> BL.ByteString -> ByteString
     ref_hmaclazy secret = ref_hmac secret . toStrict
 
+    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 . (:[])

Reply via email to