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

commit 295e72cdbc0eadb60e245ea31d1da74721c3baa2
parent 42fbbc0e8493c5c1981427e7493a3fa0b2822872
Author: Jared Tobin <jared@jtobin.io>
Date:   Fri, 18 Oct 2024 16:34:33 +0400

lib: add derive_public

Diffstat:
MREADME.md | 12++++++++++++
Mbench/Main.hs | 11+++++++++++
Mlib/Crypto/Curve/Secp256k1.hs | 16++++++++++++++++
3 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/README.md b/README.md @@ -54,6 +54,18 @@ so as to execute algorithmically in time constant with respect to secret data: ``` + benchmarking derive_public/sk = 2 + time 1.703 ms (1.680 ms .. 1.728 ms) + 0.997 R² (0.995 R² .. 0.999 R²) + mean 1.704 ms (1.684 ms .. 1.730 ms) + std dev 81.99 μs (67.86 μs .. 98.34 μs) + + benchmarking derive_public/sk = 2 ^ 255 - 19 + time 1.686 ms (1.654 ms .. 1.730 ms) + 0.998 R² (0.997 R² .. 0.999 R²) + mean 1.658 ms (1.645 ms .. 1.673 ms) + std dev 44.75 μs (34.84 μs .. 59.81 μs) + benchmarking schnorr/sign_schnorr (small secret) time 5.388 ms (5.345 ms .. 5.438 ms) 1.000 R² (0.999 R² .. 1.000 R²) diff --git a/bench/Main.hs b/bench/Main.hs @@ -20,6 +20,7 @@ main = defaultMain [ parse_point , add , mul + , derive_public , schnorr , ecdsa ] @@ -62,6 +63,16 @@ mul = env setup $ \x -> setup = pure . S.parse_int256 $ B16.decodeLenient "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed" +derive_public :: Benchmark +derive_public = env setup $ \x -> + bgroup "derive_public" [ + bench "sk = 2" $ nf S.derive_public 2 + , bench "sk = 2 ^ 255 - 19" $ nf S.derive_public x + ] + where + setup = pure . S.parse_int256 $ B16.decodeLenient + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed" + schnorr :: Benchmark schnorr = env setup $ \big -> bgroup "schnorr" [ diff --git a/lib/Crypto/Curve/Secp256k1.hs b/lib/Crypto/Curve/Secp256k1.hs @@ -43,6 +43,7 @@ module Crypto.Curve.Secp256k1 ( , double , mul , mul_unsafe + , derive_public -- Coordinate systems and transformations , Affine(..) @@ -574,6 +575,21 @@ mul_unsafe p n nr = if I.integerTestBit m 0 then add r d else r in loop nr nd nm +-- | Derive a public key (i.e., a secp256k1 point) from the provided +-- secret. +-- +-- >>> import qualified System.Entropy as E +-- >>> sk <- fmap parse_int256 (E.getEntropy 32) +-- >>> derive_public sk +-- "<secp256k1 point>" +derive_public :: Integer -> Pub +derive_public _SECRET + | not (ge _SECRET) = + error "ppad-secp256k1 (derive_public): invalid secret key" + | otherwise = + mul _CURVE_G _SECRET +{-# NOINLINE derive_public #-} + -- parsing -------------------------------------------------------------------- parse_int256 :: BS.ByteString -> Integer