libsecp256k1 0.0.3 → 0.1.0
raw patch · 11 files changed
+1106/−807 lines, 11 filesdep +entropydep +hedgehogdep +libsecp256k1dep −monad-pardep −mtldep −secp256k1-haskelldep ~memorydep ~transformersPVP ok
version bump matches the API change (PVP)
Dependencies added: entropy, hedgehog, libsecp256k1
Dependencies removed: monad-par, mtl, secp256k1-haskell
Dependency ranges changed: memory, transformers
API changes (from Hackage documentation)
- Crypto.Secp256k1: SchnorrExtra :: (ByteString -> SecKey -> PubKeyXO -> ByteString -> a -> Maybe (SizedByteArray 32 ByteString)) -> a -> SchnorrExtra a
- Crypto.Secp256k1: [schnorrExtraData] :: SchnorrExtra a -> a
- Crypto.Secp256k1: [schnorrExtraNonceFunHardened] :: SchnorrExtra a -> ByteString -> SecKey -> PubKeyXO -> ByteString -> a -> Maybe (SizedByteArray 32 ByteString)
- Crypto.Secp256k1: data SchnorrExtra a
- Crypto.Secp256k1: ecSecKeyTweakAdd :: SecKey -> Tweak -> Maybe SecKey
- Crypto.Secp256k1: ecSecKeyTweakMul :: SecKey -> Tweak -> Maybe SecKey
- Crypto.Secp256k1: schnorrSignCustom :: forall a. KeyPair -> ByteString -> SchnorrExtra a -> Maybe Signature
- Paths_libsecp256k1: getBinDir :: IO FilePath
- Paths_libsecp256k1: getDataDir :: IO FilePath
- Paths_libsecp256k1: getDataFileName :: FilePath -> IO FilePath
- Paths_libsecp256k1: getDynLibDir :: IO FilePath
- Paths_libsecp256k1: getLibDir :: IO FilePath
- Paths_libsecp256k1: getLibexecDir :: IO FilePath
- Paths_libsecp256k1: getSysconfDir :: IO FilePath
- Paths_libsecp256k1: version :: Version
+ Crypto.Secp256k1: exportSecKey :: SecKey -> ByteString
+ Crypto.Secp256k1: instance GHC.Show.Show Crypto.Secp256k1.PubKeyXO
+ Crypto.Secp256k1: instance GHC.Show.Show Crypto.Secp256k1.PubKeyXY
+ Crypto.Secp256k1: instance GHC.Show.Show Crypto.Secp256k1.RecoverableSignature
+ Crypto.Secp256k1: instance GHC.Show.Show Crypto.Secp256k1.SecKey
+ Crypto.Secp256k1: instance GHC.Show.Show Crypto.Secp256k1.Signature
+ Crypto.Secp256k1: instance GHC.Show.Show Crypto.Secp256k1.Tweak
+ Crypto.Secp256k1: keyPairSecKey :: KeyPair -> SecKey
+ Crypto.Secp256k1: secKeyTweakAdd :: SecKey -> Tweak -> Maybe SecKey
+ Crypto.Secp256k1: secKeyTweakMul :: SecKey -> Tweak -> Maybe SecKey
+ Crypto.Secp256k1.Gen: keyPairGen :: MonadGen m => m KeyPair
+ Crypto.Secp256k1.Gen: pubKeyXOGen :: MonadGen m => m PubKeyXO
+ Crypto.Secp256k1.Gen: pubKeyXYGen :: MonadGen m => m PubKeyXY
+ Crypto.Secp256k1.Gen: secKeyGen :: MonadGen m => m SecKey
+ Crypto.Secp256k1.Gen: tweakGen :: MonadGen m => m Tweak
+ Crypto.Secp256k1.Internal: decodeBase16 :: ByteString -> Either String ByteString
+ Crypto.Secp256k1.Internal: encodeBase16 :: ByteString -> ByteString
Files
- libsecp256k1.cabal +15/−10
- src/Crypto/Secp256k1.hs +95/−91
- src/Crypto/Secp256k1/Gen.hs +30/−0
- src/Crypto/Secp256k1/Internal.hs +9/−0
- src/Crypto/Secp256k1/Prim.hs +63/−62
- test/Crypto/Secp256k1/PrimSpec.hs +402/−422
- test/Crypto/Secp256k1Prop.hs +252/−0
- test/Crypto/Secp256k1Spec.hs +201/−221
- test/Main.hs +18/−0
- test/Spec.hs +9/−1
- test/Util.hs +12/−0
libsecp256k1.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: libsecp256k1-version: 0.0.3+version: 0.1.0 synopsis: Bindings for secp256k1 description: Sign and verify signatures using the secp256k1 library. category: Crypto@@ -28,6 +28,7 @@ library exposed-modules: Crypto.Secp256k1+ Crypto.Secp256k1.Gen Crypto.Secp256k1.Internal Crypto.Secp256k1.Prim other-modules:@@ -39,16 +40,21 @@ build-depends: base >=4.9 && <5 , bytestring >=0.10.8 && <0.12- , memory- , transformers+ , entropy >=0.3.8 && <0.5+ , hedgehog+ , memory >=0.14.15 && <1.0+ , transformers >=0.4.0.0 && <1.0 default-language: Haskell2010 test-suite spec type: exitcode-stdio-1.0- main-is: Spec.hs+ main-is: Main.hs other-modules: Crypto.Secp256k1.PrimSpec+ Crypto.Secp256k1Prop Crypto.Secp256k1Spec+ Spec+ Util Paths_libsecp256k1 hs-source-dirs: test@@ -57,11 +63,10 @@ HUnit , base >=4.9 && <5 , bytestring >=0.10.8 && <0.12+ , entropy >=0.3.8 && <0.5+ , hedgehog , hspec- , memory- , monad-par- , mtl- , secp256k1-haskell- , transformers+ , libsecp256k1+ , memory >=0.14.15 && <1.0+ , transformers >=0.4.0.0 && <1.0 default-language: Haskell2010- build-tool-depends: hspec-discover:hspec-discover
src/Crypto/Secp256k1.hs view
@@ -1,8 +1,6 @@ {-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE RankNTypes #-}@@ -32,6 +30,7 @@ -- * Parsing and Serialization importSecKey,+ exportSecKey, importPubKeyXY, exportPubKeyXY, importPubKeyXO,@@ -53,13 +52,14 @@ recSigToSig, derivePubKey, keyPairCreate,+ keyPairSecKey, keyPairPubKeyXY, keyPairPubKeyXO, xyToXO, -- * Tweaks- ecSecKeyTweakAdd,- ecSecKeyTweakMul,+ secKeyTweakAdd,+ secKeyTweakMul, keyPairPubKeyXOTweakAdd, pubKeyCombine, pubKeyNegate,@@ -71,8 +71,6 @@ -- * Schnorr Operations schnorrSign,- SchnorrExtra (..),- schnorrSignCustom, schnorrVerify, -- * Other@@ -86,6 +84,7 @@ import Crypto.Secp256k1.Internal import Crypto.Secp256k1.Prim (flagsEcUncompressed) import qualified Crypto.Secp256k1.Prim as Prim+import qualified Data.ByteArray.Encoding as BA import Data.ByteArray.Sized import Data.ByteString (ByteString) import qualified Data.ByteString as BS@@ -100,6 +99,7 @@ -- import Data.String.Conversions (ConvertibleStrings, cs) +import qualified Data.ByteString.Char8 as B8 import Data.Foldable (for_) import Data.Memory.PtrMethods (memCompare) import Foreign (@@ -108,6 +108,8 @@ FunPtr, Ptr, Storable,+ Word32,+ Word64, Word8, alloca, allocaArray,@@ -135,6 +137,7 @@ withForeignPtr, ) import Foreign.C (CInt (..), CSize (..))+import Foreign.Storable (Storable (..)) import GHC.Generics (Generic) import GHC.IO.Handle.Text (memcpy) import System.IO.Unsafe (unsafePerformIO)@@ -147,7 +150,16 @@ ) +-- | Secret Key newtype SecKey = SecKey {secKeyFPtr :: ForeignPtr Prim.Seckey32}+++instance Show SecKey where+ show SecKey{..} = unsafePerformIO . evalContT $ do+ secKeyPtr <- ContT (withForeignPtr secKeyFPtr)+ -- avoid allocating a new bytestring because we are only reading from this pointer+ bs <- lift (Data.ByteString.Unsafe.unsafePackCStringLen (castPtr secKeyPtr, 32))+ pure $ "0x" <> B8.unpack (BA.convertToBase BA.Base16 bs) instance Eq SecKey where sk == sk' = unsafePerformIO . evalContT $ do skp <- ContT $ withForeignPtr (secKeyFPtr sk)@@ -160,7 +172,14 @@ lift (memCompare (castPtr skp) (castPtr skp') 32) +-- | Public Key with both X and Y coordinates newtype PubKeyXY = PubKeyXY {pubKeyXYFPtr :: ForeignPtr Prim.Pubkey64}+++instance Show PubKeyXY where+ show pk = "0x" <> B8.unpack (BA.convertToBase BA.Base16 (exportPubKeyXY True pk))++ instance Eq PubKeyXY where pk == pk' = unsafePerformIO . evalContT $ do pkp <- ContT . withForeignPtr . pubKeyXYFPtr $ pk@@ -175,7 +194,14 @@ pure $ compare res 0 +-- | Public Key with only an X coordinate. newtype PubKeyXO = PubKeyXO {pubKeyXOFPtr :: ForeignPtr Prim.XonlyPubkey64}+++instance Show PubKeyXO where+ show pk = "0x" <> B8.unpack (BA.convertToBase BA.Base16 (exportPubKeyXO pk))++ instance Eq PubKeyXO where pk == pk' = unsafePerformIO . evalContT $ do pkp <- ContT . withForeignPtr . pubKeyXOFPtr $ pk@@ -190,7 +216,10 @@ pure $ compare res 0 +-- | Structure containing information equivalent to 'SecKey' and 'PubKeyXY' newtype KeyPair = KeyPair {keyPairFPtr :: ForeignPtr Prim.Keypair96}++ instance Eq KeyPair where kp == kp' = unsafePerformIO . evalContT $ do kpp <- ContT $ withForeignPtr (keyPairFPtr kp)@@ -198,7 +227,12 @@ (EQ ==) <$> lift (memCompare (castPtr kpp) (castPtr kpp') 32) +-- | Structure containing Signature (R,S) data. newtype Signature = Signature {signatureFPtr :: ForeignPtr Prim.Sig64}+++instance Show Signature where+ show sig = "0x" <> (B8.unpack . encodeBase16) (exportSignatureCompact sig) instance Eq Signature where sig == sig' = unsafePerformIO . evalContT $ do sigp <- ContT $ withForeignPtr (signatureFPtr sig)@@ -206,7 +240,14 @@ (EQ ==) <$> lift (memCompare (castPtr sigp) (castPtr sigp') 32) +-- | Structure containing Signature AND recovery ID newtype RecoverableSignature = RecoverableSignature {recoverableSignatureFPtr :: ForeignPtr Prim.RecSig65}+++instance Show RecoverableSignature where+ show recSig = "0x" <> (B8.unpack . encodeBase16) (exportRecoverableSignature recSig)++ instance Eq RecoverableSignature where rs == rs' = unsafePerformIO . evalContT $ do rsp <- ContT $ withForeignPtr (recoverableSignatureFPtr rs)@@ -214,7 +255,14 @@ (EQ ==) <$> lift (memCompare (castPtr rsp) (castPtr rsp') 32) +-- | Isomorphic to 'SecKey' but specifically used for tweaking (EC Group operations) other keys newtype Tweak = Tweak {tweakFPtr :: ForeignPtr Prim.Tweak32}+++instance Show Tweak where+ show (Tweak fptr) = show (SecKey $ castForeignPtr fptr)++ instance Eq Tweak where sk == sk' = unsafePerformIO . evalContT $ do skp <- ContT $ withForeignPtr (tweakFPtr sk)@@ -248,29 +296,39 @@ else pure Nothing +exportSecKey :: SecKey -> ByteString+exportSecKey SecKey{..} = unsafePerformIO . evalContT $ do+ secKeyPtr <- ContT (withForeignPtr secKeyFPtr)+ lift $ packByteString (secKeyPtr, 32)++ -- | Parses a 33 or 65 byte 'PubKeyXY', all other lengths will result in @Nothing@ importPubKeyXY :: ByteString -> Maybe PubKeyXY-importPubKeyXY bs = unsafePerformIO $- unsafeUseByteString bs $ \(input, len) -> do- pubkeyOutputBuf <- mallocBytes 64+importPubKeyXY bs = unsafePerformIO . evalContT $ do+ (input, len) <- ContT (unsafeUseByteString bs)+ lift $ do if len == 33 || len == 65 then do- ret <- Prim.ecPubkeyParse ctx (castPtr pubkeyOutputBuf) input len+ pubkeyOutputBuf <- mallocBytes 64+ ret <- Prim.ecPubkeyParse ctx pubkeyOutputBuf input len if isSuccess ret- then Just . PubKeyXY <$> newForeignPtr finalizerFree (castPtr pubkeyOutputBuf)+ then Just . PubKeyXY <$> newForeignPtr finalizerFree pubkeyOutputBuf else free pubkeyOutputBuf $> Nothing else pure Nothing -- | Serialize 'PubKeyXY'. First argument @True@ for compressed output (33 bytes), @False@ for uncompressed (65 bytes). exportPubKeyXY :: Bool -> PubKeyXY -> ByteString-exportPubKeyXY compress (PubKeyXY fptr) = unsafePerformIO $ do+exportPubKeyXY compress PubKeyXY{..} = unsafePerformIO . evalContT $ do let flags = if compress then Prim.flagsEcCompressed else Prim.flagsEcUncompressed let sz = if compress then 33 else 65- buf <- mallocBytes sz- alloca $ \written -> do+ ptr <- ContT (withForeignPtr pubKeyXYFPtr)+ written <- ContT alloca+ lift $ do+ poke written (fromIntegral sz)+ buf <- mallocBytes sz -- always succeeds so we don't need to check- _ret <- withForeignPtr fptr $ \ptr -> Prim.ecPubkeySerialize ctx buf written ptr flags+ _ret <- Prim.ecPubkeySerialize ctx buf written ptr flags len <- peek written unsafePackMallocCStringLen (castPtr buf, fromIntegral len) @@ -286,7 +344,7 @@ ret <- Prim.xonlyPubkeyParse ctx outBuf ptr if isSuccess ret then Just . PubKeyXO <$> newForeignPtr finalizerFree outBuf- else pure Nothing+ else free outBuf $> Nothing -- | Serializes 'PubKeyXO' to 32 byte @ByteString@@@ -307,11 +365,11 @@ -- compact | len == 64 -> Prim.ecdsaSignatureParseCompact ctx outBuf inBuf -- der- | len >= 71 && len <= 73 -> Prim.ecdsaSignatureParseDer ctx outBuf inBuf len+ | len >= 69 && len <= 73 -> Prim.ecdsaSignatureParseDer ctx outBuf inBuf len -- invalid | otherwise -> pure 0 if isSuccess ret- then Just . Signature <$> newForeignPtr finalizerFree (castPtr outBuf)+ then Just . Signature <$> newForeignPtr finalizerFree outBuf else free outBuf $> Nothing @@ -330,6 +388,7 @@ -- as of Q4'2015 73 byte sigs became nonstandard so we will never create one that big outBuf <- mallocBytes 72 alloca $ \written -> do+ poke written 72 -- always succeeds _ret <- withForeignPtr fptr $ Prim.ecdsaSignatureSerializeDer ctx outBuf written len <- peek written@@ -361,6 +420,7 @@ recIdPtr <- malloc _ret <- Prim.ecdsaRecoverableSignatureSerializeCompact ctx outBuf recIdPtr recSigPtr recId <- peek recIdPtr+ pokeByteOff outBuf 64 recId unsafePackByteString (outBuf, 65) @@ -383,16 +443,15 @@ ecdsaSign :: SecKey -> ByteString -> Maybe Signature ecdsaSign (SecKey skFPtr) msgHash | BS.length msgHash /= 32 = Nothing- | otherwise = unsafePerformIO $- evalContT $ do- skPtr <- ContT (withForeignPtr skFPtr)- (msgHashPtr, _) <- ContT (unsafeUseByteString msgHash)- sigBuf <- lift $ mallocBytes 64- ret <- lift $ Prim.ecdsaSign ctx sigBuf msgHashPtr skPtr Prim.nonceFunctionDefault nullPtr- lift $- if isSuccess ret- then Just . Signature <$> newForeignPtr finalizerFree sigBuf- else free sigBuf $> Nothing+ | otherwise = unsafePerformIO . evalContT $ do+ skPtr <- ContT (withForeignPtr skFPtr)+ (msgHashPtr, _) <- ContT (unsafeUseByteString msgHash)+ lift $ do+ sigBuf <- mallocBytes 64+ ret <- Prim.ecdsaSign ctx sigBuf msgHashPtr skPtr Prim.nonceFunctionDefault nullPtr+ if isSuccess ret+ then Just . Signature <$> newForeignPtr finalizerFree sigBuf+ else free sigBuf $> Nothing -- | Signs @ByteString@ with 'SecKey' only if @ByteString@ is 32 bytes. Retains ability to compute 'PubKeyXY' from the@@ -464,8 +523,8 @@ -- -- | Add 'Tweak' to 'SecKey'.-ecSecKeyTweakAdd :: SecKey -> Tweak -> Maybe SecKey-ecSecKeyTweakAdd SecKey{..} Tweak{..} = unsafePerformIO . evalContT $ do+secKeyTweakAdd :: SecKey -> Tweak -> Maybe SecKey+secKeyTweakAdd SecKey{..} Tweak{..} = unsafePerformIO . evalContT $ do skPtr <- ContT (withForeignPtr secKeyFPtr) skOut <- lift (mallocBytes 32) lift (memcpy skOut skPtr 32)@@ -478,8 +537,8 @@ -- | Multiply 'SecKey' by 'Tweak'.-ecSecKeyTweakMul :: SecKey -> Tweak -> Maybe SecKey-ecSecKeyTweakMul SecKey{..} Tweak{..} = unsafePerformIO . evalContT $ do+secKeyTweakMul :: SecKey -> Tweak -> Maybe SecKey+secKeyTweakMul SecKey{..} Tweak{..} = unsafePerformIO . evalContT $ do skPtr <- ContT (withForeignPtr secKeyFPtr) skOut <- lift (mallocBytes 32) lift (memcpy skOut skPtr 32)@@ -553,8 +612,8 @@ keyPairPtr <- ContT (withForeignPtr keyPairFPtr) tweakPtr <- ContT (withForeignPtr tweakFPtr) lift $ do- keyPairOut <- (mallocBytes 96)- _ <- (memcpy keyPairOut keyPairPtr 96)+ keyPairOut <- mallocBytes 96+ _ <- memcpy keyPairOut keyPairPtr 96 ret <- Prim.keypairXonlyTweakAdd ctx keyPairOut tweakPtr if isSuccess ret then Just . KeyPair <$> newForeignPtr finalizerFree keyPairOut@@ -578,62 +637,6 @@ else free sigBuf $> Nothing --- | Extra parameters object for alternative nonce generation-data SchnorrExtra a = Storable a =>- SchnorrExtra- { schnorrExtraNonceFunHardened :: ByteString -> SecKey -> PubKeyXO -> ByteString -> a -> Maybe (SizedByteArray 32 ByteString)- , schnorrExtraData :: a- }----- | Compute a schnorr signature with an alternative scheme for generating nonces, it is not recommended you use this--- unless you know what you are doing. Instead, favor the usage of 'schnorrSign'-schnorrSignCustom :: forall a. KeyPair -> ByteString -> SchnorrExtra a -> Maybe Signature-schnorrSignCustom KeyPair{..} msg SchnorrExtra{..} = unsafePerformIO . evalContT $ do- (msgPtr, msgLen) <- ContT (unsafeUseByteString msg)- keyPairPtr <- ContT (withForeignPtr keyPairFPtr)- lift $ do- sigBuf <- mallocBytes 64- -- convert fn into funptr- funptr <- mkNonceFunHardened primFn- -- allocate memory for extra data ptr- dataptr <- malloc- -- copy data to new pointer- poke dataptr schnorrExtraData- -- allocate extraparams structure- extraPtr <- mallocBytes (4 + sizeOf funptr + sizeOf dataptr)- -- fill magic- pokeByteOff extraPtr 0 (0xDA :: Word8)- pokeByteOff extraPtr 1 (0x6F :: Word8)- pokeByteOff extraPtr 2 (0xB3 :: Word8)- pokeByteOff extraPtr 3 (0x8C :: Word8)- -- fill funptr- pokeByteOff extraPtr 4 funptr- -- fill dataptr- pokeByteOff extraPtr (4 + sizeOf funptr) dataptr- ret <- Prim.schnorrsigSignCustom ctx sigBuf msgPtr msgLen keyPairPtr extraPtr- freeHaskellFunPtr funptr- free dataptr- free extraPtr- if isSuccess ret- then Just . Signature <$> newForeignPtr finalizerFree sigBuf- else free sigBuf $> Nothing- where- primFn :: Storable a => Prim.NonceFunHardened a- primFn outBuf msgPtr msgLen sk xopk algo algolen dataPtr = do- msg <- unsafePackByteString (msgPtr, msgLen)- sk <- SecKey <$> newForeignPtr_ (castPtr sk)- xopk <- PubKeyXO <$> newForeignPtr_ (castPtr xopk)- algo <- unsafePackByteString (algo, algolen)- extra <- peek dataPtr- case schnorrExtraNonceFunHardened msg sk xopk algo extra of- Nothing -> pure 0- Just bs -> evalContT $ do- (hashPtr, _) <- ContT (unsafeUseByteString (unSizedByteArray bs))- lift (memcpy outBuf hashPtr 32)- pure 1-- -- | Verify the authenticity of a schnorr signature. @True@ means the 'Signature' is correct. schnorrVerify :: PubKeyXO -> ByteString -> Signature -> Bool schnorrVerify PubKeyXO{..} bs Signature{..} = unsafePerformIO . evalContT $ do@@ -662,7 +665,7 @@ -- | Combine a list of 'PubKeyXY's into a single 'PubKeyXY'. This will result in @Nothing@ if the group operation results -- in the Point at Infinity pubKeyCombine :: [PubKeyXY] -> Maybe PubKeyXY-pubKeyCombine keys = unsafePerformIO $ do+pubKeyCombine keys@(_ : _) = unsafePerformIO $ do let n = length keys keysBuf <- mallocBytes (64 * n) for_ (zip [0 ..] keys) $ \(i, PubKeyXY{..}) ->@@ -672,6 +675,7 @@ if isSuccess ret then Just . PubKeyXY <$> newForeignPtr finalizerFree outBuf else free outBuf $> Nothing+pubKeyCombine [] = Nothing -- | Negate a 'PubKeyXY'
+ src/Crypto/Secp256k1/Gen.hs view
@@ -0,0 +1,30 @@+module Crypto.Secp256k1.Gen where++import Crypto.Secp256k1 (KeyPair, PubKeyXO, PubKeyXY, SecKey, Tweak, derivePubKey, importSecKey, importTweak, keyPairCreate, xyToXO)+import Hedgehog (MonadGen)+import Hedgehog.Gen (bytes, discard, prune)+import Hedgehog.Range (singleton)+++secKeyGen :: MonadGen m => m SecKey+secKeyGen = do+ bs <- prune $ bytes (singleton 32)+ maybe discard pure (importSecKey bs)+++pubKeyXYGen :: MonadGen m => m PubKeyXY+pubKeyXYGen = derivePubKey <$> secKeyGen+++pubKeyXOGen :: MonadGen m => m PubKeyXO+pubKeyXOGen = fst . xyToXO <$> pubKeyXYGen+++keyPairGen :: MonadGen m => m KeyPair+keyPairGen = keyPairCreate <$> secKeyGen+++tweakGen :: MonadGen m => m Tweak+tweakGen = do+ bs <- prune $ bytes (singleton 32)+ maybe discard pure (importTweak bs)
src/Crypto/Secp256k1/Internal.hs view
@@ -1,6 +1,7 @@ module Crypto.Secp256k1.Internal where import Crypto.Secp256k1.Prim+import qualified Data.ByteArray.Encoding as BA import Data.ByteString (ByteString) import qualified Data.ByteString as BS import qualified Data.ByteString.Unsafe as BU@@ -34,3 +35,11 @@ isSuccess 0 = False isSuccess 1 = True isSuccess n = error $ "isSuccess expected 0 or 1 but got " ++ show n+++encodeBase16 :: ByteString -> ByteString+encodeBase16 = BA.convertToBase BA.Base16+++decodeBase16 :: ByteString -> Either String ByteString+decodeBase16 = BA.convertFromBase BA.Base16
src/Crypto/Secp256k1/Prim.hs view
@@ -1,8 +1,9 @@+{-# LANGUAGE CApiFFI #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingStrategies #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE RankNTypes #-}+{-# OPTIONS_GHC -Wno-dodgy-foreign-imports #-} -- | -- Module : Crypto.Secp256k1.Prim@@ -220,7 +221,7 @@ -- You should call this after 'contextCreate' or -- 'contextClone' (and 'contextPreallocatedCreate' or -- 'contextClone', resp.), and you may call this repeatedly afterwards.-foreign import ccall safe "secp256k1.h secp256k1_context_randomize"+foreign import capi safe "secp256k1.h secp256k1_context_randomize" contextRandomize :: -- | __Mutated__: pointer to a context object (cannot be NULL) Ctx ->@@ -238,7 +239,7 @@ -- This function uses malloc to allocate memory. It is guaranteed that malloc is -- called at most once for every call of this function. If you need to avoid dynamic -- memory allocation entirely, see the functions in the [Preallocated](#g:preallocated) section.-foreign import ccall safe "secp256k1.h secp256k1_context_clone"+foreign import capi safe "secp256k1.h secp256k1_context_clone" contextClone :: -- | __Input:__ an existing context to copy (cannot be NULL) Ctx ->@@ -253,7 +254,7 @@ -- memory allocation entirely, see the functions in secp256k1_preallocated.h. -- -- See also 'contextRandomize'.-foreign import ccall safe "secp256k1.h secp256k1_context_create"+foreign import capi safe "secp256k1.h secp256k1_context_create" contextCreate :: -- | __Input:__ which parts of the context to initialize. ContextFlags ->@@ -270,7 +271,7 @@ -- 'contextPreallocatedCreate' or 'contextPreallocatedClone', the -- behaviour is undefined. In that case, 'contextPreallocatedDestroy' must -- be used instead.-foreign import ccall safe "secp256k1.h secp256k1_context_destroy"+foreign import capi safe "secp256k1.h secp256k1_context_destroy" contextDestroy :: -- | an existing context to destroy, constructed using 'contextCreate' or 'contextClone' Ctx ->@@ -301,7 +302,7 @@ -- type serialization/parsing functions which require a context object to maintain -- API consistency, but currently do not require expensive precomputations or dynamic -- allocations.-foreign import ccall safe "secp256k1.h secp256k1_context_no_precomp"+foreign import ccall unsafe "secp256k1.h secp256k1_context_no_precomp" contextNoPrecomp :: Ctx @@ -314,7 +315,7 @@ -- The block of memory is exclusively owned by the created context object during -- the lifetime of this context object, see the description of -- 'contextPreallocatedCreate' for details.-foreign import ccall safe "secp256k1.h secp256k1_context_preallocated_clone"+foreign import capi safe "secp256k1_preallocated.h secp256k1_context_preallocated_clone" contextPreallocatedClone :: -- | __Mutated:__ an existing context to copy (cannot be NULL) Ctx ->@@ -327,7 +328,7 @@ -- | Determine the memory size of a secp256k1 context object to be copied into -- caller-provided memory.-foreign import ccall safe "secp256k1.h secp256k1_context_preallocated_clone_size"+foreign import capi safe "secp256k1_preallocated.h secp256k1_context_preallocated_clone_size" contextPreallocatedCloneSize :: -- | __Input:__ an existing context to copy (cannot be NULL) Ctx ->@@ -353,7 +354,7 @@ -- -- See also 'contextRandomize' -- and 'contextPreallocatedDestroy'.-foreign import ccall safe "secp256k1.h secp256k1_context_preallocated_create"+foreign import capi safe "secp256k1_preallocated.h secp256k1_context_preallocated_create" contextPreallocatedCreate :: -- | __Mutated:__ a pointer to a rewritable contiguous block of memory of -- size at least 'contextPreallocatedSize' (flags)@@ -380,7 +381,7 @@ -- of memory properly after this function returns, e.g., by calling free on the -- preallocated pointer given to 'contextPreallocatedCreate' or -- 'contextPreallocatedClone'.-foreign import ccall safe "secp256k1.h secp256k1_context_preallocated_destroy"+foreign import capi safe "secp256k1_preallocated.h secp256k1_context_preallocated_destroy" contextPreallocatedDestroy :: -- | an existing context to destroy, constructed using 'contextPreallocatedCreate' or -- 'contextPreallocatedClone' (cannot be NULL)@@ -393,7 +394,7 @@ -- -- The purpose of this function is to determine how much memory must be provided -- to 'contextPreallocatedCreate'.-foreign import ccall safe "secp256k1.h secp256k1_context_preallocated_size"+foreign import capi safe "secp256k1_preallocated.h secp256k1_context_preallocated_size" contextPreallocatedSize :: -- | __Input:__ which parts of the context to initialize. CUInt ->@@ -415,7 +416,7 @@ -- crashing. -- -- See also 'contextSetIllegalCallback'.-foreign import ccall safe "secp256k1.h secp256k1_context_set_error_callback"+foreign import capi safe "secp256k1.h secp256k1_context_set_error_callback" contextSetErrorCallback :: -- | an existing context object (cannot be NULL) Ctx ->@@ -461,7 +462,7 @@ -- the data pointer argument set to NULL. -- -- See also 'contextSetErrorCallback'.-foreign import ccall safe "secp256k1.h secp256k1_context_set_illegal_callback"+foreign import capi safe "secp256k1.h secp256k1_context_set_illegal_callback" contextSetIllegalCallback :: -- | an existing context object (cannot be NULL) Ctx ->@@ -477,7 +478,7 @@ -- | Compute an EC Diffie-Hellman secret in constant time-foreign import ccall safe "secp256k1.h secp256k1_ecdh"+foreign import capi safe "secp256k1.h secp256k1_ecdh" ecdh :: -- | pointer to a context object (cannot be NULL) Ctx ->@@ -499,13 +500,13 @@ -- | A default ECDH hash function (currently equal to 'ecdhHashFunctionSha256'). -- Populates the output parameter with 32 bytes.-foreign import ccall safe "secp256k1.h &secp256k1_ecdh_hash_function_default"+foreign import capi safe "secp256k1_ecdh.h value secp256k1_ecdh_hash_function_default" ecdhHashFunctionDefault :: FunPtr (EcdhHashFun a) -- | An implementation of SHA256 hash function that applies to compressed public key. -- Populates the output parameter with 32 bytes.-foreign import ccall safe "secp256k1.h &secp256k1_ecdh_hash_function_sha256"+foreign import capi safe "secp256k1_ecdh.h value secp256k1_ecdh_hash_function_sha256" ecdhHashFunctionSha256 :: FunPtr (EcdhHashFun a) @@ -513,14 +514,14 @@ -- | A default safe nonce generation function (currently equal to 'nonceFunctionRfc6979').-foreign import ccall safe "secp256k1.h &secp256k1_nonce_function_default"+foreign import capi safe "secp256k1.h value secp256k1_nonce_function_default" nonceFunctionDefault :: FunPtr (NonceFun a) -- | An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. -- If a data pointer is passed, it is assumed to be a pointer to 32 bytes of -- extra entropy.-foreign import ccall safe "secp256k1.h &secp256k1_nonce_function_rfc6979"+foreign import capi safe "secp256k1.h value secp256k1_nonce_function_rfc6979" nonceFunctionRfc6979 :: FunPtr (NonceFun a) @@ -528,7 +529,7 @@ -- | Recover an ECDSA public key from a signature.-foreign import ccall safe "secp256k1.h secp256k1_ecdsa_recover"+foreign import capi safe "secp256k1_recovery.h secp256k1_ecdsa_recover" ecdsaRecover :: -- | pointer to a context object, initialized for verification (cannot be NULL) Ctx ->@@ -544,7 +545,7 @@ -- | Convert a recoverable signature into a normal signature.-foreign import ccall safe "secp256k1.h secp256k1_ecdsa_recoverable_signature_convert"+foreign import capi safe "secp256k1_recovery.h secp256k1_ecdsa_recoverable_signature_convert" ecdsaRecoverableSignatureConvert :: -- | a secp256k1 context object Ctx ->@@ -557,7 +558,7 @@ -- | Parse a compact ECDSA signature (64 bytes + recovery id).-foreign import ccall safe "secp256k1.h secp256k1_ecdsa_recoverable_signature_parse_compact"+foreign import capi safe "secp256k1_recovery.h secp256k1_ecdsa_recoverable_signature_parse_compact" ecdsaRecoverableSignatureParseCompact :: -- | a secp256k1 context object Ctx ->@@ -572,7 +573,7 @@ -- | Serialize an ECDSA signature in compact format (64 bytes + recovery id).-foreign import ccall safe "secp256k1.h secp256k1_ecdsa_recoverable_signature_serialize_compact"+foreign import capi safe "secp256k1_recovery.h secp256k1_ecdsa_recoverable_signature_serialize_compact" ecdsaRecoverableSignatureSerializeCompact :: -- | a secp256k1 context object Ctx ->@@ -587,7 +588,7 @@ -- | Create a recoverable ECDSA signature.-foreign import ccall safe "secp256k1.h secp256k1_ecdsa_sign_recoverable"+foreign import capi safe "secp256k1_recovery.h secp256k1_ecdsa_sign_recoverable" ecdsaSignRecoverable :: -- | pointer to a context object, initialized for signing (cannot be NULL) Ctx ->@@ -613,7 +614,7 @@ -- -- The created signature is always in lower-S form. See -- 'ecdsaSignatureNormalize' for more details.-foreign import ccall safe "secp256k1.h secp256k1_ecdsa_sign"+foreign import capi safe "secp256k1.h secp256k1_ecdsa_sign" ecdsaSign :: -- | pointer to a context object, initialized for signing (cannot be NULL) Ctx ->@@ -642,7 +643,7 @@ -- validation, but be aware that doing so results in malleable signatures. -- -- For details, see the comments for that function.-foreign import ccall safe "secp256k1.h secp256k1_ecdsa_verify"+foreign import capi safe "secp256k1.h secp256k1_ecdsa_verify" ecdsaVerify :: -- | a secp256k1 context object, initialized for verification. Ctx ->@@ -695,7 +696,7 @@ -- lower-S form, and 'ecdsaVerify' will not accept others. In case -- signatures come from a system that cannot enforce this property, -- 'ecdsaSignatureNormalize' must be called before verification.-foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_normalize"+foreign import capi safe "secp256k1.h secp256k1_ecdsa_signature_normalize" ecdsaSignatureNormalize :: -- | a secp256k1 context object Ctx ->@@ -723,7 +724,7 @@ -- After the call, sig will always be initialized. If parsing failed or R or -- S are zero, the resulting sig value is guaranteed to fail validation for any -- message and public key.-foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_parse_compact"+foreign import capi safe "secp256k1.h secp256k1_ecdsa_signature_parse_compact" ecdsaSignatureParseCompact :: -- | __Input:__ a secp256k1 context object Ctx ->@@ -743,7 +744,7 @@ -- After the call, sig will always be initialized. If parsing failed or the -- encoded numbers are out of range, signature validation with it is -- guaranteed to fail for every message and public key.-foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_parse_der"+foreign import capi safe "secp256k1.h secp256k1_ecdsa_signature_parse_der" ecdsaSignatureParseDer :: -- | __Input:__ a secp256k1 context object Ctx ->@@ -760,7 +761,7 @@ -- | Serialize an ECDSA signature in compact (64 byte) format. -- -- See 'ecdsaSignatureParseCompact' for details about the encoding.-foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_serialize_compact"+foreign import capi safe "secp256k1.h secp256k1_ecdsa_signature_serialize_compact" ecdsaSignatureSerializeCompact :: -- | __Input:__ a secp256k1 context object Ctx ->@@ -773,7 +774,7 @@ -- | Serialize an ECDSA signature in DER format.-foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_serialize_der"+foreign import capi safe "secp256k1.h secp256k1_ecdsa_signature_serialize_der" ecdsaSignatureSerializeDer :: -- | __Input:__ a secp256k1 context object Ctx ->@@ -794,7 +795,7 @@ -- | Compare two public keys using lexicographic (of compressed serialization) order-foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_cmp"+foreign import capi safe "secp256k1.h secp256k1_ec_pubkey_cmp" ecPubkeyCmp :: -- | __Input:__ a secp256k1 context object. Ctx ->@@ -825,7 +826,7 @@ -- | Compute the public key for a secret key.-foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_create"+foreign import capi safe "secp256k1.h secp256k1_ec_pubkey_create" ecPubkeyCreate :: -- | pointer to a context object, initialized for signing (cannot be NULL) Ctx ->@@ -839,7 +840,7 @@ -- | Negates a public key in place.-foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_negate"+foreign import capi safe "secp256k1.h secp256k1_ec_pubkey_negate" ecPubkeyNegate :: -- | pointer to a context object Ctx ->@@ -854,7 +855,7 @@ -- This function supports parsing compressed (33 bytes, header byte 0x02 or -- 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header -- byte 0x06 or 0x07) format public keys.-foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_parse"+foreign import capi safe "secp256k1.h secp256k1_ec_pubkey_parse" ecPubkeyParse :: -- | a secp256k1 context object. Ctx ->@@ -871,7 +872,7 @@ -- | Serialize a pubkey object into a serialized byte sequence.-foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_serialize"+foreign import capi safe "secp256k1.h secp256k1_ec_pubkey_serialize" ecPubkeySerialize :: -- | a secp256k1 context object. Ctx ->@@ -892,7 +893,7 @@ -- | Tweak a public key by adding tweak times the generator to it.-foreign import ccall unsafe "secp256k1.h secp256k1_ec_pubkey_tweak_add"+foreign import capi unsafe "secp256k1.h secp256k1_ec_pubkey_tweak_add" ecPubkeyTweakAdd :: -- | pointer to a context object initialized for validation (cannot be NULL). Ctx ->@@ -911,7 +912,7 @@ -- | Tweak a public key by multiplying it by a tweak value.-foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_tweak_mul"+foreign import capi safe "secp256k1.h secp256k1_ec_pubkey_tweak_mul" ecPubkeyTweakMul :: -- | pointer to a context object initialized for validation (cannot be NULL). Ctx ->@@ -928,7 +929,7 @@ -- | Negates a secret key in place.-foreign import ccall safe "secp256k1.h secp256k1_ec_seckey_negate"+foreign import capi safe "secp256k1.h secp256k1_ec_seckey_negate" ecSeckeyNegate :: -- | pointer to a context object Ctx ->@@ -944,7 +945,7 @@ -- | Tweak a secret key by adding tweak to it.-foreign import ccall safe "secp256k1.h secp256k1_ec_seckey_tweak_add"+foreign import capi safe "secp256k1.h secp256k1_ec_seckey_tweak_add" ecSeckeyTweakAdd :: -- | pointer to a context object (cannot be NULL). Ctx ->@@ -965,7 +966,7 @@ -- | Tweak a secret key by multiplying it by a tweak.-foreign import ccall safe "secp256k1.h secp256k1_ec_seckey_tweak_mul"+foreign import capi safe "secp256k1.h secp256k1_ec_seckey_tweak_mul" ecSeckeyTweakMul :: -- | pointer to a context object (cannot be NULL). Ctx ->@@ -989,7 +990,7 @@ -- when interpreted as an integer (most significant byte first). The -- probability of choosing a 32-byte string uniformly at random which is an -- invalid secret key is negligible.-foreign import ccall safe "secp256k1.h secp256k1_ec_seckey_verify"+foreign import capi safe "secp256k1.h secp256k1_ec_seckey_verify" ecSecKeyVerify :: -- | pointer to a context object (cannot be NULL) Ctx ->@@ -1000,7 +1001,7 @@ -- | Compute the keypair for a secret key.-foreign import ccall safe "secp256k1.h secp256k1_keypair_create"+foreign import capi safe "secp256k1_extrakeys.h secp256k1_keypair_create" keypairCreate :: -- | pointer to a context object, initialized for signing (cannot be NULL) Ctx ->@@ -1014,7 +1015,7 @@ -- | Get the public key from a keypair.-foreign import ccall safe "secp256k1.h secp256k1_keypair_pub"+foreign import capi safe "secp256k1_extrakeys.h secp256k1_keypair_pub" keypairPub :: -- | pointer to a context object (cannot be NULL) Ctx ->@@ -1029,7 +1030,7 @@ -- | Get the secret key from a keypair.-foreign import ccall safe "secp256k1.h secp256k1_keypair_sec"+foreign import capi safe "secp256k1_extrakeys.h secp256k1_keypair_sec" keypairSec :: -- | pointer to a context object (cannot be NULL) Ctx ->@@ -1045,7 +1046,7 @@ -- -- This is the same as calling 'keypairPub' and then -- 'xonlyPubkeyFromPubkey'.-foreign import ccall safe "secp256k1.h secp256k1_keypair_xonly_pub"+foreign import capi safe "secp256k1_extrakeys.h secp256k1_keypair_xonly_pub" keypairXonlyPub :: -- | pointer to a context object (cannot be NULL) Ctx ->@@ -1069,7 +1070,7 @@ -- Calling this function and then 'keypairPub' results in the same -- public key as calling 'keypairXonlyPub' and then -- 'xonlyPubkeyTweakAdd'.-foreign import ccall safe "secp256k1.h secp256k1_keypair_xonly_tweak_add"+foreign import capi safe "secp256k1_extrakeys.h secp256k1_keypair_xonly_tweak_add" keypairXonlyTweakAdd :: -- | pointer to a context object initialized for verification -- (cannot be NULL)@@ -1100,7 +1101,7 @@ -- function will fail and return 0. The hash will be tagged with algo. -- Therefore, to create BIP-340 compliant signatures, algo must be set to -- "BIP0340/nonce" and algolen to 13.-foreign import ccall safe "secp256k1.h &secp256k1_nonce_function_bip340"+foreign import capi safe "secp256k1_schnorrsig.h value secp256k1_nonce_function_bip340" nonceFunctionBip340 :: FunPtr (NonceFunHardened a) @@ -1116,7 +1117,7 @@ -- 'taggedSha256' and then sign the hash. Tagged hashing allows -- providing an context-specific tag for domain separation. This prevents -- signatures from being valid in multiple contexts by accident.-foreign import ccall safe "secp256k1.h secp256k1_schnorrsig_sign"+foreign import capi safe "secp256k1_schnorrsig.h secp256k1_schnorrsig_sign" schnorrsigSign :: -- | pointer to a context object, initialized for signing (cannot be NULL) Ctx ->@@ -1143,7 +1144,7 @@ -- -- Creates the same signatures as schnorrsig_sign if msglen is 32 and the -- extraparams.ndata is the same as aux_rand32.-foreign import ccall safe "secp256k1.h secp256k1_schnorrsig_sign_custom"+foreign import capi unsafe "secp256k1_schnorrsig.h secp256k1_schnorrsig_sign_custom" schnorrsigSignCustom :: -- | pointer to a context object, initialized for signing (cannot be NULL) Ctx ->@@ -1162,7 +1163,7 @@ -- | Verify a Schnorr signature.-foreign import ccall safe "secp256k1.h secp256k1_schnorrsig_verify"+foreign import capi safe "secp256k1_schnorrsig.h secp256k1_schnorrsig_verify" schnorrsigSignVerify :: -- | a secp256k1 context object, initialized for verification. Ctx ->@@ -1185,7 +1186,7 @@ -- SHA256(SHA256(tag)||SHA256(tag)||msg). Therefore, tagged hash -- implementations optimized for a specific tag can precompute the SHA256 state -- after hashing the tag hashes.-foreign import ccall safe "secp256k1.h secp256k1_tagged_sha256"+foreign import capi safe "secp256k1_schnorrsig.h secp256k1_tagged_sha256" taggedSha256 :: -- | pointer to a context object Ctx ->@@ -1207,7 +1208,7 @@ -- | Compare two x-only public keys using lexicographic order-foreign import ccall safe "secp256k1.h secp256k1_xonly_pubkey_cmp"+foreign import capi safe "secp256k1_schnorrsig.h secp256k1_xonly_pubkey_cmp" xonlyPubkeyCmp :: -- | a secp256k1 context object. Ctx ->@@ -1222,7 +1223,7 @@ -- | Converts a 'Pubkey64' into a 'XonlyPubkey64'.-foreign import ccall safe "secp256k1.h secp256k1_xonly_pubkey_from_pubkey"+foreign import capi safe "secp256k1_schnorrsig.h secp256k1_xonly_pubkey_from_pubkey" xonlyPubkeyFromPubkey :: -- | pointer to a context object (cannot be NULL) Ctx ->@@ -1241,7 +1242,7 @@ -- | Parse a 32-byte sequence into a 'XonlyPubkey64' object.-foreign import ccall safe "secp256k1.h secp256k1_xonly_pubkey_parse"+foreign import capi safe "secp256k1_schnorrsig.h secp256k1_xonly_pubkey_parse" xonlyPubkeyParse :: -- | a secp256k1 context object (cannot be NULL). Ctx ->@@ -1257,7 +1258,7 @@ -- | Serialize an 'XonlyPubkey64' object into a 32-byte sequence.-foreign import ccall safe "secp256k1.h secp256k1_xonly_pubkey_serialize"+foreign import capi safe "secp256k1_schnorrsig.h secp256k1_xonly_pubkey_serialize" xonlyPubkeySerialize :: -- | a secp256k1 context object (cannot be NULL). Ctx ->@@ -1277,7 +1278,7 @@ -- Note that the resulting point can not in general be represented by an x-only -- pubkey because it may have an odd Y coordinate. Instead, the output_pubkey -- is a normal 'Pubkey64'.-foreign import ccall safe "secp256k1.h secp256k1_xonly_pubkey_tweak_add"+foreign import capi safe "secp256k1_schnorrsig.h secp256k1_xonly_pubkey_tweak_add" xonlyPubkeyTweakAdd :: -- | pointer to a context object initialized for verification -- (cannot be NULL)@@ -1311,7 +1312,7 @@ -- Note that this alone does _not_ verify that the tweaked pubkey is a -- commitment. If the tweak is not chosen in a specific way, the tweaked pubkey -- can easily be the result of a different internal_pubkey and tweak.-foreign import ccall safe "secp256k1.h secp256k1_xonly_pubkey_tweak_add_check"+foreign import capi safe "secp256k1_schnorrsig.h secp256k1_xonly_pubkey_tweak_add_check" xonlyPubkeyTweakAddCheck :: -- | pointer to a context object initialized for verification -- (cannot be NULL)@@ -1338,7 +1339,7 @@ -- | Create a secp256k1 scratch space object.-foreign import ccall safe "secp256k1.h secp256k1_scratch_space_create"+foreign import capi safe "secp256k1.h secp256k1_scratch_space_create" scratchSpaceCreate :: -- | an existing context object (cannot be NULL) Ctx ->@@ -1352,7 +1353,7 @@ -- | Destroy a secp256k1 scratch space. -- -- The pointer may not be used afterwards.-foreign import ccall safe "secp256k1.h secp256k1_scratch_space_destroy"+foreign import capi safe "secp256k1.h secp256k1_scratch_space_destroy" scratchSpaceDestroy :: -- | a secp256k1 context object. Ctx ->@@ -1363,7 +1364,7 @@ -- * Deprecated {-# DEPRECATED ecPrivkeyNegate "use ecSeckeyNegate instead" #-}-foreign import ccall safe "secp256k1.h secp256k1_ec_privkey_negate"+foreign import capi safe "secp256k1.h secp256k1_ec_privkey_negate" ecPrivkeyNegate :: Ctx -> Ptr Tweak32 ->@@ -1371,7 +1372,7 @@ {-# DEPRECATED ecPrivkeyTweakAdd "use ecSeckeyTweakAdd instead" #-}-foreign import ccall safe "secp256k1.h secp256k1_ec_privkey_tweak_add"+foreign import capi safe "secp256k1.h secp256k1_ec_privkey_tweak_add" ecPrivkeyTweakAdd :: Ctx -> Ptr Seckey32 ->@@ -1380,7 +1381,7 @@ {-# DEPRECATED ecPrivkeyTweakMul "use ecSeckeyTweakMul instead" #-}-foreign import ccall safe "secp256k1.h secp256k1_ec_privkey_tweak_mul"+foreign import capi safe "secp256k1.h secp256k1_ec_privkey_tweak_mul" ecPrivkeyTweakMul :: Ctx -> Ptr Seckey32 ->
test/Crypto/Secp256k1/PrimSpec.hs view
@@ -3,15 +3,15 @@ module Crypto.Secp256k1.PrimSpec (spec) where import Control.Monad-import Control.Monad.Trans+ import Crypto.Secp256k1.Internal+import qualified Data.ByteArray.Encoding as BA import Data.ByteString ( ByteString, copy, packCStringLen, useAsCStringLen, )-import qualified Data.ByteString.Base16 as B16 import Data.Either (fromRight) import Foreign import System.Entropy@@ -21,446 +21,426 @@ spec :: Spec spec = do- 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---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---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 $- B16.decodeBase16- "03dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd44705"---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 $- B16.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 $- B16.decodeBase16- "3045022100f502bfa07af43e7ef265618b0d929a7619ee01d6150e37eb6eaaf2c8bd37\- \fb2202206f0415ab0e9a977afd78b2c26ef39b3952096d319fd4b101c768ad6c132e30\- \45"---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 $- B16.decodeBase16- "3045022100f502bfa07af43e7ef265618b0d929a7619ee01d6150e37eb6eaaf2c8bd37\- \fb2202206f0415ab0e9a977afd78b2c26ef39b3952096d319fd4b101c768ad6c132e30\- \45"---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 $- B16.decodeBase16- "3045022100f502bfa07af43e7ef265618b0d929a7619ee01d6150e37eb6eaaf2c8bd37\- \fb2202206f0415ab0e9a977afd78b2c26ef39b3952096d319fd4b101c768ad6c132e30\- \45"- pub =- fromRight undefined $- B16.decodeBase16- "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\- \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"- msg =- fromRight undefined $- B16.decodeBase16- "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"-+ pure () -signCtx :: IO Ctx-signCtx =- contextCreate sign >>= \c ->- withEntropy (contextRandomize c) >>= \r ->- unless (isSuccess r) (error "failed to randomize context") >> return c+-- 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 -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"+-- 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 -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 $- B16.decodeBase16- "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"- key =- fromRight undefined $- B16.decodeBase16- "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"+-- 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" -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 $- B16.decodeBase16- "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"+-- 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" -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 $- B16.decodeBase16- "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"- pub =- fromRight undefined $- B16.decodeBase16- "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\- \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"+-- 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" -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 $- B16.decodeBase16- "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"- tweak =- fromRight undefined $- B16.decodeBase16- "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"- expected =- fromRight undefined $- B16.decodeBase16- "ec1e3ce1cefa18a671d51125e2b249688d934b0e28f5d1665384d9b02f929059"+-- 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 -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 $- B16.decodeBase16- "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"- tweak =- fromRight undefined $- B16.decodeBase16- "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"- expected =- fromRight undefined $- B16.decodeBase16- "a96f5962493acb179f60a86a9785fc7a30e0c39b64c09d24fe064d9aef15e4c0"+-- 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" -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)+-- 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" +-- 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" -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)+-- 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" +-- 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" -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 $- B16.decodeBase16- "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\- \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"- tweak =- fromRight undefined $- B16.decodeBase16- "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"- expected =- fromRight undefined $- B16.decodeBase16- "04441c3982b97576646e0df0c96736063df6b42f2ee566d13b9f6424302d1379e518fd\- \c87a14c5435bff7a5db4552042cb4120c6b86a4bbd3d0643f3c14ad01368"+-- 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) +-- 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) -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 $- B16.decodeBase16- "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\- \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"- tweak =- fromRight undefined $- B16.decodeBase16- "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"- expected =- fromRight undefined $- B16.decodeBase16- "04f379dc99cdf5c83e433defa267fbb3377d61d6b779c06a0e4ce29ae3ff5353b12ae4\- \9c9d07e7368f2ba5a446c203255ce912322991a2d6a9d5d5761c61ed1845"+-- 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" +-- 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 $- B16.decodeBase16- "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\- \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"- pub2 =- fromRight undefined $- B16.decodeBase16- "0487d82042d93447008dfe2af762068a1e53ff394a5bf8f68a045fa642b99ea5d153f5\- \77dd2dba6c7ae4cfd7b6622409d7edd2d76dd13a8092cd3af97b77bd2c77"- pub3 =- fromRight undefined $- B16.decodeBase16- "049b101edcbe1ee37ff6b2318526a425b629e823d7d8d9154417880595a28000ee3feb\- \d908754b8ce4e491aa6fe488b41fb5d4bb3788e33c9ff95a7a9229166d59"- expected =- fromRight undefined $- B16.decodeBase16- "043d9a7ec70011efc23c33a7e62d2ea73cca87797e3b659d93bea6aa871aebde56c3bc\- \6134ca82e324b0ab9c0e601a6d2933afe7fb5d9f3aae900f5c5dc6e362c8"+-- 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"
+ test/Crypto/Secp256k1Prop.hs view
@@ -0,0 +1,252 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}++module Crypto.Secp256k1Prop where++import Control.Monad (when)+import Crypto.Secp256k1+import Crypto.Secp256k1.Gen+import Data.ByteArray.Sized (sizedByteArray)+import qualified Data.ByteString as BS+import Data.Maybe (fromJust, isJust)+import Data.Void+import Hedgehog+import Hedgehog.Gen hiding (discard, maybe)+import Hedgehog.Range (linear, singleton)+++prop_secKeyParseInvertsSerialize :: Property+prop_secKeyParseInvertsSerialize = property $ do+ sk <- forAll secKeyGen+ case importSecKey $ exportSecKey sk of+ Nothing -> failure+ Just x -> x === sk+++prop_secKeySerializeInvertsParse :: Property+prop_secKeySerializeInvertsParse = property $ do+ bs <- forAll (bytes $ singleton 32)+ case importSecKey bs of+ Nothing -> discard+ Just sk -> exportSecKey sk === bs+++prop_pubKeyXYParseInvertsSerialize :: Property+prop_pubKeyXYParseInvertsSerialize = property $ do+ pk <- forAll pubKeyXYGen+ compress <- forAll $ element [False, True]+ case importPubKeyXY (exportPubKeyXY compress pk) of+ Nothing -> failure+ Just x -> x === pk+++prop_pubKeyXYSerializeInvertsParse :: Property+prop_pubKeyXYSerializeInvertsParse = withDiscards 200 $+ property $ do+ bs <- forAll $ bytes (singleton 32)+ negate <- forAll enumBounded+ let withParity =+ flip BS.cons bs $+ if negate+ then 0x03+ else 0x02+ case importPubKeyXY withParity of+ Nothing -> discard+ Just pk -> exportPubKeyXY True pk === withParity+++prop_pubKeyXOParseInvertsSerialize :: Property+prop_pubKeyXOParseInvertsSerialize = property $ do+ pk <- forAll pubKeyXOGen+ case importPubKeyXO (exportPubKeyXO pk) of+ Nothing -> failure+ Just x -> x === pk+++prop_pubKeyXOSerializeInvertsParse :: Property+prop_pubKeyXOSerializeInvertsParse = property $ do+ bs <- forAll (bytes $ singleton 32)+ case importPubKeyXO bs of+ Nothing -> discard+ Just pk -> exportPubKeyXO pk === bs+++prop_signatureParseInvertsSerialize :: Property+prop_signatureParseInvertsSerialize = property $ do+ sk <- forAll secKeyGen+ bs <- forAll $ bytes (singleton 32)+ sig <- case ecdsaSign sk bs of+ Nothing -> failure+ Just x -> pure x+ exportDer <- forAll $ element [False, True]+ let export = if exportDer then exportSignatureDer else exportSignatureCompact+ let serialized = (export sig)+ annotateShow serialized+ annotateShow (BS.length serialized)+ case importSignature serialized of+ Nothing -> failure+ Just x -> x === sig+++prop_recoverableSignatureParseInvertsSerialize :: Property+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)+ annotateShow serialized+ annotateShow (BS.length serialized)+ case importRecoverableSignature serialized of+ Nothing -> failure+ Just x -> x === sig+++prop_validSecKeyImpliesValidTweak :: Property+prop_validSecKeyImpliesValidTweak = property $ do+ sk <- forAll secKeyGen+ assert $ isJust $ importTweak (exportSecKey sk)+++prop_ecdsaSignaturesProducedAreValid :: Property+prop_ecdsaSignaturesProducedAreValid = property $ do+ sk <- forAll secKeyGen+ msg <- forAll $ bytes (singleton 32)+ case ecdsaSign sk msg of+ Nothing -> failure+ Just sig -> assert $ ecdsaVerify msg (derivePubKey sk) sig+++prop_ecdsaRecoverableSignaturesProducedAreValid :: Property+prop_ecdsaRecoverableSignaturesProducedAreValid = property $ do+ sk <- forAll secKeyGen+ msg <- forAll $ bytes (singleton 32)+ case ecdsaSignRecoverable sk msg of+ Nothing -> failure+ Just recSig -> assert $ ecdsaVerify msg (derivePubKey sk) (recSigToSig recSig)+++prop_ecdsaSignatureValidityPreservedOverSerialization :: Property+prop_ecdsaSignatureValidityPreservedOverSerialization = property $ do+ sk <- forAll secKeyGen+ msg <- forAll $ bytes (singleton 32)+ let sig = fromJust $ ecdsaSign sk msg+ useDer <- forAll enumBounded+ let export =+ if useDer+ then exportSignatureDer+ else exportSignatureCompact+ let serialized = export sig+ let parsed = fromJust (importSignature serialized)+ assert $ ecdsaVerify msg (derivePubKey sk) parsed+++prop_ecdsaRecoverableSignatureProducesValidPubKey :: Property+prop_ecdsaRecoverableSignatureProducesValidPubKey = property $ do+ sk <- forAll secKeyGen+ msg <- forAll $ bytes (singleton 32)+ case ecdsaRecover (fromJust $ ecdsaSignRecoverable sk msg) msg of+ Nothing -> failure+ Just pk -> pk === derivePubKey sk+++prop_ecdsaRecoverableSignatureIdentity :: Property+prop_ecdsaRecoverableSignatureIdentity = property $ do+ sk <- forAll secKeyGen+ msg <- forAll $ bytes (singleton 32)+ case ecdsaSignRecoverable sk msg of+ Nothing -> failure+ Just sig -> Just (recSigToSig sig) === ecdsaSign sk msg+++prop_keyPairIdentities :: Property+prop_keyPairIdentities = property $ do+ sk <- forAll secKeyGen+ let kp = keyPairCreate sk+ keyPairSecKey kp === sk+ keyPairPubKeyXY kp === derivePubKey sk+ keyPairPubKeyXO kp === xyToXO (derivePubKey sk)+++prop_tweakDistributesOverPubKeyDerivation :: Property+prop_tweakDistributesOverPubKeyDerivation = property $ do+ sk <- forAll secKeyGen+ tweak <- forAll tweakGen+ (derivePubKey <$> secKeyTweakAdd sk tweak) === pubKeyTweakAdd (derivePubKey sk) tweak+ (derivePubKey <$> secKeyTweakMul sk tweak) === pubKeyTweakMul (derivePubKey sk) tweak+++prop_pubKeyCombineOrderIndependent :: Property+prop_pubKeyCombineOrderIndependent = property $ do+ ls <- forAll $ list (linear 0 20) pubKeyXYGen+ ls' <- forAll $ shuffle ls+ pubKeyCombine ls === pubKeyCombine ls'+++prop_negationDistributesOverPubKeyDerivation :: Property+prop_negationDistributesOverPubKeyDerivation = property $ do+ sk <- forAll secKeyGen+ derivePubKey (secKeyNegate sk) === pubKeyNegate (derivePubKey sk)+++prop_secKeyDoubleNegationIdentity :: Property+prop_secKeyDoubleNegationIdentity = property $ do+ sk <- forAll secKeyGen+ (secKeyNegate . secKeyNegate) sk === sk+++prop_pubKeyDoubleNegationIdentity :: Property+prop_pubKeyDoubleNegationIdentity = property $ do+ pk <- forAll pubKeyXYGen+ (pubKeyNegate . pubKeyNegate) pk === pk+++prop_schnorrSignaturesProducedAreValid :: Property+prop_schnorrSignaturesProducedAreValid = property $ do+ sk <- forAll secKeyGen+ msg <- forAll $ bytes (singleton 32)+ let kp = keyPairCreate sk+ case schnorrSign kp msg of+ Nothing -> failure+ Just sig -> assert $ schnorrVerify (fst $ keyPairPubKeyXO kp) msg sig+++prop_pubKeyCombineTweakIdentity :: Property+prop_pubKeyCombineTweakIdentity = property $ do+ sk <- forAll secKeyGen+ sk' <- forAll secKeyGen+ pubKeyCombine [derivePubKey sk, derivePubKey sk'] === pubKeyTweakAdd (derivePubKey sk) (fromJust $ importTweak (exportSecKey sk'))+++prop_ecdhIdentity :: Property+prop_ecdhIdentity = property $ do+ sk <- forAll secKeyGen+ sk' <- forAll secKeyGen+ ecdh sk (derivePubKey sk') === ecdh sk' (derivePubKey sk)+++prop_ecdsaSignaturesUnforgeable :: Property+prop_ecdsaSignaturesUnforgeable = property $ do+ sk <- forAll secKeyGen+ pk <- forAll pubKeyXYGen+ when (pk == derivePubKey sk) discard+ msg <- forAll $ bytes (singleton 32)+ case ecdsaSign sk msg of+ Nothing -> failure+ Just sig -> assert . not $ ecdsaVerify msg pk sig+++prop_schnorrSignaturesUnforgeable :: Property+prop_schnorrSignaturesUnforgeable = property $ do+ sk <- forAll secKeyGen+ let kp = keyPairCreate sk+ pk <- forAll pubKeyXOGen+ msg <- forAll $ bytes (singleton 32)+ case schnorrSign kp msg of+ Nothing -> failure+ Just sig -> assert . not $ schnorrVerify pk msg sig+++tests :: Group+tests = $$(discover)
test/Crypto/Secp256k1Spec.hs view
@@ -1,248 +1,228 @@ module Crypto.Secp256k1Spec (spec) where -import Control.Monad.Par-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.Either (fromRight)-import Data.Maybe (fromMaybe, isNothing)-import Data.String (fromString)-import Data.String.Conversions (cs)-import Test.HUnit (Assertion, assertEqual)-import Test.Hspec-import Test.QuickCheck+-- import Control.Monad.Par+-- import qualified Control.Monad.Par as P+import Crypto.Secp256k1+import qualified Data.ByteString as BS+import qualified Data.ByteString.Char8 as B8+import Data.Either (fromRight)+import Data.Maybe (fromMaybe, isNothing)+import Data.String (fromString)+import Test.HUnit (Assertion, assertEqual)+import Test.Hspec + spec :: Spec spec = do- describe "signatures" $ do- it "signs message" $- property signMsgTest- it "signs messages in parallel" $- property signMsgParTest- it "detects bad signature" $- property badSignatureTest- it "normalizes signatures" $- property normalizeSigTest- describe "serialization" $ do- it "serializes public key" $- property serializePubKeyTest- it "serializes public keys in parallel" $- property parSerializePubKeyTest- it "serializes DER signature" $- property serializeSigTest- it "serializes DER signatures in parallel" $- property parSerializeSigTest- it "serializes compact signature" $- property serializeCompactSigTest- it "serialize secret key" $- property serializeSecKeyTest- it "shows and reads public key" $- property (showRead :: PubKey -> Bool)- it "shows and reads secret key" $- property (showRead :: SecKey -> Bool)- it "shows and reads tweak" $- property (showReadTweak :: SecKey -> Bool)- it "shows and reads signature" $- property (showReadSig :: (SecKey, Msg) -> Bool)- it "shows and reads message" $- 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- it "negates tweak" $ property negateTweakTest--hexToBytes :: String -> BS.ByteString-hexToBytes = fromRight undefined . B16.decodeBase16 . B8.pack--isStringPubKey :: (PubKey, Bool) -> Bool-isStringPubKey (k, c) = k == fromString (cs hex) where- hex = B16.encodeBase16 $ exportPubKey c k--isStringSig :: (SecKey, Msg) -> Bool-isStringSig (k, m) = g == fromString (cs hex) where- g = signMsg k m- hex = B16.encodeBase16 $ exportSig g--isStringMsg :: Msg -> Bool-isStringMsg m = m == fromString (cs m') where- m' = B16.encodeBase16 $ getMsg m+ pure () -isStringSecKey :: SecKey -> Bool-isStringSecKey k = k == fromString (cs hex) where- hex = B16.encodeBase16 $ getSecKey k+-- 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 -isStringTweak :: SecKey -> Bool-isStringTweak k = t == fromString (cs hex) where- t = fromMaybe e . tweak $ getSecKey k- hex = B16.encodeBase16 $ getTweak t- e = error "Could not extract tweak from secret key"+-- hexToBytes :: String -> BS.ByteString+-- hexToBytes = fromRight undefined . decodeBase16 . B8.pack -showReadTweak :: SecKey -> Bool-showReadTweak k = showRead t where- t = tweak $ getSecKey k+-- 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+-- showReadSig :: (SecKey, Msg) -> Bool+-- showReadSig (k, m) = showRead sig+-- where+-- sig = signMsg k m -showRead :: (Show a, Read a, Eq a) => a -> Bool-showRead x = read (show x) == x+-- 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+-- signMsgTest :: (Msg, SecKey) -> Bool+-- 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+-- 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 :: (Msg, SecKey, PubKey) -> Bool+-- badSignatureTest (fm, fk, fp) = not $ verifySig fp fg fm+-- where+-- fg = signMsg fk fm -normalizeSigTest :: (Msg, SecKey) -> Bool-normalizeSigTest (fm, fk) = isNothing sig where- fg = signMsg fk fm- sig = normalizeSig fg+-- 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+-- serializePubKeyTest :: (PubKey, Bool) -> Bool+-- serializePubKeyTest (fp, b) =+-- case importPubKey $ exportPubKey b fp of+-- Just fp' -> fp == fp'+-- Nothing -> False -parSerializePubKeyTest :: [(PubKey, Bool)] -> Bool-parSerializePubKeyTest ps = runPar $ do- as <- mapM (spawnP . serializePubKeyTest) ps- and <$> mapM get as+-- 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+-- serializeSigTest :: (Msg, SecKey) -> Bool+-- serializeSigTest (fm, fk) =+-- case importSig $ exportSig fg of+-- Just fg' -> fg == fg'+-- Nothing -> False+-- where+-- fg = signMsg fk fm -parSerializeSigTest :: [(Msg, SecKey)] -> Bool-parSerializeSigTest ms = runPar $ do- as <- mapM (spawnP . serializeSigTest) ms- and <$> mapM get as+-- 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+-- serializeCompactSigTest :: (Msg, SecKey) -> Bool+-- serializeCompactSigTest (fm, fk) =+-- case importCompactSig $ exportCompactSig fg of+-- Just fg' -> fg == fg'+-- Nothing -> False+-- where+-- fg = signMsg fk fm -serializeSecKeyTest :: SecKey -> Bool-serializeSecKeyTest fk =- case secKey $ getSecKey fk of- Just fk' -> fk == fk'- Nothing -> False+-- 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"+-- 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" -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"+-- 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"+-- 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" -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"+-- 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"+-- 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" -combinePubKeyEmptyListTest :: Assertion-combinePubKeyEmptyListTest =- assertEqual "empty pubkey list must return Nothing" expected combined- where- expected = Nothing- combined = combinePubKeys []+-- 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 $ B16.decodeBase16 $ B8.pack- "0000000000000000000000000000000000000000000000000000000000000001"- Just oneTwk = tweak $ fromRight undefined $ B16.decodeBase16 $ B8.pack- "0000000000000000000000000000000000000000000000000000000000000001"- Just minusOneTwk = tweakNegate oneTwk- Just twoKey = tweakAddSecKey oneKey oneTwk- Just subtracted = tweakAddSecKey twoKey minusOneTwk+-- 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
+ test/Main.hs view
@@ -0,0 +1,18 @@+module Main where++import qualified Crypto.Secp256k1Prop as Secp256k1Prop+import GHC.IO.Encoding (setLocaleEncoding, utf8)+import Hedgehog (checkSequential)+import Hedgehog.Main+import qualified Spec+import Test.Hspec.Formatters+import Test.Hspec.Runner (Config (..), defaultConfig, hspecWith)+++main :: IO ()+main = do+ setLocaleEncoding utf8+ hspecWith defaultConfig{configFormatter = Just progress} Spec.spec+ defaultMain $+ [ checkSequential Secp256k1Prop.tests+ ]
test/Spec.hs view
@@ -1,1 +1,9 @@-{-# OPTIONS_GHC -F -pgmF hspec-discover #-}+module Spec where++import qualified Crypto.Secp256k1Spec as Secp256k1+import Test.Hspec+++spec :: Spec+spec = do+ Secp256k1.spec
+ test/Util.hs view
@@ -0,0 +1,12 @@+module Util where++import qualified Data.ByteArray.Encoding as BA+import Data.ByteString+++decodeBase16 :: ByteString -> Either String ByteString+decodeBase16 = BA.convertFromBase BA.Base16+++encodeBase16 :: ByteString -> ByteString+encodeBase16 = BA.convertToBase BA.Base16