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 e7f61dd076cfb19baeec5c8929a3353a23a6e0a8
parent 6e7966341c1bc5fa1feb333570a05c97e34a6b7e
Author: Jared Tobin <jared@jtobin.io>
Date:   Sun,  7 Jun 2026 17:31:52 -0230

lib: remove vestigial fake point in scalar mul

The original "soft" constant-time implementation of this function
included in early library versions relied on a fake/dummy accumulator
in order to perform a constant amount of work. When I later introduced
the stricter, fully-branchless constant time version, I kept the dummy
point around, but it's not actually necessary to do that. The branchless
constant-time select forces work on every iteration, so the dummy
accumulator doesn't actually do anything useful for us.

Removing it saves 14 field multiplications per iteration (~3.6k field
multiplications in total), shaving off about 50 microseconds from the
total time. The constant time semantics are unaffected.

Diffstat:
Mlib/Crypto/Curve/Secp256k1.hs | 10++++------
1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/lib/Crypto/Curve/Secp256k1.hs b/lib/Crypto/Curve/Secp256k1.hs @@ -567,18 +567,16 @@ mul# :: Proj -> Limb4 -> (# () | Proj #) mul# (# px, py, pz #) s | CT.decide (CT.not (ge# s)) = (# () | #) | otherwise = - let !(P gx gy gz) = _CURVE_G - !(C.Montgomery o) = C.one - in loop (0 :: Int) (# Z, o, Z #) (# gx, gy, gz #) (# px, py, pz #) s + let !(C.Montgomery o) = C.one + in loop (0 :: Int) (# Z, o, Z #) (# px, py, pz #) s where - loop !j !a !f !d !_SECRET + loop !j !a !d !_SECRET | j == _CURVE_Q_BITS = (# | a #) | otherwise = let !nd = double# d !(# nm, lsb_set #) = W.shr1_c# _SECRET !nacc = select_proj# a (add_proj# a d) lsb_set - !nf = select_proj# (add_proj# f d) f lsb_set - in loop (succ j) nacc nf nd nm + in loop (succ j) nacc nd nm {-# INLINE mul# #-} mul_vartime# :: Proj -> Limb4 -> (# () | Proj #)