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 (47306B)


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