commit 196a2bdeae3f4fbb39bf155ca9d88342afffe5d7
parent 5d1ba01983c7e005d4cb88227f6eee7932267242
Author: Jared Tobin <jared@jtobin.io>
Date: Fri, 19 Dec 2025 10:29:42 -0330
bench: benchmarks working
Diffstat:
3 files changed, 133 insertions(+), 162 deletions(-)
diff --git a/bench/Main.hs b/bench/Main.hs
@@ -15,7 +15,7 @@ import qualified Numeric.Montgomery.Secp256k1.Curve as C
instance NFData S.Projective
instance NFData S.Affine
--- instance NFData S.ECDSA
+instance NFData S.ECDSA
instance NFData S.Context
decodeLenient :: BS.ByteString -> BS.ByteString
@@ -25,50 +25,40 @@ decodeLenient bs = case B16.decode bs of
main :: IO ()
main = defaultMain [
- -- parse_point
- add
+ parse_point
+ , add
, mul
- --, precompute
+ , precompute
, mul_wnaf
, derive_pub
- --, schnorr
- --, ecdsa
+ , schnorr
+ , ecdsa
, ecdh
]
-parse_int256 :: BS.ByteString -> Integer
+parse_int256 :: BS.ByteString -> W.Wider
parse_int256 bs = case S.parse_int256 bs of
Nothing -> error "bang"
Just v -> v
--- remQ :: Benchmark
--- remQ = env setup $ \x ->
--- bgroup "remQ (remainder modulo _CURVE_Q)" [
--- bench "remQ 2 " $ nf S.remQ 2
--- , bench "remQ (2 ^ 255 - 19)" $ nf S.remQ x
--- ]
--- where
--- setup = pure . parse_int256 $ decodeLenient
--- "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
---
--- parse_point :: Benchmark
--- parse_point = bgroup "parse_point" [
--- bench "compressed" $ nf S.parse_point p_bs
--- , bench "uncompressed" $ nf S.parse_point t_bs
--- , bench "bip0340" $ nf S.parse_point (BS.drop 1 p_bs)
--- ]
---
--- parse_integer :: Benchmark
--- parse_integer = env setup $ \ ~(small, big) ->
--- bgroup "parse_int256" [
--- bench "parse_int256 (small)" $ nf parse_int256 small
--- , bench "parse_int256 (big)" $ nf parse_int256 big
--- ]
--- where
--- setup = do
--- let small = BS.replicate 32 0x00
--- big = BS.replicate 32 0xFF
--- pure (small, big)
+parse_point :: Benchmark
+parse_point = bgroup "parse_point" [
+ bench "compressed" $ nf S.parse_point p_bs
+ , bench "uncompressed" $ nf S.parse_point t_bs
+ , bench "bip0340" $ nf S.parse_point (BS.drop 1 p_bs)
+ ]
+
+parse_integer :: Benchmark
+parse_integer = env setup $ \ ~(small, big) ->
+ bgroup "parse_int256" [
+ bench "parse_int256 (small)" $ nf parse_int256 small
+ , bench "parse_int256 (big)" $ nf parse_int256 big
+ ]
+ where
+ setup = do
+ let small = BS.replicate 32 0x00
+ big = BS.replicate 32 0xFF
+ pure (small, big)
mul_fixed :: Benchmark
mul_fixed = bgroup "mul_fixed" [
@@ -86,21 +76,17 @@ add = bgroup "add" [
]
mul :: Benchmark
-mul = bench "mul" $ nf (S.mul p) (W.to 12831231)
-
-
--- mul :: Benchmark
--- mul = env setup $ \x ->
--- bgroup "mul" [
--- bench "2 G" $ nf (S.mul S._CURVE_G) (W.to 2)
--- , bench "(2 ^ 255 - 19) G" $ nf (S.mul S._CURVE_G) x
--- ]
--- where
--- setup = pure . W.to . parse_int256 $ decodeLenient
--- "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
+mul = env setup $ \x ->
+ bgroup "mul" [
+ bench "2 G" $ nf (S.mul S._CURVE_G) 2
+ , bench "(2 ^ 255 - 19) G" $ nf (S.mul S._CURVE_G) x
+ ]
+ where
+ setup = pure . parse_int256 $ decodeLenient
+ "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
--- precompute :: Benchmark
--- precompute = bench "precompute" $ nfIO (pure S.precompute)
+precompute :: Benchmark
+precompute = bench "precompute" $ nfIO (pure S.precompute)
mul_wnaf :: Benchmark
mul_wnaf = env setup $ \ ~(tex, x) ->
@@ -118,65 +104,65 @@ mul_wnaf = env setup $ \ ~(tex, x) ->
derive_pub :: Benchmark
derive_pub = env setup $ \ ~(tex, x) ->
bgroup "derive_pub" [
- bench "sk = 2" $ nf S.derive_pub (W.to 2)
+ bench "sk = 2" $ nf S.derive_pub 2
, bench "sk = 2 ^ 255 - 19" $ nf S.derive_pub x
, bench "wnaf, sk = 2" $ nf (S.derive_pub' tex) 2
- , bench "wnaf, sk = 2 ^ 255 - 19" $ nf (S.derive_pub' tex) (W.from x)
+ , bench "wnaf, sk = 2 ^ 255 - 19" $ nf (S.derive_pub' tex) x
]
where
setup = do
let !tex = S.precompute
!int = parse_int256 $ decodeLenient
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
- pure (tex, W.to int)
-
--- schnorr :: Benchmark
--- schnorr = env setup $ \ ~(tex, big) ->
--- bgroup "schnorr" [
--- bench "sign_schnorr (small)" $ nf (S.sign_schnorr 2 s_msg) s_aux
--- , bench "sign_schnorr (large)" $ nf (S.sign_schnorr big s_msg) s_aux
--- , bench "sign_schnorr' (small)" $ nf (S.sign_schnorr' tex 2 s_msg) s_aux
--- , bench "sign_schnorr' (large)" $ nf (S.sign_schnorr' tex big s_msg) s_aux
--- , bench "verify_schnorr" $ nf (S.verify_schnorr s_msg s_pk) s_sig
--- , bench "verify_schnorr'" $ nf (S.verify_schnorr' tex s_msg s_pk) s_sig
--- ]
--- where
--- setup = do
--- let !tex = S.precompute
--- !int = parse_int256 $ decodeLenient
--- "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
--- pure (tex, int)
---
--- ecdsa :: Benchmark
--- ecdsa = env setup $ \ ~(tex, big, pub, msg, sig) ->
--- bgroup "ecdsa" [
--- bench "sign_ecdsa (small)" $ nf (S.sign_ecdsa 2) s_msg
--- , bench "sign_ecdsa (large)" $ nf (S.sign_ecdsa big) s_msg
--- , bench "sign_ecdsa' (small)" $ nf (S.sign_ecdsa' tex 2) s_msg
--- , bench "sign_ecdsa' (large)" $ nf (S.sign_ecdsa' tex big) s_msg
--- , bench "verify_ecdsa" $ nf (S.verify_ecdsa msg pub) sig
--- , bench "verify_ecdsa'" $ nf (S.verify_ecdsa' tex msg pub) sig
--- ]
--- where
--- setup = do
--- let !tex = S.precompute
--- big = parse_int256 $ decodeLenient
--- "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
--- Just pub = S.derive_pub big
--- msg = "i approve of this message"
--- Just sig = S.sign_ecdsa big s_msg
--- pure (tex, big, pub, msg, sig)
+ pure (tex, int)
+
+schnorr :: Benchmark
+schnorr = env setup $ \ ~(tex, big) ->
+ bgroup "schnorr" [
+ bench "sign_schnorr (small)" $ nf (S.sign_schnorr 2 s_msg) s_aux
+ , bench "sign_schnorr (large)" $ nf (S.sign_schnorr big s_msg) s_aux
+ , bench "sign_schnorr' (small)" $ nf (S.sign_schnorr' tex 2 s_msg) s_aux
+ , bench "sign_schnorr' (large)" $ nf (S.sign_schnorr' tex big s_msg) s_aux
+ , bench "verify_schnorr" $ nf (S.verify_schnorr s_msg s_pk) s_sig
+ , bench "verify_schnorr'" $ nf (S.verify_schnorr' tex s_msg s_pk) s_sig
+ ]
+ where
+ setup = do
+ let !tex = S.precompute
+ !int = parse_int256 $ decodeLenient
+ "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
+ pure (tex, int)
+
+ecdsa :: Benchmark
+ecdsa = env setup $ \ ~(tex, big, pub, msg, sig) ->
+ bgroup "ecdsa" [
+ bench "sign_ecdsa (small)" $ nf (S.sign_ecdsa 2) s_msg
+ , bench "sign_ecdsa (large)" $ nf (S.sign_ecdsa big) s_msg
+ , bench "sign_ecdsa' (small)" $ nf (S.sign_ecdsa' tex 2) s_msg
+ , bench "sign_ecdsa' (large)" $ nf (S.sign_ecdsa' tex big) s_msg
+ , bench "verify_ecdsa" $ nf (S.verify_ecdsa msg pub) sig
+ , bench "verify_ecdsa'" $ nf (S.verify_ecdsa' tex msg pub) sig
+ ]
+ where
+ setup = do
+ let !tex = S.precompute
+ big = parse_int256 $ decodeLenient
+ "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
+ Just pub = S.derive_pub big
+ msg = "i approve of this message"
+ Just sig = S.sign_ecdsa big s_msg
+ pure (tex, big, pub, msg, sig)
ecdh :: Benchmark
ecdh = env setup $ \ ~(big, pub) ->
bgroup "ecdh" [
- bench "ecdh (small)" $ nf (S.ecdh pub) (W.to 2)
+ bench "ecdh (small)" $ nf (S.ecdh pub) 2
, bench "ecdh (large)" $ nf (S.ecdh pub) big
]
where
setup = do
let !big =
- W.to 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed
+ 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed
!(Just !pub) = S.parse_point . decodeLenient $
"bd02b9dfc8ef760708950bd972f2dc244893b61b6b46c3b19be1b2da7b034ac5"
pure (big, pub)
@@ -200,32 +186,17 @@ r = S.Projective
77311080844824646227678701997218206005272179480834599837053144390237051080427
1
--- p_bs :: BS.ByteString
--- p_bs = decodeLenient
--- "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
---
--- p :: S.Projective
--- p = case S.parse_point p_bs of
--- Nothing -> error "bang"
--- Just !pt -> pt
---
--- q_bs :: BS.ByteString
--- q_bs = decodeLenient
--- "02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9"
---
--- q :: S.Projective
--- q = case S.parse_point q_bs of
--- Nothing -> error "bang"
--- Just !pt -> pt
---
--- r_bs :: BS.ByteString
--- r_bs = decodeLenient
--- "03a2113cf152585d96791a42cdd78782757fbfb5c6b2c11b59857eb4f7fda0b0e8"
---
--- r :: S.Projective
--- r = case S.parse_point r_bs of
--- Nothing -> error "bang"
--- Just !pt -> pt
+p_bs :: BS.ByteString
+p_bs = decodeLenient
+ "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
+
+q_bs :: BS.ByteString
+q_bs = decodeLenient
+ "02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9"
+
+r_bs :: BS.ByteString
+r_bs = decodeLenient
+ "03a2113cf152585d96791a42cdd78782757fbfb5c6b2c11b59857eb4f7fda0b0e8"
s_bs :: BS.ByteString
s_bs = decodeLenient
@@ -236,38 +207,35 @@ s = case S.parse_point s_bs of
Nothing -> error "bang"
Just !pt -> pt
--- t_bs :: BS.ByteString
--- t_bs = decodeLenient "04b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9"
---
--- t :: S.Projective
--- t = case S.parse_point t_bs of
--- Nothing -> error "bang"
--- Just !pt -> pt
-
--- s_sk :: Integer
--- s_sk = parse_int256 . decodeLenient $
--- "B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF"
---
--- s_sig :: BS.ByteString
--- s_sig = decodeLenient "6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A"
---
--- s_pk_raw :: BS.ByteString
--- s_pk_raw = decodeLenient
--- "DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"
---
--- s_pk :: S.Projective
--- s_pk = case S.parse_point s_pk_raw of
--- Nothing -> error "bang"
--- Just !pt -> pt
---
--- s_msg :: BS.ByteString
--- s_msg = decodeLenient
--- "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"
---
--- s_aux :: BS.ByteString
--- s_aux = decodeLenient
--- "0000000000000000000000000000000000000000000000000000000000000001"
---
--- -- e_msg = decodeLenient "313233343030"
--- -- e_sig = decodeLenient "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba"
---
+t_bs :: BS.ByteString
+t_bs = decodeLenient "04b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9"
+
+t :: S.Projective
+t = case S.parse_point t_bs of
+ Nothing -> error "bang"
+ Just !pt -> pt
+
+s_sk :: W.Wider
+s_sk = parse_int256 . decodeLenient $
+ "B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF"
+
+s_sig :: BS.ByteString
+s_sig = decodeLenient "6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A"
+
+s_pk_raw :: BS.ByteString
+s_pk_raw = decodeLenient
+ "DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"
+
+s_pk :: S.Projective
+s_pk = case S.parse_point s_pk_raw of
+ Nothing -> error "bang"
+ Just !pt -> pt
+
+s_msg :: BS.ByteString
+s_msg = decodeLenient
+ "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"
+
+s_aux :: BS.ByteString
+s_aux = decodeLenient
+ "0000000000000000000000000000000000000000000000000000000000000001"
+
diff --git a/bench/Weight.hs b/bench/Weight.hs
@@ -2,10 +2,13 @@
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
+-- XX need to make sure arguments aren't allocating in the benchmarks
+
module Main where
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base16 as B16
+import Data.Word.Wider (Wider(..))
import Control.DeepSeq
import qualified Crypto.Curve.Secp256k1 as S
import qualified Weigh as W
@@ -20,12 +23,12 @@ decodeLenient bs = case B16.decode bs of
Nothing -> error "bang"
Just b -> b
-parse_int :: BS.ByteString -> Integer
+parse_int :: BS.ByteString -> Wider
parse_int bs = case S.parse_int256 bs of
Nothing -> error "bang"
Just v -> v
-big :: Integer
+big :: Wider
big = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed
tex :: S.Context
@@ -34,7 +37,6 @@ tex = S.precompute
-- note that 'weigh' doesn't work properly in a repl
main :: IO ()
main = W.mainWith $ do
- remQ
parse_int256
add
mul
@@ -45,11 +47,6 @@ main = W.mainWith $ do
ecdsa
ecdh
-remQ :: W.Weigh ()
-remQ = W.wgroup "remQ" $ do
- W.func "remQ 2" S.remQ 2
- W.func "remQ (2 ^ 255 - 19)" S.remQ big
-
parse_int256 :: W.Weigh ()
parse_int256 = W.wgroup "parse_int256" $ do
W.func' "parse_int (small)" parse_int (BS.replicate 32 0x00)
@@ -75,7 +72,7 @@ mul_unsafe = W.wgroup "mul_unsafe" $ do
mul_wnaf :: W.Weigh ()
mul_wnaf = W.wgroup "mul_wnaf" $ do
- W.value "precompute" S.precompute
+ W.value "precompute" S.precompute -- XX ?
W.func "2 G" (S.mul_wnaf tex) 2
W.func "(2 ^ 255 - 19) G" (S.mul_wnaf tex) big
@@ -117,7 +114,7 @@ ecdh = W.wgroup "ecdh" $ do
Just pub = S.parse_point . decodeLenient $
"bd02b9dfc8ef760708950bd972f2dc244893b61b6b46c3b19be1b2da7b034ac5"
-s_sk :: Integer
+s_sk :: Wider
s_sk = parse_int . decodeLenient $
"B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF"
diff --git a/ppad-secp256k1.cabal b/ppad-secp256k1.cabal
@@ -15,6 +15,11 @@ description:
Pure BIP0340-style Schnorr signatures, deterministic RFC6979 ECDSA, and
ECDH shared secret computation on the elliptic curve secp256k1.
+flag llvm
+ description: Use GHC's LLVM backend.
+ default: False
+ manual: True
+
source-repository head
type: git
location: git.ppad.tech/secp256k1.git
@@ -93,6 +98,7 @@ benchmark secp256k1-weigh
, bytestring
, deepseq
, ppad-base16
+ , ppad-fixed
, ppad-secp256k1
, weigh