diff --git a/.travis.yml b/.travis.yml
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,15 +12,21 @@
 
 matrix:
   include:
-    - env: ARGS="--resolver lts-8"
-      compiler: ": #stack 8.0.2"
+    - env: ARGS="--resolver lts-9.21"
+      compiler: "stack-8.0.2"
 
+    - env: ARGS="--resolver lts-11.22"
+      compiler: "stack-8.2.2"
+
+    - env: ARGS=""
+      compiler: "stack-8.4.3"
+
     - env: ARGS="--resolver nightly"
-      compiler: ": #stack nightly"
+      compiler: "stack-nightly"
 
   allow_failures:
     - env: ARGS="--resolver nightly"
-      compiler: ": #stack nightly"
+      compiler: "stack-nightly"
 
 before_install:
   - unset CC
@@ -33,4 +39,4 @@
 
 script:
   - stack $ARGS --no-terminal test --flag "cacophony:build-tools" --bench --no-run-benchmarks --haddock --no-haddock-deps
-  - stack sdist
+  - stack $ARGS sdist
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -107,6 +107,62 @@
 
   * `rekeySending` and `rekeyReceiving` -- Rekeys the given NoiseState according to section 11.3 of the protocol.
 
+## Supported Features
+
+All combinations of the following handshake parameters are officially supported and covered by the unit tests:
+
+* Patterns
+  * NN
+  * KN
+  * NK
+  * KK
+  * NX
+  * KX
+  * XN
+  * IN
+  * XK
+  * IK
+  * XX
+  * IX
+  * N
+  * K
+  * X
+  * NNpsk0
+  * NNpsk2
+  * NKpsk0
+  * NKpsk2
+  * NXpsk2
+  * XNpsk3
+  * XKpsk3
+  * XXpsk3
+  * KNpsk0
+  * KNpsk2
+  * KKpsk0
+  * KKpsk2
+  * KXpsk2
+  * INpsk1
+  * INpsk2
+  * IKpsk1
+  * IKpsk2
+  * IXpsk2
+  * Npsk0
+  * Kpsk0
+  * Xpsk1
+
+* Ciphers
+  * AESGCM
+  * ChaChaPoly1305
+
+* Curves
+  * Curve25519
+  * Curve448
+
+* Hashes
+  * BLAKE2b
+  * BLAKE2s
+  * SHA256
+  * SHA512
+
 ## Vectors
 
 Test vectors can be generated and verified using the `vectors` program. It accepts no arguments. When run,
diff --git a/cacophony.cabal b/cacophony.cabal
--- a/cacophony.cabal
+++ b/cacophony.cabal
@@ -1,9 +1,11 @@
--- This file has been generated from package.yaml by hpack version 0.17.0.
+-- This file has been generated from package.yaml by hpack version 0.28.2.
 --
 -- see: https://github.com/sol/hpack
+--
+-- hash: 272fee6928a83c4ebb4abfab6ac7c6cb68e59c5c6b0cd1d52cfbc96d04e43875
 
 name:           cacophony
-version:        0.10.0
+version:        0.10.1
 synopsis:       A library implementing the Noise protocol.
 description:    This library implements the <https://noiseprotocol.org Noise> protocol.
 category:       Cryptography
@@ -14,7 +16,6 @@
 license-file:   LICENSE
 build-type:     Simple
 cabal-version:  >= 1.10
-
 extra-source-files:
     .travis.yml
     changelog.md
@@ -42,9 +43,9 @@
   default-extensions: OverloadedStrings
   ghc-options: -Wall
   build-depends:
-      base >= 4.9 && < 4.10
+      base >=4.9 && <5
     , bytestring
-    , cryptonite
+    , cryptonite >=0.22
     , exceptions
     , free
     , lens
@@ -86,10 +87,11 @@
       tools/noise-repl
   default-extensions: OverloadedStrings
   ghc-options: -Wall -O2 -rtsopts -threaded -with-rtsopts=-N
+  build-depends:
+      base >=4.9 && <5
   if flag(build-tools)
     build-depends:
         attoparsec
-      , base
       , base16-bytestring
       , base64-bytestring
       , bytestring
@@ -105,16 +107,19 @@
       Pipe
       Socket
       Types
+      Paths_cacophony
   default-language: Haskell2010
 
 test-suite hlint
   type: exitcode-stdio-1.0
   main-is: hlint.hs
+  other-modules:
+      Paths_cacophony
   hs-source-dirs:
       tests/hlint
   ghc-options: -Wall -O2 -rtsopts -threaded -with-rtsopts=-N
   build-depends:
