{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}

{- FOURMOLU_DISABLE -}

module Bench.Crypto.DSIGN
  ( benchmarks
  ) where

import Data.Proxy
import Data.ByteString (ByteString)

import Control.DeepSeq

import Cardano.Crypto.DSIGN.Class
import Cardano.Crypto.DSIGN.Ed25519
#ifdef SECP256K1_ENABLED
import Cardano.Crypto.DSIGN.EcdsaSecp256k1
import Cardano.Crypto.DSIGN.SchnorrSecp256k1
import Cardano.Crypto.Hash.Blake2b
#endif

import Criterion

import Bench.Crypto.BenchData


benchmarks :: Benchmark
benchmarks :: Benchmark
benchmarks = String -> [Benchmark] -> Benchmark
bgroup String
"DSIGN"
  [ forall v a.
(DSIGNAlgorithm v, ContextDSIGN v ~ (), Signable v a,
 ExampleSignable v a, NFData (SignKeyDSIGN v),
 NFData (VerKeyDSIGN v), NFData (SigDSIGN v)) =>
Proxy v -> String -> Benchmark
benchDSIGN (forall {k} (t :: k). Proxy t
Proxy :: Proxy Ed25519DSIGN) String
"Ed25519"
#ifdef SECP256K1_ENABLED
  , forall v a.
(DSIGNAlgorithm v, ContextDSIGN v ~ (), Signable v a,
 ExampleSignable v a, NFData (SignKeyDSIGN v),
 NFData (VerKeyDSIGN v), NFData (SigDSIGN v)) =>
Proxy v -> String -> Benchmark
benchDSIGN (forall {k} (t :: k). Proxy t
Proxy :: Proxy EcdsaSecp256k1DSIGN) String
"EcdsaSecp256k1"
  , forall v a.
(DSIGNAlgorithm v, ContextDSIGN v ~ (), Signable v a,
 ExampleSignable v a, NFData (SignKeyDSIGN v),
 NFData (VerKeyDSIGN v), NFData (SigDSIGN v)) =>
Proxy v -> String -> Benchmark
benchDSIGN (forall {k} (t :: k). Proxy t
Proxy :: Proxy SchnorrSecp256k1DSIGN) String
"SchnorrSecp256k1"
#endif
  ]

benchDSIGN :: forall v a
           . ( DSIGNAlgorithm v
             , ContextDSIGN v ~ ()
             , Signable v a
             , ExampleSignable v a
             , NFData (SignKeyDSIGN v)
             , NFData (VerKeyDSIGN v)
             , NFData (SigDSIGN v)
             )
          => Proxy v
          -> String
          -> Benchmark
benchDSIGN :: forall v a.
(DSIGNAlgorithm v, ContextDSIGN v ~ (), Signable v a,
 ExampleSignable v a, NFData (SignKeyDSIGN v),
 NFData (VerKeyDSIGN v), NFData (SigDSIGN v)) =>
Proxy v -> String -> Benchmark
benchDSIGN Proxy v
_ String
lbl =
  String -> [Benchmark] -> Benchmark
