packages feed

cacophony-0.7.0: benchmarks/bench.hs

{-# LANGUAGE OverloadedStrings, GADTs #-}
module Main where

import Criterion.Main
import Data.ByteString        (ByteString)
import Data.ByteString.Base16 (decode)
import Data.List              (replicate)
import Data.Maybe             (fromJust)
import Data.Monoid            ((<>))
import Prelude hiding         (replicate)

import Crypto.Noise
import Crypto.Noise.Cipher
import Crypto.Noise.DH
import Crypto.Noise.Hash
import Data.ByteArray.Extend hiding (replicate)

import Handshakes
import Types

hexToScrubbedBytes :: ByteString
                   -> ScrubbedBytes
hexToScrubbedBytes = convert . fst . decode

hexToPair :: DH d
          => ByteString
          -> KeyPair d
hexToPair = fromJust . dhBytesToPair . convert . fst . decode

initiatorEphemeral :: DH d
                   => DHType d
                   -> KeyPair d
initiatorEphemeral DTCurve25519 = hexToPair "893e28b9dc6ca8d611ab664754b8ceb7bac5117349a4439a6b0569da977c464a"
initiatorEphemeral DTCurve448 = hexToPair "7fd26c8b8a0d5c98c85ff9ca1d7bc66d78578b9f2c4c170850748b27992767e6ea6cc9992a561c9d19dfc342e260c280ef4f3f9b8f879d4e"

responderEphemeral :: DH d
                   => DHType d
                   -> KeyPair d
responderEphemeral DTCurve25519 = hexToPair "bbdb4cdbd309f1a1f2e1456967fe288cadd6f712d65dc7b7793d5e63da6b375b"
responderEphemeral DTCurve448 = hexToPair "3facf7503ebee252465689f1d4e3b1dd219639ef9de4ffd6049d6d71a0f62126840febb99042421ce12af6626d98d9170260390fbc8399a5"

initiatorStatic :: DH d
                => DHType d
                -> KeyPair d
initiatorStatic DTCurve25519 = hexToPair "e61ef9919cde45dd5f82166404bd08e38bceb5dfdfded0a34c8df7ed542214d1"
initiatorStatic DTCurve448 = hexToPair "34d564c4be963d1b2a89fcfe83e6a72b5e3f5e3127f9f596ffc7575e418dfc1f4e827cfc10c9fed38e92ad56ddf8f08571430df2e76d5411"

responderStatic :: DH d
                => DHType d
                -> KeyPair d
responderStatic DTCurve25519 = hexToPair "4a3acbfdb163dec651dfa3194dece676d437029c62a408b4c5ea9114246e4893"
responderStatic DTCurve448 = hexToPair "a9b45971180882a79b89a3399544a425ef8136d278efa443ed67d3ff9d36e883bc330c6295bbf6ed73ff6fd10cbed767ad05ce03ebd27c7c"

mkKeys :: DH d
       => ScrubbedBytes
       -> Maybe ScrubbedBytes
       -> Bool
       -> DHType d
       -> HandshakeKeys d
mkKeys pro psk i d =
  HandshakeKeys { hkPrologue       = pro
                , hkPSK            = psk
                , hkLocalStatic    = if i then initiatorStatic d else responderStatic d
                , hkLocalEphemeral = if i then initiatorEphemeral d else responderEphemeral d
                , hkRemoteStatic   = if i then (snd . responderStatic) d else (snd . initiatorStatic) d
                }

mkHandshakeName :: HandshakeType
                -> Maybe ScrubbedBytes
                -> SomeCipherType
                -> SomeDHType
                -> SomeHashType
                -> String
mkHandshakeName pat psk (WrapCipherType c) (WrapDHType d) (WrapHashType h) =
  maybe "Noise_" (const "NoisePSK_") psk <>
  show pat                               <>
  "_"                                    <>
  show d                                 <>
  "_"                                    <>
  show c                                 <>
  "_"                                    <>
  show h

genMessages :: (Cipher c, DH d, Hash h)
            => Bool
            -> NoiseState c d h
            -> NoiseState c d h
            -> [ScrubbedBytes]
            -> [(ScrubbedBytes, ScrubbedBytes)]
genMessages swap = go []
  where
    go acc _ _ [] = acc
    go acc sendingState receivingState (payload : rest) =
      let writeResult           = writeMessage sendingState payload
          (ct, sendingState')   = either (error "write failed") id writeResult
          (dp, receivingState') = either (error "read failed")
                                         id
                                         $ readMessage receivingState ct in
      if swap
        then go (acc <> [(payload, dp)]) receivingState' sendingState' rest
        else go (acc <> [(payload, dp)]) sendingState' receivingState' rest

mkBench :: (HandshakeType, Int)
        -> Maybe ScrubbedBytes
        -> SomeCipherType
        -> SomeDHType
        -> SomeHashType
        -> [(ScrubbedBytes, ScrubbedBytes)]
mkBench (pat, numMsgs) psk (WrapCipherType c) (WrapDHType d) (WrapHashType h) =
  let ihk = mkKeys "" psk True d
      rhk = mkKeys "" psk False d
      ins = mkNoiseState ihk pat InitiatorRole c h
      rns = mkNoiseState rhk pat ResponderRole c h
      swap = not (pat == NoiseN || pat == NoiseK || pat == NoiseX) in

  genMessages swap ins rns $ replicate numMsgs ""

main :: IO ()
main = do
  let patterns = [ (NoiseNN, 2)
                 , (NoiseKN, 2)
                 , (NoiseNK, 2)
                 , (NoiseKK, 2)
                 , (NoiseNX, 2)
                 , (NoiseKX, 2)
                 , (NoiseXN, 3)
                 , (NoiseIN, 2)
                 , (NoiseXK, 3)
                 , (NoiseIK, 2)
                 , (NoiseXX, 3)
                 , (NoiseIX, 2)
                 , (NoiseN, 1)
                 , (NoiseK, 1)
                 , (NoiseX, 1)
                 ]
      psks     = [Nothing, Just ""]
      ciphers  = [WrapCipherType CTChaChaPoly1305, WrapCipherType CTAESGCM]
      dhs      = [WrapDHType DTCurve25519, WrapDHType DTCurve448]
      hashes   = [WrapHashType HTSHA256, WrapHashType HTSHA512, WrapHashType HTBLAKE2s, WrapHashType HTBLAKE2b]
      benches  = [bench (mkHandshakeName pat psk c d h) (nf (mkBench patPair psk c d) h) | patPair@(pat, _) <- patterns, psk <- psks, c <- ciphers, d <- dhs, h <- hashes]

  defaultMain benches