cacophony: A library implementing the Noise protocol.

[ cryptography, library, public-domain ] [ Propose Tags ]
Versions [RSS], 0.2.0, 0.3.0, 0.4.0, 0.5.0, 0.6.0, 0.7.0, 0.8.0, 0.9.0, 0.9.1, 0.9.2, 0.10.0, 0.10.1 (info)
Change log
Dependencies base (>=4.9 && <5), bytestring, cryptonite (>=0.22), exceptions, free, lens, memory, monad-coroutine, mtl, safe-exceptions, transformers [details]
License LicenseRef-PublicDomain
Maintainer John Galt <>
Revised Revision 1 made by Bodigrim at 2024-05-06T13:30:10Z
Category Cryptography
Home page
Bug tracker
Source repo head: git clone
Uploaded by jgalt at 2018-10-29T23:41:59Z
Distributions LTSHaskell:0.10.1, Stackage:0.10.1
Reverse Dependencies 1 direct, 1 indirect [details]
Executables noise-repl
Downloads 8130 total (47 in the last 30 days)
Rating 2.0 (votes: 1) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2018-11-02 [all 1 reports]

Readme for cacophony-0.10.1

[back to package description]


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
    import Crypto.Noise.Cipher.AESGCM
    import Crypto.Noise.DH -- Used to generate and manipulate keys
    import Crypto.Noise.DH.Curve25519
    import Crypto.Noise.Hash.SHA256
    import Crypto.Noise.HandshakePatterns (noiseIK)
  2. Set the handshake parameters.

    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, while the responder is only responsible for a local static key. You can use defaultHandshakeOpts to return a default set of options in which all keys are set to Nothing. The initiator must set a local ephemeral key for all handshake patterns. The responder must set a local ephemeral key for all interactive (i.e. not one-way) patterns.

    -- Initiator
    localEphemeralKey <- dhGenKey :: IO (KeyPair Curve25519)
    let dho = defaultHandshakeOpts InitiatorRole "prologue" :: HandshakeOpts Curve25519
        iho = setLocalStatic      (Just localStaticKey)
              . setLocalEphemeral (Just localEphemeralKey)
              . setRemoteStatic   (Just remoteStaticKey) -- communicated out-of-band
              $ dho
    -- Responder
    localEphemeralKey <- dhGenKey :: IO (KeyPair Curve25519)
    let dho = defaultHandshakeOpts ResponderRole "prologue" :: HandshakeOpts Curve25519
        rho = setLocalStatic      (Just localStaticKey)
              . setLocalEphemeral (Just localEphemeralKey)
              $ dho
  3. Create the Noise state.

    -- Initiator
    let ins = noiseState iho noiseIK :: NoiseState AESGCM Curve25519 SHA256
    -- Responder
    let rns = noiseState rho noiseIK :: NoiseState AESGCM Curve25519 SHA256
  4. Send and receive messages.

    -- Initiator
    let writeResult = writeMessage "They must find it difficult -- those who have taken authority as the truth, rather than truth as the authority." ins
    case writeResult of
      NoiseResultMessage ciphertext ins' -> ...
      NoiseResultNeedPSK   _ -> error "something terrible happened" -- will never happen in Noise_IK
      NoiseResultException _ -> error "something terrible happened"
    -- Responder
    let readResult = readMessage ciphertext rns
    case readResult of
      NoiseResultMessage plaintext rns' -> ...
      NoiseResultNeedPSK   _ -> error "something terrible happened"
      NoiseResultException _ -> error "something terrible happened"

    Ensure that you never re-use a NoiseState to send more than one message.

    Decrypted messages are stored internally as ScrubbedBytes and will be wiped from memory when they are destroyed.

Helper Functions

The following functions are found in Crypto.Noise.DH and are used to manipulate keys:

  • dhGenKey -- Generate a fresh (private, public) key pair
  • dhPubToBytes -- Convert a public key to ScrubbedBytes
  • dhBytesToPub -- Convert ScrubbedBytes to a public key
  • dhSecToBytes -- Convert a private key to ScrubbedBytes
  • dhBytesToPair -- Convert ScrubbedBytes to a (private, public) key pair

The following functions are found in Crypto.Noise:

  • remoteStaticKey -- For handshake patterns where the remote party's static key is transmitted, this function can be used to retrieve it. This allows for the creation of public key-based access-control lists.

  • handshakeComplete -- Returns True if the handshake is complete.

  • processPSKs -- This function repeatedly applies PSKs to a NoiseState until the list of PSKs becomes empty or the handshake pattern stops asking for PSKs.

  • handshakeHash -- Retrieves the h value associated with the conversation's SymmetricState. This value is intended to be used for channel binding. For example, the initiator might cryptographically sign this value as part of some higher-level authentication scheme. See section 11.2 of the protocol for details.

  • 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


Test vectors can be generated and verified using the vectors program. It accepts no arguments. When run, it will check for the existence of vectors/cacophony.txt within the current working directory. If it is not found, it is generated. If it is found, it is verified. All files within the vectors/ directory (regardless of their name) are also verified. Note that this program can only generate and verify vectors whose handshake patterns are pre-defined in this library.

Custom Handshakes

If the built-in handshake patterns are insufficient for your application, you can define your own. Note that this should be done with care.


noiseFOOpsk0 :: HandshakePattern
noiseFOOpsk0 = handshakePattern "FOOpsk0" $
  preInitiator s            *>
  preResponder s            *>
  initiator (psk *> e *> es *> ss) *>
  responder (e *> ee *> se)

Handshake Validation

HandshakePatterns can be validated for compliance as described in sections 7.1 and 9.3 of the protocol:

λ> let noiseBAD = handshakePattern "BAD" $ preResponder ss *> initiator (e *> se *> e)
[DHInPreMsg (0,0),InitMultipleETokens (1,2),InitSecretNotRandom (1,3)]

λ> validateHandshakePattern noiseKKpsk0

See the Crypto.Noise.Validation module for details.


Vectors generated by the vector program are formatted as minified JSON. This python script takes the path to a vector file as an argument and reformats it so that it conforms to the style specified on the Noise Wiki.


This program acts as a kind of REPL for Noise messages. It supports sending and receiving messages via UDP or via a pipe to a shell command.

All messages transmitted via a pipe are expected to be prepended by a two byte big-endian length.