bgroup String
lbl
    [ String -> Benchmarkable -> Benchmark
bench String
"genKeyDSIGN" forall a b. (a -> b) -> a -> b
$
        forall b a. NFData b => (a -> b) -> a -> Benchmarkable
nf (forall v. DSIGNAlgorithm v => Seed -> SignKeyDSIGN v
genKeyDSIGN @v) Seed
testSeed

    , forall env. NFData env => IO env -> (env -> Benchmark) -> Benchmark
env (forall (m :: * -> *) a. Monad m => a -> m a
return (forall v. DSIGNAlgorithm v => Seed -> SignKeyDSIGN v
genKeyDSIGN @v Seed
testSeed)) forall a b. (a -> b) -> a -> b
$ \SignKeyDSIGN v
signKey ->
      String -> Benchmarkable -> Benchmark
bench String
"signDSIGN" forall a b. (a -> b) -> a -> b
$
        forall b a. NFData b => (a -> b) -> a -> Benchmarkable
nf (forall v a.
(DSIGNAlgorithm v, Signable v a, HasCallStack) =>
ContextDSIGN v -> a -> SignKeyDSIGN v -> SigDSIGN v
signDSIGN @v () (forall v a. (ExampleSignable v a, Signable v a) => Proxy v -> a
exampleSignable (forall {k} (t :: k). Proxy t
Proxy @v))) SignKeyDSIGN v
signKey

    , forall env. NFData env => IO env -> (env -> Benchmark) -> Benchmark
env (let signKey :: SignKeyDSIGN v
signKey = forall v. DSIGNAlgorithm v => Seed -> SignKeyDSIGN v
genKeyDSIGN @v Seed
testSeed
               verKey :: VerKeyDSIGN v
verKey  = forall v. DSIGNAlgorithm v => SignKeyDSIGN v -> VerKeyDSIGN v
deriveVerKeyDSIGN SignKeyDSIGN v
signKey
               sig :: SigDSIGN v
sig     = forall v a.
(DSIGNAlgorithm v, Signable v a, HasCallStack) =>
ContextDSIGN v -> a -> SignKeyDSIGN v -> SigDSIGN v
signDSIGN @v () (forall v a. (ExampleSignable v a, Signable v a) => Proxy v -> a
exampleSignable (forall {k} (t :: k). Proxy t
Proxy @v)) SignKeyDSIGN v
signKey
            in forall (m :: * -> *) a. Monad m => a -> m a
return (VerKeyDSIGN v
verKey, SigDSIGN v
sig)
          ) forall a b. (a -> b) -> a -> b
$ \ ~(VerKeyDSIGN v
verKey, SigDSIGN v
sig) ->
      String -> Benchmarkable -> Benchmark
bench String
"verifyDSIGN" forall a b. (a -> b) -> a -> b
$
        forall b a. NFData b => (a -> b) -> a -> Benchmarkable
nf (forall v a.
(DSIGNAlgorithm v, Signable v a, HasCallStack) =>
ContextDSIGN v
-> VerKeyDSIGN v -> a -> SigDSIGN v -> Either String ()
verifyDSIGN @v () VerKeyDSIGN v
verKey (forall v a. (ExampleSignable v a, Signable v a) => Proxy v -> a
exampleSignable (forall {k} (t :: k). Proxy t
Proxy @v))) SigDSIGN v
sig
    ]

-- | A helper class to gloss over the differences in the 'Signable' constraint
-- for different 'DSIGNAlgorithm' instances. Some use 'ByteString', some use
-- 'MessageHash'.
class ExampleSignable v a | v -> a where
  exampleSignable :: Signable v a => Proxy v -> a

instance ExampleSignable Ed25519DSIGN ByteString where
  exampleSignable :: Signable Ed25519DSIGN ByteString =>
Proxy Ed25519DSIGN -> ByteString
exampleSignable Proxy Ed25519DSIGN
_ = ByteString
typicalMsg

#ifdef SECP256K1_ENABLED
instance ExampleSignable EcdsaSecp256k1DSIGN MessageHash where
  exampleSignable :: Signable EcdsaSecp256k1DSIGN MessageHash =>
Proxy EcdsaSecp256k1DSIGN -> MessageHash
exampleSignable Proxy EcdsaSecp256k1DSIGN
_ = forall h.
(HashAlgorithm h, SizeHash h ~ SECP256K1_ECDSA_MESSAGE_BYTES) =>
Proxy h -> ByteString -> MessageHash
hashAndPack (forall {k} (t :: k). Proxy t
Proxy @Blake2b_256) ByteString
typicalMsg

instance ExampleSignable SchnorrSecp256k1DSIGN ByteString where
  exampleSignable :: Signable SchnorrSecp256k1DSIGN ByteString =>
Proxy SchnorrSecp256k1DSIGN -> ByteString
exampleSignable Proxy SchnorrSecp256k1DSIGN
_ = ByteString
typicalMsg
#endif