-      base >= 4.9 && < 4.10
+      base >=4.9 && <5
     , hlint
   default-language: Haskell2010
 
@@ -128,7 +133,7 @@
   build-depends:
       aeson
     , attoparsec
-    , base >= 4.9 && < 4.10
+    , base >=4.9 && <5
     , base16-bytestring
     , bytestring
     , cacophony
@@ -140,6 +145,7 @@
       Types
       VectorFile
       Verify
+      Paths_cacophony
   default-language: Haskell2010
 
 benchmark bench
@@ -151,7 +157,7 @@
   ghc-options: -Wall -O2 -rtsopts -threaded -with-rtsopts=-N
   build-depends:
       async
-    , base >= 4.9 && < 4.10
+    , base >=4.9 && <5
     , base16-bytestring
     , bytestring
     , cacophony
@@ -160,4 +166,5 @@
   other-modules:
       Keys
       Types
+      Paths_cacophony
   default-language: Haskell2010
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,15 @@
+# 0.10.1
+
+* Set default GHC version to 8.4
+
+* Support GHC > 8.0.2
+
+* Parse pattern names more efficiently in unit tests
+
+* Use preferred Curve448 module from cryptonite
+
+* Add list of supported handshake parameters to README
+
 # 0.10.0
 
 * Completely refactored API
diff --git a/package.yaml b/package.yaml
--- a/package.yaml
+++ b/package.yaml
@@ -1,6 +1,6 @@
 name: cacophony
 synopsis: A library implementing the Noise protocol.
-version: 0.10.0
+version: 0.10.1
 license: PublicDomain
 license-file: LICENSE
 maintainer: John Galt <jgalt@centromere.net>
@@ -27,12 +27,14 @@
     default: False
     manual: True
 
+dependencies:
+  - base >= 4.9 && < 5
+
 library:
   source-dirs: src
   dependencies:
-    - base >= 4.9 && < 4.10
     - bytestring
-    - cryptonite
+    - cryptonite >= 0.22
     - exceptions
     - free
     - lens
@@ -74,7 +76,6 @@
     main: hlint.hs
     source-dirs: tests/hlint
     dependencies:
-      - base >= 4.9 && < 4.10
       - hlint
 
     ghc-options:
@@ -89,7 +90,6 @@
     dependencies:
       - aeson
       - attoparsec
-      - base >= 4.9 && < 4.10
       - base16-bytestring
       - bytestring
       - cacophony
@@ -111,7 +111,6 @@
     source-dirs: benchmarks
     dependencies:
       - async
-      - base >= 4.9 && < 4.10
       - base16-bytestring
       - bytestring
       - cacophony
@@ -136,7 +135,6 @@
         then:
           dependencies:
             - attoparsec
-            - base
             - base16-bytestring
             - base64-bytestring
             - bytestring
diff --git a/src/Crypto/Noise.hs b/src/Crypto/Noise.hs
--- a/src/Crypto/Noise.hs
+++ b/src/Crypto/Noise.hs
@@ -92,7 +92,7 @@
   (ns ^. nsSendingCipherState)
   where
     ctToMsg       = arr cipherTextToBytes
-    updateState   = arr $ \cs -> ns & nsSendingCipherState .~ Just cs
+    updateState   = arr $ \cs -> ns & nsSendingCipherState ?~ cs
     encryptMsg cs = (ctToMsg *** updateState) <$> encryptWithAd mempty msg cs
 
 -- | Reads a handshake or transport message and returns the embedded payload. If
@@ -115,7 +115,7 @@
   (ns ^. nsReceivingCipherState)
   where
     ct'           = cipherBytesToText ct
-    updateState   = arr $ \cs -> ns & nsReceivingCipherState .~ Just cs
+    updateState   = arr $ \cs -> ns & nsReceivingCipherState ?~ cs
     decryptMsg cs = second updateState <$> decryptWithAd mempty ct' cs
 
 -- | Given an operation ('writeMessage' or 'readMessage'), a list of PSKs, and
diff --git a/src/Crypto/Noise/DH/Curve448.hs b/src/Crypto/Noise/DH/Curve448.hs
--- a/src/Crypto/Noise/DH/Curve448.hs
+++ b/src/Crypto/Noise/DH/Curve448.hs
@@ -12,7 +12,7 @@
 
 import Crypto.Error          (throwCryptoError, maybeCryptoError)
 import Crypto.Random.Entropy (getEntropy)
