packages feed

secp256k1-haskell 0.7.0 → 1.0.0

raw patch · 6 files changed

+606/−530 lines, 6 filesdep −cerealPVP ok

version bump matches the API change (PVP)

Dependencies removed: cereal

API changes (from Hackage documentation)

- Crypto.Secp256k1: data CompactSig
- Crypto.Secp256k1: data Msg
- Crypto.Secp256k1: data PubKey
- Crypto.Secp256k1: data SecKey
- Crypto.Secp256k1: data Sig
- Crypto.Secp256k1: data Tweak
- Crypto.Secp256k1: getCompactSig :: CompactSig -> ByteString
- Crypto.Secp256k1: getMsg :: Msg -> ByteString
- Crypto.Secp256k1: getSecKey :: SecKey -> ByteString
- Crypto.Secp256k1: getTweak :: Tweak -> ByteString
- Crypto.Secp256k1: instance Data.Serialize.Serialize Crypto.Secp256k1.CompactSig
- Crypto.Secp256k1: instance Data.Serialize.Serialize Crypto.Secp256k1.Msg
- Crypto.Secp256k1: instance Data.Serialize.Serialize Crypto.Secp256k1.PubKey
- Crypto.Secp256k1: instance Data.Serialize.Serialize Crypto.Secp256k1.SecKey
- Crypto.Secp256k1: instance Data.Serialize.Serialize Crypto.Secp256k1.Sig
- Crypto.Secp256k1: instance Data.Serialize.Serialize Crypto.Secp256k1.Tweak
- Crypto.Secp256k1: instance Test.QuickCheck.Arbitrary.Arbitrary Crypto.Secp256k1.PubKey
- Crypto.Secp256k1.Internal: ctx :: Ctx
- Crypto.Secp256k1.Internal: type Ctx = Ptr LCtx
+ Crypto.Secp256k1: CompactSig :: ByteString -> CompactSig
+ Crypto.Secp256k1: Ctx :: Ptr LCtx -> Ctx
+ Crypto.Secp256k1: Msg :: ByteString -> Msg
+ Crypto.Secp256k1: PubKey :: ByteString -> PubKey
+ Crypto.Secp256k1: SecKey :: ByteString -> SecKey
+ Crypto.Secp256k1: Sig :: ByteString -> Sig
+ Crypto.Secp256k1: Tweak :: ByteString -> Tweak
+ Crypto.Secp256k1: [$sel:get:CompactSig] :: CompactSig -> ByteString
+ Crypto.Secp256k1: [$sel:get:Ctx] :: Ctx -> Ptr LCtx
+ Crypto.Secp256k1: [$sel:get:Msg] :: Msg -> ByteString
+ Crypto.Secp256k1: [$sel:get:PubKey] :: PubKey -> ByteString
+ Crypto.Secp256k1: [$sel:get:SecKey] :: SecKey -> ByteString
+ Crypto.Secp256k1: [$sel:get:Sig] :: Sig -> ByteString
+ Crypto.Secp256k1: [$sel:get:Tweak] :: Tweak -> ByteString
+ Crypto.Secp256k1: cloneContext :: Ctx -> IO Ctx
+ Crypto.Secp256k1: createContext :: IO Ctx
+ Crypto.Secp256k1: destroyContext :: Ctx -> IO ()
+ Crypto.Secp256k1: instance Data.Hashable.Class.Hashable Crypto.Secp256k1.CompactSig
+ Crypto.Secp256k1: newtype CompactSig
+ Crypto.Secp256k1: newtype Ctx
+ Crypto.Secp256k1: newtype Msg
+ Crypto.Secp256k1: newtype PubKey
+ Crypto.Secp256k1: newtype SecKey
+ Crypto.Secp256k1: newtype Sig
+ Crypto.Secp256k1: newtype Tweak
+ Crypto.Secp256k1: pubKey :: ByteString -> Maybe PubKey
+ Crypto.Secp256k1: randomizeContext :: Ctx -> IO ()
+ Crypto.Secp256k1: sig :: ByteString -> Maybe Sig
+ Crypto.Secp256k1: withContext :: (Ctx -> IO a) -> IO a
+ Crypto.Secp256k1.Internal: withRandomSeed :: (Ptr Seed32 -> IO a) -> IO a
- Crypto.Secp256k1: combinePubKeys :: [PubKey] -> Maybe PubKey
+ Crypto.Secp256k1: combinePubKeys :: Ctx -> [PubKey] -> Maybe PubKey
- Crypto.Secp256k1: derivePubKey :: SecKey -> PubKey
+ Crypto.Secp256k1: derivePubKey :: Ctx -> SecKey -> PubKey
- Crypto.Secp256k1: exportCompactSig :: Sig -> CompactSig
+ Crypto.Secp256k1: exportCompactSig :: Ctx -> Sig -> CompactSig
- Crypto.Secp256k1: exportPubKey :: Bool -> PubKey -> ByteString
+ Crypto.Secp256k1: exportPubKey :: Ctx -> Bool -> PubKey -> ByteString
- Crypto.Secp256k1: exportSig :: Sig -> ByteString
+ Crypto.Secp256k1: exportSig :: Ctx -> Sig -> ByteString
- Crypto.Secp256k1: importCompactSig :: CompactSig -> Maybe Sig
+ Crypto.Secp256k1: importCompactSig :: Ctx -> CompactSig -> Maybe Sig
- Crypto.Secp256k1: importPubKey :: ByteString -> Maybe PubKey
+ Crypto.Secp256k1: importPubKey :: Ctx -> ByteString -> Maybe PubKey
- Crypto.Secp256k1: importSig :: ByteString -> Maybe Sig
+ Crypto.Secp256k1: importSig :: Ctx -> ByteString -> Maybe Sig
- Crypto.Secp256k1: normalizeSig :: Sig -> Maybe Sig
+ Crypto.Secp256k1: normalizeSig :: Ctx -> Sig -> Maybe Sig
- Crypto.Secp256k1: signMsg :: SecKey -> Msg -> Sig
+ Crypto.Secp256k1: signMsg :: Ctx -> SecKey -> Msg -> Sig
- Crypto.Secp256k1: tweakAddPubKey :: PubKey -> Tweak -> Maybe PubKey
+ Crypto.Secp256k1: tweakAddPubKey :: Ctx -> PubKey -> Tweak -> Maybe PubKey
- Crypto.Secp256k1: tweakAddSecKey :: SecKey -> Tweak -> Maybe SecKey
+ Crypto.Secp256k1: tweakAddSecKey :: Ctx -> SecKey -> Tweak -> Maybe SecKey
- Crypto.Secp256k1: tweakMulPubKey :: PubKey -> Tweak -> Maybe PubKey
+ Crypto.Secp256k1: tweakMulPubKey :: Ctx -> PubKey -> Tweak -> Maybe PubKey
- Crypto.Secp256k1: tweakMulSecKey :: SecKey -> Tweak -> Maybe SecKey
+ Crypto.Secp256k1: tweakMulSecKey :: Ctx -> SecKey -> Tweak -> Maybe SecKey
- Crypto.Secp256k1: tweakNegate :: Tweak -> Maybe Tweak
+ Crypto.Secp256k1: tweakNegate :: Ctx -> Tweak -> Maybe Tweak
- Crypto.Secp256k1: verifySig :: PubKey -> Sig -> Msg -> Bool
+ Crypto.Secp256k1: verifySig :: Ctx -> PubKey -> Sig -> Msg -> Bool
- Crypto.Secp256k1.Internal: contextClone :: Ctx -> IO Ctx
+ Crypto.Secp256k1.Internal: contextClone :: Ptr LCtx -> IO (Ptr LCtx)
- Crypto.Secp256k1.Internal: contextCreate :: CtxFlags -> IO Ctx
+ Crypto.Secp256k1.Internal: contextCreate :: CtxFlags -> IO (Ptr LCtx)
- Crypto.Secp256k1.Internal: contextDestroy :: FunPtr (Ctx -> IO ())
+ Crypto.Secp256k1.Internal: contextDestroy :: Ptr LCtx -> IO ()
- Crypto.Secp256k1.Internal: contextRandomize :: Ctx -> Ptr Seed32 -> IO Ret
+ Crypto.Secp256k1.Internal: contextRandomize :: Ptr LCtx -> Ptr Seed32 -> IO Ret
- Crypto.Secp256k1.Internal: ecPubKeyCombine :: Ctx -> Ptr PubKey64 -> Ptr (Ptr PubKey64) -> CInt -> IO Ret
+ Crypto.Secp256k1.Internal: ecPubKeyCombine :: Ptr LCtx -> Ptr PubKey64 -> Ptr (Ptr PubKey64) -> CInt -> IO Ret
- Crypto.Secp256k1.Internal: ecPubKeyCreate :: Ctx -> Ptr PubKey64 -> Ptr SecKey32 -> IO Ret
+ Crypto.Secp256k1.Internal: ecPubKeyCreate :: Ptr LCtx -> Ptr PubKey64 -> Ptr SecKey32 -> IO Ret
- Crypto.Secp256k1.Internal: ecPubKeyParse :: Ctx -> Ptr PubKey64 -> Ptr CUChar -> CSize -> IO Ret
+ Crypto.Secp256k1.Internal: ecPubKeyParse :: Ptr LCtx -> Ptr PubKey64 -> Ptr CUChar -> CSize -> IO Ret
- Crypto.Secp256k1.Internal: ecPubKeySerialize :: Ctx -> Ptr CUChar -> Ptr CSize -> Ptr PubKey64 -> SerFlags -> IO Ret
+ Crypto.Secp256k1.Internal: ecPubKeySerialize :: Ptr LCtx -> Ptr CUChar -> Ptr CSize -> Ptr PubKey64 -> SerFlags -> IO Ret
- Crypto.Secp256k1.Internal: ecPubKeyTweakAdd :: Ctx -> Ptr PubKey64 -> Ptr Tweak32 -> IO Ret
+ Crypto.Secp256k1.Internal: ecPubKeyTweakAdd :: Ptr LCtx -> Ptr PubKey64 -> Ptr Tweak32 -> IO Ret
- Crypto.Secp256k1.Internal: ecPubKeyTweakMul :: Ctx -> Ptr PubKey64 -> Ptr Tweak32 -> IO Ret
+ Crypto.Secp256k1.Internal: ecPubKeyTweakMul :: Ptr LCtx -> Ptr PubKey64 -> Ptr Tweak32 -> IO Ret
- Crypto.Secp256k1.Internal: ecSecKeyTweakAdd :: Ctx -> Ptr SecKey32 -> Ptr Tweak32 -> IO Ret
+ Crypto.Secp256k1.Internal: ecSecKeyTweakAdd :: Ptr LCtx -> Ptr SecKey32 -> Ptr Tweak32 -> IO Ret
- Crypto.Secp256k1.Internal: ecSecKeyTweakMul :: Ctx -> Ptr SecKey32 -> Ptr Tweak32 -> IO Ret
+ Crypto.Secp256k1.Internal: ecSecKeyTweakMul :: Ptr LCtx -> Ptr SecKey32 -> Ptr Tweak32 -> IO Ret
- Crypto.Secp256k1.Internal: ecSecKeyVerify :: Ctx -> Ptr SecKey32 -> IO Ret
+ Crypto.Secp256k1.Internal: ecSecKeyVerify :: Ptr LCtx -> Ptr SecKey32 -> IO Ret
- Crypto.Secp256k1.Internal: ecTweakNegate :: Ctx -> Ptr Tweak32 -> IO Ret
+ Crypto.Secp256k1.Internal: ecTweakNegate :: Ptr LCtx -> Ptr Tweak32 -> IO Ret
- Crypto.Secp256k1.Internal: ecdsaSign :: Ctx -> Ptr Sig64 -> Ptr Msg32 -> Ptr SecKey32 -> FunPtr (NonceFun a) -> Ptr a -> IO Ret
+ Crypto.Secp256k1.Internal: ecdsaSign :: Ptr LCtx -> Ptr Sig64 -> Ptr Msg32 -> Ptr SecKey32 -> FunPtr (NonceFun a) -> Ptr a -> IO Ret
- Crypto.Secp256k1.Internal: ecdsaSignatureNormalize :: Ctx -> Ptr Sig64 -> Ptr Sig64 -> IO Ret
+ Crypto.Secp256k1.Internal: ecdsaSignatureNormalize :: Ptr LCtx -> Ptr Sig64 -> Ptr Sig64 -> IO Ret
- Crypto.Secp256k1.Internal: ecdsaSignatureParseCompact :: Ctx -> Ptr Sig64 -> Ptr Compact64 -> IO Ret
+ Crypto.Secp256k1.Internal: ecdsaSignatureParseCompact :: Ptr LCtx -> Ptr Sig64 -> Ptr Compact64 -> IO Ret
- Crypto.Secp256k1.Internal: ecdsaSignatureParseDer :: Ctx -> Ptr Sig64 -> Ptr CUChar -> CSize -> IO Ret
+ Crypto.Secp256k1.Internal: ecdsaSignatureParseDer :: Ptr LCtx -> Ptr Sig64 -> Ptr CUChar -> CSize -> IO Ret
- Crypto.Secp256k1.Internal: ecdsaSignatureSerializeCompact :: Ctx -> Ptr Compact64 -> Ptr Sig64 -> IO Ret
+ Crypto.Secp256k1.Internal: ecdsaSignatureSerializeCompact :: Ptr LCtx -> Ptr Compact64 -> Ptr Sig64 -> IO Ret
- Crypto.Secp256k1.Internal: ecdsaSignatureSerializeDer :: Ctx -> Ptr CUChar -> Ptr CSize -> Ptr Sig64 -> IO Ret
+ Crypto.Secp256k1.Internal: ecdsaSignatureSerializeDer :: Ptr LCtx -> Ptr CUChar -> Ptr CSize -> Ptr Sig64 -> IO Ret
- Crypto.Secp256k1.Internal: ecdsaVerify :: Ctx -> Ptr Sig64 -> Ptr Msg32 -> Ptr PubKey64 -> IO Ret
+ Crypto.Secp256k1.Internal: ecdsaVerify :: Ptr LCtx -> Ptr Sig64 -> Ptr Msg32 -> Ptr PubKey64 -> IO Ret
- Crypto.Secp256k1.Internal: setErrorCallback :: Ctx -> FunPtr (CString -> Ptr a -> IO ()) -> Ptr a -> IO ()
+ Crypto.Secp256k1.Internal: setErrorCallback :: Ptr LCtx -> FunPtr (CString -> Ptr a -> IO ()) -> Ptr a -> IO ()
- Crypto.Secp256k1.Internal: setIllegalCallback :: Ctx -> FunPtr (CString -> Ptr a -> IO ()) -> Ptr a -> IO ()
+ Crypto.Secp256k1.Internal: setIllegalCallback :: Ptr LCtx -> FunPtr (CString -> Ptr a -> IO ()) -> Ptr a -> IO ()

