packages feed

libsecp256k1 0.1.0 → 0.1.1

raw patch · 10 files changed

+709/−647 lines, 10 filesdep +eitherdep +monad-pardep ~hedgehogPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: either, monad-par

Dependency ranges changed: hedgehog

API changes (from Hackage documentation)

+ Crypto.Secp256k1: ecdsaNormalizeSignature :: Signature -> Signature
+ Crypto.Secp256k1: tweakNegate :: Tweak -> Tweak
- Crypto.Secp256k1.Prim: type EcdhHashFun a = Ptr CUChar " __Output:__ pointer to an array to be filled by the function" -> Ptr CUChar " __Input:__ pointer to a 32-byte x coordinate" -> Ptr CUChar " __Input:__ pointer to a 32-byte y coordinate" -> Ptr a " __Input:__ arbitrary data pointer that is passed through" -> IO CInt " __Returns:__ 1 if the point was successfully hashed. 0 will cause 'ecdh' to fail and return 0. Other return values are not allowed, and the behaviour of 'ecdh' is undefined for other return values."
+ Crypto.Secp256k1.Prim: type EcdhHashFun a = -- | __Output:__ pointer to an array to be filled by the function Ptr CUChar -> -- | __Input:__ pointer to a 32-byte x coordinate Ptr CUChar -> -- | __Input:__ pointer to a 32-byte y coordinate Ptr CUChar -> -- | __Input:__ arbitrary data pointer that is passed through Ptr a -> -- | __Returns:__ 1 if the point was successfully hashed. -- 0 will cause 'ecdh' to fail and return 0. -- Other return values are not allowed, and the behaviour of -- 'ecdh' is undefined for other return values. IO CInt
- Crypto.Secp256k1.Prim: type NonceFun a = Ptr CUChar " __Output:__ pointer to a 32-byte array to be filled by the function." -> Ptr CUChar " __Input:__ the 32-byte message hash being verified (will not be NULL)" -> Ptr CUChar " __Input:__ pointer to a 32-byte secret key (will not be NULL)" -> Ptr CUChar " __Input:__ pointer to a 16-byte array describing the signature algorithm (will be NULL for ECDSA for compatibility)." -> Ptr a " __Input:__ Arbitrary data pointer that is passed through." -> CInt " __Input:__ how many iterations we have tried to find a nonce. This will almost always be 0, but different attempt values are required to result in a different nonce." -> IO CInt " __Returns:__ 1 if a nonce was successfully generated. 0 will cause signing to fail."
+ Crypto.Secp256k1.Prim: type NonceFun a = -- | __Output:__ pointer to a 32-byte array to be filled by the function. Ptr CUChar -> -- | __Input:__ the 32-byte message hash being verified (will not be NULL) Ptr CUChar -> -- | __Input:__ pointer to a 32-byte secret key (will not be NULL) Ptr CUChar -> -- | __Input:__ pointer to a 16-byte array describing the signature -- algorithm (will be NULL for ECDSA for compatibility). Ptr CUChar -> -- | __Input:__ Arbitrary data pointer that is passed through. Ptr a -> -- | __Input:__ how many iterations we have tried to find a nonce. -- This will almost always be 0, but different attempt values -- are required to result in a different nonce. CInt -> -- | __Returns:__ 1 if a nonce was successfully generated. 0 will cause signing to fail. IO CInt
- Crypto.Secp256k1.Prim: type NonceFunHardened a = Ptr CUChar " __Output:__ pointer to a 32-byte array to be filled by the function" -> Ptr CUChar " __Input:__ the message being verified. Is NULL if and only if msglen is 0." -> CSize " __Input:__ the length of the message" -> Ptr CUChar " __Input:__ pointer to a 32-byte secret key (will not be NULL)" -> Ptr CUChar " __Input:__ the 32-byte serialized xonly pubkey corresponding to key32 (will not be NULL)" -> Ptr CUChar " __Input:__ pointer to an array describing the signature algorithm (will not be NULL)" -> CSize " __Input:__ the length of the algo array" -> Ptr a " __Input:__ arbitrary data pointer that is passed through" -> IO CInt " __Returns:__ 1 if a nonce was successfully generated. 0 will cause signing to return an error."
+ Crypto.Secp256k1.Prim: type NonceFunHardened a = -- | __Output:__ pointer to a 32-byte array to be filled by the function Ptr CUChar -> -- | __Input:__ the message being verified. Is NULL if and only if msglen is 0. Ptr CUChar -> -- | __Input:__ the length of the message CSize -> -- | __Input:__ pointer to a 32-byte secret key (will not be NULL) Ptr CUChar -> -- | __Input:__ the 32-byte serialized xonly pubkey corresponding to key32 (will not be NULL) Ptr CUChar -> -- | __Input:__ pointer to an array describing the signature algorithm (will not be NULL) Ptr CUChar -> -- | __Input:__ the length of the algo array CSize -> -- | __Input:__ arbitrary data pointer that is passed through Ptr a -> -- | __Returns:__ 1 if a nonce was successfully generated. 0 will cause signing to return an error. IO CInt

Files

