packages feed

ppad-secp256k1 0.2.1 → 0.2.2

raw patch · 3 files changed

+61/−39 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Crypto.Curve.Secp256k1: _CURVE_G :: Projective
+ Crypto.Curve.Secp256k1: _CURVE_P :: Integer
+ Crypto.Curve.Secp256k1: _CURVE_Q :: Integer
+ Crypto.Curve.Secp256k1: _CURVE_ZERO :: Projective
+ Crypto.Curve.Secp256k1: modQ :: Integer -> Integer
+ Crypto.Curve.Secp256k1: remQ :: Integer -> Integer

Files

CHANGELOG view
@@ -1,5 +1,8 @@ # Changelog +- 0.2.2 (2025-02-16)+  * Exports the secp256k1 "point at infinity" as _CURVE_ZERO.+ - 0.2.1 (2024-12-18)   * Adds 'serialize_point' for compressed-format serialization of     secp256k1 points.
lib/Crypto/Curve/Secp256k1.hs view
@@ -21,10 +21,18 @@ -- "low-S" signatures) on the elliptic curve secp256k1.  module Crypto.Curve.Secp256k1 (+  -- * Field and group parameters+    _CURVE_Q+  , _CURVE_P+  , remQ+  , modQ+   -- * secp256k1 points-    Pub+  , Pub   , derive_pub   , derive_pub'+  , _CURVE_G+  , _CURVE_ZERO    -- * Parsing   , parse_int256@@ -74,11 +82,6 @@   -- for testing/benchmarking   , _sign_ecdsa_no_hash   , _sign_ecdsa_no_hash'-  , _CURVE_P-  , _CURVE_Q-  , _CURVE_G-  , remQ-  , modQ   ) where  import Control.Monad (when)@@ -182,15 +185,6 @@   where     l = BS.length u --- replacing the following w/a series of functions with the hashed tags--- hard-coded is possible, but there is virtually no performance benefit---- (bip0340) tagged hash function-hash_tagged :: BS.ByteString -> BS.ByteString -> BS.ByteString-hash_tagged tag x =-  let !h = SHA256.hash tag-  in  SHA256.hash (h <> h <> x)- -- (bip0340) return point with x coordinate == x and with even y coordinate lift :: Integer -> Maybe Affine lift x@@ -237,7 +231,7 @@ -- Convert to affine coordinates. affine :: Projective -> Affine affine p@(Projective x y z)-  | p == _ZERO = Affine 0 0+  | p == _CURVE_ZERO = Affine 0 0   | z == 1     = Affine x y   | otherwise  = case modinv z (fi _CURVE_P) of       Nothing -> error "ppad-secp256k1 (affine): impossible point"@@ -246,7 +240,7 @@ -- Convert to projective coordinates. projective :: Affine -> Projective projective (Affine x y)-  | x == 0 && y == 0 = _ZERO+  | x == 0 && y == 0 = _CURVE_ZERO   | otherwise = Projective x y 1  -- Point is valid@@ -260,13 +254,13 @@ -- curve parameters ----------------------------------------------------------- -- see https://www.secg.org/sec2-v2.pdf for parameter specs --- secp256k1 field prime+-- | secp256k1 field prime. ----- = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1+--   = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 _CURVE_P :: Integer _CURVE_P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F --- secp256k1 group order+-- | secp256k1 group order. _CURVE_Q :: Integer _CURVE_Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 @@ -290,7 +284,7 @@ _CURVE_B :: Integer _CURVE_B = 7 --- secp256k1 generator+-- | secp256k1 generator point. -- -- = parse_point --     "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"@@ -299,9 +293,14 @@   x = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798   y = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 +-- | secp256k1 zero point / point at infinity / monoidal identity.+_CURVE_ZERO :: Projective+_CURVE_ZERO = Projective 0 1 0+ -- secp256k1 zero point / point at infinity / monoidal identity _ZERO :: Projective _ZERO = Projective 0 1 0+{-# DEPRECATED _ZERO "use _CURVE_ZERO instead" #-}  -- secp256k1 in prime order j-invariant 0 form (i.e. a == 0). weierstrass :: Integer -> Integer@@ -321,13 +320,12 @@ remP a = I.integerRem a _CURVE_P {-# INLINE remP #-} --- Division modulo secp256k1 group order.+-- | Division modulo secp256k1 group order. modQ :: Integer -> Integer modQ a = I.integerMod a _CURVE_Q {-# INLINE modQ #-} --- Division modulo secp256k1 group order, when argument is nonnegative.--- (more efficient than modQ)+-- | Division modulo secp256k1 group order, when argument is nonnegative. remQ :: Integer -> Integer remQ a = I.integerRem a _CURVE_Q {-# INLINE remQ #-}@@ -356,8 +354,8 @@         when (ev > 0) $ do           when (I.integerTestBit ev 0) $ do             numv <- readSTRef num-            modifySTRef' r (\rv -> (rv * numv) `I.integerRem` _CURVE_P)-          modifySTRef' num (\numv -> (numv * numv) `I.integerRem` _CURVE_P)+            modifySTRef' r (\rv -> remP (rv * numv))+          modifySTRef' num (\numv -> remP (numv * numv))           modifySTRef' e (`I.integerShiftR` 1)           loop @@ -555,7 +553,7 @@ mul :: Projective -> Integer -> Projective mul p _SECRET     | not (ge _SECRET) = error "ppad-secp256k1 (mul): scalar not in group"-    | otherwise  = loop (0 :: Int) _ZERO _CURVE_G p _SECRET+    | otherwise  = loop (0 :: Int) _CURVE_ZERO _CURVE_G p _SECRET   where     loop !j !acc !f !d !m       | j == _CURVE_Q_BITS = acc@@ -572,10 +570,10 @@ -- Don't use this function if the scalar could potentially be a secret. mul_unsafe :: Projective -> Integer -> Projective mul_unsafe p n-    | n == 0 = _ZERO+    | n == 0 = _CURVE_ZERO     | not (ge n) =         error "ppad-secp256k1 (mul_unsafe): scalar not in group"-    | otherwise  = loop _ZERO p n+    | otherwise  = loop _CURVE_ZERO p n   where     loop !r !d m       | m <= 0 = r@@ -635,7 +633,7 @@ -- secp256k1 points. mul_wnaf :: Context -> Integer -> Projective mul_wnaf Context {..} _SECRET =-    loop 0 _ZERO _CURVE_G _SECRET+    loop 0 _CURVE_ZERO _CURVE_G _SECRET   where     wins = 256 `quot` ctxW + 1     wsize = 2 ^ (ctxW - 1)@@ -779,8 +777,8 @@  -- | Serialize a secp256k1 point in 33-byte compressed form. -----   >>> serialize_point <secp256k1 point>---   "<33-byte bytestring>"+--   >>> serialize_point pub+--   "<33-byte compressed point>" serialize_point :: Projective -> BS.ByteString serialize_point (affine -> Affine x y) = BS.cons b (unroll32 x) where   b | I.integerTestBit y 0 = 0x03@@ -845,11 +843,11 @@             | otherwise = _SECRET            bytes_d = unroll32 d-          h_a = hash_tagged "BIP0340/aux" a+          h_a = hash_aux a           t = xor bytes_d h_a            bytes_p = unroll32 x_p-          rand = hash_tagged "BIP0340/nonce" (t <> bytes_p <> m)+          rand = hash_nonce (t <> bytes_p <> m)            k' = modQ (roll32 rand) @@ -861,7 +859,7 @@                   | otherwise = k'                  bytes_r = unroll32 x_r-                e = modQ . roll32 . hash_tagged "BIP0340/challenge"+                e = modQ . roll32 . hash_challenge                   $ bytes_r <> bytes_p <> m                  bytes_ked = unroll32 (modQ (k + e * d))@@ -920,16 +918,37 @@         let (roll32 -> r, roll32 -> s) = BS.splitAt 32 sig         in  if   r >= _CURVE_P || s >= _CURVE_Q             then False-            else let e = modQ . roll32 $ hash_tagged "BIP0340/challenge"+            else let e = modQ . roll32 $ hash_challenge                            (unroll32 r <> unroll32 x_P <> m)                      dif = add (_mul s)                                (neg (mul_unsafe (projective capP) e))-                 in  if   dif == _ZERO+                 in  if   dif == _CURVE_ZERO                      then False                      else let Affine x_R y_R = affine dif                           in  not (I.integerTestBit y_R 0 || x_R /= r) {-# INLINE _verify_schnorr #-} +-- hardcoded tag of BIP0340/aux+--+-- \x -> let h = SHA256.hash "BIP0340/aux"+--       in  SHA256.hash (h <> h <> x)+hash_aux :: BS.ByteString -> BS.ByteString+hash_aux x = SHA256.hash $+  "\241\239N^\192c\202\218m\148\202\250\157\152~\160i&X9\236\193\US\151-w\165.\216\193\204\144\241\239N^\192c\202\218m\148\202\250\157\152~\160i&X9\236\193\US\151-w\165.\216\193\204\144" <> x+{-# INLINE hash_aux #-}++-- hardcoded tag of BIP0340/nonce+hash_nonce :: BS.ByteString -> BS.ByteString+hash_nonce x = SHA256.hash $+  "\aIw4\167\155\203\&5[\155\140}\ETXO\DC2\FS\244\&4\215>\247-\218\EM\135\NULa\251R\191\235/\aIw4\167\155\203\&5[\155\140}\ETXO\DC2\FS\244\&4\215>\247-\218\EM\135\NULa\251R\191\235/" <> x+{-# INLINE hash_nonce #-}++-- hardcoded tag of BIP0340/challenge+hash_challenge :: BS.ByteString -> BS.ByteString+hash_challenge x = SHA256.hash $+  "{\181-z\159\239X2>\177\191z@}\179\130\210\243\242\216\ESC\177\"OI\254Q\143mH\211|{\181-z\159\239X2>\177\191z@}\179\130\210\243\242\216\ESC\177\"OI\254Q\143mH\211|" <> x+{-# INLINE hash_challenge #-}+ -- ecdsa ---------------------------------------------------------------------- -- see https://www.rfc-editor.org/rfc/rfc6979, https://secg.org/sec1-v2.pdf @@ -1211,7 +1230,7 @@           u1   = remQ (e * s_inv)           u2   = remQ (r * s_inv)           capR = add (_mul u1) (mul_unsafe p u2)-      in  if   capR == _ZERO+      in  if   capR == _CURVE_ZERO           then False           else let Affine (modQ -> v) _ = affine capR                in  v == r
ppad-secp256k1.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               ppad-secp256k1-version:            0.2.1+version:            0.2.2 synopsis:           Schnorr signatures & ECDSA on the elliptic curve secp256k1 license:            MIT license-file:       LICENSE