Files

CHANGELOG.md view
@@ -4,120 +4,178 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## 0.6.1+## [1.0.0] - 2023-07-28+ ### Changed++- Context data structure must be created and passed explicitly.+- Field selectors are now short and duplicates are allowed.+- Use DuplicateRecordFields and OverloadedRecordDot language extensions.++## [0.6.1] - 2022-04-18++### Changed+ - Bump version and LTS Haskell. - Update dependencies. -## 0.6.0+## [0.6.0] - 2021-08-27+ ### Changed+ - Remove all use of CPP. - Depend on base16 instead of the old base16-bytestring package. - Target ghc-9.0.1 compiler.  ### Fixed+ - Do not crash on bytestrings that are backed by null C pointers. -## 0.5.0+## [0.5.0] - 2020-10-16+ ### Changed+ - Include version boundaries and other changes submitted by Emily Pillmore. -## 0.4.0+## [0.4.0] - 2020-07-23+ ### Changed+ - Remove fragile ForeignPtr implementation in favor of just storing ByteStrings. - Reuse memory instead of copying when possible. -## 0.3.1+## [0.3.1] - 2020-07-03+ ### Fixed+ - Use unsafe calls in FFI. -## 0.3.0+## [0.3.0] - 2020-06-13+ ### Fixed+ - Compiles with all flags now.  ### Added+ - Script to compile with all flags.  ### Removed+ - Remove ECDH support. - Remove Schnorr support. - Remove Recovery support. -## 0.2.5+## [0.2.5] - 2020-06-13+ ### Changed+ - Reuse context aggressively. - Generate context in a single thread.  ### Fixed+ - Memory deallocation bug. -## 0.2.4+## [0.2.4] - 2020-06-12+ ### Changed+ - Update Cabal and package version. -## 0.2.3+## [0.2.3] - 2020-06-07+ ### Changed+ - Return meaningful error upon encountering weird ret status from upstream code.  ### Added+ - Test parallel signature creation and verification. -## 0.2.2+## [0.2.2] - 2020-04-14+ ### Removed+ - Hide tweak negation behind a flag for compatibilidy with Debian 9.  ### Fixed+ - Correct code that was not compiling with some flags enabled. -## 0.2.1+## [0.2.1] - 2020-04-10+ ### Changed+ - Do not depend on hardcoded DER signatures in tests. -## 0.2.0+## [0.2.0] - 2020-04-10+ ### Added+ - Support for ECDH APIs. - Support for Schnorr APIs.  ### Removed+ - Enabling key recovery APIs need a flag. -## 0.1.8+## [0.1.8] - 2020-01-15+ ### Added+ - Add missing `NFData` instances for some types. -## 0.1.7+## [0.1.7] - 2020-01-15+ ### Added+ - Add `NFData` instances for all types. -## 0.1.6+## [0.1.6] - 2019-12-26+ ### Added+ - Use `pkgconfig` for C library dependency. -## 0.1.5+## [0.1.5] - 2019-09-19+ ### Added+ - Flag for ECDH bindings. -## 0.1.4+## [0.1.4] - 2018-10-25+ ### Changed+ - Constrain imports to avoid clashes with a QuickCheck function. -## 0.1.3+## [0.1.3] - 2018-10-13+ ### Added+ - Hashable instances for various types. -## 0.1.2+## [0.1.2] - 2018-09-10+ ### Changed+ - Separate dependencies between library and tests. - Remove `hspec` default to prevent problems with Nix.  ### Removed+ - Dependency to `cryptohash` not needed. -## 0.1.1+## [0.1.1] - 2018-09-10+ ### Changed+ - Update changelog to reflect name and version change. - Update to LTS Haskell 12.9. -## 0.1.0+## [0.1.0] - 2018-09-10+ ### Changed+ - Name of package change from `secp256k1` to `secp256k1-haskell` to avoid Nix conflicts.
secp256k1-haskell.cabal view
@@ -1,11 +1,11 @@ cabal-version: 2.0 --- This file has been generated from package.yaml by hpack version 0.35.1.+-- This file has been generated from package.yaml by hpack version 0.35.2. -- -- see: https://github.com/sol/hpack  name:           secp256k1-haskell-version:        0.7.0+version:        1.0.0 synopsis:       Bindings for secp256k1 description:    Sign and verify signatures using the secp256k1 library. category:       Crypto@@ -41,7 +41,6 @@     , base >=4.9 && <5     , base16 >=1.0     , bytestring >=0.10.8 && <0.12-    , cereal >=0.5.4 && <0.6     , deepseq >=1.4.2 && <1.5     , entropy >=0.3.8 && <0.5     , hashable >=1.2.6 && <1.5@@ -67,7 +66,6 @@     , base >=4.9 && <5     , base16 >=1.0     , bytestring >=0.10.8 && <0.12-    , cereal >=0.5.4 && <0.6     , deepseq >=1.4.2 && <1.5     , entropy >=0.3.8 && <0.5     , hashable >=1.2.6 && <1.5
src/Crypto/Secp256k1.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ImportQualifiedPost #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedRecordDot #-}+{-# LANGUAGE NoFieldSelectors #-}  -- | -- Module      : Crypto.Secp256k1@@ -13,24 +16,32 @@ -- -- Crytpographic functions from Bitcoin’s secp256k1 library. module Crypto.Secp256k1-  ( -- * Messages-    Msg,+  ( -- * Context+    Ctx (..),+    withContext,+    randomizeContext,+    createContext,+    cloneContext,+    destroyContext,++    -- * Messages+    Msg (..),     msg,-    getMsg,      -- * Secret Keys-    SecKey,+    SecKey (..),     secKey,-    getSecKey,     derivePubKey,      -- * Public Keys-    PubKey,+    PubKey (..),+    pubKey,     importPubKey,     exportPubKey,      -- * Signatures-    Sig,+    Sig (..),+    sig,     signMsg,     verifySig,     normalizeSig,@@ -40,16 +51,14 @@     exportSig,      -- ** Compact-    CompactSig,-    getCompactSig,+    CompactSig (..),     compactSig,     exportCompactSig,     importCompactSig,      -- * Addition & Multiplication-    Tweak,+    Tweak (..),     tweak,-    getTweak,     tweakAddSecKey,     tweakMulSecKey,     tweakAddPubKey,@@ -60,6 +69,7 @@ where  import Control.DeepSeq (NFData)+import Control.Exception (bracket) import Control.Monad (replicateM, unless, (<=<)) import Crypto.Secp256k1.Internal import Data.Base16.Types (assertBase16, extractBase16)@@ -68,15 +78,12 @@ import Data.ByteString.Base16 (decodeBase16, encodeBase16, isBase16) import Data.Hashable (Hashable (..)) import Data.Maybe (fromJust, fromMaybe, isJust)-import Data.Serialize-  ( Serialize (..),-    getByteString,-    putByteString,-  ) import Data.String (IsString (..)) import Data.String.Conversions (ConvertibleStrings, cs) import Foreign-  ( alloca,+  ( Bits (bitSize),+    Ptr,+    alloca,     allocaArray,     allocaBytes,     free,@@ -102,47 +109,25 @@     readPrec,   ) -newtype PubKey = PubKey {getPubKey :: ByteString}-  deriving (Eq, Generic, NFData)--newtype Msg = Msg {getMsg :: ByteString}-  deriving (Eq, Generic, NFData)--newtype Sig = Sig {getSig :: ByteString}-  deriving (Eq, Generic, NFData)--newtype SecKey = SecKey {getSecKey :: ByteString}-  deriving (Eq, Generic, NFData)--newtype Tweak = Tweak {getTweak :: ByteString}-  deriving (Eq, Generic, NFData)--newtype CompactSig = CompactSig {getCompactSig :: ByteString}-  deriving (Eq, Generic, NFData)+newtype Ctx = Ctx {get :: Ptr LCtx} -instance Serialize PubKey where-  put (PubKey bs) = putByteString bs-  get = PubKey <$> getByteString 64+newtype PubKey = PubKey {get :: ByteString}+  deriving (Eq, Generic, Hashable, NFData) -instance Serialize Msg where-  put (Msg m) = putByteString m-  get = Msg <$> getByteString 32+newtype Msg = Msg {get :: ByteString}+  deriving (Eq, Generic, Hashable, NFData) -instance Serialize Sig where-  put (Sig bs) = putByteString bs-  get = Sig <$> getByteString 64+newtype Sig = Sig {get :: ByteString}+  deriving (Eq, Generic, Hashable, NFData) -instance Serialize SecKey where-  put (SecKey bs) = putByteString bs-  get = SecKey <$> getByteString 32+newtype SecKey = SecKey {get :: ByteString}+  deriving (Eq, Generic, Hashable, NFData) -instance Serialize Tweak where-  put (Tweak bs) = putByteString bs-  get = Tweak <$> getByteString 32+newtype Tweak = Tweak {get :: ByteString}+  deriving (Eq, Generic, Hashable, NFData) -instance Serialize CompactSig where-  put (CompactSig bs) = putByteString bs-  get = CompactSig <$> getByteString 64+newtype CompactSig = CompactSig {get :: ByteString}+  deriving (Eq, Generic, Hashable, NFData)  decodeHex :: (ConvertibleStrings a ByteString) => a -> Maybe ByteString decodeHex str =@@ -151,71 +136,56 @@     else Nothing  instance Read PubKey where-  readPrec = do+  readPrec = parens $ do     String str <- lexP-    maybe pfail return $ importPubKey =<< decodeHex str--instance Hashable PubKey where-  i `hashWithSalt` k = i `hashWithSalt` exportPubKey True k+    maybe pfail return $ pubKey =<< decodeHex str  instance IsString PubKey where-  fromString = fromMaybe e . (importPubKey <=< decodeHex)+  fromString = fromMaybe e . (pubKey <=< decodeHex)     where       e = error "Could not decode public key from hex string"  instance Show PubKey where-  showsPrec _ = shows . extractBase16 . encodeBase16 . exportPubKey True+  showsPrec _ = shows . extractBase16 . encodeBase16 . (.get)  instance Read Msg where   readPrec = parens $ do     String str <- lexP     maybe pfail return $ msg =<< decodeHex str -instance Hashable Msg where-  i `hashWithSalt` m = i `hashWithSalt` getMsg m- instance IsString Msg where   fromString = fromMaybe e . (msg <=< decodeHex)     where       e = error "Could not decode message from hex string" -instance Show Msg where-  showsPrec _ = shows . extractBase16 . encodeBase16 . getMsg+instance Show Sig where+  showsPrec _ = shows . extractBase16 . encodeBase16 . (.get)  instance Read Sig where   readPrec = parens $ do     String str <- lexP-    maybe pfail return $ importSig =<< decodeHex str+    maybe pfail return $ sig =<< decodeHex str  instance IsString Sig where-  fromString = fromMaybe e . (importSig <=< decodeHex)+  fromString = fromMaybe e . (sig <=< decodeHex)     where       e = error "Could not decode signature from hex string" -instance Hashable Sig where-  i `hashWithSalt` s = i `hashWithSalt` exportSig s--instance Show Sig where-  showsPrec _ = shows . extractBase16 . encodeBase16 . exportSig+instance Show Msg where+  showsPrec _ = shows . extractBase16 . encodeBase16 . (.get)  instance Read SecKey where   readPrec = parens $ do     String str <- lexP     maybe pfail return $ secKey =<< decodeHex str -instance Hashable SecKey where-  i `hashWithSalt` k = i `hashWithSalt` getSecKey k- instance IsString SecKey where   fromString = fromMaybe e . (secKey <=< decodeHex)     where       e = error "Colud not decode secret key from hex string"  instance Show SecKey where-  showsPrec _ = shows . extractBase16 . encodeBase16 . getSecKey--instance Hashable Tweak where-  i `hashWithSalt` t = i `hashWithSalt` getTweak t+  showsPrec _ = shows . extractBase16 . encodeBase16 . (.get)  instance Read Tweak where   readPrec = parens $ do@@ -228,8 +198,41 @@       e = error "Could not decode tweak from hex string"  instance Show Tweak where-  showsPrec _ = shows . extractBase16 . encodeBase16 . getTweak+  showsPrec _ = shows . extractBase16 . encodeBase16 . (.get) +randomizeContext :: Ctx -> IO ()+randomizeContext (Ctx ctx) = do+  ret <- withRandomSeed $ contextRandomize ctx+  unless (isSuccess ret) $ error "Could not randomize context"++createContext :: IO Ctx+createContext = Ctx <$> contextCreate signVerify++cloneContext :: Ctx -> IO Ctx+cloneContext = fmap Ctx . contextClone . (.get)++destroyContext :: Ctx -> IO ()+destroyContext = contextDestroy . (.get)++withContext :: (Ctx -> IO a) -> IO a+withContext = bracket create destroy+  where+    create = do+      ctx <- createContext+      randomizeContext ctx+      return ctx+    destroy = destroyContext++sig :: ByteString -> Maybe Sig+sig bs+  | BS.length bs == 64 = Just (Sig bs)+  | otherwise = Nothing++pubKey :: ByteString -> Maybe PubKey+pubKey bs+  | BS.length bs == 64 = Just (PubKey bs)+  | otherwise = Nothing+ -- | Import 32-byte 'ByteString' as 'Msg'. msg :: ByteString -> Maybe Msg msg bs@@ -249,8 +252,8 @@  -- | Convert signature to a normalized lower-S form. 'Nothing' indicates that it -- was already normal.-normalizeSig :: Sig -> Maybe Sig-normalizeSig (Sig sig) = unsafePerformIO $+normalizeSig :: Ctx -> Sig -> Maybe Sig+normalizeSig (Ctx ctx) (Sig sig) = unsafePerformIO $   unsafeUseByteString sig $ \(sig_in, _) -> do     sig_out <- mallocBytes 64     ret <- ecdsaSignatureNormalize ctx sig_out sig_in@@ -269,8 +272,8 @@   | otherwise = Nothing  -- | Import DER-encoded public key.-importPubKey :: ByteString -> Maybe PubKey-importPubKey bs+importPubKey :: Ctx -> ByteString -> Maybe PubKey+importPubKey (Ctx ctx) bs   | BS.null bs = Nothing   | otherwise = unsafePerformIO $       unsafeUseByteString bs $ \(input, len) -> do@@ -285,8 +288,8 @@             return Nothing  -- | Encode public key as DER. First argument 'True' for compressed output.-exportPubKey :: Bool -> PubKey -> ByteString-exportPubKey compress (PubKey in_bs) = unsafePerformIO $+exportPubKey :: Ctx -> Bool -> PubKey -> ByteString+exportPubKey (Ctx ctx) compress (PubKey in_bs) = unsafePerformIO $   unsafeUseByteString in_bs $ \(in_ptr, _) ->     alloca $ \len_ptr ->       allocaBytes len $ \out_ptr -> do@@ -299,8 +302,8 @@     len = if compress then 33 else 65     flags = if compress then compressed else uncompressed -exportCompactSig :: Sig -> CompactSig-exportCompactSig (Sig sig_bs) = unsafePerformIO $+exportCompactSig :: Ctx -> Sig -> CompactSig+exportCompactSig (Ctx ctx) (Sig sig_bs) = unsafePerformIO $   unsafeUseByteString sig_bs $ \(sig_ptr, _) -> do     out_ptr <- mallocBytes 64     ret <- ecdsaSignatureSerializeCompact ctx out_ptr sig_ptr@@ -310,8 +313,8 @@     out_bs <- unsafePackByteString (out_ptr, 64)     return $ CompactSig out_bs -importCompactSig :: CompactSig -> Maybe Sig-importCompactSig (CompactSig compact_sig) = unsafePerformIO $+importCompactSig :: Ctx -> CompactSig -> Maybe Sig+importCompactSig (Ctx ctx) (CompactSig compact_sig) = unsafePerformIO $   unsafeUseByteString compact_sig $ \(compact_ptr, _) -> do     out_sig <- mallocBytes 64     ret <- ecdsaSignatureParseCompact ctx out_sig compact_ptr@@ -324,8 +327,8 @@         return Nothing  -- | Import DER-encoded signature.-importSig :: ByteString -> Maybe Sig-importSig bs+importSig :: Ctx -> ByteString -> Maybe Sig+importSig (Ctx ctx) bs   | BS.null bs = Nothing   | otherwise = unsafePerformIO $       unsafeUseByteString bs $ \(in_ptr, in_len) -> do@@ -340,8 +343,8 @@             return Nothing  -- | Encode signature as strict DER.-exportSig :: Sig -> ByteString-exportSig (Sig in_sig) = unsafePerformIO $+exportSig :: Ctx -> Sig -> ByteString+exportSig (Ctx ctx) (Sig in_sig) = unsafePerformIO $   unsafeUseByteString in_sig $ \(in_ptr, _) ->     alloca $ \out_len ->       allocaBytes 72 $ \out_ptr -> do@@ -352,15 +355,15 @@         packByteString (out_ptr, final_len)  -- | Verify message signature. 'True' means that the signature is correct.-verifySig :: PubKey -> Sig -> Msg -> Bool-verifySig (PubKey pub_key) (Sig sig) (Msg m) = unsafePerformIO $+verifySig :: Ctx -> PubKey -> Sig -> Msg -> Bool+verifySig (Ctx ctx) (PubKey pub_key) (Sig sig) (Msg m) = unsafePerformIO $   unsafeUseByteString pub_key $ \(pub_key_ptr, _) ->     unsafeUseByteString sig $ \(sig_ptr, _) ->       unsafeUseByteString m $ \(msg_ptr, _) ->         isSuccess <$> ecdsaVerify ctx sig_ptr msg_ptr pub_key_ptr -signMsg :: SecKey -> Msg -> Sig-signMsg (SecKey sec_key) (Msg m) = unsafePerformIO $+signMsg :: Ctx -> SecKey -> Msg -> Sig+signMsg (Ctx ctx) (SecKey sec_key) (Msg m) = unsafePerformIO $   unsafeUseByteString sec_key $ \(sec_key_ptr, _) ->     unsafeUseByteString m $ \(msg_ptr, _) -> do       sig_ptr <- mallocBytes 64@@ -370,8 +373,8 @@         error "could not sign message"       Sig <$> unsafePackByteString (sig_ptr, 64) -derivePubKey :: SecKey -> PubKey-derivePubKey (SecKey sec_key) = unsafePerformIO $+derivePubKey :: Ctx -> SecKey -> PubKey+derivePubKey (Ctx ctx) (SecKey sec_key) = unsafePerformIO $   unsafeUseByteString sec_key $ \(sec_key_ptr, _) -> do     pub_key_ptr <- mallocBytes 64     ret <- ecPubKeyCreate ctx pub_key_ptr sec_key_ptr@@ -381,8 +384,8 @@     PubKey <$> unsafePackByteString (pub_key_ptr, 64)  -- | Add tweak to secret key.-tweakAddSecKey :: SecKey -> Tweak -> Maybe SecKey-tweakAddSecKey (SecKey sec_key) (Tweak t) = unsafePerformIO $+tweakAddSecKey :: Ctx -> SecKey -> Tweak -> Maybe SecKey+tweakAddSecKey (Ctx ctx) (SecKey sec_key) (Tweak t) = unsafePerformIO $   unsafeUseByteString new_bs $ \(sec_key_ptr, _) ->     unsafeUseByteString t $ \(tweak_ptr, _) -> do       ret <- ecSecKeyTweakAdd ctx sec_key_ptr tweak_ptr@@ -393,8 +396,8 @@     new_bs = BS.copy sec_key  -- | Multiply secret key by tweak.-tweakMulSecKey :: SecKey -> Tweak -> Maybe SecKey-tweakMulSecKey (SecKey sec_key) (Tweak t) = unsafePerformIO $+tweakMulSecKey :: Ctx -> SecKey -> Tweak -> Maybe SecKey+tweakMulSecKey (Ctx ctx) (SecKey sec_key) (Tweak t) = unsafePerformIO $   unsafeUseByteString new_bs $ \(sec_key_ptr, _) ->     unsafeUseByteString t $ \(tweak_ptr, _) -> do       ret <- ecSecKeyTweakMul ctx sec_key_ptr tweak_ptr@@ -405,8 +408,8 @@     new_bs = BS.copy sec_key  -- | Add tweak to public key. Tweak is multiplied first by G to obtain a point.-tweakAddPubKey :: PubKey -> Tweak -> Maybe PubKey-tweakAddPubKey (PubKey pub_key) (Tweak t) = unsafePerformIO $+tweakAddPubKey :: Ctx -> PubKey -> Tweak -> Maybe PubKey+tweakAddPubKey (Ctx ctx) (PubKey pub_key) (Tweak t) = unsafePerformIO $   unsafeUseByteString new_bs $ \(pub_key_ptr, _) ->     unsafeUseByteString t $ \(tweak_ptr, _) -> do       ret <- ecPubKeyTweakAdd ctx pub_key_ptr tweak_ptr@@ -418,8 +421,8 @@  -- | Multiply public key by tweak. Tweak is multiplied first by G to obtain a -- point.-tweakMulPubKey :: PubKey -> Tweak -> Maybe PubKey-tweakMulPubKey (PubKey pub_key) (Tweak t) = unsafePerformIO $+tweakMulPubKey :: Ctx -> PubKey -> Tweak -> Maybe PubKey+tweakMulPubKey (Ctx ctx) (PubKey pub_key) (Tweak t) = unsafePerformIO $   unsafeUseByteString new_bs $ \(pub_key_ptr, _) ->     unsafeUseByteString t $ \(tweak_ptr, _) -> do       ret <- ecPubKeyTweakMul ctx pub_key_ptr tweak_ptr@@ -430,9 +433,9 @@     new_bs = BS.copy pub_key  -- | Add multiple public keys together.-combinePubKeys :: [PubKey] -> Maybe PubKey-combinePubKeys [] = Nothing-combinePubKeys pubs = unsafePerformIO $+combinePubKeys :: Ctx -> [PubKey] -> Maybe PubKey+combinePubKeys _ [] = Nothing+combinePubKeys (Ctx ctx) pubs = unsafePerformIO $   pointers [] pubs $ \ps ->     allocaArray (length ps) $ \a -> do       out <- mallocBytes 64@@ -451,8 +454,8 @@       unsafeUseByteString pub_key $ \(p, _) ->         pointers (p : ps) pub_keys f -tweakNegate :: Tweak -> Maybe Tweak-tweakNegate (Tweak t) = unsafePerformIO $+tweakNegate :: Ctx -> Tweak -> Maybe Tweak+tweakNegate (Ctx ctx) (Tweak t) = unsafePerformIO $   unsafeUseByteString new $ \(out, _) -> do     ret <- ecTweakNegate ctx out     if isSuccess ret@@ -474,6 +477,3 @@       valid_bs = bs_gen `suchThat` isJust       bs_gen = secKey . BS.pack <$> replicateM 32 arbitraryBoundedRandom       gen_key = fromJust <$> valid_bs--instance Arbitrary PubKey where-  arbitrary = derivePubKey <$> arbitrary
src/Crypto/Secp256k1/Internal.hs view
@@ -1,46 +1,60 @@-{-|-Module      : Crypto.Secp256k1.Internal-License     : UNLICENSE-Maintainer  : Jean-Pierre Rupp <jprupp@protonmail.ch>-Stability   : experimental-Portability : POSIX+{-# LANGUAGE ImportQualifiedPost #-} -The API for this module may change at any time. This is an internal module only-exposed for hacking and experimentation.--}+-- |+-- Module      : Crypto.Secp256k1.Internal+-- License     : UNLICENSE+-- Maintainer  : Jean-Pierre Rupp <jprupp@protonmail.ch>+-- Stability   : experimental+-- Portability : POSIX+--+-- The API for this module may change at any time. This is an internal module only+-- exposed for hacking and experimentation. module Crypto.Secp256k1.Internal where -import           Data.ByteString        (ByteString)-import qualified Data.ByteString        as BS-import qualified Data.ByteString.Unsafe as BU-import           Foreign                (FunPtr, Ptr, castPtr)-import           Foreign.C              (CInt (..), CSize (..), CString, CUChar,-                                         CUInt (..))-import           System.IO.Unsafe       (unsafePerformIO)+import Data.ByteString (ByteString)+import Data.ByteString qualified as BS+import Data.ByteString.Unsafe qualified as BU+import Foreign (FunPtr, Ptr, castPtr)+import Foreign.C+  ( CInt (..),+    CSize (..),+    CString,+    CUChar,+    CUInt (..),+  )+import GHC.Generics (Selector (selDecidedStrictness))+import System.Entropy (getEntropy)  data LCtx+ data PubKey64+ data Msg32+ data Sig64-data Compact64+ data Seed32++data Compact64+ data SecKey32+ data Tweak32  type CtxFlags = CUInt+ type SerFlags = CUInt+ type Ret = CInt  type NonceFun a =-    Ptr CUChar ->-    Ptr CUChar ->-    Ptr CUChar ->-    Ptr CUChar ->-    Ptr a ->-    CInt ->-    IO CInt--type Ctx = Ptr LCtx+  Ptr CUChar ->+  Ptr CUChar ->+  Ptr CUChar ->+  Ptr CUChar ->+  Ptr a ->+  CInt ->+  IO CInt  verify :: CtxFlags verify = 0x0101@@ -64,207 +78,203 @@  unsafeUseByteString :: ByteString -> ((Ptr a, CSize) -> IO b) -> IO b unsafeUseByteString bs f =-    BU.unsafeUseAsCStringLen bs $ \(b, l) ->+  BU.unsafeUseAsCStringLen bs $ \(b, l) ->     f (castPtr b, fromIntegral l)  useByteString :: ByteString -> ((Ptr a, CSize) -> IO b) -> IO b useByteString bs f =-    BS.useAsCStringLen bs $ \(b, l) ->+  BS.useAsCStringLen bs $ \(b, l) ->     f (castPtr b, fromIntegral l)  unsafePackByteString :: (Ptr a, CSize) -> IO ByteString unsafePackByteString (b, l) =-    BU.unsafePackMallocCStringLen (castPtr b, fromIntegral l)+  BU.unsafePackMallocCStringLen (castPtr b, fromIntegral l)  packByteString :: (Ptr a, CSize) -> IO ByteString packByteString (b, l) =-    BS.packCStringLen (castPtr b, fromIntegral l)--ctx :: Ctx-ctx = unsafePerformIO $ contextCreate signVerify-{-# NOINLINE ctx #-}+  BS.packCStringLen (castPtr b, fromIntegral l) -foreign import ccall safe-    "secp256k1.h secp256k1_context_create"-    contextCreate-    :: CtxFlags-    -> IO Ctx+withRandomSeed :: (Ptr Seed32 -> IO a) -> IO a+withRandomSeed go = do+  bs <- getEntropy 32+  useByteString bs $ go . fst -foreign import ccall safe-    "secp256k1.h secp256k1_context_clone"-    contextClone-    :: Ctx-    -> IO Ctx+foreign import ccall safe "secp256k1.h secp256k1_context_create"+  contextCreate ::+    CtxFlags ->+    IO (Ptr LCtx) -foreign import ccall safe-    "secp256k1.h &secp256k1_context_destroy"-    contextDestroy-    :: FunPtr (Ctx -> IO ())+foreign import ccall safe "secp256k1.h secp256k1_context_clone"+  contextClone ::+    Ptr LCtx ->+    IO (Ptr LCtx) -foreign import ccall safe-    "secp256k1.h secp256k1_context_set_illegal_callback"-    setIllegalCallback-    :: Ctx-    -> FunPtr (CString -> Ptr a -> IO ()) -- ^ message, data-    -> Ptr a                              -- ^ data-    -> IO ()+foreign import ccall safe "secp256k1.h secp256k1_context_destroy"+  contextDestroy ::+    Ptr LCtx ->+    IO () -foreign import ccall safe-    "secp256k1.h secp256k1_context_set_error_callback"-    setErrorCallback-    :: Ctx-    -> FunPtr (CString -> Ptr a -> IO ()) -- ^ message, data-    -> Ptr a                              -- ^ data-    -> IO ()+foreign import ccall safe "secp256k1.h secp256k1_context_set_illegal_callback"+  setIllegalCallback ::+    Ptr LCtx ->+    -- | message, data+    FunPtr (CString -> Ptr a -> IO ()) ->+    -- | data+    Ptr a ->+    IO () -foreign import ccall safe-    "secp256k1.h secp256k1_ec_pubkey_parse"-    ecPubKeyParse-    :: Ctx-    -> Ptr PubKey64-    -> Ptr CUChar -- ^ encoded public key array-    -> CSize      -- ^ size of encoded public key array-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_context_set_error_callback"+  setErrorCallback ::+    Ptr LCtx ->+    -- | message, data+    FunPtr (CString -> Ptr a -> IO ()) ->+    -- | data+    Ptr a ->+    IO () -foreign import ccall safe-    "secp256k1.h secp256k1_ec_pubkey_serialize"-    ecPubKeySerialize-    :: Ctx-    -> Ptr CUChar -- ^ array for encoded public key, must be large enough-    -> Ptr CSize  -- ^ size of encoded public key, will be updated-    -> Ptr PubKey64-    -> SerFlags-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_parse"+  ecPubKeyParse ::+    Ptr LCtx ->+    Ptr PubKey64 ->+    -- | encoded public key array+    Ptr CUChar ->+    -- | size of encoded public key array+    CSize ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ecdsa_signature_parse_compact"-    ecdsaSignatureParseCompact-    :: Ctx-    -> Ptr Sig64-    -> Ptr Compact64-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_serialize"+  ecPubKeySerialize ::+    Ptr LCtx ->+    -- | array for encoded public key, must be large enough+    Ptr CUChar ->+    -- | size of encoded public key, will be updated+    Ptr CSize ->+    Ptr PubKey64 ->+    SerFlags ->+    IO Ret +foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_parse_compact"+  ecdsaSignatureParseCompact ::+    Ptr LCtx ->+    Ptr Sig64 ->+    Ptr Compact64 ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ecdsa_signature_parse_der"-    ecdsaSignatureParseDer-    :: Ctx-    -> Ptr Sig64-    -> Ptr CUChar -- ^ encoded DER signature-    -> CSize      -- ^ size of encoded signature-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_parse_der"+  ecdsaSignatureParseDer ::+    Ptr LCtx ->+    Ptr Sig64 ->+    -- | encoded DER signature+    Ptr CUChar ->+    -- | size of encoded signature+    CSize ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ecdsa_signature_serialize_der"-    ecdsaSignatureSerializeDer-    :: Ctx-    -> Ptr CUChar -- ^ array for encoded signature, must be large enough-    -> Ptr CSize  -- ^ size of encoded signature, will be updated-    -> Ptr Sig64-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_serialize_der"+  ecdsaSignatureSerializeDer ::+    Ptr LCtx ->+    -- | array for encoded signature, must be large enough+    Ptr CUChar ->+    -- | size of encoded signature, will be updated+    Ptr CSize ->+    Ptr Sig64 ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ecdsa_signature_serialize_compact"-    ecdsaSignatureSerializeCompact-    :: Ctx-    -> Ptr Compact64-    -> Ptr Sig64-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_serialize_compact"+  ecdsaSignatureSerializeCompact ::+    Ptr LCtx ->+    Ptr Compact64 ->+    Ptr Sig64 ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ecdsa_verify"-    ecdsaVerify-    :: Ctx-    -> Ptr Sig64-    -> Ptr Msg32-    -> Ptr PubKey64-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ecdsa_verify"+  ecdsaVerify ::+    Ptr LCtx ->+    Ptr Sig64 ->+    Ptr Msg32 ->+    Ptr PubKey64 ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ecdsa_signature_normalize"-    ecdsaSignatureNormalize-    :: Ctx-    -> Ptr Sig64 -- ^ output-    -> Ptr Sig64 -- ^ input-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_normalize"+  ecdsaSignatureNormalize ::+    Ptr LCtx ->+    -- | output+    Ptr Sig64 ->+    -- | input+    Ptr Sig64 ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ecdsa_sign"-    ecdsaSign-    :: Ctx-    -> Ptr Sig64-    -> Ptr Msg32-    -> Ptr SecKey32-    -> FunPtr (NonceFun a)-    -> Ptr a -- ^ nonce data-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ecdsa_sign"+  ecdsaSign ::+    Ptr LCtx ->+    Ptr Sig64 ->+    Ptr Msg32 ->+    Ptr SecKey32 ->+    FunPtr (NonceFun a) ->+    -- | nonce data+    Ptr a ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ec_seckey_verify"-    ecSecKeyVerify-    :: Ctx-    -> Ptr SecKey32-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ec_seckey_verify"+  ecSecKeyVerify ::+    Ptr LCtx ->+    Ptr SecKey32 ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ec_pubkey_create"-    ecPubKeyCreate-    :: Ctx-    -> Ptr PubKey64-    -> Ptr SecKey32-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_create"+  ecPubKeyCreate ::+    Ptr LCtx ->+    Ptr PubKey64 ->+    Ptr SecKey32 ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ec_privkey_tweak_add"-    ecSecKeyTweakAdd-    :: Ctx-    -> Ptr SecKey32-    -> Ptr Tweak32-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ec_privkey_tweak_add"+  ecSecKeyTweakAdd ::+    Ptr LCtx ->+    Ptr SecKey32 ->+    Ptr Tweak32 ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ec_privkey_negate"-    ecTweakNegate-    :: Ctx-    -> Ptr Tweak32-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ec_privkey_negate"+  ecTweakNegate ::+    Ptr LCtx ->+    Ptr Tweak32 ->+    IO Ret -foreign import ccall unsafe-    "secp256k1.h secp256k1_ec_pubkey_tweak_add"-    ecPubKeyTweakAdd-    :: Ctx-    -> Ptr PubKey64-    -> Ptr Tweak32-    -> IO Ret+foreign import ccall unsafe "secp256k1.h secp256k1_ec_pubkey_tweak_add"+  ecPubKeyTweakAdd ::+    Ptr LCtx ->+    Ptr PubKey64 ->+    Ptr Tweak32 ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ec_privkey_tweak_mul"-    ecSecKeyTweakMul-    :: Ctx-    -> Ptr SecKey32-    -> Ptr Tweak32-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ec_privkey_tweak_mul"+  ecSecKeyTweakMul ::+    Ptr LCtx ->+    Ptr SecKey32 ->+    Ptr Tweak32 ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ec_pubkey_tweak_mul"-    ecPubKeyTweakMul-    :: Ctx-    -> Ptr PubKey64-    -> Ptr Tweak32-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_tweak_mul"+  ecPubKeyTweakMul ::+    Ptr LCtx ->+    Ptr PubKey64 ->+    Ptr Tweak32 ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_context_randomize"-    contextRandomize-    :: Ctx-    -> Ptr Seed32-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_context_randomize"+  contextRandomize ::+    Ptr LCtx ->+    Ptr Seed32 ->+    IO Ret -foreign import ccall safe-    "secp256k1.h secp256k1_ec_pubkey_combine"-    ecPubKeyCombine-    :: Ctx-    -> Ptr PubKey64       -- ^ pointer to public key storage-    -> Ptr (Ptr PubKey64) -- ^ pointer to array of public keys-    -> CInt               -- ^ number of public keys-    -> IO Ret+foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_combine"+  ecPubKeyCombine ::+    Ptr LCtx ->+    -- | pointer to public key storage+    Ptr PubKey64 ->+    -- | pointer to array of public keys+    Ptr (Ptr PubKey64) ->+    -- | number of public keys+    CInt ->+    IO Ret
test/Crypto/Secp256k1/InternalSpec.hs view
@@ -2,6 +2,7 @@  module Crypto.Secp256k1.InternalSpec (spec) where +import Control.Exception import Control.Monad import Control.Monad.Trans import Crypto.Secp256k1.Internal@@ -45,22 +46,21 @@     it "multiplies public key" ecPubKeyTweakMulTest     it "combines public keys" ecPubKeyCombineTest +withCtxPtr :: CtxFlags -> (Ptr LCtx -> IO a) -> IO a+withCtxPtr f = bracket (contextCreate f) contextDestroy+ withEntropy :: (Ptr Seed32 -> IO a) -> IO a withEntropy f =   getEntropy 32 >>= \e ->     useByteString e $ \(s, _) -> f s  createContextTest :: Assertion-createContextTest = do-  context_ptr <- liftIO $ contextCreate signVerify-  assertBool "context not null" $ context_ptr /= nullPtr+createContextTest = withCtxPtr signVerify $ \ctx -> do+  assertBool "context not null" $ ctx /= nullPtr  randomizeContextTest :: Assertion-randomizeContextTest = do-  ret <--    liftIO $-      contextCreate sign >>= \x ->-        withEntropy (contextRandomize x)+randomizeContextTest = withCtxPtr sign $ \ctx -> do+  ret <- withEntropy (contextRandomize ctx)   assertBool "context randomized" $ isSuccess ret  cloneContextTest :: Assertion@@ -125,7 +125,7 @@           \fb2202206f0415ab0e9a977afd78b2c26ef39b3952096d319fd4b101c768ad6c132e30\           \45" -parseDer :: Ctx -> ByteString -> IO ByteString+parseDer :: Ptr LCtx -> ByteString -> IO ByteString parseDer x bs =   useAsCStringLen bs $ \(d, dl) ->     allocaBytes 64 $ \s -> do@@ -135,10 +135,9 @@  ecdsaSignatureSerializeDerTest :: Assertion ecdsaSignatureSerializeDerTest = do-  (ret, enc) <- liftIO $ do-    x <- contextCreate verify+  (ret, enc) <- liftIO . bracket (contextCreate verify) contextDestroy $ \x -> do     sig <- parseDer x der-    alloca $ \ol ->+    (ret, enc) <- alloca $ \ol ->       allocaBytes 72 $ \o ->         useByteString sig $ \(s, _) -> do           poke ol 72@@ -146,6 +145,7 @@           len <- fromIntegral <$> peek ol           enc <- packCStringLen (castPtr o, len)           return (ret, enc)+    return (ret, enc)   assertBool "serialization successful" $ isSuccess ret   assertEqual "signatures match" der enc   where@@ -157,19 +157,18 @@           \45"  ecdsaVerifyTest :: Assertion-ecdsaVerifyTest = do+ecdsaVerifyTest = withCtxPtr verify $ \ctx -> do   ret <- liftIO $ do-    x <- contextCreate verify-    sig <- parseDer x der+    sig <- parseDer ctx der     pk <- useByteString pub $ \(p, pl) ->       allocaBytes 64 $ \k -> do-        ret <- ecPubKeyParse x k p (fromIntegral pl)+        ret <- ecPubKeyParse ctx k p (fromIntegral pl)         unless (isSuccess ret) $ error "could not parse public key"         packByteString (k, 64)     useByteString msg $ \(m, _) ->       useByteString pk $ \(k, _) ->         useByteString sig $ \(s, _) ->-          ecdsaVerify x s m k+          ecdsaVerify ctx s m k   assertBool "signature valid" $ isSuccess ret   where     der =@@ -188,44 +187,44 @@         assertBase16           "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00" -signCtx :: IO Ctx+signCtx :: IO (Ptr LCtx) signCtx =   contextCreate sign >>= \c ->     withEntropy (contextRandomize c) >>= \r ->       unless (isSuccess r) (error "failed to randomize context") >> return c -createPubKey :: Ctx -> Ptr SecKey32 -> Ptr PubKey64 -> IO ()-createPubKey x k p = do-  ret <- ecPubKeyCreate x p k+withSignCtxPtr :: (Ptr LCtx -> IO a) -> IO a+withSignCtxPtr = bracket signCtx contextDestroy++createPubKey :: Ptr LCtx -> Ptr SecKey32 -> Ptr PubKey64 -> IO ()+createPubKey ctx k p = do+  ret <- ecPubKeyCreate ctx p k   unless (isSuccess ret) $ error "failed to create public key"  ecdsaSignTest :: Assertion ecdsaSignTest = do-  der <- liftIO $ do-    x <- signCtx+  der <- liftIO $ withSignCtxPtr $ \ctx -> do     allocaBytes 64 $ \s ->       useByteString msg $ \(m, _) ->         useByteString key $ \(k, _) ->           alloca $ \ol ->             allocaBytes 72 $ \o -> do               poke ol 72-              ret1 <- ecdsaSign x s m k nullFunPtr nullPtr+              ret1 <- ecdsaSign ctx s m k nullFunPtr nullPtr               unless (isSuccess ret1) $ error "could not sign message"-              ret2 <- ecdsaSignatureSerializeDer x o ol s+              ret2 <- ecdsaSignatureSerializeDer ctx o ol s               unless (isSuccess ret2) $ error "could not serialize signature"               len <- peek ol               packCStringLen (castPtr o, fromIntegral len)   ret <- liftIO $ do-    pub <- allocaBytes 64 $ \p ->+    pub <- withSignCtxPtr $ \ctx -> allocaBytes 64 $ \p ->       useByteString key $ \(s, _) -> do-        x <- signCtx-        createPubKey x s p+        createPubKey ctx s p         packByteString (p, 64)-    useByteString msg $ \(m, _) ->+    withCtxPtr verify $ \ctx -> useByteString msg $ \(m, _) ->       useByteString pub $ \(p, _) -> do-        x <- contextCreate verify-        s' <- parseDer x der-        useByteString s' $ \(s, _) -> ecdsaVerify x s m p+        s' <- parseDer ctx der+        useByteString s' $ \(s, _) -> ecdsaVerify ctx s m p   assertBool "signature matches" (isSuccess ret)   where     msg =@@ -238,10 +237,9 @@           "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"  ecSecKeyVerifyTest :: Assertion-ecSecKeyVerifyTest = do+ecSecKeyVerifyTest = withSignCtxPtr $ \ctx -> do   ret <- liftIO $ useByteString key $ \(k, _) -> do-    x <- signCtx-    ecSecKeyVerify x k+    ecSecKeyVerify ctx k   assertBool "valid secret key" $ isSuccess ret   where     key =@@ -250,16 +248,15 @@           "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"  ecPubkeyCreateTest :: Assertion-ecPubkeyCreateTest = do+ecPubkeyCreateTest = withSignCtxPtr $ \ctx -> do   pk <- liftIO $     useByteString key $ \(s, _) ->       allocaBytes 64 $ \k -> do-        x <- signCtx-        createPubKey x s k+        createPubKey ctx s k         allocaBytes 65 $ \o ->           alloca $ \ol -> do             poke ol 65-            rets <- ecPubKeySerialize x o ol k uncompressed+            rets <- ecPubKeySerialize ctx o ol k uncompressed             unless (isSuccess rets) $ error "failed to serialize public key"             len <- fromIntegral <$> peek ol             packCStringLen (castPtr o, len)@@ -278,13 +275,12 @@ ecSecKeyTweakAddTest :: Assertion ecSecKeyTweakAddTest = do   (ret, tweaked) <--    liftIO $-      signCtx >>= \x ->-        useByteString tweak $ \(w, _) ->-          useByteString key $ \(k, _) -> do-            ret <- ecSecKeyTweakAdd x k w-            tweaked <- packByteString (k, 32)-            return (ret, tweaked)+    liftIO . withSignCtxPtr $ \ctx ->+      useByteString tweak $ \(w, _) ->+        useByteString key $ \(k, _) -> do+          ret <- ecSecKeyTweakAdd ctx k w+          tweaked <- packByteString (k, 32)+          return (ret, tweaked)   assertBool "successful secret key tweak" $ isSuccess ret   assertEqual "tweaked keys match" expected tweaked   where@@ -303,12 +299,9 @@  ecSecKeyTweakMulTest :: Assertion ecSecKeyTweakMulTest = do-  (ret, tweaked) <- liftIO $ do-    x <- contextCreate sign-    retr <- withEntropy $ contextRandomize x-    unless (isSuccess retr) $ error "failed to randomize context"+  (ret, tweaked) <- liftIO $ withSignCtxPtr $ \ctx -> do     useByteString tweak $ \(w, _) -> useByteString key $ \(k, _) -> do-      ret <- ecSecKeyTweakMul x k w+      ret <- ecSecKeyTweakMul ctx k w       tweaked <- packByteString (k, 32)       return (ret, tweaked)   assertBool "successful secret key tweak" $ isSuccess ret@@ -327,7 +320,7 @@         assertBase16           "a96f5962493acb179f60a86a9785fc7a30e0c39b64c09d24fe064d9aef15e4c0" -serializeKey :: Ctx -> Ptr PubKey64 -> IO ByteString+serializeKey :: Ptr LCtx -> Ptr PubKey64 -> IO ByteString serializeKey x p = allocaBytes 72 $ \d -> alloca $ \dl -> do   poke dl 72   ret <- ecPubKeySerialize x d dl p uncompressed@@ -335,7 +328,7 @@   len <- peek dl   packCStringLen (castPtr d, fromIntegral len) -parseKey :: Ctx -> ByteString -> IO ByteString+parseKey :: Ptr LCtx -> ByteString -> IO ByteString parseKey x bs =   allocaBytes 64 $ \p ->     useByteString bs $ \(d, dl) -> do
test/Crypto/Secp256k1Spec.hs view
@@ -1,179 +1,179 @@+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE ImportQualifiedPost #-}+{-# LANGUAGE OverloadedRecordDot #-}+ module Crypto.Secp256k1Spec (spec) where -import Control.Monad.Par-import qualified Control.Monad.Par as P+import Control.Arrow (first)+import Control.Monad.Par qualified as P import Crypto.Secp256k1 import Data.Base16.Types (assertBase16, extractBase16)-import qualified Data.ByteString as BS+import Data.ByteString qualified as BS import Data.ByteString.Base16 (decodeBase16, encodeBase16)-import qualified Data.ByteString.Char8 as B8+import Data.ByteString.Char8 qualified as B8 import Data.Either (fromRight)-import Data.Maybe (fromMaybe, isNothing)+import Data.Maybe (fromJust, fromMaybe, isJust, isNothing) import Data.String (fromString) import Data.String.Conversions (cs)-import Test.HUnit (Assertion, assertEqual)+import Test.HUnit (Assertion, assertBool, assertEqual) import Test.Hspec import Test.QuickCheck  spec :: Spec-spec = do+spec = around withContext $ do   describe "signatures" $ do-    it "signs message" $-      property signMsgTest-    it "signs messages in parallel" $-      property signMsgParTest-    it "detects bad signature" $-      property badSignatureTest-    it "normalizes signatures" $-      property normalizeSigTest+    it "signs message" $ \ctx ->+      property $ signMsgTest ctx+    it "signs messages in parallel" $ \ctx ->+      property $ signMsgParTest ctx+    it "detects bad signature" $ \ctx ->+      property $ badSignatureTest ctx+    it "normalizes signatures" $ \ctx ->+      property $ normalizeSigTest ctx   describe "serialization" $ do-    it "serializes public key" $-      property serializePubKeyTest-    it "serializes public keys in parallel" $-      property parSerializePubKeyTest-    it "serializes DER signature" $-      property serializeSigTest-    it "serializes DER signatures in parallel" $-      property parSerializeSigTest-    it "serializes compact signature" $-      property serializeCompactSigTest-    it "serialize secret key" $+    it "serializes public key" $ \ctx ->+      property $ serializePubKeyTest ctx+    it "serializes public keys in parallel" $ \ctx ->+      property $ parSerializePubKeyTest ctx+    it "serializes DER signature" $ \ctx ->+      property $ serializeSigTest ctx+    it "serializes DER signatures in parallel" $ \ctx ->+      property $ parSerializeSigTest ctx+    it "serializes compact signature" $ \ctx ->+      property $ serializeCompactSigTest ctx+    it "serialize secret key" $ \_ ->       property serializeSecKeyTest-    it "shows and reads public key" $-      property (showRead :: PubKey -> Bool)-    it "shows and reads secret key" $+    it "shows and reads secret key" $ \_ ->       property (showRead :: SecKey -> Bool)-    it "shows and reads tweak" $-      property (showReadTweak :: SecKey -> Bool)-    it "shows and reads signature" $-      property (showReadSig :: (SecKey, Msg) -> Bool)-    it "shows and reads message" $+    it "shows and reads tweak" $ \_ ->+      property showReadTweak+    it "shows and reads message" $ \_ ->       property (showRead :: Msg -> Bool)-    it "reads public key from string" $-      property isStringPubKey-    it "reads secret key from string" $+    it "shows and reads public key" $ \ctx ->+      property $ showReadPubKey ctx+    it "reads secret key from string" $ \_ ->       property isStringSecKey-    it "reads signature from string" $-      property isStringSig-    it "reads message from string" $+    it "reads message from string" $ \_ ->       property isStringMsg-    it "reads tweak from string" $+    it "reads tweak from string" $ \_ ->       property isStringTweak   describe "tweaks" $ do-    it "add secret key" $ property tweakAddSecKeyTest-    it "multiply secret key" $ property tweakMulSecKeyTest-    it "add public key" $ property tweakAddPubKeyTest-    it "multiply public key" $ property tweakMulPubKeyTest-    it "combine public keys" $ property combinePubKeyTest-    it "can't combine 0 public keys" $ property combinePubKeyEmptyListTest-    it "negates tweak" $ property negateTweakTest+    it "add secret key" $ \ctx ->+      property $ tweakAddSecKeyTest ctx+    it "multiply secret key" $ \ctx ->+      property $ tweakMulSecKeyTest ctx+    it "add public key" $ \ctx ->+      property $ tweakAddPubKeyTest ctx+    it "multiply public key" $ \ctx ->+      property $ tweakMulPubKeyTest ctx+    it "combine public keys" $ \ctx ->+      property $ combinePubKeyTest ctx+    it "can't combine 0 public keys" $ \ctx ->+      property $ combinePubKeyEmptyListTest ctx+    it "negates tweak" $ \ctx ->+      property $ negateTweakTest ctx  hexToBytes :: String -> BS.ByteString hexToBytes = decodeBase16 . assertBase16 . B8.pack -isStringPubKey :: (PubKey, Bool) -> Bool-isStringPubKey (k, c) = k == fromString (cs hex)-  where-    hex = extractBase16 . encodeBase16 $ exportPubKey c k--isStringSig :: (SecKey, Msg) -> Bool-isStringSig (k, m) = g == fromString (cs hex)-  where-    g = signMsg k m-    hex = extractBase16 . encodeBase16 $ exportSig g- isStringMsg :: Msg -> Bool isStringMsg m = m == fromString (cs m')   where-    m' = extractBase16 . encodeBase16 $ getMsg m+    m' = (extractBase16 . encodeBase16) m.get  isStringSecKey :: SecKey -> Bool isStringSecKey k = k == fromString (cs hex)   where-    hex = extractBase16 . encodeBase16 $ getSecKey k+    hex = (extractBase16 . encodeBase16) k.get  isStringTweak :: SecKey -> Bool isStringTweak k = t == fromString (cs hex)   where-    t = fromMaybe e . tweak $ getSecKey k-    hex = extractBase16 . encodeBase16 $ getTweak t+    t = (fromMaybe e . tweak) k.get+    hex = (extractBase16 . encodeBase16) t.get     e = error "Could not extract tweak from secret key"  showReadTweak :: SecKey -> Bool showReadTweak k = showRead t   where-    t = tweak $ getSecKey k+    t = tweak k.get -showReadSig :: (SecKey, Msg) -> Bool-showReadSig (k, m) = showRead sig+showReadPubKey :: Ctx -> SecKey -> Bool+showReadPubKey ctx k =+  (read . show) p == p   where-    sig = signMsg k m+    p = derivePubKey ctx k  showRead :: (Show a, Read a, Eq a) => a -> Bool showRead x = read (show x) == x -signMsgTest :: (Msg, SecKey) -> Bool-signMsgTest (fm, fk) = verifySig fp fg fm+signMsgTest :: Ctx -> (Msg, SecKey) -> Bool+signMsgTest ctx (fm, fk) = verifySig ctx fp fg fm   where-    fp = derivePubKey fk-    fg = signMsg fk fm+    fp = derivePubKey ctx fk+    fg = signMsg ctx fk fm -signMsgParTest :: [(Msg, SecKey)] -> Bool-signMsgParTest xs = P.runPar $ do-  ys <- mapM (P.spawnP . signMsgTest) xs+signMsgParTest :: Ctx -> [(Msg, SecKey)] -> Bool+signMsgParTest ctx xs = P.runPar $ do+  ys <- mapM (P.spawnP . signMsgTest ctx) xs   and <$> mapM P.get ys -badSignatureTest :: (Msg, SecKey, PubKey) -> Bool-badSignatureTest (fm, fk, fp) = not $ verifySig fp fg fm+badSignatureTest :: Ctx -> (Msg, SecKey, SecKey) -> Bool+badSignatureTest ctx (fm, fk, fk') = not $ verifySig ctx fp fg fm   where-    fg = signMsg fk fm+    fp = derivePubKey ctx fk'+    fg = signMsg ctx fk fm -normalizeSigTest :: (Msg, SecKey) -> Bool-normalizeSigTest (fm, fk) = isNothing sig+normalizeSigTest :: Ctx -> (Msg, SecKey) -> Bool+normalizeSigTest ctx (fm, fk) = isNothing sig   where-    fg = signMsg fk fm-    sig = normalizeSig fg+    fg = signMsg ctx fk fm+    sig = normalizeSig ctx fg -serializePubKeyTest :: (PubKey, Bool) -> Bool-serializePubKeyTest (fp, b) =-  case importPubKey $ exportPubKey b fp of+serializePubKeyTest :: Ctx -> (SecKey, Bool) -> Bool+serializePubKeyTest ctx (fk, b) =+  case importPubKey ctx $ exportPubKey ctx b fp of     Just fp' -> fp == fp'     Nothing -> False+  where+    fp = derivePubKey ctx fk -parSerializePubKeyTest :: [(PubKey, Bool)] -> Bool-parSerializePubKeyTest ps = runPar $ do-  as <- mapM (spawnP . serializePubKeyTest) ps-  and <$> mapM get as+parSerializePubKeyTest :: Ctx -> [(SecKey, Bool)] -> Bool+parSerializePubKeyTest ctx ks = P.runPar $ do+  as <- mapM (P.spawnP . serializePubKeyTest ctx) ks+  and <$> mapM P.get as+  where+    ps = map (first (derivePubKey ctx)) ks -serializeSigTest :: (Msg, SecKey) -> Bool-serializeSigTest (fm, fk) =-  case importSig $ exportSig fg of+serializeSigTest :: Ctx -> (Msg, SecKey) -> Bool+serializeSigTest ctx (fm, fk) =+  case importSig ctx $ exportSig ctx fg of     Just fg' -> fg == fg'     Nothing -> False   where-    fg = signMsg fk fm+    fg = signMsg ctx fk fm -parSerializeSigTest :: [(Msg, SecKey)] -> Bool-parSerializeSigTest ms = runPar $ do-  as <- mapM (spawnP . serializeSigTest) ms-  and <$> mapM get as+parSerializeSigTest :: Ctx -> [(Msg, SecKey)] -> Bool+parSerializeSigTest ctx ms = P.runPar $ do+  as <- mapM (P.spawnP . serializeSigTest ctx) ms+  and <$> mapM P.get as -serializeCompactSigTest :: (Msg, SecKey) -> Bool-serializeCompactSigTest (fm, fk) =-  case importCompactSig $ exportCompactSig fg of+serializeCompactSigTest :: Ctx -> (Msg, SecKey) -> Bool+serializeCompactSigTest ctx (fm, fk) =+  case importCompactSig ctx $ exportCompactSig ctx fg of     Just fg' -> fg == fg'     Nothing -> False   where-    fg = signMsg fk fm+    fg = signMsg ctx fk fm  serializeSecKeyTest :: SecKey -> Bool serializeSecKeyTest fk =-  case secKey $ getSecKey fk of+  case secKey fk.get of     Just fk' -> fk == fk'     Nothing -> False -tweakAddSecKeyTest :: Assertion-tweakAddSecKeyTest =+tweakAddSecKeyTest :: Ctx -> Assertion+tweakAddSecKeyTest ctx =   assertEqual "tweaked keys match" expected tweaked   where     tweaked = do@@ -185,14 +185,14 @@         tweak $           hexToBytes             "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"-      tweakAddSecKey key twk+      tweakAddSecKey ctx key twk     expected =       secKey $         hexToBytes           "ec1e3ce1cefa18a671d51125e2b249688d934b0e28f5d1665384d9b02f929059" -tweakMulSecKeyTest :: Assertion-tweakMulSecKeyTest =+tweakMulSecKeyTest :: Ctx -> Assertion+tweakMulSecKeyTest ctx =   assertEqual "tweaked keys match" expected tweaked   where     tweaked = do@@ -204,82 +204,99 @@         tweak $           hexToBytes             "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"-      tweakMulSecKey key twk+      tweakMulSecKey ctx key twk     expected =       secKey $         hexToBytes           "a96f5962493acb179f60a86a9785fc7a30e0c39b64c09d24fe064d9aef15e4c0" -tweakAddPubKeyTest :: Assertion-tweakAddPubKeyTest =+tweakAddPubKeyTest :: Ctx -> Assertion+tweakAddPubKeyTest ctx = do+  assertBool "did not fail to decode" $ isJust tweaked+  assertBool "is not empty" $ not $ maybe False BS.null tweaked   assertEqual "tweaked keys match" expected tweaked   where     tweaked = do       pub <--        importPubKey $+        importPubKey ctx $           hexToBytes             "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"       twk <-         tweak $           hexToBytes             "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"-      tweakAddPubKey pub twk-    expected =-      importPubKey $-        hexToBytes-          "04441c3982b97576646e0df0c96736063df6b42f2ee566d13b9f6424302d1379e518fdc87a14c5435bff7a5db4552042cb4120c6b86a4bbd3d0643f3c14ad01368"+      key <- tweakAddPubKey ctx pub twk+      return $ exportPubKey ctx True key+    expected = do+      key <-+        importPubKey ctx $+          hexToBytes+            "04441c3982b97576646e0df0c96736063df6b42f2ee566d13b9f6424302d1379e518fdc87a14c5435bff7a5db4552042cb4120c6b86a4bbd3d0643f3c14ad01368"+      return $ exportPubKey ctx True key -tweakMulPubKeyTest :: Assertion-tweakMulPubKeyTest =+tweakMulPubKeyTest :: Ctx -> Assertion+tweakMulPubKeyTest ctx = do+  assertBool "did not fail to decode" $ isJust tweaked+  assertBool "is not empty" $ not $ maybe False BS.null tweaked   assertEqual "tweaked keys match" expected tweaked   where     tweaked = do       pub <--        importPubKey $+        importPubKey ctx $           hexToBytes             "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"       twk <-         tweak $           hexToBytes             "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"-      tweakMulPubKey pub twk-    expected =-      importPubKey $-        hexToBytes-          "04f379dc99cdf5c83e433defa267fbb3377d61d6b779c06a0e4ce29ae3ff5353b12ae49c9d07e7368f2ba5a446c203255ce912322991a2d6a9d5d5761c61ed1845"+      key <- tweakMulPubKey ctx pub twk+      return $ exportPubKey ctx True key+    expected = do+      key <-+        importPubKey ctx $+          hexToBytes+            "04f379dc99cdf5c83e433defa267fbb3377d61d6b779c06a0e4ce29ae3ff5353b12ae49c9d07e7368f2ba5a446c203255ce912322991a2d6a9d5d5761c61ed1845"+      return $ exportPubKey ctx True key -combinePubKeyTest :: Assertion-combinePubKeyTest =+combinePubKeyTest :: Ctx -> Assertion+combinePubKeyTest ctx = do+  assertBool "did not fail to decode" $ isJust combined+  assertBool "is not empty" $ not $ maybe False BS.null combined   assertEqual "combined keys match" expected combined   where     combined = do       pub1 <--        importPubKey $+        importPubKey ctx $           hexToBytes             "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"       pub2 <--        importPubKey $+        importPubKey ctx $           hexToBytes             "0487d82042d93447008dfe2af762068a1e53ff394a5bf8f68a045fa642b99ea5d153f577dd2dba6c7ae4cfd7b6622409d7edd2d76dd13a8092cd3af97b77bd2c77"       pub3 <--        importPubKey $+        importPubKey ctx $           hexToBytes             "049b101edcbe1ee37ff6b2318526a425b629e823d7d8d9154417880595a28000ee3febd908754b8ce4e491aa6fe488b41fb5d4bb3788e33c9ff95a7a9229166d59"-      combinePubKeys [pub1, pub2, pub3]-    expected =-      importPubKey $-        hexToBytes-          "043d9a7ec70011efc23c33a7e62d2ea73cca87797e3b659d93bea6aa871aebde56c3bc6134ca82e324b0ab9c0e601a6d2933afe7fb5d9f3aae900f5c5dc6e362c8"+      key <- combinePubKeys ctx [pub1, pub2, pub3]+      return $ exportPubKey ctx True key+    expected = do+      key <-+        importPubKey ctx $+          hexToBytes+            "043d9a7ec70011efc23c33a7e62d2ea73cca87797e3b659d93bea6aa871aebde56c3bc6134ca82e324b0ab9c0e601a6d2933afe7fb5d9f3aae900f5c5dc6e362c8"+      return $ exportPubKey ctx True key -combinePubKeyEmptyListTest :: Assertion-combinePubKeyEmptyListTest =+combinePubKeyEmptyListTest :: Ctx -> Assertion+combinePubKeyEmptyListTest ctx =   assertEqual "empty pubkey list must return Nothing" expected combined   where     expected = Nothing-    combined = combinePubKeys []+    combined = do+      key <- combinePubKeys ctx []+      return $ exportPubKey ctx True key -negateTweakTest :: Assertion-negateTweakTest =+negateTweakTest :: Ctx -> Assertion+negateTweakTest ctx =   assertEqual "can recover secret key 1 after adding tweak 1" oneKey subtracted   where     Just oneKey =@@ -290,6 +307,6 @@       tweak . decodeBase16 . assertBase16 $         B8.pack           "0000000000000000000000000000000000000000000000000000000000000001"-    Just minusOneTwk = tweakNegate oneTwk-    Just twoKey = tweakAddSecKey oneKey oneTwk-    Just subtracted = tweakAddSecKey twoKey minusOneTwk+    Just minusOneTwk = tweakNegate ctx oneTwk+    Just twoKey = tweakAddSecKey ctx oneKey oneTwk+    Just subtracted = tweakAddSecKey ctx twoKey minusOneTwk