libsecp256k1.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.34.4.+-- This file has been generated from package.yaml by hpack version 0.36.0. -- -- see: https://github.com/sol/hpack  name:           libsecp256k1-version:        0.1.0+version:        0.1.1 synopsis:       Bindings for secp256k1 description:    Sign and verify signatures using the secp256k1 library. category:       Crypto@@ -35,13 +35,15 @@       Paths_libsecp256k1   hs-source-dirs:       src+  default-extensions:+      ImportQualifiedPost   pkgconfig-depends:       libsecp256k1   build-depends:       base >=4.9 && <5     , bytestring >=0.10.8 && <0.12     , entropy >=0.3.8 && <0.5-    , hedgehog+    , hedgehog ==1.2.*     , memory >=0.14.15 && <1.0     , transformers >=0.4.0.0 && <1.0   default-language: Haskell2010@@ -58,15 +60,19 @@       Paths_libsecp256k1   hs-source-dirs:       test+  default-extensions:+      ImportQualifiedPost   ghc-options: -threaded -rtsopts -with-rtsopts=-N   build-depends:       HUnit     , base >=4.9 && <5     , bytestring >=0.10.8 && <0.12+    , either     , entropy >=0.3.8 && <0.5-    , hedgehog+    , hedgehog ==1.2.*     , hspec     , libsecp256k1     , memory >=0.14.15 && <1.0+    , monad-par     , transformers >=0.4.0.0 && <1.0   default-language: Haskell2010
src/Crypto/Secp256k1.hs view
@@ -47,6 +47,7 @@     ecdsaSign,     ecdsaSignRecoverable,     ecdsaRecover,+    ecdsaNormalizeSignature,      -- * Conversions     recSigToSig,@@ -64,6 +65,7 @@     pubKeyCombine,     pubKeyNegate,     secKeyNegate,+    tweakNegate,     pubKeyTweakAdd,     pubKeyTweakMul,     pubKeyXOTweakAdd,@@ -83,25 +85,18 @@ import Control.Monad.Trans.Cont (ContT (..), evalContT) import Crypto.Secp256k1.Internal import Crypto.Secp256k1.Prim (flagsEcUncompressed)-import qualified Crypto.Secp256k1.Prim as Prim-import qualified Data.ByteArray.Encoding as BA+import Crypto.Secp256k1.Prim qualified as Prim+import Data.ByteArray.Encoding qualified as BA import Data.ByteArray.Sized import Data.ByteString (ByteString)-import qualified Data.ByteString as BS---- import qualified Data.ByteString.Base16 as B16+import Data.ByteString qualified as BS+import Data.ByteString.Char8 qualified as B8 import Data.ByteString.Unsafe (unsafePackCStringLen, unsafePackMallocCStringLen)+import Data.Foldable (for_) import Data.Functor (($>))---- import Data.Hashable (Hashable (..)) import Data.Maybe (fromJust, fromMaybe, isJust)-import Data.String (IsString (..))---- import Data.String.Conversions (ConvertibleStrings, cs)--import qualified Data.ByteString.Char8 as B8-import Data.Foldable (for_) import Data.Memory.PtrMethods (memCompare)+import Data.String (IsString (..)) import Foreign (     Bits (..),     ForeignPtr,@@ -362,12 +357,12 @@         outBuf <- mallocBytes 64         ret <-             if-                    -- compact-                    | len == 64 -> Prim.ecdsaSignatureParseCompact ctx outBuf inBuf-                    -- der-                    | len >= 69 && len <= 73 -> Prim.ecdsaSignatureParseDer ctx outBuf inBuf len-                    -- invalid-                    | otherwise -> pure 0+                -- compact+                | len == 64 -> Prim.ecdsaSignatureParseCompact ctx outBuf inBuf+                -- der+                | len >= 69 && len <= 73 -> Prim.ecdsaSignatureParseDer ctx outBuf inBuf len+                -- invalid+                | otherwise -> pure 0         if isSuccess ret             then Just . Signature <$> newForeignPtr finalizerFree outBuf             else free outBuf $> Nothing@@ -485,6 +480,17 @@                 else free pubKeyBuf $> Nothing  +-- | Convert a 'Signature' to a normalized lower-S form. If the 'Signature' was already in its lower-S form it will+-- be equal to the input.+ecdsaNormalizeSignature :: Signature -> Signature+ecdsaNormalizeSignature Signature{..} = unsafePerformIO . evalContT $ do+    sigPtr <- ContT (withForeignPtr signatureFPtr)+    lift $ do+        outBuf <- mallocBytes 64+        _ret <- Prim.ecdsaSignatureNormalize ctx outBuf sigPtr+        Signature <$> newForeignPtr finalizerFree outBuf++ -- | Forgets the recovery id of a signature recSigToSig :: RecoverableSignature -> Signature recSigToSig RecoverableSignature{..} = unsafePerformIO . evalContT $ do@@ -722,6 +728,16 @@     withForeignPtr secKeyFPtr $ flip (memcpy outBuf) 32     _ret <- Prim.ecSeckeyNegate ctx outBuf     SecKey <$> newForeignPtr finalizerFree outBuf+++-- | Negate a 'Tweak'+tweakNegate :: Tweak -> Tweak+tweakNegate Tweak{..} = unsafePerformIO $ do+    outBuf <- mallocBytes 32+    let asKey = castForeignPtr tweakFPtr+    withForeignPtr asKey $ flip (memcpy outBuf) 32+    _ret <- Prim.ecSeckeyNegate ctx outBuf+    Tweak <$> newForeignPtr finalizerFree (castPtr outBuf)   -- | Convert 'PubKeyXY' to 'PubKeyXO'. See 'keyPairPubKeyXO' for more information on how to interpret the parity bit.
src/Crypto/Secp256k1/Gen.hs view
@@ -1,30 +1,30 @@ module Crypto.Secp256k1.Gen where -import Crypto.Secp256k1 (KeyPair, PubKeyXO, PubKeyXY, SecKey, Tweak, derivePubKey, importSecKey, importTweak, keyPairCreate, xyToXO)+import Crypto.Secp256k1 import Hedgehog (MonadGen) import Hedgehog.Gen (bytes, discard, prune) import Hedgehog.Range (singleton)  -secKeyGen :: MonadGen m => m SecKey+secKeyGen :: (MonadGen m) => m SecKey secKeyGen = do-    bs <- prune $ bytes (singleton 32)-    maybe discard pure (importSecKey bs)+    bs <- prune . bytes $ singleton 32+    maybe discard pure $ importSecKey bs  -pubKeyXYGen :: MonadGen m => m PubKeyXY+pubKeyXYGen :: (MonadGen m) => m PubKeyXY pubKeyXYGen = derivePubKey <$> secKeyGen  -pubKeyXOGen :: MonadGen m => m PubKeyXO+pubKeyXOGen :: (MonadGen m) => m PubKeyXO pubKeyXOGen = fst . xyToXO <$> pubKeyXYGen  -keyPairGen :: MonadGen m => m KeyPair+keyPairGen :: (MonadGen m) => m KeyPair keyPairGen = keyPairCreate <$> secKeyGen  -tweakGen :: MonadGen m => m Tweak+tweakGen :: (MonadGen m) => m Tweak tweakGen = do     bs <- prune $ bytes (singleton 32)     maybe discard pure (importTweak bs)
src/Crypto/Secp256k1/Internal.hs view
@@ -1,10 +1,10 @@ module Crypto.Secp256k1.Internal where  import Crypto.Secp256k1.Prim-import qualified Data.ByteArray.Encoding as BA+import Data.ByteArray.Encoding qualified as BA import Data.ByteString (ByteString)-import qualified Data.ByteString as BS-import qualified Data.ByteString.Unsafe as BU+import Data.ByteString qualified as BS+import Data.ByteString.Unsafe qualified as BU import Foreign (Ptr, castPtr) import Foreign.C (CSize) 
src/Crypto/Secp256k1/Prim.hs view
@@ -17,8 +17,8 @@ module Crypto.Secp256k1.Prim where  import Data.ByteString (ByteString)-import qualified Data.ByteString as BS-import qualified Data.ByteString.Unsafe as BU+import Data.ByteString qualified as BS+import Data.ByteString.Unsafe qualified as BU import Foreign (Bits (..), FunPtr, Ptr, castPtr) import Foreign.C (     CInt (..),
test/Crypto/Secp256k1/PrimSpec.hs view
@@ -4,12 +4,16 @@  import Control.Monad +import Control.Monad.IO.Class+import Control.Monad.Trans.Cont import Crypto.Secp256k1.Internal-import qualified Data.ByteArray.Encoding as BA+import Crypto.Secp256k1.Prim+import Data.ByteArray.Encoding qualified as BA import Data.ByteString (     ByteString,     copy,     packCStringLen,+    useAsCString,     useAsCStringLen,  ) import Data.Either (fromRight)@@ -21,426 +25,461 @@  spec :: Spec spec = do-    pure ()+    describe "housekeeping" $ do+        it "creates context" createContextTest+        it "randomizes context" randomizeContextTest+        it "clones context" cloneContextTest+    describe "serialization" $ do+        it "parses public key" ecPubkeyParseTest+        it "serializes public key" ecPubKeySerializeTest+        it "parses DER signature" ecdsaSignatureParseDerTest+        it "serializes DER signature" ecdsaSignatureSerializeDerTest+    describe "signatures" $ do+        it "verifies signature" ecdsaVerifyTest+        it "signs message" ecdsaSignTest+    describe "secret keys" $ do+        it "verifies secret key" ecSecKeyVerifyTest+        it "creates public key" ecPubkeyCreateTest+        it "adds secret key" ecSecKeyTweakAddTest+        it "multiplies secret key" ecSecKeyTweakMulTest+    describe "public keys" $ do+        it "adds public key" ecPubKeyTweakAddTest+        it "multiplies public key" ecPubKeyTweakMulTest+        it "combines public keys" ecPubKeyCombineTest ---     describe "housekeeping" $ do---         it "creates context" createContextTest---         it "randomizes context" randomizeContextTest---         it "clones context" cloneContextTest---     describe "serialization" $ do---         it "parses public key" ecPubkeyParseTest---         it "serializes public key" ecPubKeySerializeTest---         it "parses DER signature" ecdsaSignatureParseDerTest---         it "serializes DER signature" ecdsaSignatureSerializeDerTest---     describe "signatures" $ do---         it "verifies signature" ecdsaVerifyTest---         it "signs message" ecdsaSignTest---     describe "secret keys" $ do---         it "verifies secret key" ecSecKeyVerifyTest---         it "creates public key" ecPubkeyCreateTest---         it "adds secret key" ecSecKeyTweakAddTest---         it "multiplies secret key" ecSecKeyTweakMulTest---     describe "public keys" $ do---         it "adds public key" ecPubKeyTweakAddTest---         it "multiplies public key" ecPubKeyTweakMulTest---         it "combines public keys" ecPubKeyCombineTest --- withEntropy :: (Ptr Seed32 -> IO a) -> IO a--- withEntropy f =---     getEntropy 32 >>= \e ->---         useByteString e $ \(s, _) -> f s+flagsSignVerify :: ContextFlags+flagsSignVerify = flagsContextSign .|. flagsContextVerify --- createContextTest :: Assertion--- createContextTest = do---     context_ptr <- liftIO $ contextCreate signVerify---     assertBool "context not null" $ context_ptr /= nullPtr --- randomizeContextTest :: Assertion--- randomizeContextTest = do---     ret <----         liftIO $---             contextCreate sign >>= \x ->---                 withEntropy (contextRandomize x)---     assertBool "context randomized" $ isSuccess ret+withEntropy :: (Ptr Seed32 -> IO a) -> IO a+withEntropy f =+    getEntropy 32 >>= \e ->+        useByteString e $ \(s, _) -> f s --- cloneContextTest :: Assertion--- cloneContextTest = do---     (x1, x2) <- liftIO $ do---         x1 <- contextCreate signVerify---         ret <- withEntropy $ contextRandomize x1---         unless (isSuccess ret) $ error "failed to randomize context"---         x2 <- contextClone x1---         return (x1, x2)---     assertBool "original context not null" $ x1 /= nullPtr---     assertBool "cloned context not null" $ x2 /= nullPtr---     assertBool "context ptrs different" $ x1 /= x2 --- ecPubkeyParseTest :: Assertion--- ecPubkeyParseTest = do---     ret <- liftIO $---         useAsCStringLen der $ \(i, il) -> do---             x <- contextCreate verify---             allocaBytes 64 $ \pubkey ->---                 ecPubKeyParse x pubkey (castPtr i) (fromIntegral il)---     assertBool "parsed public key" (isSuccess ret)---     where---         der =---             fromRight undefined $---                 decodeBase16---                     "03dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd44705"+createContextTest :: Assertion+createContextTest = do+    context_ptr <- liftIO $ contextCreate flagsSignVerify+    assertBool "context not null" $ context_ptr /= nullPtr --- ecPubKeySerializeTest :: Assertion--- ecPubKeySerializeTest = do---     (ret, dec) <- liftIO $---         useByteString der $ \(i, il) ->---             allocaBytes 64 $ \k ->---                 alloca $ \ol ->---                     allocaBytes 72 $ \o -> do---                         poke ol 72---                         x <- contextCreate verify---                         ret1 <- ecPubKeyParse x k i il---                         unless (isSuccess ret1) $ error "failed to parse pubkey"---                         ret2 <- ecPubKeySerialize x o ol k compressed---                         len <- fromIntegral <$> peek ol---                         decoded <- packCStringLen (castPtr o, len)---                         return (ret2, decoded)---     assertBool "serialized public key successfully" $ isSuccess ret---     assertEqual "public key matches" der dec---     where---         der =---             fromRight undefined $---                 decodeBase16---                     "03dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd44705" --- ecdsaSignatureParseDerTest :: Assertion--- ecdsaSignatureParseDerTest = do---     ret <- liftIO $---         useAsCStringLen der $ \(d, dl) -> allocaBytes 64 $ \s -> do---             x <- contextCreate verify---             ecdsaSignatureParseDer x s (castPtr d) (fromIntegral dl)---     assertBool "parsed signature successfully" $ isSuccess ret---     where---         der =---             fromRight undefined $---                 decodeBase16---                     "3045022100f502bfa07af43e7ef265618b0d929a7619ee01d6150e37eb6eaaf2c8bd37\---                     \fb2202206f0415ab0e9a977afd78b2c26ef39b3952096d319fd4b101c768ad6c132e30\---                     \45"+randomizeContextTest :: Assertion+randomizeContextTest = do+    ret <- liftIO $ contextCreate flagsContextSign >>= withEntropy . contextRandomize+    assertBool "context randomized" $ isSuccess ret --- parseDer :: Ctx -> ByteString -> IO ByteString--- parseDer x bs =---     useAsCStringLen bs $ \(d, dl) ->---         allocaBytes 64 $ \s -> do---             ret <- ecdsaSignatureParseDer x s (castPtr d) (fromIntegral dl)---             unless (isSuccess ret) $ error "could not parse DER"---             packByteString (s, 64) --- ecdsaSignatureSerializeDerTest :: Assertion--- ecdsaSignatureSerializeDerTest = do---     (ret, enc) <- liftIO $ do---         x <- contextCreate verify---         sig <- parseDer x der---         alloca $ \ol ->---             allocaBytes 72 $ \o ->---                 useByteString sig $ \(s, _) -> do---                     poke ol 72---                     ret <- ecdsaSignatureSerializeDer x o ol s---                     len <- fromIntegral <$> peek ol---                     enc <- packCStringLen (castPtr o, len)---                     return (ret, enc)---     assertBool "serialization successful" $ isSuccess ret---     assertEqual "signatures match" der enc---     where---         der =---             fromRight undefined $---                 decodeBase16---                     "3045022100f502bfa07af43e7ef265618b0d929a7619ee01d6150e37eb6eaaf2c8bd37\---                     \fb2202206f0415ab0e9a977afd78b2c26ef39b3952096d319fd4b101c768ad6c132e30\---                     \45"+cloneContextTest :: Assertion+cloneContextTest = do+    (x1, x2) <- liftIO $ do+        x1 <- contextCreate flagsSignVerify+        ret <- withEntropy $ contextRandomize x1+        unless (isSuccess ret) $ error "failed to randomize context"+        x2 <- contextClone x1+        return (x1, x2)+    assertBool "original context not null" $ x1 /= nullPtr+    assertBool "cloned context not null" $ x2 /= nullPtr+    assertBool "context ptrs different" $ x1 /= x2 --- ecdsaVerifyTest :: Assertion--- ecdsaVerifyTest = do---     ret <- liftIO $ do---         x <- contextCreate verify---         sig <- parseDer x der---         pk <- useByteString pub $ \(p, pl) ->---             allocaBytes 64 $ \k -> do---                 ret <- ecPubKeyParse x 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---     assertBool "signature valid" $ isSuccess ret---     where---         der =---             fromRight undefined $---                 decodeBase16---                     "3045022100f502bfa07af43e7ef265618b0d929a7619ee01d6150e37eb6eaaf2c8bd37\---                     \fb2202206f0415ab0e9a977afd78b2c26ef39b3952096d319fd4b101c768ad6c132e30\---                     \45"---         pub =---             fromRight undefined $---                 decodeBase16---                     "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\---                     \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"---         msg =---             fromRight undefined $---                 decodeBase16---                     "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00" --- signCtx :: IO Ctx--- signCtx =---     contextCreate sign >>= \c ->---         withEntropy (contextRandomize c) >>= \r ->---             unless (isSuccess r) (error "failed to randomize context") >> return c+ecPubkeyParseTest :: Assertion+ecPubkeyParseTest = evalContT $ do+    (i, il) <- ContT (useAsCStringLen der)+    pubkey <- ContT (allocaBytes 64)+    liftIO $ do+        x <- contextCreate flagsContextVerify+        ret <- ecPubkeyParse x pubkey (castPtr i) (fromIntegral il)+        assertBool "parsed public key" (isSuccess ret)+    where+        der =+            fromRight undefined $+                decodeBase16+                    "03dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd44705" --- createPubKey :: Ctx -> Ptr SecKey32 -> Ptr PubKey64 -> IO ()--- createPubKey x k p = do---     ret <- ecPubKeyCreate x p k---     unless (isSuccess ret) $ error "failed to create public key" --- ecdsaSignTest :: Assertion--- ecdsaSignTest = do---     der <- liftIO $ do---         x <- signCtx---         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---                             unless (isSuccess ret1) $ error "could not sign message"---                             ret2 <- ecdsaSignatureSerializeDer x 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 ->---             useByteString key $ \(s, _) -> do---                 x <- signCtx---                 createPubKey x s p---                 packByteString (p, 64)---         useByteString msg $ \(m, _) ->---             useByteString pub $ \(p, _) -> do---                 x <- contextCreate verify---                 s' <- parseDer x der---                 useByteString s' $ \(s, _) -> ecdsaVerify x s m p---     assertBool "signature matches" (isSuccess ret)---     where---         msg =---             fromRight undefined $---                 decodeBase16---                     "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"---         key =---             fromRight undefined $---                 decodeBase16---                     "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"+ecPubKeySerializeTest :: Assertion+ecPubKeySerializeTest = evalContT $ do+    (i, il) <- ContT (useByteString der)+    k <- ContT (allocaBytes 64)+    ol <- ContT alloca+    o <- ContT (allocaBytes 72)+    liftIO $ do+        poke ol 72+        x <- contextCreate flagsContextVerify+        ret1 <- ecPubkeyParse x k i il+        unless (isSuccess ret1) $ error "failed to parse pubkey"+        ret2 <- ecPubkeySerialize x o ol k flagsEcCompressed+        len <- fromIntegral <$> peek ol+        decoded <- packCStringLen (castPtr o, len) --- ecSecKeyVerifyTest :: Assertion--- ecSecKeyVerifyTest = do---     ret <- liftIO $---         useByteString key $ \(k, _) -> do---             x <- signCtx---             ecSecKeyVerify x k---     assertBool "valid secret key" $ isSuccess ret---     where---         key =---             fromRight undefined $---                 decodeBase16---                     "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"+        assertBool "serialized public key successfully" $ isSuccess ret2+        assertEqual "public key matches" der decoded+    where+        der =+            fromRight undefined $+                decodeBase16+                    "03dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd44705" --- ecPubkeyCreateTest :: Assertion--- ecPubkeyCreateTest = do---     pk <- liftIO $---         useByteString key $ \(s, _) ->---             allocaBytes 64 $ \k -> do---                 x <- signCtx---                 createPubKey x s k---                 allocaBytes 65 $ \o ->---                     alloca $ \ol -> do---                         poke ol 65---                         rets <- ecPubKeySerialize x o ol k uncompressed---                         unless (isSuccess rets) $ error "failed to serialize public key"---                         len <- fromIntegral <$> peek ol---                         packCStringLen (castPtr o, len)---     assertEqual "public key matches" pub pk---     where---         key =---             fromRight undefined $---                 decodeBase16---                     "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"---         pub =---             fromRight undefined $---                 decodeBase16---                     "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\---                     \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf" --- 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)---     assertBool "successful secret key tweak" $ isSuccess ret---     assertEqual "tweaked keys match" expected tweaked---     where---         key =---             fromRight undefined $---                 decodeBase16---                     "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"---         tweak =---             fromRight undefined $---                 decodeBase16---                     "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"---         expected =---             fromRight undefined $---                 decodeBase16---                     "ec1e3ce1cefa18a671d51125e2b249688d934b0e28f5d1665384d9b02f929059"+ecdsaSignatureParseDerTest :: Assertion+ecdsaSignatureParseDerTest = evalContT $ do+    (d, dl) <- ContT (useAsCStringLen der)+    s <- ContT (allocaBytes 64)+    liftIO $ do+        x <- contextCreate flagsContextVerify+        ret <- ecdsaSignatureParseDer x s (castPtr d) (fromIntegral dl)+        assertBool "parsed signature successfully" $ isSuccess ret+    where+        der =+            fromRight undefined $+                decodeBase16+                    "3045022100f502bfa07af43e7ef265618b0d929a7619ee01d6150e37eb6eaaf2c8bd37\+                    \fb2202206f0415ab0e9a977afd78b2c26ef39b3952096d319fd4b101c768ad6c132e30\+                    \45" --- ecSecKeyTweakMulTest :: Assertion--- ecSecKeyTweakMulTest = do---     (ret, tweaked) <- liftIO $ do---         x <- contextCreate sign---         retr <- withEntropy $ contextRandomize x---         unless (isSuccess retr) $ error "failed to randomize context"---         useByteString tweak $ \(w, _) -> useByteString key $ \(k, _) -> do---             ret <- ecSecKeyTweakMul x k w---             tweaked <- packByteString (k, 32)---             return (ret, tweaked)---     assertBool "successful secret key tweak" $ isSuccess ret---     assertEqual "tweaked keys match" expected tweaked---     where---         key =---             fromRight undefined $---                 decodeBase16---                     "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"---         tweak =---             fromRight undefined $---                 decodeBase16---                     "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"---         expected =---             fromRight undefined $---                 decodeBase16---                     "a96f5962493acb179f60a86a9785fc7a30e0c39b64c09d24fe064d9aef15e4c0" --- serializeKey :: Ctx -> Ptr PubKey64 -> IO ByteString--- serializeKey x p = allocaBytes 72 $ \d -> alloca $ \dl -> do---     poke dl 72---     ret <- ecPubKeySerialize x d dl p uncompressed---     unless (isSuccess ret) $ error "could not serialize public key"---     len <- peek dl---     packCStringLen (castPtr d, fromIntegral len)+parseDer :: Ctx -> ByteString -> IO ByteString+parseDer x bs = evalContT $ do+    (d, dl) <- ContT (useAsCStringLen bs)+    s <- ContT (allocaBytes 64)+    liftIO $ do+        ret <- ecdsaSignatureParseDer x s (castPtr d) (fromIntegral dl)+        unless (isSuccess ret) $ error "could not parse DER"+        packByteString (s, 64) --- parseKey :: Ctx -> ByteString -> IO ByteString--- parseKey x bs =---     allocaBytes 64 $ \p ->---         useByteString bs $ \(d, dl) -> do---             ret <- ecPubKeyParse x p d dl---             unless (isSuccess ret) $ error "could not parse public key"---             packByteString (p, 64) --- ecPubKeyTweakAddTest :: Assertion--- ecPubKeyTweakAddTest = do---     (ret, tweaked) <- liftIO $ do---         x <- contextCreate verify---         pk <- copy <$> parseKey x pub---         useByteString tweak $ \(w, _) ->---             useByteString pk $ \(p, _) -> do---                 ret <- ecPubKeyTweakAdd x p w---                 tweaked <- serializeKey x p---                 return (ret, tweaked)---     assertBool "successful secret key tweak" $ isSuccess ret---     assertEqual "tweaked keys match" expected tweaked---     where---         pub =---             fromRight undefined $---                 decodeBase16---                     "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\---                     \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"---         tweak =---             fromRight undefined $---                 decodeBase16---                     "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"---         expected =---             fromRight undefined $---                 decodeBase16---                     "04441c3982b97576646e0df0c96736063df6b42f2ee566d13b9f6424302d1379e518fd\---                     \c87a14c5435bff7a5db4552042cb4120c6b86a4bbd3d0643f3c14ad01368"+ecdsaSignatureSerializeDerTest :: Assertion+ecdsaSignatureSerializeDerTest = evalContT $ do+    ol <- ContT alloca+    o <- ContT (allocaBytes 72)+    x <- liftIO $ contextCreate flagsContextVerify+    sig <- liftIO $ parseDer x der+    (s, _) <- ContT (useByteString sig)+    liftIO $ do+        poke ol 72+        ret <- ecdsaSignatureSerializeDer x o ol s+        len <- fromIntegral <$> peek ol+        enc <- packCStringLen (castPtr o, len)+        assertBool "serialization successful" $ isSuccess ret+        assertEqual "signatures match" der enc+    where+        der =+            fromRight undefined $+                decodeBase16+                    "3045022100f502bfa07af43e7ef265618b0d929a7619ee01d6150e37eb6eaaf2c8bd37\+                    \fb2202206f0415ab0e9a977afd78b2c26ef39b3952096d319fd4b101c768ad6c132e30\+                    \45" --- ecPubKeyTweakMulTest :: Assertion--- ecPubKeyTweakMulTest = do---     (ret, tweaked) <- liftIO $ do---         x <- contextCreate verify---         pk <- copy <$> parseKey x pub---         useByteString tweak $ \(w, _) ->---             useByteString pk $ \(p, _) -> do---                 ret <- ecPubKeyTweakMul x p w---                 tweaked <- serializeKey x p---                 return (ret, tweaked)---     assertBool "successful secret key tweak" $ isSuccess ret---     assertEqual "tweaked keys match" expected tweaked---     where---         pub =---             fromRight undefined $---                 decodeBase16---                     "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\---                     \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"---         tweak =---             fromRight undefined $---                 decodeBase16---                     "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"---         expected =---             fromRight undefined $---                 decodeBase16---                     "04f379dc99cdf5c83e433defa267fbb3377d61d6b779c06a0e4ce29ae3ff5353b12ae4\---                     \9c9d07e7368f2ba5a446c203255ce912322991a2d6a9d5d5761c61ed1845" --- ecPubKeyCombineTest :: Assertion--- ecPubKeyCombineTest = do---     (ret, com) <- liftIO $---         allocaBytes 64 $ \p1 ->---             allocaBytes 64 $ \p2 ->---                 allocaBytes 64 $ \p3 ->---                     allocaArray 3 $ \a ->---                         allocaBytes 64 $ \p -> do---                             x <- contextCreate verify---                             parse x pub1 p1---                             parse x pub2 p2---                             parse x pub3 p3---                             pokeArray a [p1, p2, p3]---                             ret <- ecPubKeyCombine x p a 3---                             com <- serializeKey x p---                             return (ret, com)---     assertBool "successful key combination" $ isSuccess ret---     assertEqual "combined keys match" expected com---     where---         parse x pub p = useByteString pub $ \(d, dl) -> do---             ret <- ecPubKeyParse x p d dl---             unless (isSuccess ret) $ error "could not parse public key"---         pub1 =---             fromRight undefined $---                 decodeBase16---                     "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\---                     \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"---         pub2 =---             fromRight undefined $---                 decodeBase16---                     "0487d82042d93447008dfe2af762068a1e53ff394a5bf8f68a045fa642b99ea5d153f5\---                     \77dd2dba6c7ae4cfd7b6622409d7edd2d76dd13a8092cd3af97b77bd2c77"---         pub3 =---             fromRight undefined $---                 decodeBase16---                     "049b101edcbe1ee37ff6b2318526a425b629e823d7d8d9154417880595a28000ee3feb\---                     \d908754b8ce4e491aa6fe488b41fb5d4bb3788e33c9ff95a7a9229166d59"---         expected =---             fromRight undefined $---                 decodeBase16---                     "043d9a7ec70011efc23c33a7e62d2ea73cca87797e3b659d93bea6aa871aebde56c3bc\---                     \6134ca82e324b0ab9c0e601a6d2933afe7fb5d9f3aae900f5c5dc6e362c8"+ecdsaVerifyTest :: Assertion+ecdsaVerifyTest = evalContT $ do+    (p, pl) <- ContT (useByteString pub)+    (m, _) <- ContT (useByteString msg)+    k <- ContT (allocaBytes 64)+    (x, pk, sig) <- liftIO $ do+        x <- contextCreate flagsContextVerify+        ret <- ecPubkeyParse x k p (fromIntegral pl)+        sig <- parseDer x der+        unless (isSuccess ret) $ error "could not parse public key"+        pk <- packByteString (k, 64)+        pure (x, pk, sig)++    (k, _) <- ContT (useByteString pk)+    (s, _) <- ContT (useByteString sig)+    ret <- liftIO $ ecdsaVerify x s m k+    liftIO $ assertBool "signature valid" $ isSuccess ret+    where+        der =+            fromRight undefined $+                decodeBase16+                    "3045022100f502bfa07af43e7ef265618b0d929a7619ee01d6150e37eb6eaaf2c8bd37\+                    \fb2202206f0415ab0e9a977afd78b2c26ef39b3952096d319fd4b101c768ad6c132e30\+                    \45"+        pub =+            fromRight undefined $+                decodeBase16+                    "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\+                    \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"+        msg =+            fromRight undefined $+                decodeBase16+                    "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"+++signCtx :: IO Ctx+signCtx = do+    c <- contextCreate flagsContextSign+    r <- withEntropy (contextRandomize c)+    unless (isSuccess r) (error "failed to randomize context")+    pure c+++createPubKey :: Ctx -> Ptr Seckey32 -> Ptr Pubkey64 -> IO ()+createPubKey x k p = do+    ret <- ecPubkeyCreate x p k+    unless (isSuccess ret) $ error "failed to create public key"+++ecdsaSignTest :: Assertion+ecdsaSignTest = do+    x <- signCtx+    der <- evalContT $ do+        s <- ContT (allocaBytes 64)+        (m, _) <- ContT (useByteString msg)+        (k, _) <- ContT (useByteString key)+        ol <- ContT alloca+        o <- ContT (allocaBytes 72)+        liftIO $ do+            poke ol 72+            ret1 <- ecdsaSign x s m k nullFunPtr nullPtr+            unless (isSuccess ret1) $ error "could not sign message"+            ret2 <- ecdsaSignatureSerializeDer x o ol s+            unless (isSuccess ret2) $ error "could not serialize signature"+            len <- peek ol+            packCStringLen (castPtr o, fromIntegral len)+    ret <- evalContT $ do+        p <- ContT (allocaBytes 64)+        (s, _) <- ContT (useByteString key)+        (m, _) <- ContT (useByteString msg)+        pub <- liftIO $ do+            x <- signCtx+            createPubKey x s p+            packByteString (p, 64)+        (p, _) <- ContT (useByteString pub)+        x <- liftIO $ contextCreate flagsContextVerify+        s' <- liftIO $ parseDer x der+        (s, _) <- ContT (useByteString s')+        liftIO $ ecdsaVerify x s m p+    assertBool "signature matches" (isSuccess ret)+    where+        msg =+            fromRight undefined $+                decodeBase16+                    "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"+        key =+            fromRight undefined $+                decodeBase16+                    "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"+++ecSecKeyVerifyTest :: Assertion+ecSecKeyVerifyTest = evalContT $ do+    (k, _) <- ContT (useByteString key)+    liftIO $ do+        x <- signCtx+        ret <- ecSecKeyVerify x k+        assertBool "valid secret key" $ isSuccess ret+    where+        key =+            fromRight undefined $+                decodeBase16+                    "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"+++ecPubkeyCreateTest :: Assertion+ecPubkeyCreateTest = evalContT $ do+    (s, _) <- ContT (useByteString key)+    k <- ContT (allocaBytes 64)+    o <- ContT (allocaBytes 65)+    ol <- ContT alloca+    liftIO $ do+        x <- signCtx+        createPubKey x s k+        poke ol 65+        rets <- ecPubkeySerialize x o ol k flagsEcUncompressed+        unless (isSuccess rets) $ error "failed to serialize public key"+        len <- fromIntegral <$> peek ol+        pk <- packCStringLen (castPtr o, len)+        assertEqual "public key matches" pub pk+    where+        key =+            fromRight undefined $+                decodeBase16+                    "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"+        pub =+            fromRight undefined $+                decodeBase16+                    "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\+                    \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"+++ecSecKeyTweakAddTest :: Assertion+ecSecKeyTweakAddTest = evalContT $ do+    (w, _) <- ContT (useByteString tweak)+    (k, _) <- ContT (useByteString key)+    liftIO $ do+        x <- signCtx+        ret <- ecSeckeyTweakAdd x k w+        tweaked <- packByteString (k, 32)++        assertBool "successful secret key tweak" $ isSuccess ret+        assertEqual "tweaked keys match" expected tweaked+    where+        key =+            fromRight undefined $+                decodeBase16+                    "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"+        tweak =+            fromRight undefined $+                decodeBase16+                    "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"+        expected =+            fromRight undefined $+                decodeBase16+                    "ec1e3ce1cefa18a671d51125e2b249688d934b0e28f5d1665384d9b02f929059"+++ecSecKeyTweakMulTest :: Assertion+ecSecKeyTweakMulTest = evalContT $ do+    (w, _) <- ContT (useByteString tweak)+    (k, _) <- ContT (useByteString key)+    liftIO $ do+        x <- contextCreate flagsContextSign+        retr <- withEntropy $ contextRandomize x+        unless (isSuccess retr) $ error "failed to randomize context"+        ret <- ecSeckeyTweakMul x k w+        tweaked <- packByteString (k, 32)++        assertBool "successful secret key tweak" $ isSuccess ret+        assertEqual "tweaked keys match" expected tweaked+    where+        key =+            fromRight undefined $+                decodeBase16+                    "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"+        tweak =+            fromRight undefined $+                decodeBase16+                    "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"+        expected =+            fromRight undefined $+                decodeBase16+                    "a96f5962493acb179f60a86a9785fc7a30e0c39b64c09d24fe064d9aef15e4c0"+++serializeKey :: Ctx -> Ptr Pubkey64 -> IO ByteString+serializeKey x p = evalContT $ do+    d <- ContT (allocaBytes 72)+    dl <- ContT alloca+    liftIO $ do+        poke dl 72+        ret <- ecPubkeySerialize x d dl p flagsEcUncompressed+        unless (isSuccess ret) $ error "could not serialize public key"+        len <- peek dl+        packCStringLen (castPtr d, fromIntegral len)+++parseKey :: Ctx -> ByteString -> IO ByteString+parseKey x bs = evalContT $ do+    p <- ContT (allocaBytes 64)+    (d, dl) <- ContT (useByteString bs)+    liftIO $ do+        ret <- ecPubkeyParse x p d dl+        unless (isSuccess ret) $ error "could not parse public key"+        packByteString (p, 64)+++ecPubKeyTweakAddTest :: Assertion+ecPubKeyTweakAddTest = do+    x <- contextCreate flagsContextVerify+    pk <- copy <$> parseKey x pub+    (w, p) <- evalContT $ do+        (w, _) <- ContT (useByteString tweak)+        (p, _) <- ContT (useByteString pk)+        pure (w, p)++    ret <- ecPubkeyTweakAdd x p w+    tweaked <- serializeKey x p++    assertBool "successful secret key tweak" $ isSuccess ret+    assertEqual "tweaked keys match" expected tweaked+    where+        pub =+            fromRight undefined $+                decodeBase16+                    "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\+                    \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"+        tweak =+            fromRight undefined $+                decodeBase16+                    "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"+        expected =+            fromRight undefined $+                decodeBase16+                    "04441c3982b97576646e0df0c96736063df6b42f2ee566d13b9f6424302d1379e518fd\+                    \c87a14c5435bff7a5db4552042cb4120c6b86a4bbd3d0643f3c14ad01368"+++ecPubKeyTweakMulTest :: Assertion+ecPubKeyTweakMulTest = do+    x <- contextCreate flagsContextVerify+    pk <- copy <$> parseKey x pub+    (w, p) <- evalContT $ do+        (w, _) <- ContT (useByteString tweak)+        (p, _) <- ContT (useByteString pk)+        pure (w, p)+    ret <- ecPubkeyTweakMul x p w+    tweaked <- serializeKey x p+    assertBool "successful secret key tweak" $ isSuccess ret+    assertEqual "tweaked keys match" expected tweaked+    where+        pub =+            fromRight undefined $+                decodeBase16+                    "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\+                    \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"+        tweak =+            fromRight undefined $+                decodeBase16+                    "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"+        expected =+            fromRight undefined $+                decodeBase16+                    "04f379dc99cdf5c83e433defa267fbb3377d61d6b779c06a0e4ce29ae3ff5353b12ae4\+                    \9c9d07e7368f2ba5a446c203255ce912322991a2d6a9d5d5761c61ed1845"+++ecPubKeyCombineTest :: Assertion+ecPubKeyCombineTest = evalContT $ do+    p1 <- ContT (allocaBytes 64)+    p2 <- ContT (allocaBytes 64)+    p3 <- ContT (allocaBytes 64)+    a <- ContT (allocaArray 3)+    p <- ContT (allocaBytes 64)++    liftIO $ do+        x <- contextCreate flagsContextVerify+        parse x pub1 p1+        parse x pub2 p2+        parse x pub3 p3+        pokeArray a [p1, p2, p3]+        ret <- ecPubkeyCombine x p a 3+        com <- serializeKey x p++        assertBool "successful key combination" $ isSuccess ret+        assertEqual "combined keys match" expected com+    where+        parse x pub p = useByteString pub $ \(d, dl) -> do+            ret <- ecPubkeyParse x p d dl+            unless (isSuccess ret) $ error "could not parse public key"+        pub1 =+            fromRight undefined $+                decodeBase16+                    "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\+                    \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"+        pub2 =+            fromRight undefined $+                decodeBase16+                    "0487d82042d93447008dfe2af762068a1e53ff394a5bf8f68a045fa642b99ea5d153f5\+                    \77dd2dba6c7ae4cfd7b6622409d7edd2d76dd13a8092cd3af97b77bd2c77"+        pub3 =+            fromRight undefined $+                decodeBase16+                    "049b101edcbe1ee37ff6b2318526a425b629e823d7d8d9154417880595a28000ee3feb\+                    \d908754b8ce4e491aa6fe488b41fb5d4bb3788e33c9ff95a7a9229166d59"+        expected =+            fromRight undefined $+                decodeBase16+                    "043d9a7ec70011efc23c33a7e62d2ea73cca87797e3b659d93bea6aa871aebde56c3bc\+                    \6134ca82e324b0ab9c0e601a6d2933afe7fb5d9f3aae900f5c5dc6e362c8"
test/Crypto/Secp256k1Prop.hs view
@@ -7,7 +7,7 @@ import Crypto.Secp256k1 import Crypto.Secp256k1.Gen import Data.ByteArray.Sized (sizedByteArray)-import qualified Data.ByteString as BS+import Data.ByteString qualified as BS import Data.Maybe (fromJust, isJust) import Data.Void import Hedgehog@@ -64,7 +64,7 @@   prop_pubKeyXOSerializeInvertsParse :: Property-prop_pubKeyXOSerializeInvertsParse = property $ do+prop_pubKeyXOSerializeInvertsParse = withDiscards 200 . property $ do     bs <- forAll (bytes $ singleton 32)     case importPubKeyXO bs of         Nothing -> discard@@ -75,12 +75,12 @@ prop_signatureParseInvertsSerialize = property $ do     sk <- forAll secKeyGen     bs <- forAll $ bytes (singleton 32)-    sig <- case ecdsaSign sk bs of-        Nothing -> failure-        Just x -> pure x++    sig <- maybe failure pure (ecdsaSign sk bs)+     exportDer <- forAll $ element [False, True]     let export = if exportDer then exportSignatureDer else exportSignatureCompact-    let serialized = (export sig)+    let serialized = export sig     annotateShow serialized     annotateShow (BS.length serialized)     case importSignature serialized of@@ -92,10 +92,10 @@ prop_recoverableSignatureParseInvertsSerialize = property $ do     sk <- forAll secKeyGen     bs <- forAll $ bytes (singleton 32)-    sig <- case ecdsaSignRecoverable sk bs of-        Nothing -> failure-        Just x -> pure x-    let serialized = (exportRecoverableSignature sig)++    sig <- maybe failure pure (ecdsaSignRecoverable sk bs)++    let serialized = exportRecoverableSignature sig     annotateShow serialized     annotateShow (BS.length serialized)     case importRecoverableSignature serialized of@@ -249,4 +249,4 @@   tests :: Group-tests = $$(discover)+tests = $$discover
test/Crypto/Secp256k1Spec.hs view
@@ -1,12 +1,12 @@ module Crypto.Secp256k1Spec (spec) where --- import Control.Monad.Par--- import qualified Control.Monad.Par as P+import Control.Monad.Par qualified as P import Crypto.Secp256k1-import qualified Data.ByteString as BS-import qualified Data.ByteString.Char8 as B8+import Crypto.Secp256k1.Internal+import Data.ByteString qualified as BS+import Data.ByteString.Char8 qualified as B8 import Data.Either (fromRight)-import Data.Maybe (fromMaybe, isNothing)+import Data.Maybe (fromMaybe, isJust, isNothing) import Data.String (fromString) import Test.HUnit (Assertion, assertEqual) import Test.Hspec@@ -14,215 +14,214 @@  spec :: Spec spec = do-    pure ()+    describe "tweaks" $ do+        it "add secret key" tweakAddSecKeyTest+        it "multiply secret key" tweakMulSecKeyTest+        it "add public key" tweakAddPubKeyTest+        it "multiply public key" tweakMulPubKeyTest+        it "combine public keys" combinePubKeyTest+        it "can't combine 0 public keys" combinePubKeyEmptyListTest+        it "negates tweak" negateTweakTest ---     describe "tweaks" $ do---         it "add secret key" tweakAddSecKeyTest---         it "multiply secret key" tweakMulSecKeyTest---         it "add public key" tweakAddPubKeyTest---         it "multiply public key" tweakMulPubKeyTest---         it "combine public keys" combinePubKeyTest---         it "can't combine 0 public keys" combinePubKeyEmptyListTest---         it "negates tweak" negateTweakTest --- hexToBytes :: String -> BS.ByteString--- hexToBytes = fromRight undefined . decodeBase16 . B8.pack+hexToBytes :: String -> BS.ByteString+hexToBytes = fromRight undefined . decodeBase16 . B8.pack --- showReadTweak :: SecKey -> Bool--- showReadTweak k = showRead t---     where---         t = tweak $ getSecKey k --- showReadSig :: (SecKey, Msg) -> Bool--- showReadSig (k, m) = showRead sig---     where---         sig = signMsg k m+signMsgTest :: (BS.ByteString, SecKey) -> Bool+signMsgTest (fm, fk) = (ecdsaVerify fm fp <$> fg) == Just True+    where+        fp = derivePubKey fk+        fg = ecdsaSign fk fm --- 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---     where---         fp = derivePubKey fk---         fg = signMsg fk fm+signMsgParTest :: [(BS.ByteString, SecKey)] -> Bool+signMsgParTest xs = P.runPar $ do+    ys <- mapM (P.spawnP . signMsgTest) xs+    and <$> mapM P.get ys --- signMsgParTest :: [(Msg, SecKey)] -> Bool--- signMsgParTest xs = P.runPar $ do---     ys <- mapM (P.spawnP . signMsgTest) xs---     and <$> mapM P.get ys --- badSignatureTest :: (Msg, SecKey, PubKey) -> Bool--- badSignatureTest (fm, fk, fp) = not $ verifySig fp fg fm---     where---         fg = signMsg fk fm+badSignatureTest :: (BS.ByteString, SecKey, PubKeyXY) -> Bool+badSignatureTest (fm, fk, fp) = (ecdsaVerify fm fp <$> fg) == Just False+    where+        fg = ecdsaSign fk fm --- normalizeSigTest :: (Msg, SecKey) -> Bool--- normalizeSigTest (fm, fk) = isNothing sig---     where---         fg = signMsg fk fm---         sig = normalizeSig fg --- serializePubKeyTest :: (PubKey, Bool) -> Bool--- serializePubKeyTest (fp, b) =---     case importPubKey $ exportPubKey b fp of---         Just fp' -> fp == fp'---         Nothing -> False+normalizeSigTest :: (BS.ByteString, SecKey) -> Bool+normalizeSigTest (fm, fk) = sig == fg+    where+        fg = ecdsaSign fk fm+        sig = ecdsaNormalizeSignature <$> fg --- parSerializePubKeyTest :: [(PubKey, Bool)] -> Bool--- parSerializePubKeyTest ps = runPar $ do---     as <- mapM (spawnP . serializePubKeyTest) ps---     and <$> mapM get as --- serializeSigTest :: (Msg, SecKey) -> Bool--- serializeSigTest (fm, fk) =---     case importSig $ exportSig fg of---         Just fg' -> fg == fg'---         Nothing -> False---     where---         fg = signMsg fk fm+serializePubKeyTest :: (PubKeyXY, Bool) -> Bool+serializePubKeyTest (fp, b) =+    case importPubKeyXY $ exportPubKeyXY b fp of+        Just fp' -> fp == fp'+        Nothing -> False --- parSerializeSigTest :: [(Msg, SecKey)] -> Bool--- parSerializeSigTest ms = runPar $ do---     as <- mapM (spawnP . serializeSigTest) ms---     and <$> mapM get as --- serializeCompactSigTest :: (Msg, SecKey) -> Bool--- serializeCompactSigTest (fm, fk) =---     case importCompactSig $ exportCompactSig fg of---         Just fg' -> fg == fg'---         Nothing -> False---     where---         fg = signMsg fk fm+parSerializePubKeyTest :: [(PubKeyXY, Bool)] -> Bool+parSerializePubKeyTest ps = P.runPar $ do+    as <- mapM (P.spawnP . serializePubKeyTest) ps+    and <$> mapM P.get as --- serializeSecKeyTest :: SecKey -> Bool--- serializeSecKeyTest fk =---     case secKey $ getSecKey fk of---         Just fk' -> fk == fk'---         Nothing -> False --- tweakAddSecKeyTest :: Assertion--- tweakAddSecKeyTest =---     assertEqual "tweaked keys match" expected tweaked---     where---         tweaked = do---             key <----                 secKey $---                     hexToBytes---                         "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"---             twk <----                 tweak $---                     hexToBytes---                         "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"---             tweakAddSecKey key twk---         expected =---             secKey $---                 hexToBytes---                     "ec1e3ce1cefa18a671d51125e2b249688d934b0e28f5d1665384d9b02f929059"+serializeSigTest :: (BS.ByteString, SecKey) -> Bool+serializeSigTest (fm, fk) =+    (fg >>= importSignature . exportSignatureDer) == fg && isJust fg+    where+        fg = ecdsaSign fk fm --- tweakMulSecKeyTest :: Assertion--- tweakMulSecKeyTest =---     assertEqual "tweaked keys match" expected tweaked---     where---         tweaked = do---             key <----                 secKey $---                     hexToBytes---                         "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"---             twk <----                 tweak $---                     hexToBytes---                         "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"---             tweakMulSecKey key twk---         expected =---             secKey $---                 hexToBytes---                     "a96f5962493acb179f60a86a9785fc7a30e0c39b64c09d24fe064d9aef15e4c0" --- tweakAddPubKeyTest :: Assertion--- tweakAddPubKeyTest =---     assertEqual "tweaked keys match" expected tweaked---     where---         tweaked = do---             pub <----                 importPubKey $---                     hexToBytes---                         "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"---             twk <----                 tweak $---                     hexToBytes---                         "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"---             tweakAddPubKey pub twk---         expected =---             importPubKey $---                 hexToBytes---                     "04441c3982b97576646e0df0c96736063df6b42f2ee566d13b9f6424302d1379e518fdc87a14c5435bff7a5db4552042cb4120c6b86a4bbd3d0643f3c14ad01368"+parSerializeSigTest :: [(BS.ByteString, SecKey)] -> Bool+parSerializeSigTest ms = P.runPar $ do+    as <- mapM (P.spawnP . serializeSigTest) ms+    and <$> mapM P.get as --- tweakMulPubKeyTest :: Assertion--- tweakMulPubKeyTest =---     assertEqual "tweaked keys match" expected tweaked---     where---         tweaked = do---             pub <----                 importPubKey $---                     hexToBytes---                         "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"---             twk <----                 tweak $---                     hexToBytes---                         "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"---             tweakMulPubKey pub twk---         expected =---             importPubKey $---                 hexToBytes---                     "04f379dc99cdf5c83e433defa267fbb3377d61d6b779c06a0e4ce29ae3ff5353b12ae49c9d07e7368f2ba5a446c203255ce912322991a2d6a9d5d5761c61ed1845" --- combinePubKeyTest :: Assertion--- combinePubKeyTest =---     assertEqual "combined keys match" expected combined---     where---         combined = do---             pub1 <----                 importPubKey $---                     hexToBytes---                         "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"---             pub2 <----                 importPubKey $---                     hexToBytes---                         "0487d82042d93447008dfe2af762068a1e53ff394a5bf8f68a045fa642b99ea5d153f577dd2dba6c7ae4cfd7b6622409d7edd2d76dd13a8092cd3af97b77bd2c77"---             pub3 <----                 importPubKey $---                     hexToBytes---                         "049b101edcbe1ee37ff6b2318526a425b629e823d7d8d9154417880595a28000ee3febd908754b8ce4e491aa6fe488b41fb5d4bb3788e33c9ff95a7a9229166d59"---             combinePubKeys [pub1, pub2, pub3]---         expected =---             importPubKey $---                 hexToBytes---                     "043d9a7ec70011efc23c33a7e62d2ea73cca87797e3b659d93bea6aa871aebde56c3bc6134ca82e324b0ab9c0e601a6d2933afe7fb5d9f3aae900f5c5dc6e362c8"+serializeCompactSigTest :: (BS.ByteString, SecKey) -> Bool+serializeCompactSigTest (fm, fk) =+    (fg >>= importSignature . exportSignatureCompact) == fg && isJust fg+    where+        fg = ecdsaSign fk fm --- combinePubKeyEmptyListTest :: Assertion--- combinePubKeyEmptyListTest =---     assertEqual "empty pubkey list must return Nothing" expected combined---     where---         expected = Nothing---         combined = combinePubKeys [] --- negateTweakTest :: Assertion--- negateTweakTest =---     assertEqual "can recover secret key 1 after adding tweak 1" oneKey subtracted---     where---         Just oneKey =---             secKey $---                 fromRight undefined $---                     decodeBase16 $---                         B8.pack---                             "0000000000000000000000000000000000000000000000000000000000000001"---         Just oneTwk =---             tweak $---                 fromRight undefined $---                     decodeBase16 $---                         B8.pack---                             "0000000000000000000000000000000000000000000000000000000000000001"---         Just minusOneTwk = tweakNegate oneTwk---         Just twoKey = tweakAddSecKey oneKey oneTwk---         Just subtracted = tweakAddSecKey twoKey minusOneTwk+serializeSecKeyTest :: SecKey -> Bool+serializeSecKeyTest fk =+    case importSecKey $ exportSecKey fk of+        Just fk' -> fk == fk'+        Nothing -> False+++tweakAddSecKeyTest :: Assertion+tweakAddSecKeyTest =+    assertEqual "tweaked keys match" expected tweaked+    where+        tweaked = do+            key <-+                importSecKey $+                    hexToBytes+                        "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"+            twk <-+                importTweak $+                    hexToBytes+                        "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"+            secKeyTweakAdd key twk+        expected =+            importSecKey $+                hexToBytes+                    "ec1e3ce1cefa18a671d51125e2b249688d934b0e28f5d1665384d9b02f929059"+++tweakMulSecKeyTest :: Assertion+tweakMulSecKeyTest =+    assertEqual "tweaked keys match" expected tweaked+    where+        tweaked = do+            key <-+                importSecKey $+                    hexToBytes+                        "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"+            twk <-+                importTweak $+                    hexToBytes+                        "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"+            secKeyTweakMul key twk+        expected =+            importSecKey $+                hexToBytes+                    "a96f5962493acb179f60a86a9785fc7a30e0c39b64c09d24fe064d9aef15e4c0"+++tweakAddPubKeyTest :: Assertion+tweakAddPubKeyTest =+    assertEqual "tweaked keys match" expected tweaked+    where+        tweaked = do+            pub <-+                importPubKeyXY $+                    hexToBytes+                        "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"+            twk <-+                importTweak $+                    hexToBytes+                        "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"+            pubKeyTweakAdd pub twk+        expected =+            importPubKeyXY $+                hexToBytes+                    "04441c3982b97576646e0df0c96736063df6b42f2ee566d13b9f6424302d1379e518fdc87a14c5435bff7a5db4552042cb4120c6b86a4bbd3d0643f3c14ad01368"+++tweakMulPubKeyTest :: Assertion+tweakMulPubKeyTest =+    assertEqual "tweaked keys match" expected tweaked+    where+        tweaked = do+            pub <-+                importPubKeyXY $+                    hexToBytes+                        "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"+            twk <-+                importTweak $+                    hexToBytes+                        "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"+            pubKeyTweakMul pub twk+        expected =+            importPubKeyXY $+                hexToBytes+                    "04f379dc99cdf5c83e433defa267fbb3377d61d6b779c06a0e4ce29ae3ff5353b12ae49c9d07e7368f2ba5a446c203255ce912322991a2d6a9d5d5761c61ed1845"+++combinePubKeyTest :: Assertion+combinePubKeyTest =+    assertEqual "combined keys match" expected combined+    where+        combined = do+            pub1 <-+                importPubKeyXY $+                    hexToBytes+                        "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"+            pub2 <-+                importPubKeyXY $+                    hexToBytes+                        "0487d82042d93447008dfe2af762068a1e53ff394a5bf8f68a045fa642b99ea5d153f577dd2dba6c7ae4cfd7b6622409d7edd2d76dd13a8092cd3af97b77bd2c77"+            pub3 <-+                importPubKeyXY $+                    hexToBytes+                        "049b101edcbe1ee37ff6b2318526a425b629e823d7d8d9154417880595a28000ee3febd908754b8ce4e491aa6fe488b41fb5d4bb3788e33c9ff95a7a9229166d59"+            pubKeyCombine [pub1, pub2, pub3]+        expected =+            importPubKeyXY $+                hexToBytes+                    "043d9a7ec70011efc23c33a7e62d2ea73cca87797e3b659d93bea6aa871aebde56c3bc6134ca82e324b0ab9c0e601a6d2933afe7fb5d9f3aae900f5c5dc6e362c8"+++combinePubKeyEmptyListTest :: Assertion+combinePubKeyEmptyListTest =+    assertEqual "empty pubkey list must return Nothing" expected combined+    where+        expected = Nothing+        combined = pubKeyCombine []+++negateTweakTest :: Assertion+negateTweakTest =+    assertEqual "can recover secret key 1 after adding tweak 1" oneKey subtracted+    where+        Just oneKey =+            importSecKey $+                fromRight undefined $+                    decodeBase16 $+                        B8.pack+                            "0000000000000000000000000000000000000000000000000000000000000001"+        Just oneTwk =+            importTweak $+                fromRight undefined $+                    decodeBase16 $+                        B8.pack+                            "0000000000000000000000000000000000000000000000000000000000000001"+        minusOneTwk = tweakNegate oneTwk+        Just twoKey = secKeyTweakAdd oneKey oneTwk+        Just subtracted = secKeyTweakAdd twoKey minusOneTwk
test/Main.hs view
@@ -1,10 +1,10 @@ module Main where -import qualified Crypto.Secp256k1Prop as Secp256k1Prop+import Crypto.Secp256k1Prop qualified as Secp256k1Prop import GHC.IO.Encoding (setLocaleEncoding, utf8) import Hedgehog (checkSequential) import Hedgehog.Main-import qualified Spec+import Spec qualified import Test.Hspec.Formatters import Test.Hspec.Runner (Config (..), defaultConfig, hspecWith) @@ -13,6 +13,6 @@ main = do     setLocaleEncoding utf8     hspecWith defaultConfig{configFormatter = Just progress} Spec.spec-    defaultMain $+    defaultMain         [ checkSequential Secp256k1Prop.tests         ]
test/Spec.hs view
@@ -1,9 +1,11 @@ module Spec where -import qualified Crypto.Secp256k1Spec as Secp256k1+import Crypto.Secp256k1.PrimSpec qualified as Prim+import Crypto.Secp256k1Spec qualified as Secp256k1 import Test.Hspec   spec :: Spec spec = do+    Prim.spec     Secp256k1.spec