commit 13eaef80bd6998ee9dac6475687c364847d5240c
parent aeed9c7a24b3fc4d51d0240b005a36ee1bc531da
Author: Jared Tobin <jared@jtobin.io>
Date: Sat, 10 Oct 2026 13:39:19 +0400
bench: use the public API; add streaming and rotation cases
Benches share a fixture module that builds its inputs in IO without
partial patterns, and rely on the library's NFData instances instead of
orphans derived through Generic. Adds 64KB encrypt/decrypt, a rotating
encrypt, and decrypt_header/decrypt_body cases.
Diffstat:
| A | bench/Fixture.hs | | | 77 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | bench/Main.hs | | | 141 | ++++++++++++++++++++++--------------------------------------------------------- |
| M | bench/Weight.hs | | | 130 | ++++++++++++++++++++++++------------------------------------------------------- |
| M | ppad-bolt8.cabal | | | 8 | ++++---- |
4 files changed, 159 insertions(+), 197 deletions(-)
diff --git a/bench/Fixture.hs b/bench/Fixture.hs
@@ -0,0 +1,77 @@
+module Fixture (
+ i_s_ent
+ , i_e_ent
+ , r_s_ent
+ , r_e_ent
+ , msg_32
+ , msg_1k
+ , msg_64k
+ , Fixture(..)
+ , fixture
+ ) where
+
+import qualified Data.ByteString as BS
+import qualified Lightning.Protocol.BOLT8 as BOLT8
+
+-- key material from BOLT #8 Appendix A
+i_s_ent, i_e_ent, r_s_ent, r_e_ent :: BS.ByteString
+i_s_ent = BS.replicate 32 0x11
+i_e_ent = BS.replicate 32 0x12
+r_s_ent = BS.replicate 32 0x21
+r_e_ent = BS.replicate 32 0x22
+
+data Fixture = Fixture {
+ fx_i :: !BOLT8.Keypair
+ , fx_r :: !BOLT8.Keypair
+ , fx_msg1 :: !BS.ByteString
+ , fx_i_hs :: !BOLT8.Initiator
+ , fx_msg2 :: !BS.ByteString
+ , fx_r_hs :: !BOLT8.Responder
+ , fx_msg3 :: !BS.ByteString
+ , fx_snd :: !BOLT8.Sender
+ , fx_snd_rot :: !BOLT8.Sender -- its next encrypt rotates the key
+ , fx_rcv :: !BOLT8.Receiver
+ , fx_ct_32 :: !BS.ByteString
+ , fx_ct_1k :: !BS.ByteString
+ , fx_ct_64k :: !BS.ByteString
+ , fx_pend_1k :: !BOLT8.Pending -- awaiting the body of fx_ct_1k
+ }
+
+fixture :: IO Fixture
+fixture = do
+ i <- orFail "keypair" (maybe (Left ()) Right (BOLT8.keypair i_s_ent))
+ r <- orFail "keypair" (maybe (Left ()) Right (BOLT8.keypair r_s_ent))
+ (msg1, i_hs) <- orFail "act1" (BOLT8.act1 i (BOLT8.keypair_pub r) i_e_ent)
+ (msg2, r_hs) <- orFail "act2" (BOLT8.act2 r r_e_ent msg1)
+ (msg3, i_res) <- orFail "act3" (BOLT8.act3 i_hs msg2)
+ r_res <- orFail "finalize" (BOLT8.finalize r_hs msg3)
+ let snd0 = BOLT8.handshake_sender i_res
+ rcv0 = BOLT8.handshake_receiver r_res
+ snd_rot <- advance (499 :: Int) snd0
+ (ct_32, _) <- orFail "encrypt" (BOLT8.encrypt snd0 msg_32)
+ (ct_1k, _) <- orFail "encrypt" (BOLT8.encrypt snd0 msg_1k)
+ (ct_64k, _) <- orFail "encrypt" (BOLT8.encrypt snd0 msg_64k)
+ (_, pend_1k) <- orFail "header"
+ (BOLT8.decrypt_header rcv0 (BS.take 18 ct_1k))
+ pure Fixture {
+ fx_i = i, fx_r = r
+ , fx_msg1 = msg1, fx_i_hs = i_hs
+ , fx_msg2 = msg2, fx_r_hs = r_hs
+ , fx_msg3 = msg3
+ , fx_snd = snd0, fx_snd_rot = snd_rot
+ , fx_rcv = rcv0
+ , fx_ct_32 = ct_32, fx_ct_1k = ct_1k, fx_ct_64k = ct_64k
+ , fx_pend_1k = pend_1k
+ }
+ where
+ orFail :: Show e => String -> Either e a -> IO a
+ orFail msg = either (\e -> fail (msg <> ": " <> show e)) pure
+ advance 0 s = pure s
+ advance n s = do
+ (_, s') <- orFail "encrypt" (BOLT8.encrypt s msg_32)
+ advance (n - 1) s'
+
+msg_32, msg_1k, msg_64k :: BS.ByteString
+msg_32 = BS.replicate 32 0x00
+msg_1k = BS.replicate 1024 0x00
+msg_64k = BS.replicate 65535 0x00
diff --git a/bench/Main.hs b/bench/Main.hs
@@ -1,113 +1,50 @@
-{-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-}
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE OverloadedStrings #-}
-
module Main where
-import Control.DeepSeq
import Criterion.Main
import qualified Data.ByteString as BS
-import qualified Lightning.Protocol.BOLT8.Internal as BOLT8
-
-instance NFData BOLT8.Pub where
- rnf p = rnf (BOLT8.serialize_pub p)
-
-instance NFData BOLT8.Sec
-instance NFData BOLT8.Error
-instance NFData BOLT8.Key32
-instance NFData BOLT8.SessionNonce
-instance NFData BOLT8.Session
-instance NFData BOLT8.HandshakeState
-instance NFData BOLT8.Handshake
-instance NFData (BOLT8.HandshakeFor a) where
- rnf (BOLT8.HandshakeFor s) = rnf s
+import Fixture
+import qualified Lightning.Protocol.BOLT8 as BOLT8
main :: IO ()
-main = defaultMain [
- keys
- , handshake
- , messages
- ]
-
--- test keys (from BOLT #8 spec)
-i_s_ent, i_e_ent, r_s_ent, r_e_ent :: BS.ByteString
-i_s_ent = BS.replicate 32 0x11
-i_e_ent = BS.replicate 32 0x12
-r_s_ent = BS.replicate 32 0x21
-r_e_ent = BS.replicate 32 0x22
+main = do
+ fx <- fixture
+ defaultMain [
+ keys fx
+ , handshake fx
+ , transport fx
+ ]
-keys :: Benchmark
-keys = bgroup "keys" [
+keys :: Fixture -> Benchmark
+keys fx = bgroup "keys" [
bench "keypair" $ nf BOLT8.keypair i_s_ent
- , bench "parse_pub" $ nf BOLT8.parse_pub r_s_pub_bs
- , bench "serialize_pub" $
- nf BOLT8.serialize_pub r_s_pub
+ , bench "parse_pub" $ nf BOLT8.parse_pub pub_bs
+ , bench "serialize_pub" $ nf BOLT8.serialize_pub pub
]
where
- Just (_, r_s_pub) = BOLT8.keypair r_s_ent
- r_s_pub_bs = BOLT8.serialize_pub r_s_pub
-
-handshake :: Benchmark
-handshake = env setup $
- \ ~(i_s_sec, i_s_pub, r_s_sec, r_s_pub,
- msg1, i_hs, msg2, r_hs, msg3) ->
- bgroup "handshake" [
- bench "act1" $
- nf (BOLT8.act1 i_s_sec i_s_pub r_s_pub) i_e_ent
- , bench "act2" $
- nf (BOLT8.act2 r_s_sec r_s_pub r_e_ent) msg1
- , bench "act3" $
- nf (BOLT8.act3 i_hs) msg2
- , bench "finalize" $
- nf (BOLT8.finalize r_hs) msg3
- ]
- where
- setup = do
- let Just (!i_s_sec, !i_s_pub) =
- BOLT8.keypair i_s_ent
- Just (!r_s_sec, !r_s_pub) =
- BOLT8.keypair r_s_ent
- Right (!msg1, !i_hs) =
- BOLT8.act1 i_s_sec i_s_pub r_s_pub i_e_ent
- Right (!msg2, !r_hs) =
- BOLT8.act2 r_s_sec r_s_pub r_e_ent msg1
- Right (!msg3, _) = BOLT8.act3 i_hs msg2
- pure ( i_s_sec, i_s_pub, r_s_sec, r_s_pub
- , msg1, i_hs, msg2, r_hs, msg3 )
+ pub = BOLT8.keypair_pub (fx_r fx)
+ pub_bs = BOLT8.serialize_pub pub
+
+handshake :: Fixture -> Benchmark
+handshake fx = bgroup "handshake" [
+ bench "act1" $
+ nf (BOLT8.act1 (fx_i fx) (BOLT8.keypair_pub (fx_r fx))) i_e_ent
+ , bench "act2" $ nf (BOLT8.act2 (fx_r fx) r_e_ent) (fx_msg1 fx)
+ , bench "act3" $ nf (BOLT8.act3 (fx_i_hs fx)) (fx_msg2 fx)
+ , bench "finalize" $ nf (BOLT8.finalize (fx_r_hs fx)) (fx_msg3 fx)
+ ]
-messages :: Benchmark
-messages = env setup $
- \ ~(i_sess, r_sess, ct_small, ct_large) ->
- bgroup "messages" [
- bench "encrypt (32B)" $
- nf (BOLT8.encrypt i_sess) small_msg
- , bench "encrypt (1KB)" $
- nf (BOLT8.encrypt i_sess) large_msg
- , bench "decrypt (32B)" $
- nf (BOLT8.decrypt r_sess) ct_small
- , bench "decrypt (1KB)" $
- nf (BOLT8.decrypt r_sess) ct_large
- ]
- where
- small_msg = BS.replicate 32 0x00
- large_msg = BS.replicate 1024 0x00
- setup = do
- let Just (!i_s_sec, !i_s_pub) =
- BOLT8.keypair i_s_ent
- Just (!r_s_sec, !r_s_pub) =
- BOLT8.keypair r_s_ent
- Right (msg1, i_hs) =
- BOLT8.act1 i_s_sec i_s_pub r_s_pub i_e_ent
- Right (msg2, r_hs) =
- BOLT8.act2 r_s_sec r_s_pub r_e_ent msg1
- Right (msg3, i_result) =
- BOLT8.act3 i_hs msg2
- Right r_result =
- BOLT8.finalize r_hs msg3
- !i_sess = BOLT8.session i_result
- !r_sess = BOLT8.session r_result
- Right (!ct_small, _) =
- BOLT8.encrypt i_sess small_msg
- Right (!ct_large, _) =
- BOLT8.encrypt i_sess large_msg
- pure (i_sess, r_sess, ct_small, ct_large)
+transport :: Fixture -> Benchmark
+transport fx = bgroup "transport" [
+ bench "encrypt (32B)" $ nf (BOLT8.encrypt (fx_snd fx)) msg_32
+ , bench "encrypt (1KB)" $ nf (BOLT8.encrypt (fx_snd fx)) msg_1k
+ , bench "encrypt (64KB)" $ nf (BOLT8.encrypt (fx_snd fx)) msg_64k
+ , bench "encrypt (32B, rotating)" $
+ nf (BOLT8.encrypt (fx_snd_rot fx)) msg_32
+ , bench "decrypt (32B)" $ nf (BOLT8.decrypt (fx_rcv fx)) (fx_ct_32 fx)
+ , bench "decrypt (1KB)" $ nf (BOLT8.decrypt (fx_rcv fx)) (fx_ct_1k fx)
+ , bench "decrypt (64KB)" $ nf (BOLT8.decrypt (fx_rcv fx)) (fx_ct_64k fx)
+ , bench "decrypt_header" $
+ nf (BOLT8.decrypt_header (fx_rcv fx)) (BS.take 18 (fx_ct_1k fx))
+ , bench "decrypt_body (1KB)" $
+ nf (BOLT8.decrypt_body (fx_pend_1k fx)) (BS.drop 18 (fx_ct_1k fx))
+ ]
diff --git a/bench/Weight.hs b/bench/Weight.hs
@@ -1,98 +1,46 @@
-{-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-}
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE OverloadedStrings #-}
-
module Main where
-import Control.DeepSeq
import qualified Data.ByteString as BS
-import qualified Lightning.Protocol.BOLT8.Internal as BOLT8
+import Fixture
+import qualified Lightning.Protocol.BOLT8 as BOLT8
import Weigh
-instance NFData BOLT8.Pub where
- rnf p = rnf (BOLT8.serialize_pub p)
-
-instance NFData BOLT8.Sec
-instance NFData BOLT8.Error
-instance NFData BOLT8.Key32
-instance NFData BOLT8.SessionNonce
-instance NFData BOLT8.Session
-instance NFData BOLT8.HandshakeState
-instance NFData BOLT8.Handshake
-instance NFData (BOLT8.HandshakeFor a) where
- rnf (BOLT8.HandshakeFor s) = rnf s
-
-- note that 'weigh' doesn't work properly in a repl
main :: IO ()
-main = mainWith $ do
- keys
- handshake
- messages
-
--- test keys (from BOLT #8 spec)
-i_s_ent, i_e_ent, r_s_ent, r_e_ent :: BS.ByteString
-i_s_ent = BS.replicate 32 0x11
-i_e_ent = BS.replicate 32 0x12
-r_s_ent = BS.replicate 32 0x21
-r_e_ent = BS.replicate 32 0x22
-
-keys :: Weigh ()
-keys =
- let Just (_, !r_s_pub) = BOLT8.keypair r_s_ent
- !r_s_pub_bs = BOLT8.serialize_pub r_s_pub
- in wgroup "keys" $ do
- func "keypair" BOLT8.keypair i_s_ent
- func "parse_pub" BOLT8.parse_pub r_s_pub_bs
- func "serialize_pub"
- BOLT8.serialize_pub r_s_pub
-
-handshake :: Weigh ()
-handshake =
- let Just (!i_s_sec, !i_s_pub) =
- BOLT8.keypair i_s_ent
- Just (!r_s_sec, !r_s_pub) =
- BOLT8.keypair r_s_ent
- Right (!msg1, !i_hs) =
- BOLT8.act1 i_s_sec i_s_pub r_s_pub i_e_ent
- Right (!msg2, !r_hs) =
- BOLT8.act2 r_s_sec r_s_pub r_e_ent msg1
- Right (!msg3, _) = BOLT8.act3 i_hs msg2
- in wgroup "handshake" $ do
- func "act1"
- (BOLT8.act1 i_s_sec i_s_pub r_s_pub) i_e_ent
- func "act2"
- (BOLT8.act2 r_s_sec r_s_pub r_e_ent) msg1
- func "act3" (BOLT8.act3 i_hs) msg2
- func "finalize" (BOLT8.finalize r_hs) msg3
-
-messages :: Weigh ()
-messages =
- let Just (!i_s_sec, !i_s_pub) =
- BOLT8.keypair i_s_ent
- Just (!r_s_sec, !r_s_pub) =
- BOLT8.keypair r_s_ent
- Right (msg1, i_hs) =
- BOLT8.act1 i_s_sec i_s_pub r_s_pub i_e_ent
- Right (msg2, r_hs) =
- BOLT8.act2 r_s_sec r_s_pub r_e_ent msg1
- Right (msg3, i_result) =
- BOLT8.act3 i_hs msg2
- Right r_result =
- BOLT8.finalize r_hs msg3
- !i_sess = BOLT8.session i_result
- !r_sess = BOLT8.session r_result
- !small_msg = BS.replicate 32 0x00
- !large_msg = BS.replicate 1024 0x00
- Right (!ct_small, _) =
- BOLT8.encrypt i_sess small_msg
- Right (!ct_large, _) =
- BOLT8.encrypt i_sess large_msg
- in wgroup "messages" $ do
- func "encrypt (32B)"
- (BOLT8.encrypt i_sess) small_msg
- func "encrypt (1KB)"
- (BOLT8.encrypt i_sess) large_msg
- func "decrypt (32B)"
- (BOLT8.decrypt r_sess) ct_small
- func "decrypt (1KB)"
- (BOLT8.decrypt r_sess) ct_large
+main = do
+ fx <- fixture
+ mainWith $ do
+ keys fx
+ handshake fx
+ transport fx
+
+keys :: Fixture -> Weigh ()
+keys fx = wgroup "keys" $ do
+ func "keypair" BOLT8.keypair i_s_ent
+ func "parse_pub" BOLT8.parse_pub pub_bs
+ func "serialize_pub" BOLT8.serialize_pub pub
+ where
+ pub = BOLT8.keypair_pub (fx_r fx)
+ pub_bs = BOLT8.serialize_pub pub
+
+handshake :: Fixture -> Weigh ()
+handshake fx = wgroup "handshake" $ do
+ func "act1"
+ (BOLT8.act1 (fx_i fx) (BOLT8.keypair_pub (fx_r fx))) i_e_ent
+ func "act2" (BOLT8.act2 (fx_r fx) r_e_ent) (fx_msg1 fx)
+ func "act3" (BOLT8.act3 (fx_i_hs fx)) (fx_msg2 fx)
+ func "finalize" (BOLT8.finalize (fx_r_hs fx)) (fx_msg3 fx)
+
+transport :: Fixture -> Weigh ()
+transport fx = wgroup "transport" $ do
+ func "encrypt (32B)" (BOLT8.encrypt (fx_snd fx)) msg_32
+ func "encrypt (1KB)" (BOLT8.encrypt (fx_snd fx)) msg_1k
+ func "encrypt (64KB)" (BOLT8.encrypt (fx_snd fx)) msg_64k
+ func "encrypt (32B, rotating)" (BOLT8.encrypt (fx_snd_rot fx)) msg_32
+ func "decrypt (32B)" (BOLT8.decrypt (fx_rcv fx)) (fx_ct_32 fx)
+ func "decrypt (1KB)" (BOLT8.decrypt (fx_rcv fx)) (fx_ct_1k fx)
+ func "decrypt (64KB)" (BOLT8.decrypt (fx_rcv fx)) (fx_ct_64k fx)
+ func "decrypt_header"
+ (BOLT8.decrypt_header (fx_rcv fx)) (BS.take 18 (fx_ct_1k fx))
+ func "decrypt_body (1KB)"
+ (BOLT8.decrypt_body (fx_pend_1k fx)) (BS.drop 18 (fx_ct_1k fx))
diff --git a/ppad-bolt8.cabal b/ppad-bolt8.cabal
@@ -67,15 +67,15 @@ benchmark bolt8-bench
default-language: Haskell2010
hs-source-dirs: bench
main-is: Main.hs
+ other-modules: Fixture
ghc-options:
- -rtsopts -O2 -Wall -fno-warn-orphans
+ -rtsopts -O2 -Wall
build-depends:
base
, bytestring
, criterion
- , deepseq
, ppad-bolt8
benchmark bolt8-weigh
@@ -83,14 +83,14 @@ benchmark bolt8-weigh
default-language: Haskell2010
hs-source-dirs: bench
main-is: Weight.hs
+ other-modules: Fixture
ghc-options:
- -rtsopts -O2 -Wall -fno-warn-orphans
+ -rtsopts -O2 -Wall
build-depends:
base
, bytestring
- , deepseq
, ppad-bolt8
, weigh