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

Secp256k1.hs (46107B)


      1 {-# OPTIONS_HADDOCK prune #-}
      2 {-# LANGUAGE BangPatterns #-}
      3 {-# LANGUAGE CPP #-}
      4 {-# LANGUAGE DeriveGeneric #-}
      5 {-# LANGUAGE DerivingStrategies #-}
      6 {-# LANGUAGE LambdaCase #-}
      7 {-# LANGUAGE MagicHash #-}
      8 {-# LANGUAGE OverloadedStrings #-}
      9 {-# LANGUAGE PatternSynonyms #-}
     10 {-# LANGUAGE RecordWildCards #-}
     11 {-# LANGUAGE UnboxedTuples #-}
     12 {-# LANGUAGE ViewPatterns #-}
     13 
     14 #include "MachDeps.h"
     15 #if WORD_SIZE_IN_BITS != 64
     16 #error "ppad-secp256k1 requires a 64-bit architecture"
     17 #endif
     18 
     19 -- |
     20 -- Module: Crypto.Curve.Secp256k1
     21 -- Copyright: (c) 2024 Jared Tobin
     22 -- License: MIT
     23 -- Maintainer: Jared Tobin <jared@ppad.tech>
     24 --
     25 -- Pure [BIP0340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki)
     26 -- Schnorr signatures, deterministic
     27 -- [RFC6979](https://www.rfc-editor.org/rfc/rfc6979) ECDSA (with
     28 -- [BIP0146](https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki)-style
     29 -- "low-S" signatures), and ECDH shared secret computation
     30 --  on the elliptic curve secp256k1.
     31 
     32 module Crypto.Curve.Secp256k1 (
     33   -- * Parsing
     34     parse_int256
     35   , parse_point
     36   , parse_sig
     37 
     38   -- * Serializing
     39   , serialize_point
     40 
     41   -- * secp256k1 points
     42   , Pub
     43   , derive_pub
     44   , derive_pub'
     45   , _CURVE_G
     46   , _CURVE_ZERO
     47   , ge
     48   , fe
     49 
     50   -- * ECDH
     51   , ecdh
     52 
     53   -- * BIP0340 Schnorr signatures
     54   , sign_schnorr
     55   , verify_schnorr
     56 
     57   -- * RFC6979 ECDSA
     58   , ECDSA(..)
     59   , SigType(..)
     60   , sign_ecdsa
     61   , sign_ecdsa_unrestricted
     62   , verify_ecdsa
     63   , verify_ecdsa_unrestricted
     64 
     65   -- * Fast variants
     66   , Context
     67   , precompute
     68   , sign_schnorr'
     69   , verify_schnorr'
     70   , sign_ecdsa'
     71   , sign_ecdsa_unrestricted'
     72   , verify_ecdsa'
     73   , verify_ecdsa_unrestricted'
     74 
     75   -- Elliptic curve group operations
     76   , neg
     77   , add
     78   , add_mixed
     79   , add_proj
     80   , double
     81   , mul
     82   , mul_vartime
     83   , mul_wnaf
     84 
     85   -- * Field and group parameters
     86   , _CURVE_Q
     87   , _CURVE_P
     88 
     89   -- Coordinate systems and transformations
     90   , Affine(..)
     91   , Projective(..)
     92   , affine
     93   , projective
     94   , valid
     95 
     96   -- for testing/benchmarking
     97   , _precompute
     98   , _sign_ecdsa_no_hash
     99   , _sign_ecdsa_no_hash'
    100   , roll32
    101   , unsafe_roll32
    102   , unroll32
    103   , select_proj
    104   ) where
    105 
    106 import Control.Monad (guard)
    107 import Control.Monad.ST
    108 import qualified Crypto.DRBG.HMAC.SHA256 as DRBG
    109 import qualified Crypto.Hash.SHA256 as SHA256
    110 import qualified Data.Bits as B
    111 import qualified Data.ByteString as BS
    112 import qualified Data.ByteString.Internal as BI
    113 import qualified Data.ByteString.Unsafe as BU
    114 import qualified Data.Choice as CT
    115 import qualified Data.Maybe as M
    116 import Data.Primitive.ByteArray (ByteArray(..), MutableByteArray(..))
    117 import qualified Data.Primitive.ByteArray as BA
    118 import Data.Word (Word8)
    119 import Data.Word.Limb (Limb(..))
    120 import qualified Data.Word.Limb as L
    121 import Data.Word.Wider (Wider(..))
    122 import qualified Data.Word.Wider as W
    123 import qualified Foreign.Storable as Storable (pokeByteOff)
    124 import qualified GHC.Exts as Exts
    125 import GHC.Generics
    126 import qualified GHC.Word (Word(..), Word8(..))
    127 import qualified Numeric.Montgomery.Secp256k1.Curve as C
    128 import qualified Numeric.Montgomery.Secp256k1.Scalar as S
    129 import Prelude hiding (sqrt)
    130 
    131 -- convenience synonyms -------------------------------------------------------
    132 
    133 -- Unboxed Wider/Montgomery synonym.
    134 type Limb4 = (# Limb, Limb, Limb, Limb #)
    135 
    136 -- Unboxed Projective synonym.
    137 type Proj = (# Limb4, Limb4, Limb4 #)
    138 
    139 pattern Z :: Limb4
    140 pattern Z = (# Limb 0##, Limb 0##, Limb 0##, Limb 0## #)
    141 
    142 pattern P :: Limb4 -> Limb4 -> Limb4 -> Projective
    143 pattern P x y z = Projective (C.Montgomery x) (C.Montgomery y) (C.Montgomery z)
    144 {-# COMPLETE P #-}
    145 
    146 -- utilities ------------------------------------------------------------------
    147 
    148 fi :: (Integral a, Num b) => a -> b
    149 fi = fromIntegral
    150 {-# INLINE fi #-}
    151 
    152 -- convert a Word8 to a Limb
    153 limb :: Word8 -> Limb
    154 limb (GHC.Word.W8# (Exts.word8ToWord# -> w)) = Limb w
    155 {-# INLINABLE limb #-}
    156 
    157 -- convert a Limb to a Word8
    158 word8 :: Limb -> Word8
    159 word8 (Limb w) = GHC.Word.W8# (Exts.wordToWord8# w)
    160 {-# INLINABLE word8 #-}
    161 
    162 -- convert a Limb to a Word8 after right-shifting
    163 word8s :: Limb -> Exts.Int# -> Word8
    164 word8s l s =
    165   let !(Limb w) = L.shr# l s
    166   in  GHC.Word.W8# (Exts.wordToWord8# w)
    167 {-# INLINABLE word8s #-}
    168 
    169 -- convert a Word8 to a Wider
    170 word8_to_wider :: Word8 -> Wider
    171 word8_to_wider w = Wider (# limb w, Limb 0##, Limb 0##, Limb 0## #)
    172 {-# INLINABLE word8_to_wider #-}
    173 
    174 -- unsafely extract the first 64-bit word from a big-endian-encoded bytestring
    175 unsafe_word0 :: BS.ByteString -> Limb
    176 unsafe_word0 bs =
    177           (limb (BU.unsafeIndex bs 00) `L.shl#` 56#)
    178   `L.or#` (limb (BU.unsafeIndex bs 01) `L.shl#` 48#)
    179   `L.or#` (limb (BU.unsafeIndex bs 02) `L.shl#` 40#)
    180   `L.or#` (limb (BU.unsafeIndex bs 03) `L.shl#` 32#)
    181   `L.or#` (limb (BU.unsafeIndex bs 04) `L.shl#` 24#)
    182   `L.or#` (limb (BU.unsafeIndex bs 05) `L.shl#` 16#)
    183   `L.or#` (limb (BU.unsafeIndex bs 06) `L.shl#` 08#)
    184   `L.or#` (limb (BU.unsafeIndex bs 07))
    185 {-# INLINABLE unsafe_word0 #-}
    186 
    187 -- unsafely extract the second 64-bit word from a big-endian-encoded bytestring
    188 unsafe_word1 :: BS.ByteString -> Limb
    189 unsafe_word1 bs =
    190           (limb (BU.unsafeIndex bs 08) `L.shl#` 56#)
    191   `L.or#` (limb (BU.unsafeIndex bs 09) `L.shl#` 48#)
    192   `L.or#` (limb (BU.unsafeIndex bs 10) `L.shl#` 40#)
    193   `L.or#` (limb (BU.unsafeIndex bs 11) `L.shl#` 32#)
    194   `L.or#` (limb (BU.unsafeIndex bs 12) `L.shl#` 24#)
    195   `L.or#` (limb (BU.unsafeIndex bs 13) `L.shl#` 16#)
    196   `L.or#` (limb (BU.unsafeIndex bs 14) `L.shl#` 08#)
    197   `L.or#` (limb (BU.unsafeIndex bs 15))
    198 {-# INLINABLE unsafe_word1 #-}
    199 
    200 -- unsafely extract the third 64-bit word from a big-endian-encoded bytestring
    201 unsafe_word2 :: BS.ByteString -> Limb
    202 unsafe_word2 bs =
    203           (limb (BU.unsafeIndex bs 16) `L.shl#` 56#)
    204   `L.or#` (limb (BU.unsafeIndex bs 17) `L.shl#` 48#)
    205   `L.or#` (limb (BU.unsafeIndex bs 18) `L.shl#` 40#)
    206   `L.or#` (limb (BU.unsafeIndex bs 19) `L.shl#` 32#)
    207   `L.or#` (limb (BU.unsafeIndex bs 20) `L.shl#` 24#)
    208   `L.or#` (limb (BU.unsafeIndex bs 21) `L.shl#` 16#)
    209   `L.or#` (limb (BU.unsafeIndex bs 22) `L.shl#` 08#)
    210   `L.or#` (limb (BU.unsafeIndex bs 23))
    211 {-# INLINABLE unsafe_word2 #-}
    212 
    213 -- unsafely extract the fourth 64-bit word from a big-endian-encoded bytestring
    214 unsafe_word3 :: BS.ByteString -> Limb
    215 unsafe_word3 bs =
    216           (limb (BU.unsafeIndex bs 24) `L.shl#` 56#)
    217   `L.or#` (limb (BU.unsafeIndex bs 25) `L.shl#` 48#)
    218   `L.or#` (limb (BU.unsafeIndex bs 26) `L.shl#` 40#)
    219   `L.or#` (limb (BU.unsafeIndex bs 27) `L.shl#` 32#)
    220   `L.or#` (limb (BU.unsafeIndex bs 28) `L.shl#` 24#)
    221   `L.or#` (limb (BU.unsafeIndex bs 29) `L.shl#` 16#)
    222   `L.or#` (limb (BU.unsafeIndex bs 30) `L.shl#` 08#)
    223   `L.or#` (limb (BU.unsafeIndex bs 31))
    224 {-# INLINABLE unsafe_word3 #-}
    225 
    226 -- 256-bit big-endian bytestring decoding. the input size is not checked!
    227 unsafe_roll32 :: BS.ByteString -> Wider
    228 unsafe_roll32 bs =
    229   let !w0 = unsafe_word0 bs
    230       !w1 = unsafe_word1 bs
    231       !w2 = unsafe_word2 bs
    232       !w3 = unsafe_word3 bs
    233   in  Wider (# w3, w2, w1, w0 #)
    234 {-# INLINABLE unsafe_roll32 #-}
    235 
    236 -- arbitrary-size big-endian bytestring decoding
    237 roll32 :: BS.ByteString -> Maybe Wider
    238 roll32 bs
    239     | BS.length stripped > 32 = Nothing
    240     | otherwise = Just $! BS.foldl' alg 0 stripped
    241   where
    242     stripped = BS.dropWhile (== 0) bs
    243     alg !a (word8_to_wider -> !b) = (a `W.shl_limb` 8) `W.or` b
    244 {-# INLINABLE roll32 #-}
    245 
    246 -- 256-bit big-endian bytestring encoding
    247 unroll32 :: Wider -> BS.ByteString
    248 unroll32 (Wider (# w0, w1, w2, w3 #)) =
    249   BI.unsafeCreate 32 $ \ptr -> do
    250     -- w0
    251     Storable.pokeByteOff ptr 00 (word8s w3 56#)
    252     Storable.pokeByteOff ptr 01 (word8s w3 48#)
    253     Storable.pokeByteOff ptr 02 (word8s w3 40#)
    254     Storable.pokeByteOff ptr 03 (word8s w3 32#)
    255     Storable.pokeByteOff ptr 04 (word8s w3 24#)
    256     Storable.pokeByteOff ptr 05 (word8s w3 16#)
    257     Storable.pokeByteOff ptr 06 (word8s w3 08#)
    258     Storable.pokeByteOff ptr 07 (word8 w3)
    259     -- w1
    260     Storable.pokeByteOff ptr 08 (word8s w2 56#)
    261     Storable.pokeByteOff ptr 09 (word8s w2 48#)
    262     Storable.pokeByteOff ptr 10 (word8s w2 40#)
    263     Storable.pokeByteOff ptr 11 (word8s w2 32#)
    264     Storable.pokeByteOff ptr 12 (word8s w2 24#)
    265     Storable.pokeByteOff ptr 13 (word8s w2 16#)
    266     Storable.pokeByteOff ptr 14 (word8s w2 08#)
    267     Storable.pokeByteOff ptr 15 (word8 w2)
    268     -- w2
    269     Storable.pokeByteOff ptr 16 (word8s w1 56#)
    270     Storable.pokeByteOff ptr 17 (word8s w1 48#)
    271     Storable.pokeByteOff ptr 18 (word8s w1 40#)
    272     Storable.pokeByteOff ptr 19 (word8s w1 32#)
    273     Storable.pokeByteOff ptr 20 (word8s w1 24#)
    274     Storable.pokeByteOff ptr 21 (word8s w1 16#)
    275     Storable.pokeByteOff ptr 22 (word8s w1 08#)
    276     Storable.pokeByteOff ptr 23 (word8 w1)
    277     -- w3
    278     Storable.pokeByteOff ptr 24 (word8s w0 56#)
    279     Storable.pokeByteOff ptr 25 (word8s w0 48#)
    280     Storable.pokeByteOff ptr 26 (word8s w0 40#)
    281     Storable.pokeByteOff ptr 27 (word8s w0 32#)
    282     Storable.pokeByteOff ptr 28 (word8s w0 24#)
    283     Storable.pokeByteOff ptr 29 (word8s w0 16#)
    284     Storable.pokeByteOff ptr 30 (word8s w0 08#)
    285     Storable.pokeByteOff ptr 31 (word8 w0)
    286 {-# INLINABLE unroll32 #-}
    287 
    288 -- modQ via conditional subtraction
    289 modQ :: Wider -> Wider
    290 modQ x = W.select x (x - _CURVE_Q) (CT.not (W.lt x _CURVE_Q))
    291 {-# INLINABLE modQ #-}
    292 
    293 -- bytewise xor
    294 xor :: BS.ByteString -> BS.ByteString -> BS.ByteString
    295 xor = BS.packZipWith B.xor
    296 {-# INLINABLE xor #-}
    297 
    298 -- constants ------------------------------------------------------------------
    299 
    300 -- | secp256k1 field prime.
    301 --
    302 --   >>> _CURVE_P
    303 --   0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
    304 _CURVE_P :: Wider
    305 _CURVE_P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
    306 
    307 -- | secp256k1 group order.
    308 --
    309 --   >>> _CURVE_Q
    310 --   0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
    311 _CURVE_Q :: Wider
    312 _CURVE_Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
    313 
    314 -- | half of the secp256k1 group order.
    315 _CURVE_QH :: Wider
    316 _CURVE_QH = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0
    317 
    318 -- bitlength of group order
    319 --
    320 -- = smallest integer such that _CURVE_Q < 2 ^ _CURVE_Q_BITS
    321 _CURVE_Q_BITS :: Int
    322 _CURVE_Q_BITS = 256
    323 
    324 -- bytelength of _CURVE_Q
    325 --
    326 -- = _CURVE_Q_BITS / 8
    327 _CURVE_Q_BYTES :: Int
    328 _CURVE_Q_BYTES = 32
    329 
    330 -- secp256k1 weierstrass form, /b/ coefficient
    331 _CURVE_B :: Wider
    332 _CURVE_B = 7
    333 
    334 -- secp256k1 weierstrass form, /b/ coefficient, montgomery form
    335 _CURVE_Bm :: C.Montgomery
    336 _CURVE_Bm = 7
    337 
    338 -- _CURVE_Bm * 3
    339 _CURVE_Bm3 :: C.Montgomery
    340 _CURVE_Bm3 = 21
    341 
    342 -- Is field element?
    343 fe :: Wider -> Bool
    344 fe n = case W.cmp_vartime n 0 of
    345   GT -> case W.cmp_vartime n _CURVE_P of
    346     LT -> True
    347     _  -> False
    348   _ -> False
    349 {-# INLINE fe #-}
    350 
    351 -- Is group element?
    352 ge :: Wider -> Bool
    353 ge (Wider n) = CT.decide (ge# n)
    354 {-# INLINE ge #-}
    355 
    356 -- curve points ---------------------------------------------------------------
    357 
    358 -- curve point, affine coordinates
    359 data Affine = Affine !C.Montgomery !C.Montgomery
    360   deriving stock (Show, Generic)
    361 
    362 -- curve point, projective coordinates
    363 data Projective = Projective {
    364     px :: !C.Montgomery
    365   , py :: !C.Montgomery
    366   , pz :: !C.Montgomery
    367   }
    368   deriving stock (Show, Generic)
    369 
    370 instance Eq Projective where
    371   Projective ax ay az == Projective bx by bz =
    372     let !x1z2 = ax * bz
    373         !x2z1 = bx * az
    374         !y1z2 = ay * bz
    375         !y2z1 = by * az
    376     in  CT.decide (CT.and (C.eq x1z2 x2z1) (C.eq y1z2 y2z1))
    377 
    378 -- | A public key, i.e. secp256k1 point.
    379 type Pub = Projective
    380 
    381 -- Convert to affine coordinates.
    382 affine :: Projective -> Affine
    383 affine (Projective x y z) =
    384   let !iz = C.inv z
    385   in  Affine (x * iz) (y * iz)
    386 {-# INLINABLE affine #-}
    387 
    388 -- Convert to projective coordinates.
    389 projective :: Affine -> Projective
    390 projective (Affine x y)
    391   | C.eq_vartime x 0 || C.eq_vartime y 0 = _CURVE_ZERO
    392   | otherwise = Projective x y 1
    393 
    394 -- | secp256k1 generator point.
    395 _CURVE_G :: Projective
    396 _CURVE_G = Projective x y z where
    397   !x = C.Montgomery
    398     (# Limb 15507633332195041431##, Limb  2530505477788034779##
    399     ,  Limb 10925531211367256732##, Limb 11061375339145502536## #)
    400   !y = C.Montgomery
    401     (# Limb 12780836216951778274##, Limb 10231155108014310989##
    402     ,  Limb 8121878653926228278##,  Limb 14933801261141951190## #)
    403   !z = C.Montgomery
    404     (# Limb 0x1000003D1##, Limb 0##, Limb 0##, Limb 0## #)
    405 
    406 -- | secp256k1 zero point, point at infinity, or monoidal identity.
    407 _CURVE_ZERO :: Projective
    408 _CURVE_ZERO = Projective 0 1 0
    409 
    410 -- secp256k1 zero point, point at infinity, or monoidal identity
    411 _ZERO :: Projective
    412 _ZERO = Projective 0 1 0
    413 {-# DEPRECATED _ZERO "use _CURVE_ZERO instead" #-}
    414 
    415 -- secp256k1 in short weierstrass form (y ^ 2 = x ^ 3 + 7)
    416 weierstrass :: C.Montgomery -> C.Montgomery
    417 weierstrass x = C.sqr x * x + _CURVE_Bm
    418 {-# INLINE weierstrass #-}
    419 
    420 -- Point is valid
    421 valid :: Projective -> Bool
    422 valid (affine -> Affine x y) = C.eq_vartime (C.sqr y) (weierstrass x)
    423 
    424 -- (bip0340) return point with x coordinate == x and with even y coordinate
    425 --
    426 -- conceptually:
    427 --   y ^ 2 = x ^ 3 + 7
    428 --   y     = "+-" sqrt (x ^ 3 + 7)
    429 --     (n.b. for solution y, p - y is also a solution)
    430 --   y + (p - y) = p (odd)
    431 --     (n.b. sum is odd, so one of y and p - y must be odd, and the other even)
    432 --   if y even, return (x, y)
    433 --   else,      return (x, p - y)
    434 lift_vartime :: C.Montgomery -> Maybe Affine
    435 lift_vartime x = do
    436   let !c = weierstrass x
    437   !y <- C.sqrt_vartime c
    438   let !y_e | C.odd_vartime y = negate y
    439            | otherwise = y
    440   pure $! Affine x y_e
    441 
    442 even_y_vartime :: Projective -> Projective
    443 even_y_vartime p = case affine p of
    444   Affine _ (C.retr -> y)
    445     | CT.decide (W.odd y) -> neg p
    446     | otherwise -> p
    447 
    448 -- Constant-time selection of Projective points.
    449 select_proj :: Projective -> Projective -> CT.Choice -> Projective
    450 select_proj (Projective ax ay az) (Projective bx by bz) c =
    451   Projective (C.select ax bx c) (C.select ay by c) (C.select az bz c)
    452 {-# INLINE select_proj #-}
    453 
    454 -- unboxed internals ----------------------------------------------------------
    455 
    456 -- algo 7, renes et al, 2015
    457 add_proj# :: Proj -> Proj -> Proj
    458 add_proj# (# x1, y1, z1 #) (# x2, y2, z2 #) =
    459   let !(C.Montgomery b3) = _CURVE_Bm3
    460       !t0a  = C.mul# x1 x2
    461       !t1a  = C.mul# y1 y2
    462       !t2a  = C.mul# z1 z2
    463       !t3a  = C.add# x1 y1
    464       !t4a  = C.add# x2 y2
    465       !t3b  = C.mul# t3a t4a
    466       !t4b  = C.add# t0a t1a
    467       !t3c  = C.sub# t3b t4b
    468       !t4c  = C.add# y1 z1
    469       !x3a  = C.add# y2 z2
    470       !t4d  = C.mul# t4c x3a
    471       !x3b  = C.add# t1a t2a
    472       !t4e  = C.sub# t4d x3b
    473       !x3c  = C.add# x1 z1
    474       !y3a  = C.add# x2 z2
    475       !x3d  = C.mul# x3c y3a
    476       !y3b  = C.add# t0a t2a
    477       !y3c  = C.sub# x3d y3b
    478       !x3e  = C.add# t0a t0a
    479       !t0b  = C.add# x3e t0a
    480       !t2b  = C.mul# b3 t2a
    481       !z3a  = C.add# t1a t2b
    482       !t1b  = C.sub# t1a t2b
    483       !y3d  = C.mul# b3 y3c
    484       !x3f  = C.mul# t4e y3d
    485       !t2c  = C.mul# t3c t1b
    486       !x3g  = C.sub# t2c x3f
    487       !y3e  = C.mul# y3d t0b
    488       !t1c  = C.mul# t1b z3a
    489       !y3f  = C.add# t1c y3e
    490       !t0c  = C.mul# t0b t3c
    491       !z3b  = C.mul# z3a t4e
    492       !z3c  = C.add# z3b t0c
    493   in  (# x3g, y3f, z3c #)
    494 {-# INLINE add_proj# #-}
    495 
    496 -- algo 8, renes et al, 2015
    497 add_mixed# :: Proj -> Proj -> Proj
    498 add_mixed# (# x1, y1, z1 #) (# x2, y2, _z2 #) =
    499   let !(C.Montgomery b3) = _CURVE_Bm3
    500       !t0a  = C.mul# x1 x2
    501       !t1a  = C.mul# y1 y2
    502       !t3a  = C.add# x2 y2
    503       !t4a  = C.add# x1 y1
    504       !t3b  = C.mul# t3a t4a
    505       !t4b  = C.add# t0a t1a
    506       !t3c  = C.sub# t3b t4b
    507       !t4c  = C.mul# y2 z1
    508       !t4d  = C.add# t4c y1
    509       !y3a  = C.mul# x2 z1
    510       !y3b  = C.add# y3a x1
    511       !x3a  = C.add# t0a t0a
    512       !t0b  = C.add# x3a t0a
    513       !t2a  = C.mul# b3 z1
    514       !z3a  = C.add# t1a t2a
    515       !t1b  = C.sub# t1a t2a
    516       !y3c  = C.mul# b3 y3b
    517       !x3b  = C.mul# t4d y3c
    518       !t2b  = C.mul# t3c t1b
    519       !x3c  = C.sub# t2b x3b
    520       !y3d  = C.mul# y3c t0b
    521       !t1c  = C.mul# t1b z3a
    522       !y3e  = C.add# t1c y3d
    523       !t0c  = C.mul# t0b t3c
    524       !z3b  = C.mul# z3a t4d
    525       !z3c  = C.add# z3b t0c
    526   in  (# x3c, y3e, z3c #)
    527 {-# INLINE add_mixed# #-}
    528 
    529 -- algo 9, renes et al, 2015
    530 double# :: Proj -> Proj
    531 double# (# x, y, z #) =
    532   let !(C.Montgomery b3) = _CURVE_Bm3
    533       !t0  = C.sqr# y
    534       !z3a = C.add# t0 t0
    535       !z3b = C.add# z3a z3a
    536       !z3c = C.add# z3b z3b
    537       !t1  = C.mul# y z
    538       !t2a = C.sqr# z
    539       !t2b = C.mul# b3 t2a
    540       !x3a = C.mul# t2b z3c
    541       !y3a = C.add# t0 t2b
    542       !z3d = C.mul# t1 z3c
    543       !t1b = C.add# t2b t2b
    544       !t2c = C.add# t1b t2b
    545       !t0b = C.sub# t0 t2c
    546       !y3b = C.mul# t0b y3a
    547       !y3c = C.add# x3a y3b
    548       !t1c = C.mul# x y
    549       !x3b = C.mul# t0b t1c
    550       !x3c = C.add# x3b x3b
    551   in  (# x3c, y3c, z3d #)
    552 {-# INLINE double# #-}
    553 
    554 select_proj# :: Proj -> Proj -> CT.Choice -> Proj
    555 select_proj# (# ax, ay, az #) (# bx, by, bz #) c =
    556   (# W.select# ax bx c, W.select# ay by c, W.select# az bz c #)
    557 {-# INLINE select_proj# #-}
    558 
    559 neg# :: Proj -> Proj
    560 neg# (# x, y, z #) = (# x, C.neg# y, z #)
    561 {-# INLINE neg# #-}
    562 
    563 mul# :: Proj -> Limb4 -> (# () | Proj #)
    564 mul# (# px, py, pz #) s
    565     | CT.decide (CT.not (ge# s)) = (# () | #)
    566     | otherwise =
    567         let !(P gx gy gz) = _CURVE_G
    568             !(C.Montgomery o) = C.one
    569         in  loop (0 :: Int) (# Z, o, Z #) (# gx, gy, gz #) (# px, py, pz #) s
    570   where
    571     loop !j !a !f !d !_SECRET
    572       | j == _CURVE_Q_BITS = (# | a #)
    573       | otherwise =
    574           let !nd = double# d
    575               !(# nm, lsb_set #) = W.shr1_c# _SECRET
    576               !nacc = select_proj# a (add_proj# a d) lsb_set
    577               !nf   = select_proj# (add_proj# f d) f lsb_set
    578           in  loop (succ j) nacc nf nd nm
    579 {-# INLINE mul# #-}
    580 
    581 mul_vartime# :: Proj -> Limb4 -> (# () | Proj #)
    582 mul_vartime# (# px, py, pz #) s
    583     | zero# s =
    584         let !(P zx zy zz) = _CURVE_ZERO
    585         in  (# | (# zx, zy, zz #) #)
    586     | CT.decide (CT.not (ge# s)) = (# () | #)
    587     | otherwise =
    588         let !(P zx zy zz) = _CURVE_ZERO
    589         in  (# | loop (# zx, zy, zz #) (# px, py, pz #) s #)
    590   where
    591     zero# (# Limb a, Limb b, Limb c, Limb d #) = Exts.isTrue#
    592       ((a `Exts.or#` b `Exts.or#` c `Exts.or#` d) `Exts.eqWord#` 0##)
    593 
    594     loop !r !d !m
    595       | zero# m = r
    596       | otherwise =
    597           let !nd = double# d
    598               !(# nm, lsb_set #) = W.shr1_c# m
    599               !nr = if CT.decide lsb_set then add_proj# r d else r
    600           in  loop nr nd nm
    601 {-# INLINE mul_vartime# #-}
    602 
    603 ge# :: Limb4 -> CT.Choice
    604 ge# n =
    605   let !(Wider q) = _CURVE_Q
    606   in  CT.and (W.gt# n Z) (W.lt# n q)
    607 {-# INLINE ge# #-}
    608 
    609 mul_wnaf# :: ByteArray -> Int -> Limb4 -> (# () | Proj #)
    610 mul_wnaf# ctxArray ctxW ls
    611     | CT.decide (CT.not (ge# ls)) = (# () | #)
    612     | otherwise =
    613         let !(P zx zy zz) = _CURVE_ZERO
    614             !(P gx gy gz) = _CURVE_G
    615         in  (# | loop 0 (# zx, zy, zz #) (# gx, gy, gz #) ls #)
    616   where
    617     !one                  = (# Limb 1##, Limb 0##, Limb 0##, Limb 0## #)
    618     !wins                 = fi (256 `quot` ctxW + 1)
    619     !size@(GHC.Word.W# s) = 2 ^ (ctxW - 1)
    620     !(GHC.Word.W# mask)   = 2 ^ ctxW - 1
    621     !(GHC.Word.W# texW)   = fi ctxW
    622     !(GHC.Word.W# mnum)   = 2 ^ ctxW
    623 
    624     loop !j@(GHC.Word.W# w) !acc !f !n@(# Limb lo, _, _, _ #)
    625       | j == wins = acc
    626       | otherwise =
    627           let !(GHC.Word.W# off0) = j * size
    628               !b0          = Exts.and# lo mask
    629               !bor         = CT.from_word_gt# b0 s
    630 
    631               !(# n0, _ #) = W.shr_limb# n (Exts.word2Int# texW)
    632               !n0_plus_1   = W.add_w# n0 one
    633               !n1          = W.select# n0 n0_plus_1 bor
    634 
    635               !abs_b       = CT.select_word# b0 (Exts.minusWord# mnum b0) bor
    636               !is_zero     = CT.from_word_eq# b0 0##
    637               !c0          = CT.from_bit# (Exts.and# w 1##)
    638               !off_nz      = Exts.minusWord# (Exts.plusWord# off0 abs_b) 1##
    639               !off         = CT.select_word# off0 off_nz (CT.not is_zero)
    640 
    641               !pr          = ct_index_proj# ctxArray off0 s off
    642               !neg_pr      = neg# pr
    643               !pt_zero     = select_proj# pr neg_pr c0
    644               !pt_nonzero  = select_proj# pr neg_pr bor
    645 
    646               !f_added     = add_proj# f pt_zero
    647               !acc_added   = add_proj# acc pt_nonzero
    648               !nacc        = select_proj# acc_added acc is_zero
    649               !nf          = select_proj# f f_added is_zero
    650           in  loop (succ j) nacc nf n1
    651 {-# INLINE mul_wnaf# #-}
    652 
    653 -- retrieve a point (as an unboxed tuple) from a context array
    654 index_proj# :: ByteArray -> Exts.Int# -> Proj
    655 index_proj# (ByteArray arr#) i# =
    656   let !base# = i# Exts.*# 12#
    657       !x = (# Limb (Exts.indexWordArray# arr# base#)
    658             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 01#))
    659             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 02#))
    660             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 03#)) #)
    661       !y = (# Limb (Exts.indexWordArray# arr# (base# Exts.+# 04#))
    662             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 05#))
    663             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 06#))
    664             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 07#)) #)
    665       !z = (# Limb (Exts.indexWordArray# arr# (base# Exts.+# 08#))
    666             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 09#))
    667             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 10#))
    668             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 11#)) #)
    669   in  (# x, y, z #)
    670 {-# INLINE index_proj# #-}
    671 
    672 -- Constant-time table lookup within a window.
    673 --
    674 -- Unconditionally scans all entries from 'base' to 'base + size - 1',
    675 -- selecting the one where 'index' equals 'target'.
    676 ct_index_proj#
    677   :: ByteArray
    678   -> Exts.Word#  -- ^ base index
    679   -> Exts.Word#  -- ^ size of window
    680   -> Exts.Word#  -- ^ target index
    681   -> Proj
    682 ct_index_proj# arr base size target = loop 0## (# Z, Z, Z #) where
    683   loop i acc
    684     | Exts.isTrue# (i `Exts.geWord#` size) = acc
    685     | otherwise =
    686         let !idx  = Exts.plusWord# base i
    687             !pt   = index_proj# arr (Exts.word2Int# idx)
    688             !eq   = CT.from_word_eq# idx target
    689             !nacc = select_proj# acc pt eq
    690         in  loop (Exts.plusWord# i 1##) nacc
    691 {-# INLINE ct_index_proj# #-}
    692 
    693 -- ec arithmetic --------------------------------------------------------------
    694 
    695 -- Negate secp256k1 point.
    696 neg :: Projective -> Projective
    697 neg (P x y z) =
    698   let !(# px, py, pz #) = neg# (# x, y, z #)
    699   in  P px py pz
    700 {-# INLINABLE neg #-}
    701 
    702 -- Elliptic curve addition on secp256k1.
    703 add :: Projective -> Projective -> Projective
    704 add p q = add_proj p q
    705 {-# INLINABLE add #-}
    706 
    707 -- algo 7, "complete addition formulas for prime order elliptic curves,"
    708 -- renes et al, 2015
    709 --
    710 -- https://eprint.iacr.org/2015/1060.pdf
    711 add_proj :: Projective -> Projective -> Projective
    712 add_proj (P ax ay az) (P bx by bz) =
    713   let !(# x, y, z #) = add_proj# (# ax, ay, az #) (# bx, by, bz #)
    714   in  P x y z
    715 {-# INLINABLE add_proj #-}
    716 
    717 -- algo 8, renes et al, 2015
    718 add_mixed :: Projective -> Projective -> Projective
    719 add_mixed (P ax ay az) (P bx by bz) =
    720   let !(# x, y, z #) = add_mixed# (# ax, ay, az #) (# bx, by, bz #)
    721   in  P x y z
    722 {-# INLINABLE add_mixed #-}
    723 
    724 -- algo 9, renes et al, 2015
    725 double :: Projective -> Projective
    726 double (Projective (C.Montgomery ax) (C.Montgomery ay) (C.Montgomery az)) =
    727   let !(# x, y, z #) = double# (# ax, ay, az #)
    728   in  P x y z
    729 {-# INLINABLE double #-}
    730 
    731 -- Timing-safe scalar multiplication of secp256k1 points.
    732 mul :: Projective -> Wider -> Maybe Projective
    733 mul (P x y z) (Wider s) = case mul# (# x, y, z #) s of
    734   (# () | #)               -> Nothing
    735   (# | (# px, py, pz #) #) -> Just $! P px py pz
    736 {-# INLINABLE mul #-}
    737 
    738 -- Timing-unsafe scalar multiplication of secp256k1 points.
    739 --
    740 -- Don't use this function if the scalar could potentially be a secret.
    741 mul_vartime :: Projective -> Wider -> Maybe Projective
    742 mul_vartime (P x y z) (Wider s) = case mul_vartime# (# x, y, z #) s of
    743   (# () | #)               -> Nothing
    744   (# | (# px, py, pz #) #) -> Just $! P px py pz
    745 
    746 -- | Precomputed multiples of the secp256k1 base or generator point.
    747 data Context = Context {
    748     ctxW     :: {-# UNPACK #-} !Int
    749   , ctxArray :: {-# UNPACK #-} !ByteArray
    750   } deriving Generic
    751 
    752 instance Show Context where
    753   show Context {} = "<secp256k1 context>"
    754 
    755 -- | Create a secp256k1 context by precomputing multiples of the curve's
    756 --   generator point.
    757 --
    758 --   This should be used once to create a 'Context' to be reused
    759 --   repeatedly afterwards.
    760 --
    761 --   >>> let !tex = precompute
    762 --   >>> sign_ecdsa' tex sec msg
    763 --   >>> sign_schnorr' tex sec msg aux
    764 precompute :: Context
    765 precompute = _precompute 4
    766 
    767 -- This is a highly-optimized version of a function originally
    768 -- translated from noble-secp256k1's "precompute". Points are stored in
    769 -- a ByteArray by arranging each limb into slices of 12 consecutive
    770 -- slots (each Projective point consists of three Montgomery values,
    771 -- each of which consists of four limbs, summing to twelve limbs in
    772 -- total).
    773 --
    774 -- Each point takes 96 bytes to store in this fashion, so the total size of
    775 -- the ByteArray is (size * 96) bytes.
    776 _precompute :: Int -> Context
    777 _precompute ctxW = Context {..} where
    778   capJ = (2 :: Int) ^ (ctxW - 1)
    779   ws = 256 `quot` ctxW + 1
    780   size = ws * capJ
    781 
    782   -- construct the context array
    783   ctxArray = runST $ do
    784     marr <- BA.newByteArray (size * 96)
    785     loop_w marr _CURVE_G 0
    786     BA.unsafeFreezeByteArray marr
    787 
    788   -- write a point into the i^th 12-slot slice in the array
    789   write :: MutableByteArray s -> Int -> Projective -> ST s ()
    790   write marr i
    791       (P (# Limb x0, Limb x1, Limb x2, Limb x3 #)
    792          (# Limb y0, Limb y1, Limb y2, Limb y3 #)
    793          (# Limb z0, Limb z1, Limb z2, Limb z3 #)) = do
    794     let !base = i * 12
    795     BA.writeByteArray marr (base + 00) (GHC.Word.W# x0)
    796     BA.writeByteArray marr (base + 01) (GHC.Word.W# x1)
    797     BA.writeByteArray marr (base + 02) (GHC.Word.W# x2)
    798     BA.writeByteArray marr (base + 03) (GHC.Word.W# x3)
    799     BA.writeByteArray marr (base + 04) (GHC.Word.W# y0)
    800     BA.writeByteArray marr (base + 05) (GHC.Word.W# y1)
    801     BA.writeByteArray marr (base + 06) (GHC.Word.W# y2)
    802     BA.writeByteArray marr (base + 07) (GHC.Word.W# y3)
    803     BA.writeByteArray marr (base + 08) (GHC.Word.W# z0)
    804     BA.writeByteArray marr (base + 09) (GHC.Word.W# z1)
    805     BA.writeByteArray marr (base + 10) (GHC.Word.W# z2)
    806     BA.writeByteArray marr (base + 11) (GHC.Word.W# z3)
    807 
    808   -- loop over windows
    809   loop_w :: MutableByteArray s -> Projective -> Int -> ST s ()
    810   loop_w !marr !p !w
    811     | w == ws = pure ()
    812     | otherwise = do
    813         nb <- loop_j marr p p (w * capJ) 0
    814         let np = double nb
    815         loop_w marr np (succ w)
    816 
    817   -- loop within windows
    818   loop_j
    819     :: MutableByteArray s
    820     -> Projective
    821     -> Projective
    822     -> Int
    823     -> Int
    824     -> ST s Projective
    825   loop_j !marr !p !b !idx !j = do
    826     write marr idx b
    827     if   j == capJ - 1
    828     then pure b
    829     else do
    830       let !nb = add b p
    831       loop_j marr p nb (succ idx) (succ j)
    832 
    833 -- Timing-safe wNAF (w-ary non-adjacent form) scalar multiplication of
    834 -- secp256k1 points.
    835 mul_wnaf :: Context -> Wider -> Maybe Projective
    836 mul_wnaf Context {..} (Wider s) = case mul_wnaf# ctxArray ctxW s of
    837   (# () | #)               -> Nothing
    838   (# | (# px, py, pz #) #) -> Just $! P px py pz
    839 {-# INLINABLE mul_wnaf #-}
    840 
    841 -- | Derive a public key (i.e., a secp256k1 point) from the provided
    842 --   secret.
    843 --
    844 --   >>> import qualified System.Entropy as E
    845 --   >>> sk <- fmap parse_int256 (E.getEntropy 32)
    846 --   >>> derive_pub sk
    847 --   Just "<secp256k1 point>"
    848 derive_pub :: Wider -> Maybe Pub
    849 derive_pub = mul _CURVE_G
    850 {-# NOINLINE derive_pub #-}
    851 
    852 -- | The same as 'derive_pub', except uses a 'Context' to optimise
    853 --   internal calculations.
    854 --
    855 --   >>> import qualified System.Entropy as E
    856 --   >>> sk <- fmap parse_int256 (E.getEntropy 32)
    857 --   >>> let !tex = precompute
    858 --   >>> derive_pub' tex sk
    859 --   Just "<secp256k1 point>"
    860 derive_pub' :: Context -> Wider -> Maybe Pub
    861 derive_pub' = mul_wnaf
    862 {-# NOINLINE derive_pub' #-}
    863 
    864 -- parsing --------------------------------------------------------------------
    865 
    866 -- | Parse a 'Wider', /e.g./ a Schnorr or ECDSA secret key.
    867 --
    868 --   >>> import qualified Data.ByteString as BS
    869 --   >>> parse_int256 (BS.replicate 32 0xFF)
    870 --   Just <2^256 - 1>
    871 parse_int256 :: BS.ByteString -> Maybe Wider
    872 parse_int256 bs = do
    873   guard (BS.length bs == 32)
    874   pure $! unsafe_roll32 bs
    875 {-# INLINABLE parse_int256 #-}
    876 
    877 -- | Parse compressed secp256k1 point (33 bytes), uncompressed point (65
    878 --   bytes), or BIP0340-style point (32 bytes).
    879 --
    880 --   >>> parse_point <33-byte compressed point>
    881 --   Just <Pub>
    882 --   >>> parse_point <65-byte uncompressed point>
    883 --   Just <Pub>
    884 --   >>> parse_point <32-byte bip0340 public key>
    885 --   Just <Pub>
    886 --   >>> parse_point <anything else>
    887 --   Nothing
    888 parse_point :: BS.ByteString -> Maybe Projective
    889 parse_point bs
    890     | len == 32 = _parse_bip0340 bs
    891     | len == 33 = _parse_compressed h t
    892     | len == 65 = _parse_uncompressed h t
    893     | otherwise = Nothing
    894   where
    895     len = BS.length bs
    896     h = BU.unsafeIndex bs 0 -- lazy
    897     t = BS.drop 1 bs
    898 
    899 -- input is guaranteed to be 32B in length
    900 _parse_bip0340 :: BS.ByteString -> Maybe Projective
    901 _parse_bip0340 = fmap projective . lift_vartime . C.to . unsafe_roll32
    902 
    903 -- bytestring input is guaranteed to be 32B in length
    904 _parse_compressed :: Word8 -> BS.ByteString -> Maybe Projective
    905 _parse_compressed h (unsafe_roll32 -> x)
    906   | h /= 0x02 && h /= 0x03 = Nothing
    907   | not (fe x) = Nothing
    908   | otherwise = do
    909       let !mx = C.to x
    910       !my <- C.sqrt_vartime (weierstrass mx)
    911       let !yodd = CT.decide (W.odd (C.retr my))
    912           !hodd = B.testBit h 0
    913       pure $!
    914         if   hodd /= yodd
    915         then Projective mx (negate my) 1
    916         else Projective mx my 1
    917 
    918 -- bytestring input is guaranteed to be 64B in length
    919 _parse_uncompressed :: Word8 -> BS.ByteString -> Maybe Projective
    920 _parse_uncompressed h bs = do
    921   let (unsafe_roll32 -> x, unsafe_roll32 -> y) = BS.splitAt _CURVE_Q_BYTES bs
    922   guard (h == 0x04)
    923   let !p = Projective (C.to x) (C.to y) 1
    924   guard (valid p)
    925   pure $! p
    926 
    927 -- | Parse an ECDSA signature encoded in 64-byte "compact" form.
    928 --
    929 --   >>> parse_sig <64-byte compact signature>
    930 --   Just "<ecdsa signature>"
    931 parse_sig :: BS.ByteString -> Maybe ECDSA
    932 parse_sig bs = do
    933   guard (BS.length bs == 64)
    934   let (r0, s0) = BS.splitAt 32 bs
    935   r <- roll32 r0
    936   s <- roll32 s0
    937   pure $! ECDSA r s
    938 
    939 -- serializing ----------------------------------------------------------------
    940 
    941 -- | Serialize a secp256k1 point in 33-byte compressed form.
    942 --
    943 --   >>> serialize_point pub
    944 --   "<33-byte compressed point>"
    945 serialize_point :: Projective -> BS.ByteString
    946 serialize_point (affine -> Affine (C.from -> x) (C.from -> y)) =
    947   let !(Wider (# Limb w, _, _, _ #)) = y
    948       !b | B.testBit (GHC.Word.W# w) 0 = 0x03
    949          | otherwise = 0x02
    950   in  BS.cons b (unroll32 x)
    951 
    952 -- ecdh -----------------------------------------------------------------------
    953 
    954 -- SEC1-v2 3.3.1, plus SHA256 hash
    955 
    956 -- | Compute a shared secret, given a secret key and public secp256k1 point,
    957 --   via Elliptic Curve Diffie-Hellman (ECDH).
    958 --
    959 --   The shared secret is the SHA256 hash of the x-coordinate of the
    960 --   point obtained by scalar multiplication.
    961 --
    962 --   >>> let sec_alice = 0x03
    963 --   >>> let sec_bob   = 2 ^ 128 - 1
    964 --   >>> let Just pub_alice = derive_pub sec_alice
    965 --   >>> let Just pub_bob   = derive_pub sec_bob
    966 --   >>> let secret_as_computed_by_alice = ecdh pub_bob sec_alice
    967 --   >>> let secret_as_computed_by_bob   = ecdh pub_alice sec_bob
    968 --   >>> secret_as_computed_by_alice == secret_as_computed_by_bob
    969 --   True
    970 ecdh
    971   :: Projective          -- ^ public key
    972   -> Wider               -- ^ secret key
    973   -> Maybe BS.ByteString -- ^ shared secret
    974 ecdh pub _SECRET = do
    975   pt@(P _ _ (C.Montgomery -> z)) <- mul pub _SECRET
    976   let !(Affine (C.retr -> x) _) = affine pt
    977       !result = SHA256.hash (unroll32 x)
    978   if CT.decide (C.eq z 0) then Nothing else Just result
    979 
    980 -- schnorr --------------------------------------------------------------------
    981 -- see https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
    982 
    983 -- | Create a 64-byte Schnorr signature for the provided message, using
    984 --   the provided secret key.
    985 --
    986 --   BIP0340 recommends that 32 bytes of fresh auxiliary entropy be
    987 --   generated and added at signing time as additional protection
    988 --   against side-channel attacks (namely, to thwart so-called "fault
    989 --   injection" attacks). This entropy is /supplemental/ to security,
    990 --   and the cryptographic security of the signature scheme itself does
    991 --   not rely on it, so it is not strictly required; 32 zero bytes can
    992 --   be used in its stead (and can be supplied via 'mempty').
    993 --
    994 --   >>> import qualified System.Entropy as E
    995 --   >>> aux <- E.getEntropy 32
    996 --   >>> sign_schnorr sec msg aux
    997 --   Just "<64-byte schnorr signature>"
    998 sign_schnorr
    999   :: Wider          -- ^ secret key
   1000   -> BS.ByteString  -- ^ message
   1001   -> BS.ByteString  -- ^ 32 bytes of auxilliary random data
   1002   -> Maybe BS.ByteString  -- ^ 64-byte Schnorr signature
   1003 sign_schnorr = _sign_schnorr (mul _CURVE_G)
   1004 
   1005 -- | The same as 'sign_schnorr', except uses a 'Context' to optimise
   1006 --   internal calculations.
   1007 --
   1008 --   You can expect about a 2x performance increase when using this
   1009 --   function, compared to 'sign_schnorr'.
   1010 --
   1011 --   >>> import qualified System.Entropy as E
   1012 --   >>> aux <- E.getEntropy 32
   1013 --   >>> let !tex = precompute
   1014 --   >>> sign_schnorr' tex sec msg aux
   1015 --   Just "<64-byte schnorr signature>"
   1016 sign_schnorr'
   1017   :: Context        -- ^ secp256k1 context
   1018   -> Wider          -- ^ secret key
   1019   -> BS.ByteString  -- ^ message
   1020   -> BS.ByteString  -- ^ 32 bytes of auxilliary random data
   1021   -> Maybe BS.ByteString  -- ^ 64-byte Schnorr signature
   1022 sign_schnorr' tex = _sign_schnorr (mul_wnaf tex)
   1023 
   1024 _sign_schnorr
   1025   :: (Wider -> Maybe Projective)  -- partially-applied multiplication function
   1026   -> Wider                        -- secret key
   1027   -> BS.ByteString                -- message
   1028   -> BS.ByteString                -- 32 bytes of auxilliary random data
   1029   -> Maybe BS.ByteString
   1030 _sign_schnorr _mul _SECRET m a = do
   1031   p <- _mul _SECRET
   1032   let Affine (C.retr -> x_p) (C.retr -> y_p) = affine p
   1033       s       = S.to _SECRET
   1034       d       = S.select s (negate s) (W.odd y_p)
   1035       bytes_d = unroll32 (S.retr d)
   1036       bytes_p = unroll32 x_p
   1037       t       = xor bytes_d (hash_aux a)
   1038       rand    = hash_nonce (t <> bytes_p <> m)
   1039       k'      = S.to (unsafe_roll32 rand)
   1040   guard (not (S.eq_vartime k' 0)) -- negligible probability
   1041   pt <- _mul (S.retr k')
   1042   let Affine (C.retr -> x_r) (C.retr -> y_r) = affine pt
   1043       k         = S.select k' (negate k') (W.odd y_r)
   1044       bytes_r   = unroll32 x_r
   1045       rand'     = hash_challenge (bytes_r <> bytes_p <> m)
   1046       e         = S.to (unsafe_roll32 rand')
   1047       bytes_ked = unroll32 (S.retr (k + e * d))
   1048       sig       = bytes_r <> bytes_ked
   1049   -- NB for benchmarking we morally want to remove the precautionary
   1050   --    verification check here.
   1051   --
   1052   -- guard (verify_schnorr m p sig)
   1053   pure $! sig
   1054 {-# INLINE _sign_schnorr #-}
   1055 
   1056 -- | Verify a 64-byte Schnorr signature for the provided message with
   1057 --   the supplied public key.
   1058 --
   1059 --   >>> verify_schnorr msg pub <valid signature>
   1060 --   True
   1061 --   >>> verify_schnorr msg pub <invalid signature>
   1062 --   False
   1063 verify_schnorr
   1064   :: BS.ByteString  -- ^ message
   1065   -> Pub            -- ^ public key
   1066   -> BS.ByteString  -- ^ 64-byte Schnorr signature
   1067   -> Bool
   1068 verify_schnorr = _verify_schnorr (mul_vartime _CURVE_G)
   1069 
   1070 -- | The same as 'verify_schnorr', except uses a 'Context' to optimise
   1071 --   internal calculations.
   1072 --
   1073 --   You can expect about a 1.5x performance increase when using this
   1074 --   function, compared to 'verify_schnorr'.
   1075 --
   1076 --   >>> let !tex = precompute
   1077 --   >>> verify_schnorr' tex msg pub <valid signature>
   1078 --   True
   1079 --   >>> verify_schnorr' tex msg pub <invalid signature>
   1080 --   False
   1081 verify_schnorr'
   1082   :: Context        -- ^ secp256k1 context
   1083   -> BS.ByteString  -- ^ message
   1084   -> Pub            -- ^ public key
   1085   -> BS.ByteString  -- ^ 64-byte Schnorr signature
   1086   -> Bool
   1087 verify_schnorr' tex = _verify_schnorr (mul_wnaf tex)
   1088 
   1089 _verify_schnorr
   1090   :: (Wider -> Maybe Projective) -- partially-applied multiplication function
   1091   -> BS.ByteString
   1092   -> Pub
   1093   -> BS.ByteString
   1094   -> Bool
   1095 _verify_schnorr _mul m p sig
   1096   | BS.length sig /= 64 = False
   1097   | otherwise = M.isJust $ do
   1098       let capP = even_y_vartime p
   1099           (unsafe_roll32 -> r, unsafe_roll32 -> s) = BS.splitAt 32 sig
   1100       guard (fe r && ge s)
   1101       let Affine (C.retr -> x_P) _ = affine capP
   1102           e = modQ . unsafe_roll32 $
   1103             hash_challenge (unroll32 r <> unroll32 x_P <> m)
   1104       pt0 <- _mul s
   1105       pt1 <- mul_vartime capP e
   1106       let dif = add pt0 (neg pt1)
   1107       guard (dif /= _CURVE_ZERO)
   1108       let Affine (C.from -> x_R) (C.from -> y_R) = affine dif
   1109       guard $ not (CT.decide (W.odd y_R) || not (W.eq_vartime x_R r))
   1110 {-# INLINE _verify_schnorr #-}
   1111 
   1112 -- hardcoded tag of BIP0340/aux
   1113 --
   1114 -- \x -> let h = SHA256.hash "BIP0340/aux"
   1115 --       in  SHA256.hash (h <> h <> x)
   1116 hash_aux :: BS.ByteString -> BS.ByteString
   1117 hash_aux x = SHA256.hash $
   1118   "\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
   1119 {-# INLINE hash_aux #-}
   1120 
   1121 -- hardcoded tag of BIP0340/nonce
   1122 hash_nonce :: BS.ByteString -> BS.ByteString
   1123 hash_nonce x = SHA256.hash $
   1124   "\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
   1125 {-# INLINE hash_nonce #-}
   1126 
   1127 -- hardcoded tag of BIP0340/challenge
   1128 hash_challenge :: BS.ByteString -> BS.ByteString
   1129 hash_challenge x = SHA256.hash $
   1130   "{\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
   1131 {-# INLINE hash_challenge #-}
   1132 
   1133 -- ecdsa ----------------------------------------------------------------------
   1134 -- see https://www.rfc-editor.org/rfc/rfc6979, https://secg.org/sec1-v2.pdf
   1135 
   1136 -- RFC6979 2.3.2
   1137 bits2int :: BS.ByteString -> Wider
   1138 bits2int = unsafe_roll32
   1139 {-# INLINABLE bits2int #-}
   1140 
   1141 -- RFC6979 2.3.3
   1142 int2octets :: Wider -> BS.ByteString
   1143 int2octets = unroll32
   1144 {-# INLINABLE int2octets #-}
   1145 
   1146 -- RFC6979 2.3.4
   1147 bits2octets :: BS.ByteString -> BS.ByteString
   1148 bits2octets bs =
   1149   let z1 = bits2int bs
   1150       z2 = modQ z1
   1151   in  int2octets z2
   1152 
   1153 -- | An ECDSA signature.
   1154 data ECDSA = ECDSA {
   1155     ecdsa_r :: !Wider
   1156   , ecdsa_s :: !Wider
   1157   }
   1158   deriving (Generic)
   1159 
   1160 instance Show ECDSA where
   1161   show _ = "<ecdsa signature>"
   1162 
   1163 -- ECDSA signature type.
   1164 data SigType =
   1165     LowS
   1166   | Unrestricted
   1167   deriving Show
   1168 
   1169 -- Indicates whether to hash the message or assume it has already been
   1170 -- hashed.
   1171 data HashFlag =
   1172     Hash
   1173   | NoHash
   1174   deriving Show
   1175 
   1176 -- Convert an ECDSA signature to low-S form.
   1177 low :: ECDSA -> ECDSA
   1178 low (ECDSA r s) = ECDSA r (W.select s (_CURVE_Q - s) (W.gt s _CURVE_QH))
   1179 {-# INLINE low #-}
   1180 
   1181 -- | Produce an ECDSA signature for the provided message, using the
   1182 --   provided private key.
   1183 --
   1184 --   'sign_ecdsa' produces a "low-s" signature, as is commonly required
   1185 --   in applications using secp256k1. If you need a generic ECDSA
   1186 --   signature, use 'sign_ecdsa_unrestricted'.
   1187 --
   1188 --   >>> sign_ecdsa sec msg
   1189 --   Just "<ecdsa signature>"
   1190 sign_ecdsa
   1191   :: Wider         -- ^ secret key
   1192   -> BS.ByteString -- ^ message
   1193   -> Maybe ECDSA
   1194 sign_ecdsa = _sign_ecdsa (mul _CURVE_G) LowS Hash
   1195 
   1196 -- | The same as 'sign_ecdsa', except uses a 'Context' to optimise internal
   1197 --   calculations.
   1198 --
   1199 --   You can expect about a 10x performance increase when using this
   1200 --   function, compared to 'sign_ecdsa'.
   1201 --
   1202 --   >>> let !tex = precompute
   1203 --   >>> sign_ecdsa' tex sec msg
   1204 --   Just "<ecdsa signature>"
   1205 sign_ecdsa'
   1206   :: Context       -- ^ secp256k1 context
   1207   -> Wider         -- ^ secret key
   1208   -> BS.ByteString -- ^ message
   1209   -> Maybe ECDSA
   1210 sign_ecdsa' tex = _sign_ecdsa (mul_wnaf tex) LowS Hash
   1211 
   1212 -- | Produce an ECDSA signature for the provided message, using the
   1213 --   provided private key.
   1214 --
   1215 --   'sign_ecdsa_unrestricted' produces an unrestricted ECDSA signature,
   1216 --   which is less common in applications using secp256k1 due to the
   1217 --   signature's inherent malleability. If you need a conventional
   1218 --   "low-s" signature, use 'sign_ecdsa'.
   1219 --
   1220 --   >>> sign_ecdsa_unrestricted sec msg
   1221 --   Just "<ecdsa signature>"
   1222 sign_ecdsa_unrestricted
   1223   :: Wider         -- ^ secret key
   1224   -> BS.ByteString -- ^ message
   1225   -> Maybe ECDSA
   1226 sign_ecdsa_unrestricted = _sign_ecdsa (mul _CURVE_G) Unrestricted Hash
   1227 
   1228 -- | The same as 'sign_ecdsa_unrestricted', except uses a 'Context' to
   1229 --   optimise internal calculations.
   1230 --
   1231 --   You can expect about a 10x performance increase when using this
   1232 --   function, compared to 'sign_ecdsa_unrestricted'.
   1233 --
   1234 --   >>> let !tex = precompute
   1235 --   >>> sign_ecdsa_unrestricted' tex sec msg
   1236 --   Just "<ecdsa signature>"
   1237 sign_ecdsa_unrestricted'
   1238   :: Context       -- ^ secp256k1 context
   1239   -> Wider         -- ^ secret key
   1240   -> BS.ByteString -- ^ message
   1241   -> Maybe ECDSA
   1242 sign_ecdsa_unrestricted' tex = _sign_ecdsa (mul_wnaf tex) Unrestricted Hash
   1243 
   1244 -- Produce a "low-s" ECDSA signature for the provided message, using
   1245 -- the provided private key. Assumes that the message has already been
   1246 -- pre-hashed.
   1247 --
   1248 -- (Useful for testing against noble-secp256k1's suite, in which messages
   1249 -- in the test vectors have already been hashed.)
   1250 _sign_ecdsa_no_hash
   1251   :: Wider         -- ^ secret key
   1252   -> BS.ByteString -- ^ message digest
   1253   -> Maybe ECDSA
   1254 _sign_ecdsa_no_hash = _sign_ecdsa (mul _CURVE_G) LowS NoHash
   1255 
   1256 _sign_ecdsa_no_hash'
   1257   :: Context
   1258   -> Wider
   1259   -> BS.ByteString
   1260   -> Maybe ECDSA
   1261 _sign_ecdsa_no_hash' tex = _sign_ecdsa (mul_wnaf tex) LowS NoHash
   1262 
   1263 _sign_ecdsa
   1264   :: (Wider -> Maybe Projective) -- partially-applied multiplication function
   1265   -> SigType
   1266   -> HashFlag
   1267   -> Wider
   1268   -> BS.ByteString
   1269   -> Maybe ECDSA
   1270 _sign_ecdsa _mul ty hf _SECRET m = runST $ do
   1271     -- RFC6979 sec 3.3a
   1272     let entropy = int2octets _SECRET
   1273         nonce   = bits2octets h
   1274     drbg <- DRBG.new entropy nonce mempty
   1275     -- RFC6979 sec 2.4
   1276     sign_loop drbg
   1277   where
   1278     d  = S.to _SECRET
   1279     hm = S.to (bits2int h)
   1280     h  = case hf of
   1281       Hash -> SHA256.hash m
   1282       NoHash -> m
   1283 
   1284     sign_loop g = do
   1285       k <- gen_k g
   1286       let mpair = do
   1287             kg <- _mul k
   1288             let Affine (S.to . C.retr -> r) _ = affine kg
   1289                 ki = S.inv (S.to k)
   1290                 s  = (hm + d * r) * ki
   1291             pure $! (S.retr r, S.retr s)
   1292       case mpair of
   1293         Nothing -> do
   1294           DRBG.wipe g
   1295           pure Nothing
   1296         Just (r, s)
   1297           | W.eq_vartime r 0 -> sign_loop g -- negligible probability
   1298           | otherwise -> do
   1299               DRBG.wipe g
   1300               let !sig = Just $! ECDSA r s
   1301               pure $ case ty of
   1302                 Unrestricted -> sig
   1303                 LowS -> fmap low sig
   1304 {-# INLINE _sign_ecdsa #-}
   1305 
   1306 -- RFC6979 sec 3.3b
   1307 gen_k :: DRBG.DRBG s -> ST s Wider
   1308 gen_k g = loop g where
   1309   loop drbg = do
   1310     bytes <- DRBG.gen drbg mempty (fi _CURVE_Q_BYTES)
   1311     case bytes of
   1312       Left {}  -> error "ppad-secp256k1: internal error (please report a bug!)"
   1313       Right bs -> do
   1314         let can = bits2int bs
   1315         case W.cmp_vartime can _CURVE_Q of
   1316           LT -> pure can
   1317           _  -> loop drbg -- 2 ^ -128 probability
   1318 {-# INLINE gen_k #-}
   1319 
   1320 -- | Verify a "low-s" ECDSA signature for the provided message and
   1321 --   public key,
   1322 --
   1323 --   Fails to verify otherwise-valid "high-s" signatures. If you need to
   1324 --   verify generic ECDSA signatures, use 'verify_ecdsa_unrestricted'.
   1325 --
   1326 --   >>> verify_ecdsa msg pub valid_sig
   1327 --   True
   1328 --   >>> verify_ecdsa msg pub invalid_sig
   1329 --   False
   1330 verify_ecdsa
   1331   :: BS.ByteString -- ^ message
   1332   -> Pub           -- ^ public key
   1333   -> ECDSA         -- ^ signature
   1334   -> Bool
   1335 verify_ecdsa m p sig@(ECDSA _ s)
   1336   | CT.decide (W.gt s _CURVE_QH) = False
   1337   | otherwise = verify_ecdsa_unrestricted m p sig
   1338 
   1339 -- | The same as 'verify_ecdsa', except uses a 'Context' to optimise
   1340 --   internal calculations.
   1341 --
   1342 --   You can expect about a 2x performance increase when using this
   1343 --   function, compared to 'verify_ecdsa'.
   1344 --
   1345 --   >>> let !tex = precompute
   1346 --   >>> verify_ecdsa' tex msg pub valid_sig
   1347 --   True
   1348 --   >>> verify_ecdsa' tex msg pub invalid_sig
   1349 --   False
   1350 verify_ecdsa'
   1351   :: Context       -- ^ secp256k1 context
   1352   -> BS.ByteString -- ^ message
   1353   -> Pub           -- ^ public key
   1354   -> ECDSA         -- ^ signature
   1355   -> Bool
   1356 verify_ecdsa' tex m p sig@(ECDSA _ s)
   1357   | CT.decide (W.gt s _CURVE_QH) = False
   1358   | otherwise = verify_ecdsa_unrestricted' tex m p sig
   1359 
   1360 -- | Verify an unrestricted ECDSA signature for the provided message and
   1361 --   public key.
   1362 --
   1363 --   >>> verify_ecdsa_unrestricted msg pub valid_sig
   1364 --   True
   1365 --   >>> verify_ecdsa_unrestricted msg pub invalid_sig
   1366 --   False
   1367 verify_ecdsa_unrestricted
   1368   :: BS.ByteString -- ^ message
   1369   -> Pub           -- ^ public key
   1370   -> ECDSA         -- ^ signature
   1371   -> Bool
   1372 verify_ecdsa_unrestricted = _verify_ecdsa_unrestricted (mul_vartime _CURVE_G)
   1373 
   1374 -- | The same as 'verify_ecdsa_unrestricted', except uses a 'Context' to
   1375 --   optimise internal calculations.
   1376 --
   1377 --   You can expect about a 2x performance increase when using this
   1378 --   function, compared to 'verify_ecdsa_unrestricted'.
   1379 --
   1380 --   >>> let !tex = precompute
   1381 --   >>> verify_ecdsa_unrestricted' tex msg pub valid_sig
   1382 --   True
   1383 --   >>> verify_ecdsa_unrestricted' tex msg pub invalid_sig
   1384 --   False
   1385 verify_ecdsa_unrestricted'
   1386   :: Context       -- ^ secp256k1 context
   1387   -> BS.ByteString -- ^ message
   1388   -> Pub           -- ^ public key
   1389   -> ECDSA         -- ^ signature
   1390   -> Bool
   1391 verify_ecdsa_unrestricted' tex = _verify_ecdsa_unrestricted (mul_wnaf tex)
   1392 
   1393 _verify_ecdsa_unrestricted
   1394   :: (Wider -> Maybe Projective) -- partially-applied multiplication function
   1395   -> BS.ByteString
   1396   -> Pub
   1397   -> ECDSA
   1398   -> Bool
   1399 _verify_ecdsa_unrestricted _mul m p (ECDSA r0 s0) = M.isJust $ do
   1400   -- SEC1-v2 4.1.4
   1401   let h = SHA256.hash m
   1402   guard (ge r0 && ge s0)
   1403   let r  = S.to r0
   1404       s  = S.to s0
   1405       e  = S.to (bits2int h)
   1406       si = S.inv s
   1407       u1 = S.retr (e * si)
   1408       u2 = S.retr (r * si)
   1409   pt0 <- _mul u1
   1410   pt1 <- mul_vartime p u2
   1411   let capR = add pt0 pt1
   1412   guard (capR /= _CURVE_ZERO)
   1413   let Affine (S.to . C.retr -> v) _ = affine capR
   1414   guard (S.eq_vartime v r)
   1415 {-# INLINE _verify_ecdsa_unrestricted #-}
   1416