1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE ExistentialQuantification #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE TypeFamilies #-}
5module Main where
6
7import Gauge.Main
8
9import           Crypto.Cipher.AES
10import qualified Crypto.Cipher.AESGCMSIV as AESGCMSIV
11import           Crypto.Cipher.Blowfish
12import           Crypto.Cipher.CAST5
13import qualified Crypto.Cipher.ChaChaPoly1305 as CP
14import           Crypto.Cipher.DES
15import           Crypto.Cipher.Twofish
16import           Crypto.Cipher.Types
17import           Crypto.ECC
18import           Crypto.Error
19import           Crypto.Hash
20import qualified Crypto.KDF.BCrypt as BCrypt
21import qualified Crypto.KDF.PBKDF2 as PBKDF2
22import           Crypto.Number.Basic (numBits)
23import           Crypto.Number.Generate
24import qualified Crypto.PubKey.DH as DH
25import qualified Crypto.PubKey.ECC.Types as ECC
26import qualified Crypto.PubKey.ECC.Prim as ECC
27import qualified Crypto.PubKey.ECDSA as ECDSA
28import qualified Crypto.PubKey.Ed25519 as Ed25519
29import qualified Crypto.PubKey.EdDSA as EdDSA
30import           Crypto.Random
31
32import           Control.DeepSeq (NFData)
33import           Data.ByteArray (ByteArray, Bytes)
34import qualified Data.ByteString as B
35
36import qualified Crypto.PubKey.ECC.P256 as P256
37
38import Number.F2m
39
40data HashAlg = forall alg . HashAlgorithm alg => HashAlg alg
41
42benchHash =
43    [ env oneKB $ \b -> bgroup "1KB" $ map (doHashBench b) hashAlgs
44    , env oneMB $ \b -> bgroup "1MB" $ map (doHashBench b) hashAlgs
45    ]
46  where
47    doHashBench b (name, HashAlg alg) = bench name $ nf (hashWith alg) b
48
49    oneKB :: IO Bytes
50    oneKB = getRandomBytes 1024
51
52    oneMB :: IO Bytes
53    oneMB = getRandomBytes $ 1024 * 1024
54
55    hashAlgs =
56        [ ("MD2", HashAlg MD2)
57        , ("MD4", HashAlg MD4)
58        , ("MD5", HashAlg MD5)
59        , ("SHA1", HashAlg SHA1)
60        , ("SHA224", HashAlg SHA224)
61        , ("SHA256", HashAlg SHA256)
62        , ("SHA384", HashAlg SHA384)
63        , ("SHA512", HashAlg SHA512)
64        , ("SHA512t_224", HashAlg SHA512t_224)
65        , ("SHA512t_256", HashAlg SHA512t_256)
66        , ("RIPEMD160", HashAlg RIPEMD160)
67        , ("Tiger", HashAlg Tiger)
68        --, ("Skein256-160", HashAlg Skein256_160)
69        , ("Skein256-256", HashAlg Skein256_256)
70        --, ("Skein512-160", HashAlg Skein512_160)
71        , ("Skein512-384", HashAlg Skein512_384)
72        , ("Skein512-512", HashAlg Skein512_512)
73        --, ("Skein512-896", HashAlg Skein512_896)
74        , ("Whirlpool", HashAlg Whirlpool)
75        , ("Keccak-224", HashAlg Keccak_224)
76        , ("Keccak-256", HashAlg Keccak_256)
77        , ("Keccak-384", HashAlg Keccak_384)
78        , ("Keccak-512", HashAlg Keccak_512)
79        , ("SHA3-224", HashAlg SHA3_224)
80        , ("SHA3-256", HashAlg SHA3_256)
81        , ("SHA3-384", HashAlg SHA3_384)
82        , ("SHA3-512", HashAlg SHA3_512)
83        , ("Blake2b-160", HashAlg Blake2b_160)
84        , ("Blake2b-224", HashAlg Blake2b_224)
85        , ("Blake2b-256", HashAlg Blake2b_256)
86        , ("Blake2b-384", HashAlg Blake2b_384)
87        , ("Blake2b-512", HashAlg Blake2b_512)
88        , ("Blake2s-160", HashAlg Blake2s_160)
89        , ("Blake2s-224", HashAlg Blake2s_224)
90        , ("Blake2s-256", HashAlg Blake2s_256)
91        ]
92
93benchPBKDF2 =
94    [ bgroup "64"
95        [ bench "cryptonite-PBKDF2-100-64" $ nf (pbkdf2 64) 100
96        , bench "cryptonite-PBKDF2-1000-64" $ nf (pbkdf2 64) 1000
97        , bench "cryptonite-PBKDF2-10000-64" $ nf (pbkdf2 64) 10000
98        ]
99    , bgroup "128"
100        [ bench "cryptonite-PBKDF2-100-128" $ nf (pbkdf2 128) 100
101        , bench "cryptonite-PBKDF2-1000-128" $ nf (pbkdf2 128) 1000
102        , bench "cryptonite-PBKDF2-10000-128" $ nf (pbkdf2 128) 10000
103        ]
104    ]
105  where
106        pbkdf2 :: Int -> Int -> B.ByteString
107        pbkdf2 n iter = PBKDF2.generate (PBKDF2.prfHMAC SHA512) (params n iter) mypass mysalt
108
109        mypass, mysalt :: B.ByteString
110        mypass = "password"
111        mysalt = "salt"
112
113        params n iter = PBKDF2.Parameters iter n
114
115benchBCrypt =
116    [ bench "cryptonite-BCrypt-4"  $ nf bcrypt 4
117    , bench "cryptonite-BCrypt-5"  $ nf bcrypt 5
118    , bench "cryptonite-BCrypt-7"  $ nf bcrypt 7
119    , bench "cryptonite-BCrypt-11" $ nf bcrypt 11
120    ]
121  where
122        bcrypt :: Int -> B.ByteString
123        bcrypt cost = BCrypt.bcrypt cost mysalt mypass
124
125        mypass, mysalt :: B.ByteString
126        mypass = "password"
127        mysalt = "saltsaltsaltsalt"
128
129benchBlockCipher =
130    [ bgroup "ECB" benchECB
131    , bgroup "CBC" benchCBC
132    ]
133  where
134        benchECB =
135            [ bench "DES-input=1024" $ nf (run (undefined :: DES) cipherInit key8) input1024
136            , bench "Blowfish128-input=1024" $ nf (run (undefined :: Blowfish128) cipherInit key16) input1024
137            , bench "Twofish128-input=1024" $ nf (run (undefined :: Twofish128) cipherInit key16) input1024
138            , bench "CAST5-128-input=1024" $ nf (run (undefined :: CAST5) cipherInit key16) input1024
139            , bench "AES128-input=1024" $ nf (run (undefined :: AES128) cipherInit key16) input1024
140            , bench "AES256-input=1024" $ nf (run (undefined :: AES256) cipherInit key32) input1024
141            ]
142          where run :: (ByteArray ba, ByteArray key, BlockCipher c)
143                    => c -> (key -> CryptoFailable c) -> key -> ba -> ba
144                run _witness initF key input =
145                    (ecbEncrypt (throwCryptoError (initF key))) input
146
147        benchCBC =
148            [ bench "DES-input=1024" $ nf (run (undefined :: DES) cipherInit key8 iv8) input1024
149            , bench "Blowfish128-input=1024" $ nf (run (undefined :: Blowfish128) cipherInit key16 iv8) input1024
150            , bench "Twofish128-input=1024" $ nf (run (undefined :: Twofish128) cipherInit key16 iv16) input1024
151            , bench "CAST5-128-input=1024" $ nf (run (undefined :: CAST5) cipherInit key16 iv8) input1024
152            , bench "AES128-input=1024" $ nf (run (undefined :: AES128) cipherInit key16 iv16) input1024
153            , bench "AES256-input=1024" $ nf (run (undefined :: AES256) cipherInit key32 iv16) input1024
154            ]
155          where run :: (ByteArray ba, ByteArray key, BlockCipher c)
156                    => c -> (key -> CryptoFailable c) -> key -> IV c -> ba -> ba
157                run _witness initF key iv input =
158                    (cbcEncrypt (throwCryptoError (initF key))) iv input
159
160        key8  = B.replicate 8 0
161        key16 = B.replicate 16 0
162        key32 = B.replicate 32 0
163        input1024 = B.replicate 1024 0
164
165        iv8 :: BlockCipher c => IV c
166        iv8  = maybe (error "iv size 8") id  $ makeIV key8
167
168        iv16 :: BlockCipher c => IV c
169        iv16 = maybe (error "iv size 16") id $ makeIV key16
170
171benchAE =
172    [ bench "ChaChaPoly1305" $ nf (cp key32) (input64, input1024)
173    , bench "AES-GCM" $ nf (gcm key32) (input64, input1024)
174    , bench "AES-CCM" $ nf (ccm key32) (input64, input1024)
175    , bench "AES-GCM-SIV" $ nf (gcmsiv key32) (input64, input1024)
176    ]
177  where cp k (ini, plain) =
178            let iniState            = throwCryptoError $ CP.initialize k (throwCryptoError $ CP.nonce12 nonce12)
179                afterAAD            = CP.finalizeAAD (CP.appendAAD ini iniState)
180                (out, afterEncrypt) = CP.encrypt plain afterAAD
181                outtag              = CP.finalize afterEncrypt
182             in (outtag, out)
183
184        gcm k (ini, plain) =
185            let ctx = throwCryptoError (cipherInit k) :: AES256
186                state = throwCryptoError $ aeadInit AEAD_GCM ctx nonce12
187             in aeadSimpleEncrypt state ini plain 16
188
189        ccm k (ini, plain) =
190            let ctx = throwCryptoError (cipherInit k) :: AES256
191                mode = AEAD_CCM 1024 CCM_M16 CCM_L3
192                state = throwCryptoError $ aeadInit mode ctx nonce12
193             in aeadSimpleEncrypt state ini plain 16
194
195        gcmsiv k (ini, plain) =
196            let ctx = throwCryptoError (cipherInit k) :: AES256
197                iv = throwCryptoError (AESGCMSIV.nonce nonce12)
198             in AESGCMSIV.encrypt ctx iv ini plain
199
200        input64 = B.replicate 64 0
201        input1024 = B.replicate 1024 0
202
203        nonce12 :: B.ByteString
204        nonce12 = B.replicate 12 0
205
206        key32 = B.replicate 32 0
207
208benchECC =
209    [ bench "pointAddTwoMuls-baseline"  $ nf run_b (n1, p1, n2, p2)
210    , bench "pointAddTwoMuls-optimized" $ nf run_o (n1, p1, n2, p2)
211    , bench "pointAdd-ECC" $ nf run_c (p1, p2)
212    , bench "pointMul-ECC" $ nf run_d (n1, p2)
213    ]
214  where run_b (n, p, k, q) = ECC.pointAdd c (ECC.pointMul c n p)
215                                            (ECC.pointMul c k q)
216
217        run_o (n, p, k, q) = ECC.pointAddTwoMuls c n p k q
218        run_c (p, q) = ECC.pointAdd c p q
219        run_d (n, p) = ECC.pointMul c n p
220
221        c  = ECC.getCurveByName ECC.SEC_p256r1
222        p1 = ECC.pointBaseMul c n1
223        p2 = ECC.pointBaseMul c n2
224        n1 = 0x2ba9daf2363b2819e69b34a39cf496c2458a9b2a21505ea9e7b7cbca42dc7435
225        n2 = 0xf054a7f60d10b8c2cf847ee90e9e029f8b0e971b09ca5f55c4d49921a11fadc1
226
227benchP256 =
228    [ bench "pointAddTwoMuls-P256"  $ nf run_p (n1, p1, n2, p2)
229    , bench "pointAdd-P256"  $ nf run_q (p1, p2)
230    , bench "pointMul-P256"  $ nf run_t (n1, p1)
231    ]
232  where run_p (n, p, k, q) = P256.pointAdd (P256.pointMul n p) (P256.pointMul k q)
233        run_q (p, q) = P256.pointAdd p q
234        run_t (n, p) = P256.pointMul n p
235
236        xS = 0xde2444bebc8d36e682edd27e0f271508617519b3221a8fa0b77cab3989da97c9
237        yS = 0xc093ae7ff36e5380fc01a5aad1e66659702de80f53cec576b6350b243042a256
238        xT = 0x55a8b00f8da1d44e62f6b3b25316212e39540dc861c89575bb8cf92e35e0986b
239        yT = 0x5421c3209c2d6c704835d82ac4c3dd90f61a8a52598b9e7ab656e9d8c8b24316
240        p1 = P256.pointFromIntegers (xS, yS)
241        p2 = P256.pointFromIntegers (xT, yT)
242        n1 = throwCryptoError $ P256.scalarFromInteger 0x2ba9daf2363b2819e69b34a39cf496c2458a9b2a21505ea9e7b7cbca42dc7435
243        n2 = throwCryptoError $ P256.scalarFromInteger 0xf054a7f60d10b8c2cf847ee90e9e029f8b0e971b09ca5f55c4d49921a11fadc1
244
245
246
247benchFFDH = map doFFDHBench primes
248  where
249    doFFDHBench (e, p) =
250        let bits = numBits p
251            params = DH.Params { DH.params_p = p, DH.params_g = 2, DH.params_bits = bits }
252         in env (generate e params) $ bench (show bits) . nf (run params)
253
254    generate e params = do
255        aPriv <- DH.PrivateNumber `fmap` generatePriv e
256        bPriv <- DH.PrivateNumber `fmap` generatePriv e
257        return (aPriv, DH.calculatePublic params bPriv)
258
259    generatePriv e = generateParams e (Just SetHighest) False
260
261    run params (priv, pub) = DH.getShared params priv pub
262
263    -- RFC 7919: prime p with minimal size of exponent
264    primes = [ (225, 0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B423861285C97FFFFFFFFFFFFFFFF)
265             , (275, 0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF)
266             , (325, 0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6AFFFFFFFFFFFFFFFF)
267             , (375, 0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD9020BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA63BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3ACDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477A52471F7A9A96910B855322EDB6340D8A00EF092350511E30ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538CD72B03746AE77F5E62292C311562A846505DC82DB854338AE49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B045B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF)
268             , (400, 0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD9020BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA63BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3ACDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477A52471F7A9A96910B855322EDB6340D8A00EF092350511E30ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538CD72B03746AE77F5E62292C311562A846505DC82DB854338AE49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B045B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C8381E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665CB2C0F1CC01BD70229388839D2AF05E454504AC78B7582822846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA4571EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88CD68C8BB7C5C6424CFFFFFFFFFFFFFFFF)
269             ]
270
271data CurveDH = forall c . (EllipticCurveDH c, NFData (Scalar c), NFData (Point c)) => CurveDH c
272
273benchECDH = map doECDHBench curves
274  where
275    doECDHBench (name, CurveDH c) =
276        let proxy = Just c -- using Maybe as Proxy
277         in env (generate proxy) $ bench name . nf (run proxy)
278
279    generate proxy = do
280        KeyPair _      aScalar <- curveGenerateKeyPair proxy
281        KeyPair bPoint _       <- curveGenerateKeyPair proxy
282        return (aScalar, bPoint)
283
284    run proxy (s, p) = throwCryptoError (ecdh proxy s p)
285
286    curves = [ ("P256R1", CurveDH Curve_P256R1)
287             , ("P384R1", CurveDH Curve_P384R1)
288             , ("P521R1", CurveDH Curve_P521R1)
289             , ("X25519", CurveDH Curve_X25519)
290             , ("X448",   CurveDH Curve_X448)
291             ]
292
293data CurveHashECDSA =
294    forall curve hashAlg . (ECDSA.EllipticCurveECDSA curve,
295                            NFData (Scalar curve),
296                            NFData (Point curve),
297                            HashAlgorithm hashAlg) => CurveHashECDSA curve hashAlg
298
299benchECDSA = map doECDSABench curveHashes
300  where
301    doECDSABench (name, CurveHashECDSA c hashAlg) =
302        let proxy = Just c -- using Maybe as Proxy
303         in bgroup name
304                [ env (signGenerate proxy) $ bench "sign" . nfIO . signRun proxy hashAlg
305                , env (verifyGenerate proxy hashAlg) $ bench "verify" . nf (verifyRun proxy hashAlg)
306                ]
307
308    signGenerate proxy = do
309        m <- tenKB
310        s <- curveGenerateScalar proxy
311        return (s, m)
312
313    signRun proxy hashAlg (priv, msg) = ECDSA.sign proxy priv hashAlg msg
314
315    verifyGenerate proxy hashAlg = do
316        m <- tenKB
317        KeyPair p s <- curveGenerateKeyPair proxy
318        sig <- ECDSA.sign proxy s hashAlg m
319        return (p, sig, m)
320
321    verifyRun proxy hashAlg (pub, sig, msg) = ECDSA.verify proxy hashAlg pub sig msg
322
323    tenKB :: IO Bytes
324    tenKB = getRandomBytes 10240
325
326    curveHashes = [ ("secp256r1_sha256", CurveHashECDSA Curve_P256R1 SHA256)
327                  , ("secp384r1_sha384", CurveHashECDSA Curve_P384R1 SHA384)
328                  , ("secp521r1_sha512", CurveHashECDSA Curve_P521R1 SHA512)
329                  ]
330
331benchEdDSA =
332    [ bgroup "EdDSA-Ed25519" benchGenEd25519
333    , bgroup "Ed25519"       benchEd25519
334    ]
335  where
336    benchGen prx alg =
337        [ bench "sign"   $ perBatchEnv (genEnv prx alg) (run_gen_sign   prx)
338        , bench "verify" $ perBatchEnv (genEnv prx alg) (run_gen_verify prx)
339        ]
340
341    benchGenEd25519 = benchGen (Just Curve_Edwards25519) SHA512
342    benchEd25519    =
343        [ bench "sign"   $ perBatchEnv ed25519Env run_ed25519_sign
344        , bench "verify" $ perBatchEnv ed25519Env run_ed25519_verify
345        ]
346
347    msg = B.empty -- empty message = worst-case scenario showing API overhead
348
349    genEnv prx alg _ = do
350        sec <- EdDSA.generateSecretKey prx
351        let pub = EdDSA.toPublic prx alg sec
352            sig = EdDSA.sign prx sec pub msg
353        return (sec, pub, sig)
354
355    run_gen_sign prx (sec, pub, _) = return (EdDSA.sign prx sec pub msg)
356
357    run_gen_verify prx (_, pub, sig) = return (EdDSA.verify prx pub msg sig)
358
359    ed25519Env _ = do
360        sec <- Ed25519.generateSecretKey
361        let pub = Ed25519.toPublic sec
362            sig = Ed25519.sign sec pub msg
363        return (sec, pub, sig)
364
365    run_ed25519_sign (sec, pub, _) = return (Ed25519.sign sec pub msg)
366
367    run_ed25519_verify (_, pub, sig) = return (Ed25519.verify pub msg sig)
368
369main = defaultMain
370    [ bgroup "hash" benchHash
371    , bgroup "block-cipher" benchBlockCipher
372    , bgroup "AE" benchAE
373    , bgroup "pbkdf2" benchPBKDF2
374    , bgroup "bcrypt" benchBCrypt
375    , bgroup "ECC" benchECC
376    , bgroup "P256" benchP256
377    , bgroup "DH"
378          [ bgroup "FFDH" benchFFDH
379          , bgroup "ECDH" benchECDH
380          ]
381    , bgroup "ECDSA" benchECDSA
382    , bgroup "EdDSA" benchEdDSA
383    , bgroup "F2m" benchF2m
384    ]
385