diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # Revision history for sha256
 
+## 0.1.0.3 -- 2025-05-31
+
+* Added documentation for hkdf
+
+* Improved support for GHC < 9.4
+
 ## 0.1.0.2 -- 2025-01-21
 
 * Duplicate a C function used from the hash-string package, because hackage's
diff --git a/lib/Crypto/Sha256/Hkdf.hs b/lib/Crypto/Sha256/Hkdf.hs
--- a/lib/Crypto/Sha256/Hkdf.hs
+++ b/lib/Crypto/Sha256/Hkdf.hs
@@ -47,6 +47,36 @@
 import           Crypto.Sha256.Hmac
 import           Crypto.Sha256.Hkdf.Subtle
 
+-- | @hkdf salt ikm info len@ returns a hash of the given length in bytes.
+--   There are two useful partial applications, @hkdf salt@ and @hkdf salt ikm@.
+--   This function has been implemented in a point-free style so that these
+--   partial applications do actually perform partial evaluation.
+--
+--   Exactly like 'hmac', each reused application of @hkdf salt@ will save 2
+--   SHA256 block computations for keys up to 64 bytes long, or 4 blocks for
+--   keys 65-119 bytes long with one additional block computation for every 64
+--   bytes of key thereafter.
+--
+--   Each reused application of @hkdf salt ikm@ will save everything mentioned
+--   above, plus an additional 4 blocks for an ikm that is up to 55 bytes long,
+--   plus one additional block for every 64 bytes of ikm thereafter.
+--
+--   This results in a precomputed pseudorandom key. From this point, each
+--   output block requires 2 additional SHA256 block computations if the info
+--   tag is 0-22 bytes long, and one additional SHA256 block computation per
+--   output block for every 64 bytes of tag thereafter. Each output block is
+--   32 bytes long.
+--
+--   According to RFC 5869, hkdf-sha256 is only defined for up to 255 output
+--   blocks, resulting in a maximum output length of 8160 bytes. However, this
+--   implementation extends the definition to arbitrary output lengths by
+--   wrapping the output counter. According to NIST SP 800-108, this mode of
+--   operation is not recommended for more than 256 blocks of output, resulting
+--   in a maximum output length of 8196 bytes.
+--
+--   Note that if you request two outputs with the same parameters other than
+--   length, then the shorter output will be a prefix of the longer output.
+
 hkdf :: HmacKeyPlain -- ^ salt
      -> ByteString -- ^ initial keying material
      -> ByteString -- ^ info tag
@@ -54,6 +84,8 @@
      -> ByteString
 hkdf = (fmap . fmap . fmap . fmap $ HS.toByteString) hkdf'
 
+-- | variation of 'hkdf' that returns a 'HashString'
+
 hkdf' :: HmacKeyPlain -- ^ salt
       -> ByteString -- ^ initial keying material
       -> ByteString -- ^ info tag
@@ -63,6 +95,9 @@
            mconcat (HS.takeBytes len (hkdfGen_toList' gen))
         ) hkdfGen
 
+-- | variation of 'hkdf' that returns an unbounded stream of 32-byte output
+--   blocks.
+
 hkdfList
   :: HmacKeyPlain -- ^ salt
   -> ByteString -- ^ initial keying material
@@ -70,6 +105,9 @@
   -> [ByteString]
 hkdfList = (fmap . fmap . fmap $ hkdfGen_toList) hkdfGen
 
+-- | variation of 'hkdf' that returns an unbounded stream of 32-byte output
+--   blocks as 'HashString's
+
 hkdfList'
   :: HmacKeyPlain -- ^ salt
   -> ByteString -- ^ initial keying material
@@ -77,6 +115,8 @@
   -> [HashString]
 hkdfList' = (fmap . fmap . fmap $ hkdfGen_toList') hkdfGen
 
+-- | variation of 'hkdf' that returns a plain-old-data representation of
+--   the output generator.
 
 hkdfGen
   :: HmacKeyPlain -- ^ salt
diff --git a/sha256.cabal b/sha256.cabal
--- a/sha256.cabal
+++ b/sha256.cabal
@@ -1,5 +1,5 @@
 name:                sha256
-version:             0.1.0.2
+version:             0.1.0.3
 synopsis:
   A modern binding to SHA256, HMAC, HKDF, and PBKDF2
 description:
@@ -38,6 +38,9 @@
                    , hash-string
                    , network-byte-order
                    , ghc-prim
+
+  if impl(ghc < 9.4)
+    build-depends: data-array-byte
 
   hs-source-dirs:    lib
   include-dirs:      csrc
