packages feed

secp256k1-haskell 0.2.5 → 0.3.0

raw patch · 6 files changed

+24/−740 lines, 6 files

Files

CHANGELOG.md view
@@ -4,10 +4,25 @@ 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.3.0+### 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 ### Changed - Reuse context aggressively. - Generate context in a single thread.++### Fixed+- Memory deallocation bug.  ## 0.2.4 ### Changed
README.md view
@@ -1,3 +1,5 @@+[![Build Status](https://travis-ci.org/haskoin/secp256k1-haskell.svg?branch=master)](https://travis-ci.org/haskoin/secp256k1-haskell)+ # Haskell bindings for secp256k1  This project contains Haskell bindings for the
secp256k1-haskell.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: f64a6c7d68d58fab5fc141dd7bda78089fe9403dc39525641eba1ca0fd92593c+-- hash: d55c31829652e236145323f89ee1ec9c61e4f18712778a13011c688d36db8b19  name:           secp256k1-haskell-version:        0.2.5+version:        0.3.0 synopsis:       Bindings for secp256k1 description:    Sign and verify signatures using the secp256k1 library. category:       Crypto@@ -27,26 +27,6 @@   type: git   location: https://github.com/haskoin/secp256k1-haskell.git -flag ecdh-  description: Enable (experimental) ECDH APIs-  manual: True-  default: False--flag negate-  description: Enable tweak negate-  manual: True-  default: False--flag recovery-  description: Enable signature key recovery APIs-  manual: True-  default: False--flag schnorr-  description: Enable BIP-340 (Schnorr) APIs-  manual: True-  default: False- library   exposed-modules:       Crypto.Secp256k1@@ -68,14 +48,6 @@     , entropy     , hashable     , string-conversions-  if flag(ecdh)-    cpp-options: -DECDH-  if flag(schnorr)-    cpp-options: -DSCHNORR-  if flag(recovery)-    cpp-options: -DRECOVERY-  if flag(negate)-    cpp-options: -DNEGATE   default-language: Haskell2010  test-suite spec@@ -103,13 +75,5 @@     , mtl     , secp256k1-haskell     , string-conversions-  if flag(ecdh)-    cpp-options: -DECDH-  if flag(schnorr)-    cpp-options: -DSCHNORR-  if flag(recovery)-    cpp-options: -DRECOVERY-  if flag(negate)-    cpp-options: -DNEGATE   default-language: Haskell2010   build-tool-depends: hspec-discover:hspec-discover
src/Crypto/Secp256k1.hs view
@@ -39,16 +39,6 @@     , CompactSig(..)     , exportCompactSig     , importCompactSig-#ifdef RECOVERY-    -- ** Recovery-    , RecSig-    , CompactRecSig(..)-    , importCompactRecSig-    , exportCompactRecSig-    , convertRecSig-    , signRecMsg-    , recover-#endif      -- * Addition & Multiplication     , Tweak@@ -59,29 +49,7 @@     , tweakAddPubKey     , tweakMulPubKey     , combinePubKeys-#ifdef NEGATE     , tweakNegate-#endif--#ifdef ECDH-    -- * Diffie Hellman-    , ecdh-#endif--#ifdef SCHNORR-    , XOnlyPubKey-    , SchnorrSig-    , signMsgSchnorr-    , exportSchnorrSig-    , importSchnorrSig-    , exportXOnlyPubKey-    , importXOnlyPubKey-    , verifyMsgSchnorr-    , deriveXOnlyPubKey-    , schnorrTweakAddPubKey-    , schnorrTweakAddSecKey-    , testTweakXOnlyPubKey-#endif     ) where  import           Control.Monad             (replicateM, unless, (<=<))@@ -93,9 +61,8 @@ import           Data.Maybe                (fromJust, fromMaybe, isJust) import           Data.String               (IsString (..)) import           Data.String.Conversions   (ConvertibleStrings, cs)-import           Foreign                   (ForeignPtr, alloca,-                                            allocaArray, allocaBytes,-                                            mallocForeignPtr,+import           Foreign                   (ForeignPtr, alloca, allocaArray,+                                            allocaBytes, mallocForeignPtr,                                             nullPtr, peek, poke, pokeArray,                                             withForeignPtr) import           System.IO.Unsafe          (unsafePerformIO)@@ -113,10 +80,6 @@ newtype SecKey = SecKey (ForeignPtr SecKey32) newtype Tweak = Tweak (ForeignPtr Tweak32) newtype RecSig = RecSig (ForeignPtr RecSig65)-#ifdef SCHNORR-newtype XOnlyPubKey = XOnlyPubKey (ForeignPtr XOnlyPubKey64)-newtype SchnorrSig = SchnorrSig (ForeignPtr SchnorrSig64)-#endif  instance NFData PubKey where     rnf (PubKey p) = p `seq` ()@@ -185,30 +148,6 @@ instance Show Sig where     showsPrec _ = shows . B16.encode . exportSig -#ifdef RECOVERY-recSigFromString :: String -> Maybe RecSig-recSigFromString str = do-    bs <- decodeHex str-    rs <- either (const Nothing) Just $ decode bs-    importCompactRecSig rs--instance Hashable RecSig where-    i `hashWithSalt` s = i `hashWithSalt` encode (exportCompactRecSig s)--instance Read RecSig where-    readPrec = parens $ do-        String str <- lexP-        maybe pfail return $ recSigFromString str--instance IsString RecSig where-    fromString = fromMaybe e . recSigFromString-      where-        e = error "Could not decode signature from hex string"--instance Show RecSig where-    showsPrec _ = shows . B16.encode . encode . exportCompactRecSig-#endif- instance Read SecKey where     readPrec = parens $ do         String str <- lexP@@ -248,61 +187,12 @@ instance Eq Sig where     fg1 == fg2 = exportCompactSig fg1 == exportCompactSig fg2 -#ifdef RECOVERY-instance Eq RecSig where-    fg1 == fg2 = exportCompactRecSig fg1 == exportCompactRecSig fg2-#endif- instance Eq SecKey where     fk1 == fk2 = getSecKey fk1 == getSecKey fk2  instance Eq Tweak where     ft1 == ft2 = getTweak ft1 == getTweak ft2 -#ifdef SCHNORR-instance NFData SchnorrSig where-    rnf (SchnorrSig p) = p `seq` ()--instance Show SchnorrSig where-    showsPrec _ = shows . B16.encode . exportSchnorrSig--instance Read SchnorrSig where-    readPrec = parens $ do-        String str <- lexP-        maybe pfail return $ importSchnorrSig =<< decodeHex str--instance Eq SchnorrSig where-    fg1 == fg2 = exportSchnorrSig fg1 == exportSchnorrSig fg2--instance IsString SchnorrSig where-    fromString = fromMaybe e . (importSchnorrSig <=< decodeHex) where-        e = error "Could not decode Schnorr signature from hex string"--instance Hashable SchnorrSig where-    i `hashWithSalt` s = i `hashWithSalt` exportSchnorrSig s--instance NFData XOnlyPubKey where-    rnf (XOnlyPubKey p) = p `seq` ()--instance Show XOnlyPubKey where-    showsPrec _ = shows . B16.encode . exportXOnlyPubKey--instance Read XOnlyPubKey where-    readPrec = do-        String str <- lexP-        maybe pfail return $ importXOnlyPubKey =<< decodeHex str--instance Eq XOnlyPubKey where-    fp1 == fp2 = getXOnlyPubKey fp1 == getXOnlyPubKey fp2--instance IsString XOnlyPubKey where-    fromString = fromMaybe e . (importXOnlyPubKey <=< decodeHex) where-        e = error "Could not decode public key from hex string"--instance Hashable XOnlyPubKey where-    i `hashWithSalt` k = i `hashWithSalt` exportXOnlyPubKey k-#endif- -- | Import 32-byte 'ByteString' as 'Msg'. msg :: ByteString -> Maybe Msg msg bs@@ -500,65 +390,8 @@     pointers ps (PubKey fp : pubs') f =         withForeignPtr fp $ \p -> pointers (p:ps) pubs' f -#ifdef RECOVERY--- | Parse a compact ECDSA signature (64 bytes + recovery id).-importCompactRecSig :: CompactRecSig -> Maybe RecSig-importCompactRecSig cr =-  if getCompactRecSigV cr `notElem` [0,1,2,3]-  then Nothing-  else withContext $ \ctx -> alloca $ \pc -> do-    let-      c = CompactSig (getCompactRecSigR cr) (getCompactRecSigS cr)-      recid = fromIntegral $ getCompactRecSigV cr-    poke pc c-    fg <- mallocForeignPtr-    ret <- withForeignPtr fg $ \pg ->-        ecdsaRecoverableSignatureParseCompact ctx pg pc recid-    if isSuccess ret then return $ Just $ RecSig fg else return Nothing---- | Serialize an ECDSA signature in compact format (64 bytes + recovery id).-exportCompactRecSig :: RecSig -> CompactRecSig-exportCompactRecSig (RecSig fg) = withContext $ \ctx ->-    withForeignPtr fg $ \pg -> alloca $ \pc -> alloca $ \pr -> do-        ret <- ecdsaRecoverableSignatureSerializeCompact ctx pc pr pg-        unless (isSuccess ret) $ error "Could not obtain compact signature"-        CompactSig r s <- peek pc-        v <- fromIntegral <$> peek pr-        return $ CompactRecSig r s v---- | Convert a recoverable signature into a normal signature.-convertRecSig :: RecSig -> Sig-convertRecSig (RecSig frg) = withContext $ \ctx ->-    withForeignPtr frg $ \prg -> do-        fg <- mallocForeignPtr-        ret <- withForeignPtr fg $ \pg ->-            ecdsaRecoverableSignatureConvert ctx pg prg-        unless (isSuccess ret) $-            error "Could not convert a recoverable signature"-        return $ Sig fg---- | Create a recoverable ECDSA signature.-signRecMsg :: SecKey -> Msg -> RecSig-signRecMsg (SecKey fk) (Msg fm) = withContext $ \ctx ->-    withForeignPtr fk $ \k -> withForeignPtr fm $ \m -> do-        fg <- mallocForeignPtr-        ret <- withForeignPtr fg $ \g ->-            ecdsaSignRecoverable ctx g m k nullPtr nullPtr-        unless (isSuccess ret) $ error "could not sign message"-        return $ RecSig fg---- | Recover an ECDSA public key from a signature.-recover :: RecSig -> Msg -> Maybe PubKey-recover (RecSig frg) (Msg fm) = withContext $ \ctx ->-    withForeignPtr frg $ \prg -> withForeignPtr fm $ \pm -> do-        fp <- mallocForeignPtr-        ret <- withForeignPtr fp $ \pp -> ecdsaRecover ctx pp prg pm-        if isSuccess ret then return $ Just $ PubKey fp else return Nothing-#endif--#ifdef NEGATE tweakNegate :: Tweak -> Maybe Tweak-tweakNegate (Tweak fk) = withContext $ \ctx -> do+tweakNegate (Tweak fk) = unsafePerformIO $ do     fnew <- mallocForeignPtr     peeked <- withForeignPtr fk peek     ret <- withForeignPtr fnew $ \n -> do@@ -568,122 +401,7 @@         if isSuccess ret             then Just (Tweak fnew)             else Nothing-#endif -#ifdef ECDH--- | Compute Diffie-Hellman secret.-ecdh :: PubKey -> SecKey -> ByteString-ecdh (PubKey pk) (SecKey sk) = withContext $ \ctx ->-    withForeignPtr pk $ \pkPtr -> withForeignPtr sk $ \skPtr ->-        allocaBytes size $ \o -> do-            ret <- ecEcdh ctx o pkPtr skPtr nullPtr nullPtr-            unless (isSuccess ret) $ error "ecdh failed"-            packByteString (o, size)-  where-    size :: Integral a => a-    size = 32-#endif--#ifdef SCHNORR--- Get 64-byte x-only public key.-getXOnlyPubKey :: XOnlyPubKey -> ByteString-getXOnlyPubKey (XOnlyPubKey fp) =-    fromShort $ getXOnlyPubKey64 $ unsafePerformIO $ withForeignPtr fp peek---- | Add tweak to public key. Tweak is multiplied first by G to obtain a point.-schnorrTweakAddPubKey :: XOnlyPubKey -> Tweak -> Maybe (XOnlyPubKey, CInt)-schnorrTweakAddPubKey (XOnlyPubKey fp) (Tweak ft) = withContext $ \ctx ->-    withForeignPtr fp $ \p -> withForeignPtr ft $ \t -> alloca $ \is_negated -> do-        fp' <- mallocForeignPtr-        ret <- withForeignPtr fp' $ \p' -> do-            pub <- peek p-            poke p' pub-            schnorrPubKeyTweakAdd ctx p' is_negated t-        peeked_is_negated <- peek is_negated-        if isSuccess ret then return $ Just $ (XOnlyPubKey fp', peeked_is_negated) else return Nothing---- | Add tweak to secret key.-schnorrTweakAddSecKey :: SecKey -> Tweak -> Maybe SecKey-schnorrTweakAddSecKey (SecKey fk) (Tweak ft) = withContext $ \ctx ->-    withForeignPtr fk $ \k -> withForeignPtr ft $ \t -> do-        fk' <- mallocForeignPtr-        ret <- withForeignPtr fk' $ \k' ->  do-            key <- peek k-            poke k' key-            schnorrSecKeyTweakAdd ctx k' t-        if isSuccess ret then return $ Just $ SecKey fk' else return Nothing--signMsgSchnorr :: SecKey -> Msg -> SchnorrSig-signMsgSchnorr (SecKey fk) (Msg fm) =-  withContext $ \ctx ->-    withForeignPtr fk $ \k ->-      withForeignPtr fm $ \m -> do-        fg <- mallocForeignPtr-        ret <--          withForeignPtr fg $ \g ->-            schnorrSign ctx g m k nullPtr nullPtr-        unless (isSuccess ret) $ error "could not schnorr-sign message"-        return $ SchnorrSig fg--exportSchnorrSig :: SchnorrSig -> ByteString-exportSchnorrSig (SchnorrSig fg) = withContext $ \ctx ->-    withForeignPtr fg $ \g -> allocaBytes 64 $ \o -> do-        ret <- signatureSerializeSchnorr ctx o g-        unless (isSuccess ret) $ error "could not serialize schnorr signature"-        packByteString (o, 64)--importXOnlyPubKey :: ByteString -> Maybe XOnlyPubKey-importXOnlyPubKey bs-    | BS.length bs == 32 = withContext $ \ctx -> do-        fp <- mallocForeignPtr-        ret <- withForeignPtr fp $ \pfp -> useByteString bs $ \(inp, _) ->-            schnorrXOnlyPubKeyParse ctx pfp inp-        if isSuccess ret-            then return $ Just $ XOnlyPubKey fp-            else return Nothing-    | otherwise = Nothing--importSchnorrSig :: ByteString -> Maybe SchnorrSig-importSchnorrSig bs-    | BS.length bs == 64 = withContext $ \ctx -> do-        fp <- mallocForeignPtr-        ret <- withForeignPtr fp $ \pfp -> useByteString bs $ \(inp, _) ->-            schnorrSignatureParse ctx pfp inp-        if isSuccess ret-            then return $ Just $ SchnorrSig fp-            else return Nothing-    | otherwise = Nothing--verifyMsgSchnorr :: XOnlyPubKey -> SchnorrSig -> Msg -> Bool-verifyMsgSchnorr (XOnlyPubKey fp) (SchnorrSig fg) (Msg fm) = withContext $ \ctx ->-    withForeignPtr fp $ \p -> withForeignPtr fg $ \g ->-        withForeignPtr fm $ \m -> isSuccess <$> schnorrSignatureVerify ctx g m p--exportXOnlyPubKey :: XOnlyPubKey -> ByteString-exportXOnlyPubKey (XOnlyPubKey pub) = withContext $ \ctx ->-    withForeignPtr pub $ \p -> allocaBytes 32 $ \o -> do-        ret <- schnorrPubKeySerialize ctx o p-        unless (isSuccess ret) $ error "could not serialize x-only public key"-        packByteString (o, 32)--deriveXOnlyPubKey :: SecKey -> XOnlyPubKey-deriveXOnlyPubKey (SecKey fk) = withContext $ \ctx -> withForeignPtr fk $ \k -> do-    fp <- mallocForeignPtr-    ret <- withForeignPtr fp $ \p -> schnorrXOnlyPubKeyCreate ctx p k-    unless (isSuccess ret) $ error "could not derive x-only public key"-    return $ XOnlyPubKey fp--testTweakXOnlyPubKey :: XOnlyPubKey -> CInt -> XOnlyPubKey -> Tweak -> Bool-testTweakXOnlyPubKey (XOnlyPubKey fp) is_negated (XOnlyPubKey internal) (Tweak ft) =-    withContext $ \ctx ->-    withForeignPtr fp $ \p ->-    withForeignPtr internal $ \internalp ->-    withForeignPtr ft $ \t -> do-        ret <- xOnlyPubKeyTweakTest ctx p is_negated internalp t-        return $ isSuccess ret--- End of Schnorr block-#endif- instance Arbitrary Msg where     arbitrary = gen_msg       where@@ -699,10 +417,3 @@  instance Arbitrary PubKey where     arbitrary = derivePubKey <$> arbitrary--#ifdef SCHNORR-instance Arbitrary XOnlyPubKey where-    arbitrary = do-        key <- arbitrary-        return $ deriveXOnlyPubKey key-#endif
src/Crypto/Secp256k1/Internal.hs view
@@ -23,8 +23,8 @@ import qualified Data.Serialize.Get    as Get import qualified Data.Serialize.Put    as Put import           Data.Void             (Void)-import           Foreign               (FunPtr, Ptr, Storable (..),-                                        alloca, castPtr, copyArray)+import           Foreign               (FunPtr, Ptr, Storable (..), alloca,+                                        castPtr, copyArray) import           Foreign.C             (CInt (..), CSize (..), CString, CUChar,                                         CUInt (..)) import           GHC.Generics          (Generic)@@ -52,16 +52,6 @@ newtype RecSig65 = RecSig65 { getRecSig65 :: ShortByteString }     deriving (Read, Show, Eq, Ord, Generic, NFData) -#ifdef RECOVERY-data CompactRecSig =-    CompactRecSig-        { getCompactRecSigR :: !ShortByteString-        , getCompactRecSigS :: !ShortByteString-        , getCompactRecSigV :: !Word8-        }-    deriving (Show, Eq, Ord, Generic, NFData)-#endif- newtype Seed32 = Seed32 { getSeed32 :: ShortByteString }     deriving (Read, Show, Eq, Ord, Generic, NFData) @@ -86,14 +76,6 @@ newtype Ret = Ret { getRet :: CInt }     deriving (Read, Show, Eq, Ord, Generic, NFData) -#ifdef SCHNORR-newtype XOnlyPubKey64 = XOnlyPubKey64 { getXOnlyPubKey64 :: ShortByteString }-    deriving (Read, Show, Eq, Ord, Generic, NFData)--newtype SchnorrSig64 = SchnorrSig64 { getSchnorrSig64 :: ShortByteString }-    deriving (Read, Show, Eq, Ord, Generic, NFData)-#endif- verify :: CtxFlags verify = CtxFlags 0x0101 @@ -116,22 +98,6 @@ packByteString :: (Ptr CUChar, CSize) -> IO ByteString packByteString (b, l) = BS.packCStringLen (castPtr b, fromIntegral l) -#if SCHNORR-instance Storable XOnlyPubKey64 where-    sizeOf _ = 64-    alignment _ = 1-    peek p = XOnlyPubKey64 . toShort <$> packByteString (castPtr p, 64)-    poke p (XOnlyPubKey64 k) = useByteString (fromShort k) $-        \(b, _) -> copyArray (castPtr p) b 64--instance Storable SchnorrSig64 where-    sizeOf _ = 64-    alignment _ = 1-    peek p = SchnorrSig64 . toShort <$> packByteString (castPtr p, 64)-    poke p (SchnorrSig64 k) = useByteString (fromShort k) $-        \(b, _) -> copyArray (castPtr p) b 64-#endif- instance Storable PubKey64 where     sizeOf _ = 64     alignment _ = 1@@ -173,47 +139,6 @@         Put.putShortByteString r         Put.putShortByteString s -#ifdef RECOVERY-instance Storable RecSig65 where-    sizeOf _ = 65-    alignment _ = 1-    peek p = RecSig65 . toShort <$> packByteString (castPtr p, 65)-    poke p (RecSig65 k) = useByteString (fromShort k) $-        \(b, _) -> copyArray (castPtr p) b 65--instance Storable CompactRecSig where-    sizeOf _ = 65-    alignment _ = 1-    peek p = do-        bs <- BS.packCStringLen (castPtr p, 65)-        let (r, s) = BS.splitAt 32 $ BS.take 64 bs-            v = BS.last bs-        return CompactRecSig { getCompactRecSigR = toShort r-                             , getCompactRecSigS = toShort s-                             , getCompactRecSigV = v-                             }-    poke p CompactRecSig{..} =-        useByteString bs $ \(b, _) -> copyArray (castPtr p) b 65-      where-        bs = fromShort getCompactRecSigR `BS.append`-             fromShort getCompactRecSigS `BS.snoc`-             getCompactRecSigV--instance Serialize CompactRecSig where-    get = do-        r <- Get.getByteString 32-        s <- Get.getByteString 32-        v <- Get.getWord8-        return CompactRecSig { getCompactRecSigR = toShort r-                             , getCompactRecSigS = toShort s-                             , getCompactRecSigV = v-                             }-    put (CompactRecSig r s v) = do-        Put.putShortByteString r-        Put.putShortByteString s-        Put.putWord8 v-#endif- instance Storable Msg32 where     sizeOf _ = 32     alignment _ = 1@@ -410,14 +335,12 @@     -> Ptr Tweak32     -> IO Ret -#ifdef NEGATE foreign import ccall     "secp256k1.h secp256k1_ec_privkey_negate"     ecTweakNegate     :: Ptr Ctx     -> Ptr Tweak32     -> IO Ret-#endif  foreign import ccall     "secp256k1.h secp256k1_ec_pubkey_tweak_add"@@ -458,156 +381,3 @@     -> Ptr (Ptr PubKey64) -- ^ pointer to array of public keys     -> CInt -- ^ number of public keys     -> IO Ret--#ifdef RECOVERY-foreign import ccall-    "secp256k1_recovery.h secp256k1_ecdsa_recoverable_signature_parse_compact"-    ecdsaRecoverableSignatureParseCompact-    :: Ptr Ctx-    -> Ptr RecSig65-    -> Ptr CompactSig-    -> CInt-    -> IO Ret--foreign import ccall-    "secp256k1_recovery.h secp256k1_ecdsa_recoverable_signature_convert"-    ecdsaRecoverableSignatureConvert-    :: Ptr Ctx-    -> Ptr Sig64-    -> Ptr RecSig65-    -> IO Ret--foreign import ccall-    "secp256k1_recovery.h secp256k1_ecdsa_recoverable_signature_serialize_compact"-    ecdsaRecoverableSignatureSerializeCompact-    :: Ptr Ctx-    -> Ptr CompactSig-    -> Ptr CInt-    -> Ptr RecSig65-    -> IO Ret--foreign import ccall-    "secp256k1_recovery.h secp256k1_ecdsa_sign_recoverable"-    ecdsaSignRecoverable-    :: Ptr Ctx-    -> Ptr RecSig65-    -> Ptr Msg32-    -> Ptr SecKey32-    -> Ptr Void-    -> Ptr a -- ^ nonce data-    -> IO Ret--foreign import ccall-    "secp256k1_recovery.h secp256k1_ecdsa_recover"-    ecdsaRecover-    :: Ptr Ctx-    -> Ptr PubKey64-    -> Ptr RecSig65-    -> Ptr Msg32-    -> IO Ret-#endif--#ifdef SCHNORR-foreign import ccall-    "secp256k1.h secp256k1_xonly_pubkey_tweak_add"-    schnorrPubKeyTweakAdd-    :: Ptr Ctx-    -> Ptr XOnlyPubKey64-    -> Ptr CInt-    -> Ptr Tweak32-    -> IO Ret--foreign import ccall-    "secp256k1.h secp256k1_xonly_seckey_tweak_add"-    schnorrSecKeyTweakAdd-    :: Ptr Ctx-    -> Ptr SecKey32-    -> Ptr Tweak32-    -> IO Ret--foreign import ccall-    "secp256k1.h secp256k1_schnorrsig_serialize"-    signatureSerializeSchnorr-    :: Ptr Ctx-    -> Ptr CUChar -- ^ array for encoded signature, must be large enough-    -> Ptr SchnorrSig64-    -> IO Ret--foreign import ccall-    "secp256k1.h secp256k1_schnorrsig_sign"-    schnorrSign-    :: Ptr Ctx-    -> Ptr SchnorrSig64-    -> Ptr Msg32-    -> Ptr SecKey32-    -- TODO-    -- This is actually an "extended nonce function" in the C code. So this signature is broken,-    -- but we pass a nullFunPtr (and this module is Internal), so it doesn't matter right now.-    -> Ptr Void-    -> Ptr a -- ^ nonce data-    -> IO Ret--foreign import ccall-    "secp256k1.h secp256k1_xonly_pubkey_tweak_test"-    xOnlyPubKeyTweakTest-    :: Ptr Ctx-    -> Ptr XOnlyPubKey64 -- output_pubkey-    -> CInt -- is_negated-    -> Ptr XOnlyPubKey64 -- internal_pubkey-    -> Ptr Tweak32-    -> IO Ret--foreign import ccall-    "secp256k1.h secp256k1_xonly_pubkey_serialize"-    schnorrPubKeySerialize-    :: Ptr Ctx-    -> Ptr CUChar -- 32 bytes output buffer-    -> Ptr XOnlyPubKey64-    -> IO Ret--foreign import ccall-    "secp256k1.h secp256k1_schnorrsig_verify"-    schnorrSignatureVerify-    :: Ptr Ctx-    -> Ptr SchnorrSig64-    -> Ptr Msg32-    -> Ptr XOnlyPubKey64-    -> IO Ret--foreign import ccall-    "secp256k1.h secp256k1_schnorrsig_parse"-    schnorrSignatureParse-    :: Ptr Ctx-    -> Ptr SchnorrSig64 -- out-    -> Ptr CUChar -- in-    -> IO Ret--foreign import ccall-    "secp256k1.h secp256k1_xonly_pubkey_parse"-    schnorrXOnlyPubKeyParse-    :: Ptr Ctx-    -> Ptr XOnlyPubKey64 -- out-    -> Ptr CUChar -- in-    -> IO Ret--foreign import ccall-    "secp256k1.h secp256k1_xonly_pubkey_create"-    schnorrXOnlyPubKeyCreate-    :: Ptr Ctx-    -> Ptr XOnlyPubKey64-    -> Ptr SecKey32-    -> IO Ret-#endif--#ifdef ECDH-foreign import ccall-    "secp256k1_ecdh.h secp256k1_ecdh"-    ecEcdh-    :: Ptr Ctx-    -> Ptr CUChar-    -> Ptr PubKey64-    -> Ptr SecKey32-    -> Ptr a-    -> Ptr b-    -> IO Ret-#endif
test/Crypto/Secp256k1Spec.hs view
@@ -61,53 +61,7 @@         it "multiply public key" $ property tweakMulPubKeyTest         it "combine public keys" $ property combinePubKeyTest         it "can't combine 0 public keys" $ property combinePubKeyEmptyListTest-#ifdef RECOVERY-    describe "recovery" $ do-        it "recovers public keys" $-            property recoverTest-        it "recovers key from signed message" $-            property signRecMsgTest-        it "does not recover bad public keys" $-            property badRecoverTest-        it "detects bad recoverable signature" $-            property badRecSignatureTest-        it "serializes compact recoverable signature" $-            property serializeCompactRecSigTest-        it "shows and reads recoverable signature" $-            property (showReadRecSig :: (SecKey, Msg) -> Bool)-        it "reads recoverable signature from string" $ property $ isStringRecSig-#endif-#ifdef NEGATE-    describe "negate" $         it "negates tweak" $ property negateTweakTest-#endif-#ifdef ECDH-    describe "ecdh" $ do-        it "computes dh secret" $ property computeDhSecret-#endif-#ifdef SCHNORR-    describe "schnorr (bip-340)" $ do-        it "validates test vector 0" $-            property bip340Vector0-        it "rejects test vector 5" $-            property $-            failingVectorToAssertion InvalidPubKey-              (-                hexToBytes "eefdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34",-                hexToBytes "243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89",-                hexToBytes "667c2f778e0616e611bd0c14b8a600c5884551701a949ef0ebfd72d452d64e844160bcfc3f466ecb8facd19ade57d8699d74e7207d78c6aedc3799b52a8e0598"-              )-        it "rejects test vector 6" $-            property $-            failingVectorToAssertion InvalidSig-              (-                hexToBytes "dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659",-                hexToBytes "243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89",-                hexToBytes "f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9935554d1aa5f0374e5cdaacb3925035c7c169b27c4426df0a6b19af3baeab138"-              )-        it "makes a valid taproot key spend signature" $-            property taprootKeySpend-#endif  hexToBytes :: String -> BS.ByteString hexToBytes = fst . B16.decode . B8.pack@@ -121,13 +75,6 @@     g = signMsg k m     hex = B16.encode $ exportSig g -#ifdef RECOVERY-isStringRecSig :: (SecKey, Msg) -> Bool-isStringRecSig (k, m) = g == fromString (cs hex) where-    g = signRecMsg k m-    hex = B16.encode . S.encode $ exportCompactRecSig g-#endif- isStringMsg :: Msg -> Bool isStringMsg m = m == fromString (cs m') where     m' = B16.encode $ getMsg m@@ -150,12 +97,6 @@ showReadSig (k, m) = showRead sig where     sig = signMsg k m -#ifdef RECOVERY-showReadRecSig :: (SecKey, Msg) -> Bool-showReadRecSig (k, m) = showRead recSig where-    recSig = signRecMsg k m-#endif- showRead :: (Show a, Read a, Eq a) => a -> Bool showRead x = read (show x) == x @@ -169,36 +110,10 @@     ys <- mapM (P.spawnP . signMsgTest) xs     and <$> mapM P.get ys -#ifdef RECOVERY-signRecMsgTest :: (Msg, SecKey) -> Bool-signRecMsgTest (fm, fk) = verifySig fp fg fm where-    fp = derivePubKey fk-    fg = convertRecSig $ signRecMsg fk fm--recoverTest :: (Msg, SecKey) -> Bool-recoverTest (fm, fk) = recover fg fm == Just fp where-    fp = derivePubKey fk-    fg = signRecMsg fk fm--badRecoverTest :: (Msg, SecKey, Msg) -> Property-badRecoverTest (fm, fk, fm') =-  fm' /= fm ==> fp' /= Nothing ==> fp' /= Just fp-  where-    fg  = signRecMsg fk fm-    fp  = derivePubKey fk-    fp' = recover fg fm'-#endif- badSignatureTest :: (Msg, SecKey, PubKey) -> Bool badSignatureTest (fm, fk, fp) = not $ verifySig fp fg fm where     fg = signMsg fk fm -#ifdef RECOVERY-badRecSignatureTest :: (Msg, SecKey, PubKey) -> Bool-badRecSignatureTest (fm, fk, fp) = not $ verifySig fp fg fm where-    fg = convertRecSig $ signRecMsg fk fm-#endif- normalizeSigTest :: (Msg, SecKey) -> Bool normalizeSigTest (fm, fk) = not norm && sig == fg where     fg = signMsg fk fm@@ -226,16 +141,6 @@   where     fg = signMsg fk fm -#ifdef RECOVERY-serializeCompactRecSigTest :: (Msg, SecKey) -> Bool-serializeCompactRecSigTest (fm, fk) =-    case importCompactRecSig $ exportCompactRecSig fg of-        Just fg' -> fg == fg'-        Nothing  -> False-  where-    fg = signRecMsg fk fm-#endif- serializeSecKeyTest :: SecKey -> Bool serializeSecKeyTest fk =     case secKey $ getSecKey fk of@@ -316,7 +221,6 @@     expected = Nothing     combined = combinePubKeys [] -#ifdef NEGATE negateTweakTest :: Assertion negateTweakTest =     assertEqual "can recover secret key 1 after adding tweak 1" oneKey subtracted@@ -328,85 +232,3 @@     Just minusOneTwk = tweakNegate oneTwk     Just twoKey = tweakAddSecKey oneKey oneTwk     Just subtracted = tweakAddSecKey twoKey minusOneTwk-#endif--#ifdef ECDH-computeDhSecret :: Assertion-computeDhSecret =-    assertEqual "ecdh computes known secret" expected computed-  where-    computed = do-        pub <- importPubKey $ hexToBytes-            "028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7"-        sec <- secKey $ hexToBytes-            "1212121212121212121212121212121212121212121212121212121212121212"-        pure $ ecdh pub sec-    expected = Just $ hexToBytes-        "1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3"-#endif--#ifdef SCHNORR-data VectorError = InvalidPubKey | InvalidSig | InvalidMsg | InvalidSigFormat-  deriving (Eq, Show)--failingVectorToAssertion :: VectorError -> (BS.ByteString, BS.ByteString, BS.ByteString) -> Assertion-failingVectorToAssertion expectedFailure (pubBytes, msgBytes, sigBytes) =-    assertEqual ("expected error " <> show expectedFailure <> " occurs") (Left expectedFailure) computed-  where-    computed :: Either VectorError ()-    computed =-        let-            pubM = importXOnlyPubKey pubBytes-            sigM = importSchnorrSig sigBytes-            msgM = msg $ msgBytes-        in-            case (pubM, sigM, msgM) of-                (Nothing, _, _) -> Left InvalidPubKey-                (_, Nothing, _) -> Left InvalidSigFormat-                (_, _, Nothing) -> Left InvalidMsg-                (Just pub, Just sig, Just msg) ->-                    if verifyMsgSchnorr pub sig msg-                        then Right ()-                        else Left InvalidSig--bip340Vector0 :: Assertion-bip340Vector0 =-  passingVectorToAssertion 0-    (-      BS.replicate 31 0 <> B8.pack ['\x01']-      , BS.replicate 32 0-      , hexToBytes "db46b5cdc554edbd7765611b75d7bdbc639cf538fb6e9ef04a61884b765343aae148954f27eb69291a9045862f8ae4fa53436c117e9397c70275d5398066d44b"-    )---- Integer is BIP-340 vector test number-passingVectorToAssertion :: Integer -> (BS.ByteString, BS.ByteString, BS.ByteString) -> Assertion-passingVectorToAssertion idx (secBytes, msgBytes, sigBytes) =-    assertEqual ("BIP-340 test vector " <> show idx <> " signature matches") expectedSig computedSig-  where-    expectedSig :: Maybe SchnorrSig-    expectedSig = importSchnorrSig $ sigBytes-    computedSig :: Maybe SchnorrSig-    computedSig = do-        sec <- secKey secBytes-        msg <- msg $ msgBytes-        pure $ signMsgSchnorr sec msg---- This test is ported from the C code, it is called 'test_schnorrsig_taproot'.--- But this version was modified to use fixed keys and messages.-taprootKeySpend :: Assertion-taprootKeySpend =-    assertEqual "derivation succeded and resulting signature is valid" (Just True) computed-  where-    computed = do-        sec <- secKey $ BS.replicate 32 32-        msgToSign <- msg $ BS.replicate 32 00--        let internalPub = deriveXOnlyPubKey sec-        twea <- tweak $ exportXOnlyPubKey internalPub-        (outputPub, isNegated) <- schnorrTweakAddPubKey internalPub twea--        -- This is a 'key spend' in Taproot terminology:-        tweakSec <- schnorrTweakAddSecKey sec twea-        let sig = signMsgSchnorr tweakSec msgToSign-        pure $ verifyMsgSchnorr outputPub sig msgToSign-#endif