-- | Creates a handshake or transport message with the provided payload. Note
--   that the payload may not be authenticated or encrypted at all points during
--   the handshake. Please see section 7.4 of the protocol document for details.
--
--   If a previous call to this function indicated that a pre-shared key is
--   needed, it shall be provided as the payload. See the documentation of
--   'NoiseResult' for details.
--
--   To prevent catastrophic key re-use, this function may only be used to
--   secure 2^64 - 1 post-handshake messages.
writeMessage :: (Cipher c, DH d, Hash h)
             => ScrubbedBytes
             -> NoiseState c d h
             -> NoiseResult c d h
writeMessage msg ns = maybe
  (convertHandshakeResult $ resumeHandshake msg ns)
  (convertTransportResult . encryptMsg)
  (ns ^. nsSendingCipherState)
  where
    ctToMsg       = arr cipherTextToBytes
    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
--   the handshake fails, a 'HandshakeError' will be returned. After the
--   handshake is complete, if decryption fails a 'DecryptionError' is returned.
--
--   If a previous call to this function indicated that a pre-shared key is
--   needed, it shall be provided as the payload. See the documentation of
--   'NoiseResult' for details.
--
--   To prevent catastrophic key re-use, this function may only be used to
--   receive 2^64 - 1 post-handshake messages.
writeMessage :: (Cipher c, DH d, Hash h)
             => ScrubbedBytes
             -> NoiseState c d h
             -> NoiseResult c d h
writeMessage msg ns = maybe
  (convertHandshakeResult $ resumeHandshake msg ns)
  (convertTransportResult . encryptMsg)
  (ns ^. nsSendingCipherState)
  where
    ctToMsg       = arr cipherTextToBytes
    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
--   the handshake fails, a 'HandshakeError' will be returned. After the
--   handshake is complete, if decryption fails a 'DecryptionError' is returned.
--
--   If a previous call to this function indicated that a pre-shared key is
--   needed, it shall be provided as the payload. See the documentation of
--   'NoiseResult' for details.
--
--   To prevent catastrophic key re-use, this function may only be used to
--   receive 2^64 - 1 post-handshake messages.
writeMessage msg ns = maybe
  (convertHandshakeResult $ resumeHandshake msg ns)
  (convertTransportResult . encryptMsg)
  (ns ^. nsSendingCipherState)
  where
    ctToMsg       = arr cipherTextToBytes
    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
--   the handshake fails, a 'HandshakeError' will be returned. After the
--   handshake is complete, if decryption fails a 'DecryptionError' is returned.
--
--   If a previous call to this function indicated that a pre-shared key is
--   needed, it shall be provided as the payload. See the documentation of
--   'NoiseResult' for details.
--
--   To prevent catastrophic key re-use, this function may only be used to
--   receive 2^64 - 1 post-handshake messages.