readMessage :: (Cipher c, DH d, Hash h)
            => ScrubbedBytes
            -> NoiseState c d h
            -> NoiseResult c d h
readMessage ct ns = maybe
  (convertHandshakeResult $ resumeHandshake ct ns)
  (convertTransportResult . decryptMsg)
  (ns ^. nsReceivingCipherState)
  where
    ct'           = cipherBytesToText ct
    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
--   a 'NoiseResult', this function will repeatedly apply PSKs to the NoiseState
--   until no more are requested or the list of PSKs becomes empty. This is
--   useful for patterns which require two or more PSKs, and you know exactly
--   what they all should be ahead of time.
readMessage :: (Cipher c, DH d, Hash h)
            => ScrubbedBytes
            -> NoiseState c d h
            -> NoiseResult c d h
readMessage ct ns = maybe
  (convertHandshakeResult $ resumeHandshake ct ns)
  (convertTransportResult . decryptMsg)
  (ns ^. nsReceivingCipherState)
  where
    ct'           = cipherBytesToText ct
    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
--   a 'NoiseResult', this function will repeatedly apply PSKs to the NoiseState
--   until no more are requested or the list of PSKs becomes empty. This is
--   useful for patterns which require two or more PSKs, and you know exactly
--   what they all should be ahead of time.
readMessage ct ns = maybe
  (convertHandshakeResult $ resumeHandshake ct ns)
  (convertTransportResult . decryptMsg)
  (ns ^. nsReceivingCipherState)
  where
    ct'           = cipherBytesToText ct
    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
--   a 'NoiseResult', this function will repeatedly apply PSKs to the NoiseState
--   until no more are requested or the list of PSKs becomes empty. This is
--   useful for patterns which require two or more PSKs, and you know exactly
--   what they all should be ahead of time.