secp256k1

Pure Haskell Schnorr, ECDSA on the elliptic curve secp256k1 (docs.ppad.tech/secp256k1).
git clone git://git.ppad.tech/secp256k1.git
Log | Files | Refs | README | LICENSE

Main.hs (6797B)


      1 {-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-}
      2 {-# LANGUAGE BangPatterns #-}
      3 {-# LANGUAGE OverloadedStrings #-}
      4 
      5 module Main where
      6 
      7 import qualified Data.ByteString as BS
      8 import qualified Data.ByteString.Base16 as B16
      9 import Control.DeepSeq
     10 import Criterion.Main
     11 import qualified Crypto.Curve.Secp256k1 as S
     12 
     13 instance NFData S.Projective
     14 instance NFData S.Affine
     15 instance NFData S.ECDSA
     16 instance NFData S.Context
     17 
     18 main :: IO ()
     19 main = defaultMain [
     20     parse_point
     21   , add
     22   , mul
     23   , precompute
     24   , mul_wnaf
     25   , derive_pub
     26   , schnorr
     27   , ecdsa
     28   ]
     29 
     30 remQ :: Benchmark
     31 remQ = env setup $ \x ->
     32     bgroup "remQ (remainder modulo _CURVE_Q)" [
     33       bench "remQ 2 " $ nf S.remQ 2
     34     , bench "remQ (2 ^ 255 - 19)" $ nf S.remQ x
     35     ]
     36   where
     37     setup = pure . S.parse_int256 $ B16.decodeLenient
     38       "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
     39 
     40 parse_point :: Benchmark
     41 parse_point = bgroup "parse_point" [
     42     bench "compressed" $ nf S.parse_point p_bs
     43   , bench "uncompressed" $ nf S.parse_point t_bs
     44   , bench "bip0340" $ nf S.parse_point (BS.drop 1 p_bs)
     45   ]
     46 
     47 parse_integer :: Benchmark
     48 parse_integer = env setup $ \ ~(small, big) ->
     49     bgroup "parse_int256" [
     50       bench "parse_int256 (small)" $ nf S.parse_int256 small
     51     , bench "parse_int256 (big)" $ nf S.parse_int256 big
     52     ]
     53   where
     54     setup = do
     55       let small = BS.replicate 32 0x00
     56           big   = BS.replicate 32 0xFF
     57       pure (small, big)
     58 
     59 add :: Benchmark
     60 add = bgroup "add" [
     61     bench "2 p (double, trivial projective point)" $ nf (S.add p) p
     62   , bench "2 r (double, nontrivial projective point)" $ nf (S.add r) r
     63   , bench "p + q (trivial projective points)" $ nf (S.add p) q
     64   , bench "p + s (nontrivial mixed points)" $ nf (S.add p) s
     65   , bench "s + r (nontrivial projective points)" $ nf (S.add s) r
     66   ]
     67 
     68 mul :: Benchmark
     69 mul = env setup $ \x ->
     70     bgroup "mul" [
     71       bench "2 G" $ nf (S.mul S._CURVE_G) 2
     72     , bench "(2 ^ 255 - 19) G" $ nf (S.mul S._CURVE_G) x
     73     ]
     74   where
     75     setup = pure . S.parse_int256 $ B16.decodeLenient
     76       "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
     77 
     78 precompute :: Benchmark
     79 precompute = bench "precompute" $ nfIO (pure S.precompute)
     80 
     81 mul_wnaf :: Benchmark
     82 mul_wnaf = env setup $ \ ~(tex, x) ->
     83     bgroup "mul_wnaf" [
     84       bench "2 G" $ nf (S.mul_wnaf tex) 2
     85     , bench "(2 ^ 255 - 19) G" $ nf (S.mul_wnaf tex) x
     86     ]
     87   where
     88     setup = do
     89       let !tex = S.precompute
     90           !int = S.parse_int256 $ B16.decodeLenient
     91             "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
     92       pure (tex, int)
     93 
     94 derive_pub :: Benchmark
     95 derive_pub = env setup $ \ ~(tex, x) ->
     96     bgroup "derive_pub" [
     97       bench "sk = 2" $ nf S.derive_pub 2
     98     , bench "sk = 2 ^ 255 - 19" $ nf S.derive_pub x
     99     , bench "wnaf, sk = 2" $ nf (S.derive_pub' tex) 2
    100     , bench "wnaf, sk = 2 ^ 255 - 19" $ nf (S.derive_pub' tex) x
    101     ]
    102   where
    103     setup = do
    104       let !tex = S.precompute
    105           !int = S.parse_int256 $ B16.decodeLenient
    106             "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
    107       pure (tex, int)
    108 
    109 schnorr :: Benchmark
    110 schnorr = env setup $ \ ~(tex, big) ->
    111     bgroup "schnorr" [
    112       bench "sign_schnorr (small)" $ nf (S.sign_schnorr 2 s_msg) s_aux
    113     , bench "sign_schnorr (large)" $ nf (S.sign_schnorr big s_msg) s_aux
    114     , bench "sign_schnorr' (small)" $ nf (S.sign_schnorr' tex 2 s_msg) s_aux
    115     , bench "sign_schnorr' (large)" $ nf (S.sign_schnorr' tex big s_msg) s_aux
    116     , bench "verify_schnorr" $ nf (S.verify_schnorr s_msg s_pk) s_sig
    117     , bench "verify_schnorr'" $ nf (S.verify_schnorr' tex s_msg s_pk) s_sig
    118     ]
    119   where
    120     setup = do
    121       let !tex = S.precompute
    122           !int = S.parse_int256 $ B16.decodeLenient
    123             "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
    124       pure (tex, int)
    125 
    126 ecdsa :: Benchmark
    127 ecdsa = env setup $ \ ~(tex, big, pub, msg, sig) ->
    128     bgroup "ecdsa" [
    129       bench "sign_ecdsa (small)" $ nf (S.sign_ecdsa 2) s_msg
    130     , bench "sign_ecdsa (large)" $ nf (S.sign_ecdsa big) s_msg
    131     , bench "sign_ecdsa' (small)" $ nf (S.sign_ecdsa' tex 2) s_msg
    132     , bench "sign_ecdsa' (large)" $ nf (S.sign_ecdsa' tex big) s_msg
    133     , bench "verify_ecdsa" $ nf (S.verify_ecdsa msg pub) sig
    134     , bench "verify_ecdsa'" $ nf (S.verify_ecdsa' tex msg pub) sig
    135     ]
    136   where
    137     setup = do
    138       let !tex = S.precompute
    139           big = S.parse_int256 $ B16.decodeLenient
    140             "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
    141           pub = S.derive_pub big
    142           msg = "i approve of this message"
    143           sig = S.sign_ecdsa big s_msg
    144       pure (tex, big, pub, msg, sig)
    145 
    146 p_bs :: BS.ByteString
    147 p_bs = B16.decodeLenient
    148   "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
    149 
    150 p :: S.Projective
    151 p = case S.parse_point p_bs of
    152   Nothing -> error "bang"
    153   Just !pt -> pt
    154 
    155 q_bs :: BS.ByteString
    156 q_bs = B16.decodeLenient
    157   "02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9"
    158 
    159 q :: S.Projective
    160 q = case S.parse_point q_bs of
    161   Nothing -> error "bang"
    162   Just !pt -> pt
    163 
    164 r_bs :: BS.ByteString
    165 r_bs = B16.decodeLenient
    166   "03a2113cf152585d96791a42cdd78782757fbfb5c6b2c11b59857eb4f7fda0b0e8"
    167 
    168 r :: S.Projective
    169 r = case S.parse_point r_bs of
    170   Nothing -> error "bang"
    171   Just !pt -> pt
    172 
    173 s_bs :: BS.ByteString
    174 s_bs = B16.decodeLenient
    175   "0306413898a49c93cccf3db6e9078c1b6a8e62568e4a4770e0d7d96792d1c580ad"
    176 
    177 s :: S.Projective
    178 s = case S.parse_point s_bs of
    179   Nothing -> error "bang"
    180   Just !pt -> pt
    181 
    182 t_bs :: BS.ByteString
    183 t_bs = B16.decodeLenient "04b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9"
    184 
    185 t :: S.Projective
    186 t = case S.parse_point t_bs of
    187   Nothing -> error "bang"
    188   Just !pt -> pt
    189 
    190 s_sk :: Integer
    191 s_sk = S.parse_int256 . B16.decodeLenient $
    192   "B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF"
    193 
    194 s_sig :: BS.ByteString
    195 s_sig = B16.decodeLenient "6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A"
    196 
    197 s_pk_raw :: BS.ByteString
    198 s_pk_raw = B16.decodeLenient
    199   "DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"
    200 
    201 s_pk :: S.Projective
    202 s_pk = case S.parse_point s_pk_raw of
    203   Nothing -> error "bang"
    204   Just !pt -> pt
    205 
    206 s_msg :: BS.ByteString
    207 s_msg = B16.decodeLenient
    208   "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"
    209 
    210 s_aux :: BS.ByteString
    211 s_aux = B16.decodeLenient
    212   "0000000000000000000000000000000000000000000000000000000000000001"
    213 
    214 -- e_msg = B16.decodeLenient "313233343030"
    215 -- e_sig = B16.decodeLenient "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba"
    216