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 +10/−4
- src/Crypto/Secp256k1.hs +35/−19
- src/Crypto/Secp256k1/Gen.hs +8/−8
- src/Crypto/Secp256k1/Internal.hs +3/−3
- src/Crypto/Secp256k1/Prim.hs +2/−2
- test/Crypto/Secp256k1/PrimSpec.hs +440/−401
- test/Crypto/Secp256k1Prop.hs +11/−11
- test/Crypto/Secp256k1Spec.hs +194/−195
- test/Main.hs +3/−3
- test/Spec.hs +3/−1
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