fixed

Pure Haskell large fixed-width integers.
git clone git://git.ppad.tech/fixed.git
Log | Files | Refs | README | LICENSE

commit b70839aef46fc10c553c02837b15722eff9d8056
parent c093234ac07dbaf2961159363209b012082a0f40
Author: Jared Tobin <jared@jtobin.io>
Date:   Fri, 21 Nov 2025 13:19:11 +0400

bench: skeleton

Skeleton copy-pasted from ppad-secp256k1.

Diffstat:
Abench/Main.hs | 217+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abench/Weight.hs | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mppad-fixed.cabal | 28++++++++++++++++++++++++++++
3 files changed, 400 insertions(+), 0 deletions(-)

diff --git a/bench/Main.hs b/bench/Main.hs @@ -0,0 +1,217 @@ +{-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE OverloadedStrings #-} + +module Main where + +import Criterion.Main + +main :: IO () +main = pure () + +-- parse_int256 :: BS.ByteString -> Integer +-- 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) +-- +-- add :: Benchmark +-- add = bgroup "add" [ +-- bench "2 p (double, trivial projective point)" $ nf (S.add p) p +-- , bench "2 r (double, nontrivial projective point)" $ nf (S.add r) r +-- , bench "p + q (trivial projective points)" $ nf (S.add p) q +-- , bench "p + s (nontrivial mixed points)" $ nf (S.add p) s +-- , bench "s + r (nontrivial projective points)" $ nf (S.add s) r +-- ] +-- +-- mul :: Benchmark +-- 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) +-- +-- mul_wnaf :: Benchmark +-- mul_wnaf = env setup $ \ ~(tex, x) -> +-- bgroup "mul_wnaf" [ +-- bench "2 G" $ nf (S.mul_wnaf tex) 2 +-- , bench "(2 ^ 255 - 19) G" $ nf (S.mul_wnaf tex) x +-- ] +-- where +-- setup = do +-- let !tex = S.precompute +-- !int = parse_int256 $ decodeLenient +-- "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed" +-- pure (tex, int) +-- +-- derive_pub :: Benchmark +-- derive_pub = env setup $ \ ~(tex, x) -> +-- bgroup "derive_pub" [ +-- 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) x +-- ] +-- where +-- setup = do +-- let !tex = S.precompute +-- !int = parse_int256 $ decodeLenient +-- "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed" +-- 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) 2 +-- , bench "ecdh (large)" $ nf (S.ecdh pub) big +-- ] +-- where +-- setup = do +-- let !big = +-- 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed +-- !(Just !pub) = S.parse_point . decodeLenient $ +-- "bd02b9dfc8ef760708950bd972f2dc244893b61b6b46c3b19be1b2da7b034ac5" +-- pure (big, pub) +-- +-- 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 +-- +-- s_bs :: BS.ByteString +-- s_bs = decodeLenient +-- "0306413898a49c93cccf3db6e9078c1b6a8e62568e4a4770e0d7d96792d1c580ad" +-- +-- s :: S.Projective +-- 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" +-- diff --git a/bench/Weight.hs b/bench/Weight.hs @@ -0,0 +1,155 @@ +{-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE OverloadedStrings #-} + +module Main where + +import qualified Data.Word.Wider as W +import qualified Numeric.Montgomery.Secp256k1.Curve as C +import qualified Numeric.Montgomery.Secp256k1.Scalar as S +import qualified Weigh + +-- note that 'weigh' doesn't work properly in a repl +main :: IO () +main = W.mainWith $ do + add + +add = W.wgroup "add" $ do + W.func "M(1) + M(2)" (C.add one) (to (W.to 2)) + W.func "M(1) + M(2 ^ 255 - 19)" (C.add one) (to (W.to (2 ^ 255 - 19))) + + +-- +-- +-- 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) +-- W.func' "parse_int (big)" parse_int (BS.replicate 32 0xFF) +-- +-- add :: W.Weigh () +-- add = W.wgroup " add" $ do +-- W.func "2 p (double, trivial projective point)" (S.add p) p +-- W.func "2 r (double, nontrivial projective point)" (S.add r) r +-- W.func "p + q (trivial projective points)" (S.add p) q +-- W.func "p + s (nontrivial mixed points)" (S.add p) s +-- W.func "s + r (nontrivial projective points)" (S.add s) r +-- +-- mul :: W.Weigh () +-- mul = W.wgroup "mul" $ do +-- W.func "2 G" (S.mul S._CURVE_G) 2 +-- W.func "(2 ^ 255 - 19) G" (S.mul S._CURVE_G) big +-- +-- mul_unsafe :: W.Weigh () +-- mul_unsafe = W.wgroup "mul_unsafe" $ do +-- W.func "2 G" (S.mul_unsafe S._CURVE_G) 2 +-- W.func "(2 ^ 255 - 19) G" (S.mul_unsafe S._CURVE_G) big +-- +-- mul_wnaf :: W.Weigh () +-- mul_wnaf = W.wgroup "mul_wnaf" $ do +-- W.value "precompute" S.precompute +-- W.func "2 G" (S.mul_wnaf tex) 2 +-- W.func "(2 ^ 255 - 19) G" (S.mul_wnaf tex) big +-- +-- derive_pub :: W.Weigh () +-- derive_pub = W.wgroup "derive_pub" $ do +-- W.func "sk = 2" S.derive_pub 2 +-- W.func "sk = 2 ^ 255 - 19" S.derive_pub big +-- W.func "wnaf, sk = 2" (S.derive_pub' tex) 2 +-- W.func "wnaf, sk = 2 ^ 255 - 19" (S.derive_pub' tex) big +-- +-- schnorr :: W.Weigh () +-- schnorr = W.wgroup "schnorr" $ do +-- W.func "sign_schnorr (small)" (S.sign_schnorr 2 s_msg) s_aux +-- W.func "sign_schnorr (large)" (S.sign_schnorr big s_msg) s_aux +-- W.func "sign_schnorr' (small)" (S.sign_schnorr' tex 2 s_msg) s_aux +-- W.func "sign_schnorr' (large)" (S.sign_schnorr' tex big s_msg) s_aux +-- W.func "verify_schnorr" (S.verify_schnorr s_msg s_pk) s_sig +-- W.func "verify_schnorr'" (S.verify_schnorr' tex s_msg s_pk) s_sig +-- +-- ecdsa :: W.Weigh () +-- ecdsa = W.wgroup "ecdsa" $ do +-- W.func "sign_ecdsa (small)" (S.sign_ecdsa 2) s_msg +-- W.func "sign_ecdsa (large)" (S.sign_ecdsa big) s_msg +-- W.func "sign_ecdsa' (small)" (S.sign_ecdsa' tex 2) s_msg +-- W.func "sign_ecdsa' (large)" (S.sign_ecdsa' tex big) s_msg +-- W.func "verify_ecdsa" (S.verify_ecdsa msg pub) sig +-- W.func "verify_ecdsa'" (S.verify_ecdsa' tex msg pub) sig +-- where +-- Just pub = S.derive_pub big +-- msg = "i approve of this message" +-- Just sig = S.sign_ecdsa big s_msg +-- +-- ecdh :: W.Weigh () +-- ecdh = W.wgroup "ecdh" $ do +-- W.func "ecdh (small)" (S.ecdh pub) 2 +-- W.func "ecdh (large)" (S.ecdh pub) b +-- where +-- b = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed +-- Just pub = S.parse_point . decodeLenient $ +-- "bd02b9dfc8ef760708950bd972f2dc244893b61b6b46c3b19be1b2da7b034ac5" +-- +-- s_sk :: Integer +-- s_sk = parse_int . 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" +-- +-- 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 +-- +-- s_bs :: BS.ByteString +-- s_bs = decodeLenient +-- "0306413898a49c93cccf3db6e9078c1b6a8e62568e4a4770e0d7d96792d1c580ad" +-- +-- s :: S.Projective +-- s = case S.parse_point s_bs of +-- Nothing -> error "bang" +-- Just !pt -> pt + diff --git a/ppad-fixed.cabal b/ppad-fixed.cabal @@ -33,3 +33,31 @@ library base >= 4.9 && < 5 , deepseq >= 1.5 && < 1.6 +benchmark fixed-bench + type: exitcode-stdio-1.0 + default-language: Haskell2010 + hs-source-dirs: bench + main-is: Main.hs + + ghc-options: + -rtsopts -O2 -Wall -fno-warn-orphans + + build-depends: + base + , criterion + , ppad-fixed + +benchmark fixed-weigh + type: exitcode-stdio-1.0 + default-language: Haskell2010 + hs-source-dirs: bench + main-is: Weight.hs + + ghc-options: + -rtsopts -O2 -Wall -fno-warn-orphans + + build-depends: + base + , ppad-fixed + , weigh +