secp256k1-haskell 0.2.2 → 0.2.3
raw patch · 5 files changed
+102/−56 lines, 5 filesdep +monad-par
Dependencies added: monad-par
Files
- CHANGELOG.md +7/−0
- secp256k1-haskell.cabal +13/−3
- src/Crypto/Secp256k1/Internal.hs +1/−1
- test/Crypto/Secp256k1/InternalSpec.hs +11/−12
- test/Crypto/Secp256k1Spec.hs +70/−40
CHANGELOG.md view
@@ -4,6 +4,13 @@ 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.2.3+### Changed+- Return meaningful error upon encountering weird ret status from upstream code.++### Added+- Test parallel signature creation and verification.+ ## 0.2.2 ### Removed - Hide tweak negation behind a flag for compatibilidy with Debian 9.
secp256k1-haskell.cabal view
@@ -1,13 +1,13 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.31.2.+-- This file has been generated from package.yaml by hpack version 0.33.0. -- -- see: https://github.com/sol/hpack ----- hash: 0b75b1185f390c0f03f09dfc8e18349a5bce92770b10888fc121279d4fa9953f+-- hash: 16aee2fed95caee7ec390abc8e88433479bf9a3c51dc68b00b1d5eaaebe5b5a1 name: secp256k1-haskell-version: 0.2.2+version: 0.2.3 synopsis: Bindings for secp256k1 library from Bitcoin Core description: Sign and verify signatures using the very fast C secp256k1 library from Pieter Wuille. Has Haskell types and abstractions for keys and signatures. category: Crypto@@ -86,6 +86,7 @@ Paths_secp256k1_haskell hs-source-dirs: test+ ghc-options: -threaded -rtsopts -with-rtsopts=-N build-depends: HUnit , QuickCheck@@ -97,8 +98,17 @@ , entropy , hashable , hspec+ , monad-par , 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/Internal.hs view
@@ -261,7 +261,7 @@ isSuccess :: Ret -> Bool isSuccess (Ret 0) = False isSuccess (Ret 1) = True-isSuccess _ = undefined+isSuccess (Ret n) = error $ "isSuccess expected 0 or 1 but got " <> show n {-# NOINLINE fctx #-} fctx :: ForeignPtr Ctx
test/Crypto/Secp256k1/InternalSpec.hs view
@@ -219,6 +219,12 @@ withEntropy (contextRandomize c) >>= \r -> unless (isSuccess r) (error "failed to randomize context") >> return c +createPubKey :: Ptr Ctx -> Ptr SecKey32 -> Ptr PubKey64 -> SecKey32 -> IO ()+createPubKey x k p key = do+ poke k key+ ret <- ecPubKeyCreate x p k+ unless (isSuccess ret) $ error "failed to create public key"+ ecdsaSignTest :: Assertion ecdsaSignTest = do der <- liftIO $ do@@ -234,14 +240,11 @@ ret2 <- ecdsaSignatureSerializeDer x o ol s unless (isSuccess ret2) $ error "could not serialize signature" len <- peek ol- der <- packCStringLen (castPtr o, fromIntegral len)- return der+ packCStringLen (castPtr o, fromIntegral len) ret <- liftIO $ do p <- alloca $ \p -> alloca $ \k -> do- poke k key x <- signCtx- ret <- ecPubKeyCreate x p k- unless (isSuccess ret) $ error "failed to create public key"+ createPubKey x k p key return p alloca $ \m -> alloca $ \s -> do x <- contextCreate verify@@ -270,20 +273,16 @@ ecPubkeyCreateTest :: Assertion ecPubkeyCreateTest = do- (ret, pk) <- liftIO $ alloca $ \p -> alloca $ \k -> do- poke k key+ pk <- liftIO $ alloca $ \p -> alloca $ \k -> do x <- signCtx- ret <- ecPubKeyCreate x p k- unless (isSuccess ret) $ error "failed to create public key"+ createPubKey x k p key allocaBytes 65 $ \o -> alloca $ \ol -> do poke ol 65 rets <- ecPubKeySerialize x o ol p uncompressed unless (isSuccess rets) $ error "failed to serialize public key" len <- fromIntegral <$> peek ol- pk <- packCStringLen (castPtr o, len)- return (ret, pk)- assertBool "successful pubkey creation" $ isSuccess ret+ packCStringLen (castPtr o, len) assertEqual "public key matches" pub pk where key = SecKey32 $ toShort $ fst $ B16.decode
test/Crypto/Secp256k1Spec.hs view
@@ -1,87 +1,112 @@ {-# LANGUAGE CPP #-} module Crypto.Secp256k1Spec (spec) where +import qualified Control.Monad.Par as P import Crypto.Secp256k1 import qualified Data.ByteString as BS import qualified Data.ByteString.Base16 as B16 import qualified Data.ByteString.Char8 as B8 import Data.Maybe (fromMaybe)+import qualified Data.Serialize as S import Data.String (fromString) import Data.String.Conversions (cs) import Test.Hspec import Test.HUnit (Assertion, assertEqual)-import Test.QuickCheck (property)+import Test.QuickCheck spec :: Spec spec = do describe "signatures" $ do- it "signs message" $ property $ signMsgTest- it "detects bad signature" $ property $ badSignatureTest- it "normalizes signatures" $ property $ normalizeSigTest-#ifdef RECOVERY- 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-#endif+ it "signs message" $+ property signMsgTest+ it "signs messages in parallel" $+ property signMsgParTest+ it "detects bad signature" $+ property badSignatureTest+ it "normalizes signatures" $+ property normalizeSigTest describe "serialization" $ do- it "serializes public key" $ property $ serializePubKeyTest- it "serializes DER signature" $ property $ serializeSigTest- it "serializes compact signature" $ property $ serializeCompactSigTest- it "serialize secret key" $ property $ serializeSecKeyTest+ it "serializes public key" $+ property serializePubKeyTest+ it "serializes DER signature" $+ property serializeSigTest+ it "serializes compact signature" $+ property serializeCompactSigTest+ it "serialize secret key" $+ property serializeSecKeyTest it "shows and reads public key" $- property $ (showRead :: PubKey -> Bool)+ property (showRead :: PubKey -> Bool) it "shows and reads secret key" $- property $ (showRead :: SecKey -> Bool)+ property (showRead :: SecKey -> Bool) it "shows and reads tweak" $- property $ (showReadTweak :: SecKey -> Bool)+ property (showReadTweak :: SecKey -> Bool) it "shows and reads signature" $- property $ (showReadSig :: (SecKey, Msg) -> Bool)- it "shows and reads message" $ property $ (showRead :: Msg -> Bool)- it "reads public key from string" $ property $ isStringPubKey- it "reads secret key from string" $ property $ isStringSecKey- it "reads signature from string" $ property $ isStringSig- it "reads message from string" $ property $ isStringMsg- it "reads tweak from string" $ property $ isStringTweak+ property (showReadSig :: (SecKey, Msg) -> Bool)+ it "shows and reads message" $+ property (showRead :: Msg -> Bool)+ it "reads public key from string" $+ property isStringPubKey+ it "reads secret key from string" $+ property isStringSecKey+ it "reads signature from string" $+ property isStringSig+ it "reads message from string" $+ property isStringMsg+ it "reads tweak from string" $+ property isStringTweak+ describe "tweaks" $ do+ it "add secret key" $ property tweakAddSecKeyTest+ it "multiply secret key" $ property tweakMulSecKeyTest+ it "add public key" $ property tweakAddPubKeyTest+ it "multiply public key" $ property tweakMulPubKeyTest+ it "combine public keys" $ property combinePubKeyTest+ it "can't combine 0 public keys" $ property combinePubKeyEmptyListTest #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+ property serializeCompactRecSigTest it "shows and reads recoverable signature" $- property $ (showReadRecSig :: (SecKey, Msg) -> Bool)+ property (showReadRecSig :: (SecKey, Msg) -> Bool) it "reads recoverable signature from string" $ property $ isStringRecSig #endif- describe "tweaks" $ do- it "add secret key" $ property $ tweakAddSecKeyTest- it "multiply secret key" $ property $ tweakMulSecKeyTest- it "add public key" $ property $ tweakAddPubKeyTest- it "multiply public key" $ property $ tweakMulPubKeyTest- it "combine public keys" $ property $ combinePubKeyTest- it "can't combine 0 public keys" $ property $ combinePubKeyEmptyListTest #ifdef NEGATE- it "negates tweak" $ property $ negateTweakTest+ describe "negate" $+ it "negates tweak" $ property negateTweakTest #endif #ifdef ECDH describe "ecdh" $ do- it "computes dh secret" $ property $ computeDhSecret+ 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 $+ 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 $+ it "rejects test vector 6" $+ property $ failingVectorToAssertion InvalidSig ( hexToBytes "dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659", hexToBytes "243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89", hexToBytes "f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9935554d1aa5f0374e5cdaacb3925035c7c169b27c4426df0a6b19af3baeab138" )- it "makes a valid taproot key spend signature" $ property taprootKeySpend+ it "makes a valid taproot key spend signature" $+ property taprootKeySpend #endif hexToBytes :: String -> BS.ByteString@@ -100,7 +125,7 @@ isStringRecSig :: (SecKey, Msg) -> Bool isStringRecSig (k, m) = g == fromString (cs hex) where g = signRecMsg k m- hex = B16.encode . encode $ exportCompactRecSig g+ hex = B16.encode . S.encode $ exportCompactRecSig g #endif isStringMsg :: Msg -> Bool@@ -138,6 +163,11 @@ signMsgTest (fm, fk) = verifySig fp fg fm where fp = derivePubKey fk fg = signMsg fk fm++signMsgParTest :: [(Msg, SecKey)] -> Bool+signMsgParTest xs = P.runPar $ do+ ys <- mapM (P.spawnP . signMsgTest) xs+ and <$> mapM P.get ys #ifdef RECOVERY signRecMsgTest :: (Msg, SecKey) -> Bool