libsecp256k1-0.2.0: test/Crypto/Secp256k1Spec.hs
module Crypto.Secp256k1Spec (spec) where
import Control.Monad.Par qualified as P
import Crypto.Secp256k1
import Crypto.Secp256k1.Internal
import Data.ByteArray.Encoding (Base (Base16), convertFromBase)
import Data.ByteString qualified as BS
import Data.ByteString.Char8 qualified as B8
import Data.Either (fromRight)
import Data.Maybe (fromMaybe, isJust, isNothing)
import Data.String (fromString)
import Test.HUnit (Assertion, assertEqual)
import Test.Hspec
spec :: Spec
spec = do
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
signMsgTest :: (BS.ByteString, SecKey) -> Bool
signMsgTest (fm, fk) = (ecdsaVerify fm fp <$> fg) == Just True
where
fp = derivePubKey fk
fg = ecdsaSign fk fm
signMsgParTest :: [(BS.ByteString, SecKey)] -> Bool
signMsgParTest xs = P.runPar $ do
ys <- mapM (P.spawnP . signMsgTest) xs
and <$> mapM P.get ys
badSignatureTest :: (BS.ByteString, SecKey, PubKeyXY) -> Bool
badSignatureTest (fm, fk, fp) = (ecdsaVerify fm fp <$> fg) == Just False
where
fg = ecdsaSign fk fm
normalizeSigTest :: (BS.ByteString, SecKey) -> Bool
normalizeSigTest (fm, fk) = sig == fg
where
fg = ecdsaSign fk fm
sig = ecdsaNormalizeSignature <$> fg
serializePubKeyTest :: (PubKeyXY, Bool) -> Bool
serializePubKeyTest (fp, b) =
case importPubKeyXY $ exportPubKeyXY b fp of
Just fp' -> fp == fp'
Nothing -> False
parSerializePubKeyTest :: [(PubKeyXY, Bool)] -> Bool
parSerializePubKeyTest ps = P.runPar $ do
as <- mapM (P.spawnP . serializePubKeyTest) ps
and <$> mapM P.get as
serializeSigTest :: (BS.ByteString, SecKey) -> Bool
serializeSigTest (fm, fk) =
(fg >>= importSignatureDer . exportSignatureDer) == fg && isJust fg
where
fg = ecdsaSign fk fm
parSerializeSigTest :: [(BS.ByteString, SecKey)] -> Bool
parSerializeSigTest ms = P.runPar $ do
as <- mapM (P.spawnP . serializeSigTest) ms
and <$> mapM P.get as
serializeCompactSigTest :: (BS.ByteString, SecKey) -> Bool
serializeCompactSigTest (fm, fk) =
(fg >>= importSignatureCompact . exportSignatureCompact) == fg && isJust fg
where
fg = ecdsaSign fk fm
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