-import qualified Crypto.PubKey.Ed448 as C
+import qualified Crypto.PubKey.Curve448 as C
 import Crypto.Noise.DH
 import Data.ByteArray        (ScrubbedBytes, convert)
 
diff --git a/src/Crypto/Noise/Internal/Handshake/Interpreter.hs b/src/Crypto/Noise/Internal/Handshake/Interpreter.hs
--- a/src/Crypto/Noise/Internal/Handshake/Interpreter.hs
+++ b/src/Crypto/Noise/Internal/Handshake/Interpreter.hs
@@ -20,7 +20,7 @@
 import Crypto.Noise.DH
 import Crypto.Noise.Exception
 import Crypto.Noise.Hash
-import Crypto.Noise.Internal.Handshake.Pattern hiding (e, s, ee, es, se, ss)
+import Crypto.Noise.Internal.Handshake.Pattern hiding (ss)
 import Crypto.Noise.Internal.Handshake.State
 import Crypto.Noise.Internal.CipherState
 import Crypto.Noise.Internal.SymmetricState
diff --git a/src/Crypto/Noise/Internal/Handshake/Pattern.hs b/src/Crypto/Noise/Internal/Handshake/Pattern.hs
--- a/src/Crypto/Noise/Internal/Handshake/Pattern.hs
+++ b/src/Crypto/Noise/Internal/Handshake/Pattern.hs
@@ -10,6 +10,7 @@
 import Control.Applicative.Free
 import Control.Lens
 import Data.ByteString (ByteString)
+import Data.Semigroup (Semigroup(..))
 
 data Token next
   = E   next
@@ -94,6 +95,9 @@
     scanP (Psk _) = HasPSK True
     scanP _       = mempty
 
+instance Semigroup HasPSK where
+  (HasPSK a) <> (HasPSK b) = HasPSK $ a || b
+
 instance Monoid HasPSK where
-  mempty = HasPSK False
-  (HasPSK a) `mappend` (HasPSK b) = HasPSK $ a || b
+  mempty  = HasPSK False
+  mappend = (<>)
diff --git a/src/Crypto/Noise/Internal/Handshake/State.hs b/src/Crypto/Noise/Internal/Handshake/State.hs
--- a/src/Crypto/Noise/Internal/Handshake/State.hs
+++ b/src/Crypto/Noise/Internal/Handshake/State.hs
@@ -23,7 +23,7 @@
 import Crypto.Noise.Cipher
 import Crypto.Noise.DH
 import Crypto.Noise.Hash
-import Crypto.Noise.Internal.Handshake.Pattern hiding (e, s, ee, es, se, ss)
+import Crypto.Noise.Internal.Handshake.Pattern hiding (ss)
 import Crypto.Noise.Internal.SymmetricState
 
 -- | Represents the side of the conversation upon which a party resides.
diff --git a/src/Crypto/Noise/Internal/NoiseState.hs b/src/Crypto/Noise/Internal/NoiseState.hs
--- a/src/Crypto/Noise/Internal/NoiseState.hs
+++ b/src/Crypto/Noise/Internal/NoiseState.hs
@@ -76,7 +76,7 @@
           -- The handshake pattern has not finished running. Save the suspension
           -- and the mutated HandshakeState and return what was yielded.
           Left (Request req resp) -> do
