New HMAC-DRBG and SHA-2 Libraries

Just FYI, I’ve dropped a few simple libraries supporting SHA-{256,512}, HMAC-SHA{256, 512}, and HMAC-DRBG. You can find the repos here:

Each is packaged there as a Nix flake, and each is also available on Hackage.

This is the first battery of a series of libraries I’m writing that were primarily inspired by noble-cryptography after the death (or at least deprecation) of cryptonite. The libraries are pure, readable, concise GHC Haskell, having minimal dependencies, and aim for clarity, security, performance, and user-friendliness.

I finally got around to going through most of the famous cryptopals challenges challenges last year and have since felt like writing some “foundational” cryptography (and cryptography-adjacent) libraries that I myself would want to use. I’d like to understand them well, test and benchmark them myself, eke out performance and UX wins where I can get them, etc. etc.

An example is found in the case of ppad-hmac-drbg – I want to use this DRBG in the manner I’m accustomed to using generators from e.g. mwc-random, in which I can utilise any PrimMonad to handle the generator state:

ghci> :set -XOverloadedStrings
ghci> import qualified Crypto.DRBG.HMAC as DRBG
ghci> import qualified Crypto.Hash.SHA256 as SHA256
ghci>
ghci> let entropy = "very random"
ghci> let nonce = "very unused"
ghci> let personalization_string = "very personal"
ghci>
ghci> drbg <- DRBG.new SHA256.hmac entropy nonce personalization_string
ghci> bytes <- DRBG.gen mempty 32 drbg
ghci> more_bytes <- DRBG.gen mempty 16 drbg

I haven’t actually tried the other DRBG library I found on Hackage, but it has different UX, a lot of dependencies, and has since apparently been deprecated. The generator in ppad-hmac-drbg matches my preferred UX, passes the official DRBGVS vectors, depends only on ‘base’, ‘bytestring’, and ‘primitive’, and can be used with arbitrary appropriate HMAC functions (and is maintained!).

The ppad-sha256 and ppad-sha512 libraries depend only on ‘base’ and ‘bytestring’ and are faster than any other pure Haskell SHA-2 implementations I’m aware of, even if the performance differences are moral, rather than practical, victories:

ppad-sha256’s SHA-256, vs SHA’s, on a 32B input:

  benchmarking ppad-sha256/SHA256 (32B input)/hash
  time                 1.898 μs   (1.858 μs .. 1.941 μs)
                       0.997 R²   (0.996 R² .. 0.999 R²)
  mean                 1.874 μs   (1.856 μs .. 1.902 μs)
  std dev              75.90 ns   (60.30 ns .. 101.8 ns)
  variance introduced by outliers: 55% (severely inflated)

  benchmarking SHA/SHA256 (32B input)/sha256
  time                 2.929 μs   (2.871 μs .. 2.995 μs)
                       0.997 R²   (0.995 R² .. 0.998 R²)
  mean                 2.879 μs   (2.833 μs .. 2.938 μs)
  std dev              170.4 ns   (130.4 ns .. 258.9 ns)
  variance introduced by outliers: 71% (severely inflated)

And the same, but now a HMAC-SHA256 battle:

  benchmarking ppad-sha256/HMAC-SHA256 (32B input)/hmac
  time                 7.287 μs   (7.128 μs .. 7.424 μs)
                       0.996 R²   (0.995 R² .. 0.998 R²)
  mean                 7.272 μs   (7.115 μs .. 7.455 μs)
  std dev              565.2 ns   (490.9 ns .. 689.7 ns)
  variance introduced by outliers: 80% (severely inflated)

  benchmarking SHA/HMAC-SHA256 (32B input)/hmacSha256
  time                 11.42 μs   (11.09 μs .. 11.80 μs)
                       0.994 R²   (0.992 R² .. 0.997 R²)
  mean                 11.36 μs   (11.09 μs .. 11.61 μs)
  std dev              903.5 ns   (766.5 ns .. 1.057 μs)
  variance introduced by outliers: 79% (severely inflated)

The performance differential is larger on larger inputs; I think the difference between the two on a contrived 1GB input was 22 vs 32s, all on my mid-2020 MacBook Air. I haven’t bothered to implement e.g. SHA-224 and SHA-384, which are trivial adjustments of SHA-256 and SHA-512, but if anyone could use them for some reason, please just let me know.

Anyway: enjoy, and let me know if you get any use out of these. Expect more releases in this spirit!