commit 295e72cdbc0eadb60e245ea31d1da74721c3baa2
parent 42fbbc0e8493c5c1981427e7493a3fa0b2822872
Author: Jared Tobin <jared@jtobin.io>
Date: Fri, 18 Oct 2024 16:34:33 +0400
lib: add derive_public
Diffstat:
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