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


      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 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 Zero :: Wider
    140 pattern Zero = Wider Z
    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 !(P gx gy gz) = _CURVE_G
    571             !(C.Montgomery o) = C.one
    572         in  loop (0 :: Int) (# Z, o, Z #) (# gx, gy, gz #) (# px, py, pz #) s
    573   where
    574     loop !j !a !f !d !_SECRET
    575       | j == _CURVE_Q_BITS = (# | a #)
    576       | otherwise =
    577           let !nd = double# d
    578               !(# nm, lsb_set #) = W.shr1_c# _SECRET
    579               !nacc = select_proj# a (add_proj# a d) lsb_set
    580               !nf   = select_proj# (add_proj# f d) f lsb_set
    581           in  loop (succ j) nacc nf nd nm
    582 {-# INLINE mul# #-}
    583 
    584 ge# :: Limb4 -> CT.Choice
    585 ge# n =
    586   let !(Wider q) = _CURVE_Q
    587   in  CT.and (W.gt# n Z) (W.lt# n q)
    588 {-# INLINE ge# #-}
    589 
    590 mul_wnaf# :: ByteArray -> Int -> Limb4 -> (# () | Proj #)
    591 mul_wnaf# ctxArray ctxW ls
    592     | CT.decide (CT.not (ge# ls)) = (# () | #)
    593     | otherwise =
    594         let !(P zx zy zz) = _CURVE_ZERO
    595             !(P gx gy gz) = _CURVE_G
    596         in  (# | loop 0 (# zx, zy, zz #) (# gx, gy, gz #) ls #)
    597   where
    598     !one                  = (# Limb 1##, Limb 0##, Limb 0##, Limb 0## #)
    599     !wins                 = fi (256 `quot` ctxW + 1)
    600     !size@(GHC.Word.W# s) = 2 ^ (ctxW - 1)
    601     !(GHC.Word.W# mask)   = 2 ^ ctxW - 1
    602     !(GHC.Word.W# texW)   = fi ctxW
    603     !(GHC.Word.W# mnum)   = 2 ^ ctxW
    604 
    605     loop !j@(GHC.Word.W# w) !acc !f !n@(# Limb lo, _, _, _ #)
    606       | j == wins = acc
    607       | otherwise =
    608           let !(GHC.Word.W# off0) = j * size
    609               !b0          = Exts.and# lo mask
    610               !bor         = CT.from_word_gt# b0 s
    611 
    612               !(# n0, _ #) = W.shr_limb# n (Exts.word2Int# texW)
    613               !n0_plus_1   = W.add_w# n0 one
    614               !n1          = W.select# n0 n0_plus_1 bor
    615 
    616               !abs_b       = CT.select_word# b0 (Exts.minusWord# mnum b0) bor
    617               !is_zero     = CT.from_word_eq# b0 0##
    618               !c0          = CT.from_bit# (Exts.and# w 1##)
    619               !off_nz      = Exts.minusWord# (Exts.plusWord# off0 abs_b) 1##
    620               !off         = CT.select_word# off0 off_nz (CT.not is_zero)
    621 
    622               !pr          = ct_index_proj# ctxArray off0 s off
    623               !neg_pr      = neg# pr
    624               !pt_zero     = select_proj# pr neg_pr c0
    625               !pt_nonzero  = select_proj# pr neg_pr bor
    626 
    627               !f_added     = add_proj# f pt_zero
    628               !acc_added   = add_proj# acc pt_nonzero
    629               !nacc        = select_proj# acc_added acc is_zero
    630               !nf          = select_proj# f f_added is_zero
    631           in  loop (succ j) nacc nf n1
    632 {-# INLINE mul_wnaf# #-}
    633 
    634 -- retrieve a point (as an unboxed tuple) from a context array
    635 index_proj# :: ByteArray -> Exts.Int# -> Proj
    636 index_proj# (ByteArray arr#) i# =
    637   let !base# = i# Exts.*# 12#
    638       !x = (# Limb (Exts.indexWordArray# arr# base#)
    639             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 01#))
    640             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 02#))
    641             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 03#)) #)
    642       !y = (# Limb (Exts.indexWordArray# arr# (base# Exts.+# 04#))
    643             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 05#))
    644             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 06#))
    645             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 07#)) #)
    646       !z = (# Limb (Exts.indexWordArray# arr# (base# Exts.+# 08#))
    647             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 09#))
    648             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 10#))
    649             , Limb (Exts.indexWordArray# arr# (base# Exts.+# 11#)) #)
    650   in  (# x, y, z #)
    651 {-# INLINE index_proj# #-}
    652 
    653 -- Constant-time table lookup within a window.
    654 --
    655 -- Unconditionally scans all entries from 'base' to 'base + size - 1',
    656 -- selecting the one where 'index' equals 'target'.
    657 ct_index_proj#
    658   :: ByteArray
    659   -> Exts.Word#  -- ^ base index
    660   -> Exts.Word#  -- ^ size of window
    661   -> Exts.Word#  -- ^ target index
    662   -> Proj
    663 ct_index_proj# arr base size target = loop 0## (# Z, Z, Z #) where
    664   loop i acc
    665     | Exts.isTrue# (i `Exts.geWord#` size) = acc
    666     | otherwise =
    667         let !idx  = Exts.plusWord# base i
    668             !pt   = index_proj# arr (Exts.word2Int# idx)
    669             !eq   = CT.from_word_eq# idx target
    670             !nacc = select_proj# acc pt eq
    671         in  loop (Exts.plusWord# i 1##) nacc
    672 {-# INLINE ct_index_proj# #-}
    673 
    674 -- ec arithmetic --------------------------------------------------------------
    675 
    676 -- Negate secp256k1 point.
    677 neg :: Projective -> Projective
    678 neg (P x y z) =
    679   let !(# px, py, pz #) = neg# (# x, y, z #)
    680   in  P px py pz
    681 {-# INLINABLE neg #-}
    682 
    683 -- Elliptic curve addition on secp256k1.
    684 add :: Projective -> Projective -> Projective
    685 add p q = add_proj p q
    686 {-# INLINABLE add #-}
    687 
    688 -- algo 7, "complete addition formulas for prime order elliptic curves,"
    689 -- renes et al, 2015
    690 --
    691 -- https://eprint.iacr.org/2015/1060.pdf
    692 add_proj :: Projective -> Projective -> Projective
    693 add_proj (P ax ay az) (P bx by bz) =
    694   let !(# x, y, z #) = add_proj# (# ax, ay, az #) (# bx, by, bz #)
    695   in  P x y z
    696 {-# INLINABLE add_proj #-}
    697 
    698 -- algo 8, renes et al, 2015
    699 add_mixed :: Projective -> Projective -> Projective
    700 add_mixed (P ax ay az) (P bx by bz) =
    701   let !(# x, y, z #) = add_mixed# (# ax, ay, az #) (# bx, by, bz #)
    702   in  P x y z
    703 {-# INLINABLE add_mixed #-}
    704 
    705 -- algo 9, renes et al, 2015
    706 double :: Projective -> Projective
    707 double (Projective (C.Montgomery ax) (C.Montgomery ay) (C.Montgomery az)) =
    708   let !(# x, y, z #) = double# (# ax, ay, az #)
    709   in  P x y z
    710 {-# INLINABLE double #-}
    711 
    712 -- Timing-safe scalar multiplication of secp256k1 points.
    713 mul :: Projective -> Wider -> Maybe Projective
    714 mul (P x y z) (Wider s) = case mul# (# x, y, z #) s of
    715   (# () | #)               -> Nothing
    716   (# | (# px, py, pz #) #) -> Just $! P px py pz
    717 {-# INLINABLE mul #-}
    718 
    719 -- Timing-unsafe scalar multiplication of secp256k1 points.
    720 --
    721 -- Don't use this function if the scalar could potentially be a secret.
    722 mul_vartime :: Projective -> Wider -> Maybe Projective
    723 mul_vartime p = \case
    724     Zero -> pure _CURVE_ZERO
    725     n | not (ge n) -> Nothing
    726       | otherwise  -> pure $! loop _CURVE_ZERO p n
    727   where
    728     loop !r !d = \case
    729       Zero -> r
    730       m ->
    731         let !nd = double d
    732             !(# nm, lsb_set #) = W.shr1_c m
    733             !nr = if CT.decide lsb_set then add r d else r
    734         in  loop nr nd nm
    735 
    736 -- | Precomputed multiples of the secp256k1 base or generator point.
    737 data Context = Context {
    738     ctxW     :: {-# UNPACK #-} !Int
    739   , ctxArray :: {-# UNPACK #-} !ByteArray
    740   } deriving Generic
    741 
    742 instance Show Context where
    743   show Context {} = "<secp256k1 context>"
    744 
    745 -- | Create a secp256k1 context by precomputing multiples of the curve's
    746 --   generator point.
    747 --
    748 --   This should be used once to create a 'Context' to be reused
    749 --   repeatedly afterwards.
    750 --
    751 --   >>> let !tex = precompute
    752 --   >>> sign_ecdsa' tex sec msg
    753 --   >>> sign_schnorr' tex sec msg aux
    754 precompute :: Context
    755 precompute = _precompute 4
    756 
    757 -- This is a highly-optimized version of a function originally
    758 -- translated from noble-secp256k1's "precompute". Points are stored in
    759 -- a ByteArray by arranging each limb into slices of 12 consecutive
    760 -- slots (each Projective point consists of three Montgomery values,
    761 -- each of which consists of four limbs, summing to twelve limbs in
    762 -- total).
    763 --
    764 -- Each point takes 96 bytes to store in this fashion, so the total size of
    765 -- the ByteArray is (size * 96) bytes.
    766 _precompute :: Int -> Context
    767 _precompute ctxW = Context {..} where
    768   capJ = (2 :: Int) ^ (ctxW - 1)
    769   ws = 256 `quot` ctxW + 1
    770   size = ws * capJ
    771 
    772   -- construct the context array
    773   ctxArray = runST $ do
    774     marr <- BA.newByteArray (size * 96)
    775     loop_w marr _CURVE_G 0
    776     BA.unsafeFreezeByteArray marr
    777 
    778   -- write a point into the i^th 12-slot slice in the array
    779   write :: MutableByteArray s -> Int -> Projective -> ST s ()
    780   write marr i
    781       (P (# Limb x0, Limb x1, Limb x2, Limb x3 #)
    782          (# Limb y0, Limb y1, Limb y2, Limb y3 #)
    783          (# Limb z0, Limb z1, Limb z2, Limb z3 #)) = do
    784     let !base = i * 12
    785     BA.writeByteArray marr (base + 00) (GHC.Word.W# x0)
    786     BA.writeByteArray marr (base + 01) (GHC.Word.W# x1)
    787     BA.writeByteArray marr (base + 02) (GHC.Word.W# x2)
    788     BA.writeByteArray marr (base + 03) (GHC.Word.W# x3)
    789     BA.writeByteArray marr (base + 04) (GHC.Word.W# y0)
    790     BA.writeByteArray marr (base + 05) (GHC.Word.W# y1)
    791     BA.writeByteArray marr (base + 06) (GHC.Word.W# y2)
    792     BA.writeByteArray marr (base + 07) (GHC.Word.W# y3)
    793     BA.writeByteArray marr (base + 08) (GHC.Word.W# z0)
    794     BA.writeByteArray marr (base + 09) (GHC.Word.W# z1)
    795     BA.writeByteArray marr (base + 10) (GHC.Word.W# z2)
    796     BA.writeByteArray marr (base + 11) (GHC.Word.W# z3)
    797 
    798   -- loop over windows
    799   loop_w :: MutableByteArray s -> Projective -> Int -> ST s ()
    800   loop_w !marr !p !w
    801     | w == ws = pure ()
    802     | otherwise = do
    803         nb <- loop_j marr p p (w * capJ) 0
    804         let np = double nb
    805         loop_w marr np (succ w)
    806 
    807   -- loop within windows
    808   loop_j
    809     :: MutableByteArray s
    810     -> Projective
    811     -> Projective
    812     -> Int
    813     -> Int
    814     -> ST s Projective
    815   loop_j !marr !p !b !idx !j = do
    816     write marr idx b
    817     if   j == capJ - 1
    818     then pure b
    819     else do
    820       let !nb = add b p
    821       loop_j marr p nb (succ idx) (succ j)
    822 
    823 -- Timing-safe wNAF (w-ary non-adjacent form) scalar multiplication of
    824 -- secp256k1 points.
    825 mul_wnaf :: Context -> Wider -> Maybe Projective
    826 mul_wnaf Context {..} (Wider s) = case mul_wnaf# ctxArray ctxW s of
    827   (# () | #)               -> Nothing
    828   (# | (# px, py, pz #) #) -> Just $! P px py pz
    829 {-# INLINABLE mul_wnaf #-}
    830 
    831 -- | Derive a public key (i.e., a secp256k1 point) from the provided
    832 --   secret.
    833 --
    834 --   >>> import qualified System.Entropy as E
    835 --   >>> sk <- fmap parse_int256 (E.getEntropy 32)
    836 --   >>> derive_pub sk
    837 --   Just "<secp256k1 point>"
    838 derive_pub :: Wider -> Maybe Pub
    839 derive_pub = mul _CURVE_G
    840 {-# NOINLINE derive_pub #-}
    841 
    842 -- | The same as 'derive_pub', except uses a 'Context' to optimise
    843 --   internal calculations.
    844 --
    845 --   >>> import qualified System.Entropy as E
    846 --   >>> sk <- fmap parse_int256 (E.getEntropy 32)
    847 --   >>> let !tex = precompute
    848 --   >>> derive_pub' tex sk
    849 --   Just "<secp256k1 point>"
    850 derive_pub' :: Context -> Wider -> Maybe Pub
    851 derive_pub' = mul_wnaf
    852 {-# NOINLINE derive_pub' #-}
    853 
    854 -- parsing --------------------------------------------------------------------
    855 
    856 -- | Parse a 'Wider', /e.g./ a Schnorr or ECDSA secret key.
    857 --
    858 --   >>> import qualified Data.ByteString as BS
    859 --   >>> parse_int256 (BS.replicate 32 0xFF)
    860 --   Just <2^256 - 1>
    861 parse_int256 :: BS.ByteString -> Maybe Wider
    862 parse_int256 bs = do
    863   guard (BS.length bs == 32)
    864   pure $! unsafe_roll32 bs
    865 {-# INLINABLE parse_int256 #-}
    866 
    867 -- | Parse compressed secp256k1 point (33 bytes), uncompressed point (65
    868 --   bytes), or BIP0340-style point (32 bytes).
    869 --
    870 --   >>> parse_point <33-byte compressed point>
    871 --   Just <Pub>
    872 --   >>> parse_point <65-byte uncompressed point>
    873 --   Just <Pub>
    874 --   >>> parse_point <32-byte bip0340 public key>
    875 --   Just <Pub>
    876 --   >>> parse_point <anything else>
    877 --   Nothing
    878 parse_point :: BS.ByteString -> Maybe Projective
    879 parse_point bs
    880     | len == 32 = _parse_bip0340 bs
    881     | len == 33 = _parse_compressed h t
    882     | len == 65 = _parse_uncompressed h t
    883     | otherwise = Nothing
    884   where
    885     len = BS.length bs
    886     h = BU.unsafeIndex bs 0 -- lazy
    887     t = BS.drop 1 bs
    888 
    889 -- input is guaranteed to be 32B in length
    890 _parse_bip0340 :: BS.ByteString -> Maybe Projective
    891 _parse_bip0340 = fmap projective . lift_vartime . C.to . unsafe_roll32
    892 
    893 -- bytestring input is guaranteed to be 32B in length
    894 _parse_compressed :: Word8 -> BS.ByteString -> Maybe Projective
    895 _parse_compressed h (unsafe_roll32 -> x)
    896   | h /= 0x02 && h /= 0x03 = Nothing
    897   | not (fe x) = Nothing
    898   | otherwise = do
    899       let !mx = C.to x
    900       !my <- C.sqrt_vartime (weierstrass mx)
    901       let !yodd = CT.decide (W.odd (C.retr my))
    902           !hodd = B.testBit h 0
    903       pure $!
    904         if   hodd /= yodd
    905         then Projective mx (negate my) 1
    906         else Projective mx my 1
    907 
    908 -- bytestring input is guaranteed to be 64B in length
    909 _parse_uncompressed :: Word8 -> BS.ByteString -> Maybe Projective
    910 _parse_uncompressed h bs = do
    911   let (unsafe_roll32 -> x, unsafe_roll32 -> y) = BS.splitAt _CURVE_Q_BYTES bs
    912   guard (h == 0x04)
    913   let !p = Projective (C.to x) (C.to y) 1
    914   guard (valid p)
    915   pure $! p
    916 
    917 -- | Parse an ECDSA signature encoded in 64-byte "compact" form.
    918 --
    919 --   >>> parse_sig <64-byte compact signature>
    920 --   Just "<ecdsa signature>"
    921 parse_sig :: BS.ByteString -> Maybe ECDSA
    922 parse_sig bs = do
    923   guard (BS.length bs == 64)
    924   let (r0, s0) = BS.splitAt 32 bs
    925   r <- roll32 r0
    926   s <- roll32 s0
    927   pure $! ECDSA r s
    928 
    929 -- serializing ----------------------------------------------------------------
    930 
    931 -- | Serialize a secp256k1 point in 33-byte compressed form.
    932 --
    933 --   >>> serialize_point pub
    934 --   "<33-byte compressed point>"
    935 serialize_point :: Projective -> BS.ByteString
    936 serialize_point (affine -> Affine (C.from -> x) (C.from -> y)) =
    937   let !(Wider (# Limb w, _, _, _ #)) = y
    938       !b | B.testBit (GHC.Word.W# w) 0 = 0x03
    939          | otherwise = 0x02
    940   in  BS.cons b (unroll32 x)
    941 
    942 -- ecdh -----------------------------------------------------------------------
    943 
    944 -- SEC1-v2 3.3.1, plus SHA256 hash
    945 
    946 -- | Compute a shared secret, given a secret key and public secp256k1 point,
    947 --   via Elliptic Curve Diffie-Hellman (ECDH).
    948 --
    949 --   The shared secret is the SHA256 hash of the x-coordinate of the
    950 --   point obtained by scalar multiplication.
    951 --
    952 --   >>> let sec_alice = 0x03
    953 --   >>> let sec_bob   = 2 ^ 128 - 1
    954 --   >>> let Just pub_alice = derive_pub sec_alice
    955 --   >>> let Just pub_bob   = derive_pub sec_bob
    956 --   >>> let secret_as_computed_by_alice = ecdh pub_bob sec_alice
    957 --   >>> let secret_as_computed_by_bob   = ecdh pub_alice sec_bob
    958 --   >>> secret_as_computed_by_alice == secret_as_computed_by_bob
    959 --   True
    960 ecdh
    961   :: Projective          -- ^ public key
    962   -> Wider               -- ^ secret key
    963   -> Maybe BS.ByteString -- ^ shared secret
    964 ecdh pub _SECRET = do
    965   pt@(P _ _ (C.Montgomery -> z)) <- mul pub _SECRET
    966   let !(Affine (C.retr -> x) _) = affine pt
    967       !result = SHA256.hash (unroll32 x)
    968   if CT.decide (C.eq z 0) then Nothing else Just result
    969 
    970 -- schnorr --------------------------------------------------------------------
    971 -- see https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
    972 
    973 -- | Create a 64-byte Schnorr signature for the provided message, using
    974 --   the provided secret key.
    975 --
    976 --   BIP0340 recommends that 32 bytes of fresh auxiliary entropy be
    977 --   generated and added at signing time as additional protection
    978 --   against side-channel attacks (namely, to thwart so-called "fault
    979 --   injection" attacks). This entropy is /supplemental/ to security,
    980 --   and the cryptographic security of the signature scheme itself does
    981 --   not rely on it, so it is not strictly required; 32 zero bytes can
    982 --   be used in its stead (and can be supplied via 'mempty').
    983 --
    984 --   >>> import qualified System.Entropy as E
    985 --   >>> aux <- E.getEntropy 32
    986 --   >>> sign_schnorr sec msg aux
    987 --   Just "<64-byte schnorr signature>"
    988 sign_schnorr
    989   :: Wider          -- ^ secret key
    990   -> BS.ByteString  -- ^ message
    991   -> BS.ByteString  -- ^ 32 bytes of auxilliary random data
    992   -> Maybe BS.ByteString  -- ^ 64-byte Schnorr signature
    993 sign_schnorr = _sign_schnorr (mul _CURVE_G)
    994 
    995 -- | The same as 'sign_schnorr', except uses a 'Context' to optimise
    996 --   internal calculations.
    997 --
    998 --   You can expect about a 2x performance increase when using this
    999 --   function, compared to 'sign_schnorr'.
   1000 --
   1001 --   >>> import qualified System.Entropy as E
   1002 --   >>> aux <- E.getEntropy 32
   1003 --   >>> let !tex = precompute
   1004 --   >>> sign_schnorr' tex sec msg aux
   1005 --   Just "<64-byte schnorr signature>"
   1006 sign_schnorr'
   1007   :: Context        -- ^ secp256k1 context
   1008   -> Wider          -- ^ secret key
   1009   -> BS.ByteString  -- ^ message
   1010   -> BS.ByteString  -- ^ 32 bytes of auxilliary random data
   1011   -> Maybe BS.ByteString  -- ^ 64-byte Schnorr signature
   1012 sign_schnorr' tex = _sign_schnorr (mul_wnaf tex)
   1013 
   1014 _sign_schnorr
   1015   :: (Wider -> Maybe Projective)  -- partially-applied multiplication function
   1016   -> Wider                        -- secret key
   1017   -> BS.ByteString                -- message
   1018   -> BS.ByteString                -- 32 bytes of auxilliary random data
   1019   -> Maybe BS.ByteString
   1020 _sign_schnorr _mul _SECRET m a = do
   1021   p <- _mul _SECRET
   1022   let Affine (C.retr -> x_p) (C.retr -> y_p) = affine p
   1023       s       = S.to _SECRET
   1024       d       = S.select s (negate s) (W.odd y_p)
   1025       bytes_d = unroll32 (S.retr d)
   1026       bytes_p = unroll32 x_p
   1027       t       = xor bytes_d (hash_aux a)
   1028       rand    = hash_nonce (t <> bytes_p <> m)
   1029       k'      = S.to (unsafe_roll32 rand)
   1030   guard (not (S.eq_vartime k' 0)) -- negligible probability
   1031   pt <- _mul (S.retr k')
   1032   let Affine (C.retr -> x_r) (C.retr -> y_r) = affine pt
   1033       k         = S.select k' (negate k') (W.odd y_r)
   1034       bytes_r   = unroll32 x_r
   1035       rand'     = hash_challenge (bytes_r <> bytes_p <> m)
   1036       e         = S.to (unsafe_roll32 rand')
   1037       bytes_ked = unroll32 (S.retr (k + e * d))
   1038       sig       = bytes_r <> bytes_ked
   1039   -- NB for benchmarking we morally want to remove the precautionary
   1040   --    verification check here.
   1041   --
   1042   -- guard (verify_schnorr m p sig)
   1043   pure $! sig
   1044 {-# INLINE _sign_schnorr #-}
   1045 
   1046 -- | Verify a 64-byte Schnorr signature for the provided message with
   1047 --   the supplied public key.
   1048 --
   1049 --   >>> verify_schnorr msg pub <valid signature>
   1050 --   True
   1051 --   >>> verify_schnorr msg pub <invalid signature>
   1052 --   False
   1053 verify_schnorr
   1054   :: BS.ByteString  -- ^ message
   1055   -> Pub            -- ^ public key
   1056   -> BS.ByteString  -- ^ 64-byte Schnorr signature
   1057   -> Bool
   1058 verify_schnorr = _verify_schnorr (mul_vartime _CURVE_G)
   1059 
   1060 -- | The same as 'verify_schnorr', except uses a 'Context' to optimise
   1061 --   internal calculations.
   1062 --
   1063 --   You can expect about a 1.5x performance increase when using this
   1064 --   function, compared to 'verify_schnorr'.
   1065 --
   1066 --   >>> let !tex = precompute
   1067 --   >>> verify_schnorr' tex msg pub <valid signature>
   1068 --   True
   1069 --   >>> verify_schnorr' tex msg pub <invalid signature>
   1070 --   False
   1071 verify_schnorr'
   1072   :: Context        -- ^ secp256k1 context
   1073   -> BS.ByteString  -- ^ message
   1074   -> Pub            -- ^ public key
   1075   -> BS.ByteString  -- ^ 64-byte Schnorr signature
   1076   -> Bool
   1077 verify_schnorr' tex = _verify_schnorr (mul_wnaf tex)
   1078 
   1079 _verify_schnorr
   1080   :: (Wider -> Maybe Projective) -- partially-applied multiplication function
   1081   -> BS.ByteString
   1082   -> Pub
   1083   -> BS.ByteString
   1084   -> Bool
   1085 _verify_schnorr _mul m p sig
   1086   | BS.length sig /= 64 = False
   1087   | otherwise = M.isJust $ do
   1088       let capP = even_y_vartime p
   1089           (unsafe_roll32 -> r, unsafe_roll32 -> s) = BS.splitAt 32 sig
   1090       guard (fe r && ge s)
   1091       let Affine (C.retr -> x_P) _ = affine capP
   1092           e = modQ . unsafe_roll32 $
   1093             hash_challenge (unroll32 r <> unroll32 x_P <> m)
   1094       pt0 <- _mul s
   1095       pt1 <- mul_vartime capP e
   1096       let dif = add pt0 (neg pt1)
   1097       guard (dif /= _CURVE_ZERO)
   1098       let Affine (C.from -> x_R) (C.from -> y_R) = affine dif
   1099       guard $ not (CT.decide (W.odd y_R) || not (W.eq_vartime x_R r))
   1100 {-# INLINE _verify_schnorr #-}
   1101 
   1102 -- hardcoded tag of BIP0340/aux
   1103 --
   1104 -- \x -> let h = SHA256.hash "BIP0340/aux"
   1105 --       in  SHA256.hash (h <> h <> x)
   1106 hash_aux :: BS.ByteString -> BS.ByteString
   1107 hash_aux x = SHA256.hash $
   1108   "\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
   1109 {-# INLINE hash_aux #-}
   1110 
   1111 -- hardcoded tag of BIP0340/nonce
   1112 hash_nonce :: BS.ByteString -> BS.ByteString
   1113 hash_nonce x = SHA256.hash $
   1114   "\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
   1115 {-# INLINE hash_nonce #-}
   1116 
   1117 -- hardcoded tag of BIP0340/challenge
   1118 hash_challenge :: BS.ByteString -> BS.ByteString
   1119 hash_challenge x = SHA256.hash $
   1120   "{\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
   1121 {-# INLINE hash_challenge #-}
   1122 
   1123 -- ecdsa ----------------------------------------------------------------------
   1124 -- see https://www.rfc-editor.org/rfc/rfc6979, https://secg.org/sec1-v2.pdf
   1125 
   1126 -- RFC6979 2.3.2
   1127 bits2int :: BS.ByteString -> Wider
   1128 bits2int = unsafe_roll32
   1129 {-# INLINABLE bits2int #-}
   1130 
   1131 -- RFC6979 2.3.3
   1132 int2octets :: Wider -> BS.ByteString
   1133 int2octets = unroll32
   1134 {-# INLINABLE int2octets #-}
   1135 
   1136 -- RFC6979 2.3.4
   1137 bits2octets :: BS.ByteString -> BS.ByteString
   1138 bits2octets bs =
   1139   let z1 = bits2int bs
   1140       z2 = modQ z1
   1141   in  int2octets z2
   1142 
   1143 -- | An ECDSA signature.
   1144 data ECDSA = ECDSA {
   1145     ecdsa_r :: !Wider
   1146   , ecdsa_s :: !Wider
   1147   }
   1148   deriving (Generic)
   1149 
   1150 instance Show ECDSA where
   1151   show _ = "<ecdsa signature>"
   1152 
   1153 -- ECDSA signature type.
   1154 data SigType =
   1155     LowS
   1156   | Unrestricted
   1157   deriving Show
   1158 
   1159 -- Indicates whether to hash the message or assume it has already been
   1160 -- hashed.
   1161 data HashFlag =
   1162     Hash
   1163   | NoHash
   1164   deriving Show
   1165 
   1166 -- Convert an ECDSA signature to low-S form.
   1167 low :: ECDSA -> ECDSA
   1168 low (ECDSA r s) = ECDSA r (W.select s (_CURVE_Q - s) (W.gt s _CURVE_QH))
   1169 {-# INLINE low #-}
   1170 
   1171 -- | Produce an ECDSA signature for the provided message, using the
   1172 --   provided private key.
   1173 --
   1174 --   'sign_ecdsa' produces a "low-s" signature, as is commonly required
   1175 --   in applications using secp256k1. If you need a generic ECDSA
   1176 --   signature, use 'sign_ecdsa_unrestricted'.
   1177 --
   1178 --   >>> sign_ecdsa sec msg
   1179 --   Just "<ecdsa signature>"
   1180 sign_ecdsa
   1181   :: Wider         -- ^ secret key
   1182   -> BS.ByteString -- ^ message
   1183   -> Maybe ECDSA
   1184 sign_ecdsa = _sign_ecdsa (mul _CURVE_G) LowS Hash
   1185 
   1186 -- | The same as 'sign_ecdsa', except uses a 'Context' to optimise internal
   1187 --   calculations.
   1188 --
   1189 --   You can expect about a 10x performance increase when using this
   1190 --   function, compared to 'sign_ecdsa'.
   1191 --
   1192 --   >>> let !tex = precompute
   1193 --   >>> sign_ecdsa' tex sec msg
   1194 --   Just "<ecdsa signature>"
   1195 sign_ecdsa'
   1196   :: Context       -- ^ secp256k1 context
   1197   -> Wider         -- ^ secret key
   1198   -> BS.ByteString -- ^ message
   1199   -> Maybe ECDSA
   1200 sign_ecdsa' tex = _sign_ecdsa (mul_wnaf tex) LowS Hash
   1201 
   1202 -- | Produce an ECDSA signature for the provided message, using the
   1203 --   provided private key.
   1204 --
   1205 --   'sign_ecdsa_unrestricted' produces an unrestricted ECDSA signature,
   1206 --   which is less common in applications using secp256k1 due to the
   1207 --   signature's inherent malleability. If you need a conventional
   1208 --   "low-s" signature, use 'sign_ecdsa'.
   1209 --
   1210 --   >>> sign_ecdsa_unrestricted sec msg
   1211 --   Just "<ecdsa signature>"
   1212 sign_ecdsa_unrestricted
   1213   :: Wider         -- ^ secret key
   1214   -> BS.ByteString -- ^ message
   1215   -> Maybe ECDSA
   1216 sign_ecdsa_unrestricted = _sign_ecdsa (mul _CURVE_G) Unrestricted Hash
   1217 
   1218 -- | The same as 'sign_ecdsa_unrestricted', except uses a 'Context' to
   1219 --   optimise internal calculations.
   1220 --
   1221 --   You can expect about a 10x performance increase when using this
   1222 --   function, compared to 'sign_ecdsa_unrestricted'.
   1223 --
   1224 --   >>> let !tex = precompute
   1225 --   >>> sign_ecdsa_unrestricted' tex sec msg
   1226 --   Just "<ecdsa signature>"
   1227 sign_ecdsa_unrestricted'
   1228   :: Context       -- ^ secp256k1 context
   1229   -> Wider         -- ^ secret key
   1230   -> BS.ByteString -- ^ message
   1231   -> Maybe ECDSA
   1232 sign_ecdsa_unrestricted' tex = _sign_ecdsa (mul_wnaf tex) Unrestricted Hash
   1233 
   1234 -- Produce a "low-s" ECDSA signature for the provided message, using
   1235 -- the provided private key. Assumes that the message has already been
   1236 -- pre-hashed.
   1237 --
   1238 -- (Useful for testing against noble-secp256k1's suite, in which messages
   1239 -- in the test vectors have already been hashed.)
   1240 _sign_ecdsa_no_hash
   1241   :: Wider         -- ^ secret key
   1242   -> BS.ByteString -- ^ message digest
   1243   -> Maybe ECDSA
   1244 _sign_ecdsa_no_hash = _sign_ecdsa (mul _CURVE_G) LowS NoHash
   1245 
   1246 _sign_ecdsa_no_hash'
   1247   :: Context
   1248   -> Wider
   1249   -> BS.ByteString
   1250   -> Maybe ECDSA
   1251 _sign_ecdsa_no_hash' tex = _sign_ecdsa (mul_wnaf tex) LowS NoHash
   1252 
   1253 _sign_ecdsa
   1254   :: (Wider -> Maybe Projective) -- partially-applied multiplication function
   1255   -> SigType
   1256   -> HashFlag
   1257   -> Wider
   1258   -> BS.ByteString
   1259   -> Maybe ECDSA
   1260 _sign_ecdsa _mul ty hf _SECRET m = runST $ do
   1261     -- RFC6979 sec 3.3a
   1262     let entropy = int2octets _SECRET
   1263         nonce   = bits2octets h
   1264     drbg <- DRBG.new hmac entropy nonce mempty
   1265     -- RFC6979 sec 2.4
   1266     sign_loop drbg
   1267   where
   1268     hmac k b = case SHA256.hmac k b of
   1269       SHA256.MAC mac -> mac
   1270 
   1271     d  = S.to _SECRET
   1272     hm = S.to (bits2int h)
   1273     h  = case hf of
   1274       Hash -> SHA256.hash m
   1275       NoHash -> m
   1276 
   1277     sign_loop g = do
   1278       k <- gen_k g
   1279       let mpair = do
   1280             kg <- _mul k
   1281             let Affine (S.to . C.retr -> r) _ = affine kg
   1282                 ki = S.inv (S.to k)
   1283                 s  = (hm + d * r) * ki
   1284             pure $! (S.retr r, S.retr s)
   1285       case mpair of
   1286         Nothing -> pure Nothing
   1287         Just (r, s)
   1288           | W.eq_vartime r 0 -> sign_loop g -- negligible probability
   1289           | otherwise ->
   1290               let !sig = Just $! ECDSA r s
   1291               in  case ty of
   1292                     Unrestricted -> pure sig
   1293                     LowS -> pure (fmap low sig)
   1294 {-# INLINE _sign_ecdsa #-}
   1295 
   1296 -- RFC6979 sec 3.3b
   1297 gen_k :: DRBG.DRBG s -> ST s Wider
   1298 gen_k g = loop g where
   1299   loop drbg = do
   1300     bytes <- DRBG.gen mempty (fi _CURVE_Q_BYTES) drbg
   1301     case bytes of
   1302       Left {}  -> error "ppad-secp256k1: internal error (please report a bug!)"
   1303       Right bs -> do
   1304         let can = bits2int bs
   1305         case W.cmp_vartime can _CURVE_Q of
   1306           LT -> pure can
   1307           _  -> loop drbg -- 2 ^ -128 probability
   1308 {-# INLINE gen_k #-}
   1309 
   1310 -- | Verify a "low-s" ECDSA signature for the provided message and
   1311 --   public key,
   1312 --
   1313 --   Fails to verify otherwise-valid "high-s" signatures. If you need to
   1314 --   verify generic ECDSA signatures, use 'verify_ecdsa_unrestricted'.
   1315 --
   1316 --   >>> verify_ecdsa msg pub valid_sig
   1317 --   True
   1318 --   >>> verify_ecdsa msg pub invalid_sig
   1319 --   False
   1320 verify_ecdsa
   1321   :: BS.ByteString -- ^ message
   1322   -> Pub           -- ^ public key
   1323   -> ECDSA         -- ^ signature
   1324   -> Bool
   1325 verify_ecdsa m p sig@(ECDSA _ s)
   1326   | CT.decide (W.gt s _CURVE_QH) = False
   1327   | otherwise = verify_ecdsa_unrestricted m p sig
   1328 
   1329 -- | The same as 'verify_ecdsa', except uses a 'Context' to optimise
   1330 --   internal calculations.
   1331 --
   1332 --   You can expect about a 2x performance increase when using this
   1333 --   function, compared to 'verify_ecdsa'.
   1334 --
   1335 --   >>> let !tex = precompute
   1336 --   >>> verify_ecdsa' tex msg pub valid_sig
   1337 --   True
   1338 --   >>> verify_ecdsa' tex msg pub invalid_sig
   1339 --   False
   1340 verify_ecdsa'
   1341   :: Context       -- ^ secp256k1 context
   1342   -> BS.ByteString -- ^ message
   1343   -> Pub           -- ^ public key
   1344   -> ECDSA         -- ^ signature
   1345   -> Bool
   1346 verify_ecdsa' tex m p sig@(ECDSA _ s)
   1347   | CT.decide (W.gt s _CURVE_QH) = False
   1348   | otherwise = verify_ecdsa_unrestricted' tex m p sig
   1349 
   1350 -- | Verify an unrestricted ECDSA signature for the provided message and
   1351 --   public key.
   1352 --
   1353 --   >>> verify_ecdsa_unrestricted msg pub valid_sig
   1354 --   True
   1355 --   >>> verify_ecdsa_unrestricted msg pub invalid_sig
   1356 --   False
   1357 verify_ecdsa_unrestricted
   1358   :: BS.ByteString -- ^ message
   1359   -> Pub           -- ^ public key
   1360   -> ECDSA         -- ^ signature
   1361   -> Bool
   1362 verify_ecdsa_unrestricted = _verify_ecdsa_unrestricted (mul_vartime _CURVE_G)
   1363 
   1364 -- | The same as 'verify_ecdsa_unrestricted', except uses a 'Context' to
   1365 --   optimise internal calculations.
   1366 --
   1367 --   You can expect about a 2x performance increase when using this
   1368 --   function, compared to 'verify_ecdsa_unrestricted'.
   1369 --
   1370 --   >>> let !tex = precompute
   1371 --   >>> verify_ecdsa_unrestricted' tex msg pub valid_sig
   1372 --   True
   1373 --   >>> verify_ecdsa_unrestricted' tex msg pub invalid_sig
   1374 --   False
   1375 verify_ecdsa_unrestricted'
   1376   :: Context       -- ^ secp256k1 context
   1377   -> BS.ByteString -- ^ message
   1378   -> Pub           -- ^ public key
   1379   -> ECDSA         -- ^ signature
   1380   -> Bool
   1381 verify_ecdsa_unrestricted' tex = _verify_ecdsa_unrestricted (mul_wnaf tex)
   1382 
   1383 _verify_ecdsa_unrestricted
   1384   :: (Wider -> Maybe Projective) -- partially-applied multiplication function
   1385   -> BS.ByteString
   1386   -> Pub
   1387   -> ECDSA
   1388   -> Bool
   1389 _verify_ecdsa_unrestricted _mul m p (ECDSA r0 s0) = M.isJust $ do
   1390   -- SEC1-v2 4.1.4
   1391   let h = SHA256.hash m
   1392   guard (ge r0 && ge s0)
   1393   let r  = S.to r0
   1394       s  = S.to s0
   1395       e  = S.to (bits2int h)
   1396       si = S.inv s
   1397       u1 = S.retr (e * si)
   1398       u2 = S.retr (r * si)
   1399   pt0 <- _mul u1
   1400   pt1 <- mul_vartime p u2
   1401   let capR = add pt0 pt1
   1402   guard (capR /= _CURVE_ZERO)
   1403   let Affine (S.to . C.retr -> v) _ = affine capR
   1404   guard (S.eq_vartime v r)
   1405 {-# INLINE _verify_ecdsa_unrestricted #-}
   1406