A library implementing the Noise protocol.

Version on this page:0.6.0
LTS Haskell 21.13:0.10.1
Stackage Nightly 2023-09-24:0.10.1
Latest on Hackage:0.10.1

See all snapshots cacophony appears in

LicenseRef-PublicDomain licensed by John Galt
Maintained by
This version can be pinned in stack with:cacophony-0.6.0@sha256:9af4e79de2199a3e45536615e01fd13062540ddbd354edcce1fede39eb1bdc95,4431

Module documentation for 0.6.0


Build Status Haskell

This library implements the Noise protocol.

Basic usage

  1. Import the modules for the kind of handshake you’d like to use.

    For example, if you want to use Noise_IK_25519_AESGCM_SHA256, your imports would be:

    import Crypto.Noise.Cipher.AESGCM
    import Crypto.Noise.Curve.Curve25519
    import Crypto.Noise.Hash.SHA256
    import Crypto.Noise.Handshake
    import Crypto.Noise.HandshakePatterns (noiseIK)
  2. Define the functions that will be called during various stages of the handshake.

    writeMsg   :: ByteString -> IO ()
    readMsg    :: IO ByteString
    payloadIn  :: Plaintext -> IO ()
    payloadOut :: IO Plaintext
    staticIn   :: PublicKey d -> IO Bool

    writeMsg and readMsg will typically be functions that write to and read from a socket.

    The payloadIn and payloadOut functions are called when payloads are received and needed.

    The staticIn function is called when a static key is received from the remote peer. If this function returns False, the handshake is immediately aborted. Otherwise, it continues normally. See the documentation of HandshakeCallbacks for details.

    If you don’t need to use payloads and want to accept all remote static keys, do the following:

    let hc = HandshakeCallbacks (writeMsg socket)
                                 (readMsg socket)
                                 (\_ -> return ())
                                 (return "")
                                 (\_ -> return True)
  3. Create the handshake state.

    Select a handshake pattern to use. Patterns are defined in the Crypto.Noise.HandshakePatterns module. Ensure that you provide the keys which are required by the handshake pattern you choose. For example, the Noise_IK pattern requires that the initiator provides a local static key and a remote static key. Remote keys are communicated out-of-band.

    let initiatorState = handshakeState $ HandshakeOpts
       (Just "pre-shared-key")
       (Just local_static_key)
       Nothing                  -- local ephemeral key
       (Just remote_static_key) -- communicated out-of-band
       Nothing                  -- remote ephemeral key
       True                     -- we are the initiator
    let responderState = handshakeState $ HandshakeOpts
       (Just "pre-shared-key")
       (Just local_static_key)
       Nothing -- local ephemeral key
       Nothing -- we don't know their static key yet
       Nothing -- remote ephemeral key
       False   -- we are the responder
  4. Run the handshake:

    (encryptionCipherState, decryptionCipherState) <- runHandshake initiatorState hc
    (encryptionCipherState, decryptionCipherState) <- runHandshake responderState hc
  5. Send and receive transport messages:

    let (cipherText, encryptionCipherState') = encryptPayload "hello world" encryptionCipherState
    let (Plaintext pt, decryptionCipherState') = decryptPayload msg decryptionCipherState

    Ensure that you never re-use a cipher state.

Example code

An echo-server and echo-client are located within the examples/ directory. The binary protocol is as follows:

C -> S: [pattern byte] [cipher byte] [curve byte] [hash byte]
C -> S: [num bytes (uint16 big endian)] [message]
S -> C: [num bytes (uint16 big endian)] [message]

message is any raw Noise handshake or message data.

Byte definitions

byte pattern cipher curve hash
0 NN ChaChaPoly 25519 SHA256
1 KN AESGCM 448 SHA512
4 NX
5 KX
6 XN
7 IN
8 XK
9 IK
a XX
b IX
c XR



  • Added ability to abort handshakes based on the remote party’s public key

  • Improved documentation

  • Factored out ScrubbedBytes utilities to separate module

  • Added echo-server and echo-client example

  • Renamed HandshakeStateParams to HandshakeOpts


  • Added Curve448 support

  • Major refactoring and API changes A DSL was created to represent handshake patterns.

  • Added GHC 7.10.3 to unit tests


  • Improved documentation

  • Added basic benchmarks

  • Added better exception handling

  • Improved handshakeState API

  • Added psk2 functionality

  • Unit test cleanup

  • Renamed symmetricHandshake to symmetricState

  • Added BLAKE2, SHA512, AESGCM support


  • Brought API up to date with current version of spec (17)


  • Added support for one-way handshakes

  • Fixed Noise_IX

  • Added helper functions for ScrubbedBytes / ByteString conversion

  • First version.