commit b7bd940fe55541047bc12fd523880b924df8049e
parent f2031cfb310fda6bbe02150668e084cdabea0eca
Author: Jared Tobin <jared@jtobin.io>
Date: Sun, 17 May 2026 18:52:59 -0230
bench: criterion + weigh entries for wNAF derive_* variants
Adds apostrophe-suffixed variants to both bench targets, alongside
their non-wNAF counterparts so the comparison is direct. Also adds
derive_per_commitment_point to the criterion suite (wasn't covered
before).
Results on M-series macOS, -O2:
derive_pubkey: 148.7 us -> 45.4 us (3.3x)
derive_per_commitment_point: 141.2 us -> 37.7 us (3.7x)
Weigh allocation matches non-wNAF once the precompute table is
forced before mainWith — without that, the one-time ~50 KB ctxArray
build gets billed to whichever apostrophe-suffixed entry happens to
touch tex first.
ppad-secp256k1 added to both bench targets' build-depends.
Diffstat:
3 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/bench/Main.hs b/bench/Main.hs
@@ -3,6 +3,7 @@
module Main where
+import qualified Crypto.Curve.Secp256k1 as S
import Control.DeepSeq (NFData(..))
import Criterion.Main
import Data.Word (Word64)
@@ -11,6 +12,7 @@ import Lightning.Protocol.BOLT3
import Lightning.Protocol.BOLT3.Types
( Pubkey(..), Point(..)
, PaymentHash(..), PerCommitmentPoint(..)
+ , PerCommitmentSecret(..)
, CommitmentNumber(..)
)
@@ -163,11 +165,25 @@ instance NFData ValidationError where
rnf NoOutputs = ()
rnf (TooManyOutputs a) = rnf a
+-- | Precomputed wNAF context, built once and reused across the
+-- apostrophe-suffixed benches. NOINLINE keeps it from being
+-- re-created on every call site.
+tex :: S.Context
+tex = S.precompute
+{-# NOINLINE tex #-}
+
main :: IO ()
main = defaultMain [
bgroup "key derivation" [
bench "derive_pubkey" $
whnf (derive_pubkey basepoint) perCommitmentPoint
+ , bench "derive_pubkey'" $
+ whnf (derive_pubkey' tex basepoint) perCommitmentPoint
+ , bench "derive_per_commitment_point" $
+ whnf derive_per_commitment_point samplePcs
+ , bench "derive_per_commitment_point'" $
+ whnf (derive_per_commitment_point' tex)
+ samplePcs
, bench "derive_revocationpubkey" $
whnf (derive_revocationpubkey revocationBasepoint) perCommitmentPoint
]
@@ -313,6 +329,10 @@ main = defaultMain [
0xf9, 0x04, 0xf5, 0x50, 0x25, 0x3a, 0x0f, 0x3e, 0xf3, 0xf5, 0xaa,
0x2f, 0xe6, 0x83, 0x8a, 0x95, 0xb2, 0x16, 0x69, 0x14, 0x68, 0xe2]
+ samplePcs :: PerCommitmentSecret
+ samplePcs =
+ PerCommitmentSecret (BS.replicate 32 0x01)
+
-- Secret generation test data
seed = BS.replicate 32 0xFF
diff --git a/bench/Weight.hs b/bench/Weight.hs
@@ -3,6 +3,7 @@
module Main where
+import qualified Crypto.Curve.Secp256k1 as S
import Control.DeepSeq (NFData(..))
import qualified Data.ByteString as BS
import Data.Word (Word32, Word64)
@@ -10,10 +11,17 @@ import Lightning.Protocol.BOLT3
import Lightning.Protocol.BOLT3.Types
( Pubkey(..), Point(..)
, PaymentHash(..), PerCommitmentPoint(..)
+ , PerCommitmentSecret(..)
, CommitmentNumber(..)
)
import Weigh
+-- | Precomputed wNAF context; reused across every apostrophe-
+-- suffixed weigh entry.
+tex :: S.Context
+tex = S.precompute
+{-# NOINLINE tex #-}
+
-- NFData instances for weigh
-- (Satoshi, MilliSatoshi, Point, PaymentHash, PerCommitmentSecret
-- derive NFData via ppad-bolt1)
@@ -165,11 +173,20 @@ instance NFData SecretStore where
rnf ss = ss `seq` ()
main :: IO ()
-main = mainWith $ do
+main = tex `seq` mainWith $ do
+ -- 'tex' is forced before mainWith so the one-time wNAF
+ -- precompute (~50 KB) doesn't get billed to whichever
+ -- apostrophe-suffixed func happens to evaluate it first.
setColumns [Case, Allocated, GCs, Max]
-- Key derivation allocations
func "derive_pubkey" (derive_pubkey basepoint) perCommitmentPoint
+ func "derive_pubkey'"
+ (derive_pubkey' tex basepoint) perCommitmentPoint
+ func "derive_per_commitment_point"
+ derive_per_commitment_point samplePcs
+ func "derive_per_commitment_point'"
+ (derive_per_commitment_point' tex) samplePcs
func "derive_revocationpubkey"
(derive_revocationpubkey revocationBasepoint) perCommitmentPoint
@@ -306,6 +323,10 @@ main = mainWith $ do
0xf9, 0x04, 0xf5, 0x50, 0x25, 0x3a, 0x0f, 0x3e, 0xf3, 0xf5, 0xaa,
0x2f, 0xe6, 0x83, 0x8a, 0x95, 0xb2, 0x16, 0x69, 0x14, 0x68, 0xe2]
+ samplePcs :: PerCommitmentSecret
+ samplePcs =
+ PerCommitmentSecret (BS.replicate 32 0x01)
+
-- Secret generation test data
seed = BS.replicate 32 0xFF
diff --git a/ppad-bolt3.cabal b/ppad-bolt3.cabal
@@ -77,6 +77,7 @@ benchmark bolt3-bench
, criterion
, deepseq
, ppad-bolt3
+ , ppad-secp256k1 >= 0.5.4 && < 0.6
benchmark bolt3-weigh
type: exitcode-stdio-1.0
@@ -92,5 +93,6 @@ benchmark bolt3-weigh
, bytestring
, deepseq
, ppad-bolt3
+ , ppad-secp256k1 >= 0.5.4 && < 0.6
, weigh