-            let ns' = ns & nsHandshakeSuspension .~ Just (Handshake . resp)
+            let ns' = ns & nsHandshakeSuspension ?~ (Handshake . resp)
                          & nsHandshakeState      .~ hs
             return (req, ns')
           -- The handshake pattern has finished running. Create the CipherStates.
@@ -84,10 +84,10 @@
             let (cs1, cs2) = split (hs ^. hsSymmetricState)
 
                 ns'        = if hs ^. hsOpts . hoRole == InitiatorRole
-                               then ns & nsSendingCipherState   .~ Just cs1
-                                       & nsReceivingCipherState .~ Just cs2
-                               else ns & nsSendingCipherState   .~ Just cs2
-                                       & nsReceivingCipherState .~ Just cs1
+                               then ns & nsSendingCipherState   ?~ cs1
+                                       & nsReceivingCipherState ?~ cs2
+                               else ns & nsSendingCipherState   ?~ cs2
+                                       & nsReceivingCipherState ?~ cs1
 
                 ns''       = ns' & nsHandshakeState .~ hs
 
diff --git a/stack.yaml b/stack.yaml
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,4 +1,4 @@
-resolver: lts-8.19
+resolver: lts-12.16
 packages:
   - '.'
 extra-deps: []
diff --git a/tests/vectors/Types.hs b/tests/vectors/Types.hs
--- a/tests/vectors/Types.hs
+++ b/tests/vectors/Types.hs
@@ -1,15 +1,15 @@
 {-# LANGUAGE RecordWildCards, RankNTypes, GADTs, KindSignatures #-}
 module Types where
 
-import Control.Monad      (mzero)
 import Data.Aeson
-import Data.Aeson.Types   (typeMismatch)
+import Data.Aeson.Types      (typeMismatch)
 import Data.Attoparsec.ByteString.Char8
-import Data.Maybe         (fromMaybe)
-import Data.Monoid        ((<>))
-import Data.Text          (pack)
-import Data.Text.Encoding (encodeUtf8)
-import Data.Tuple         (swap)
+import Data.ByteString.Char8 (ByteString, unpack)
+import Data.Maybe            (fromMaybe)
+import Data.Monoid           ((<>))
+import Data.Text             (pack)
+import Data.Text.Encoding    (encodeUtf8)
+import Data.Tuple            (swap)
 
 import Crypto.Noise
 import Crypto.Noise.Cipher.ChaChaPoly1305
@@ -91,7 +91,7 @@
 data SomeHashType where
   WrapHashType :: forall h. Hash h => HashType h -> SomeHashType
 
-patternMap :: [(String, PatternName)]
+patternMap :: [(ByteString, PatternName)]
 patternMap =
   [ ("NN", PatternNN)
   , ("KN", PatternKN)
@@ -131,19 +131,19 @@
   , ("Xpsk1" , PatternXpsk1)
   ]
 
-dhMap :: [(String, SomeDHType)]
+dhMap :: [(ByteString, SomeDHType)]
 dhMap =
   [ ("25519", WrapDHType Curve25519)
   , ("448"  , WrapDHType Curve448)
   ]
 
-cipherMap :: [(String, SomeCipherType)]
+cipherMap :: [(ByteString, SomeCipherType)]
 cipherMap =
   [ ("AESGCM"    , WrapCipherType AESGCM)
   , ("ChaChaPoly", WrapCipherType ChaChaPoly1305)
   ]
 
-hashMap :: [(String, SomeHashType)]
+hashMap :: [(ByteString, SomeHashType)]
 hashMap =
   [ ("BLAKE2b", WrapHashType BLAKE2b)
   , ("BLAKE2s", WrapHashType BLAKE2s)
@@ -155,15 +155,18 @@
 parseHandshakeName = do
   _ <- string "Noise_"
 
-  let untilUnderscore = anyChar `manyTill'` (char '_')
-      untilEOI        = anyChar `manyTill'` endOfInput
+  let untilUnderscore = do
+        val <- takeWhile1 (/= '_')
+        skipWhile (== '_')
+        return val
 
+      untilEOI        = takeByteString
+
   pattern <- (flip lookup patternMap) <$> untilUnderscore
   dh      <- (flip lookup dhMap)      <$> untilUnderscore
   cipher  <- (flip lookup cipherMap)  <$> untilUnderscore
   hash    <- (flip lookup hashMap)    <$> untilEOI
 
-
   let mHandshakeName = do
         p <- pattern
         d <- dh
@@ -215,7 +218,7 @@
 
 instance FromJSON HandshakeName where
   parseJSON (String s) =
-    either (const mzero) pure $ parseOnly parseHandshakeName (encodeUtf8 s)
+    either fail pure $ parseOnly parseHandshakeName (encodeUtf8 s)
   parseJSON bad        = typeMismatch "HandshakeName" bad
 
 instance ToJSON HandshakeName where
@@ -232,7 +235,7 @@
                           <> show hsHash
 
 instance Show PatternName where
-  show = fromMaybe "unknown" . flip lookup (map swap patternMap)
+  show = unpack . fromMaybe "unknown" . flip lookup (map swap patternMap)
 
 instance Show SomeCipherType where
   show (WrapCipherType ChaChaPoly1305) = "ChaChaPoly"
diff --git a/tools/noise-repl/Socket.hs b/tools/noise-repl/Socket.hs
--- a/tools/noise-repl/Socket.hs
+++ b/tools/noise-repl/Socket.hs
@@ -2,7 +2,7 @@
 
 import Data.ByteString.Char8
 import Data.Monoid           ((<>))
-import Network.Socket hiding (send, sendTo, recv, recvFrom)
+import Network.Socket hiding (recvFrom)
 import Network.Socket.ByteString
 import Prelude hiding        (putStrLn)
 import System.Exit           (exitFailure)
