morley-1.4.0: test/Test/Tezos/Crypto.hs
-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ
-- | Tests for 'Tezos.Crypto'.
module Test.Tezos.Crypto
( test_Roundtrip
, test_Signing
, unit_Key_Hashing
) where
import Fmt (pretty)
import Test.Hspec (Expectation, shouldSatisfy)
import Test.HUnit (Assertion, (@?=))
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (testCase)
import Tezos.Crypto
import Test.Util.Hedgehog (aesonRoundtrip, roundtripTreeSTB)
test_Roundtrip :: [TestTree]
test_Roundtrip =
[ testGroup "parse . format ≡ pure"
[ roundtripTreeSTB genPublicKey formatPublicKey parsePublicKey
, roundtripTreeSTB genSignature formatSignature parseSignature
, roundtripTreeSTB genKeyHash formatKeyHash parseKeyHash
]
, testGroup "JSON encoding/deconding"
[ aesonRoundtrip genPublicKey
, aesonRoundtrip genSignature
, aesonRoundtrip genKeyHash
]
]
----------------------------------------------------------------------------
-- Signing
----------------------------------------------------------------------------
test_Signing :: [TestTree]
test_Signing =
[ testGroup "Formatting"
[ testGroup "parsePublicKey"
[ testCase "Successfully parses valid sample data" $
mapM_ (parsePublicKeySample . sdPublicKey) sampleSignatures
, testCase "Fails to parse invalid data" $ do
parsePublicKeyInvalid ""
parsePublicKeyInvalid "aaa"
parsePublicKeyInvalid
"edpkuwTWKgQNnhR5v17H2DYHbfcxYepARyrPGbf1tbMoGQAj8Ljr3v"
parsePublicKeyInvalid
"edsigtrs8bK7vNfiR4Kd9dWasVa1bAWaQSu2ipnmLGZuwQa8ktCEMYVKqbWsbJ7zTS8dgYT9tiSUKorWCPFHosL5zPsiDwBQ6vb"
parsePublicKeyInvalid
"sppk7Ze7NMs6EHF2uB8qq8GrEgJvE9PWYkUijN3LcesafzQuGyniHBd"
parsePublicKeyInvalid
"spsig1Ng2bs4PXCbjaFGuojk9K5Pt3CkfbUZyHLLrBxHSmTqrUUxQggi4yJBit3Ljqnqr61UpdTewTLiu4schSCfZvaRwu412oZ"
parsePublicKeyInvalid
"p2pk68C6tJr7pNLvgBH63K3hBVoztCPCA36zcWhXFUGywQJTjYbfpxk"
parsePublicKeyInvalid
"p2sigRmXDp38VNVaEQH28LYukfLPn8QB5hPEberhvQrrUpRscDZJrrApbRh2u46PTVTwKXjxTLKNN9dyLhPQU6U6jWPGxe4d9v"
]
, testGroup "parseSignature"
[ testCase "Successfully parses valid sample data" $
mapM_ (parseSignatureSample . sdSignature) sampleSignatures
, testCase "Fails to parse invalid data" $ do
parseSignatureInvalid ""
parseSignatureInvalid "bbb"
parseSignatureInvalid
"edpkuwTWKgQNnhR5v17H2DYHbfcxYepARyrPGbf1tbMoGQAj8Ljr3V"
parseSignatureInvalid
"edsigtrs8bK7vNfiR4Kd9dWasVa1bAWaQSu2ipnmLGZuwQa8ktCEMYVKqbWsbJ7zTS8dgYT9tiSUKorWCPFHosL5zPsiDwBQ6vB"
parseSignatureInvalid
"sppk7cdA7Afj8MvuBFrP6KsTLfbM5DtH9GwYaRZwCf5tBVCz6UKGQFR"
parseSignatureInvalid
"spsig1Ng2bs4PXCbjaFGuojk9K5Pt3ckfbUZyHLLrBxHSmTqrUUxQggi4yJBit3Ljqnqr61UpdTewTLiu4schSCfZvaRwu412oZ"
parseSignatureInvalid
"p2pk68C6tJr7pNLvgBH63K3hBVoztCPCA36zcWhXFUGywQJTjYBfpxk"
parseSignatureInvalid
"p2sigRmXDp38VNVaEQH28LYukfLPn8QB5hPEberhvQrrUpRscDZJrrApbrh2u46PTVTwKXjxTLKNN9dyLhPQU6U6jWPGxe4d9v"
]
]
, testCase "checkSignature" $ mapM_ checkSignatureSample sampleSignatures
]
data SignatureData = SignatureData
{ sdPublicKey :: Text
, sdBytes :: ByteString
, sdSignature :: Text
, sdValid :: Bool
}
-- These signatures have been produced by `tezos-client`.
sampleSignatures :: [SignatureData]
sampleSignatures =
[ SignatureData
{ sdPublicKey = "edpkuwTWKgQNnhR5v17H2DYHbfcxYepARyrPGbf1tbMoGQAj8Ljr3V"
, sdBytes = "\0"
, sdSignature = "edsigtrs8bK7vNfiR4Kd9dWasVa1bAWaQSu2ipnmLGZuwQa8ktCEMYVKqbWsbJ7zTS8dgYT9tiSUKorWCPFHosL5zPsiDwBQ6vb"
, sdValid = True
}
, SignatureData
{ sdPublicKey = "edpkupH22qrz1sNQt5HSvWfRJFfyJ9dhNbZLptE6GR4JbMoBcACZZH"
, sdBytes = "\0\0"
, sdSignature = "edsigtj8LhbJ2B3qhZvqzA49raG65dydFcWZW9b9L7ntF3bb29zxaBFFL8SM1jeBUY66hG122znyVA4wpzLdwxcNZwSK3Szu7iD"
, sdValid = True
}
, SignatureData
{ sdPublicKey = "edpkupH22qrz1sNQt5HSvWfRJFfyJ9dhNbZLptE6GR4JbMoBcACZZH"
, sdBytes = "kot"
, sdSignature = "edsigtrs8bK7vNfiR4Kd9dWasVa1bAWaQSu2ipnmLGZuwQa8ktCEMYVKqbWsbJ7zTS8dgYT9tiSUKorWCPFHosL5zPsiDwBQ6vb"
, sdValid = False
}
]
<>
[ SignatureData
{ sdPublicKey = "sppk7cdA7Afj8MvuBFrP6KsTLfbM5DtH9GwYaRZwCf5tBVCz6UKGQFR"
, sdBytes = "\0"
, sdSignature = "spsig1Ng2bs4PXCbjaFGuojk9K5Pt3CkfbUZyHLLrBxHSmTqrUUxQggi4yJBit3Ljqnqr61UpdTewTLiu4schSCfZvaRwu412oZ"
-- TODO (#18): should be valid, but crypto is not implemented yet.
, sdValid = False
}
, SignatureData
{ sdPublicKey = "sppk7Ze7NMs6EHF2uB8qq8GrEgJvE9PWYkUijN3LcesafzQuGyniHBD"
, sdBytes = "\0\0"
, sdSignature = "spsig1aP7D9oheiraNuM1NgziMPSPKS1F9kSWyFqkE8WigaeU5Uzb3LwY34F7Y7RsF6sY5ZfUda1NWdrC5V4KEfm9jeU1eniHmy"
-- TODO (#18): should be valid, but crypto is not implemented yet.
, sdValid = False
}
, SignatureData
{ sdPublicKey = "sppk7Ze7NMs6EHF2uB8qq8GrEgJvE9PWYkUijN3LcesafzQuGyniHBD"
, sdBytes = "kot"
, sdSignature = "spsig1PJ9LG9ovbpVJ3CucFWL7iBaQZjqEWMvppgLjYiiSwzcxpuUqHr2BUVZDUwkmZKzMNDWJdgtyhYiicz197TbhS4LPpnxDY"
, sdValid = False
}
]
<>
-- TODO (#18): add valid samples for P256
[ SignatureData
{ sdPublicKey = "p2pk68C6tJr7pNLvgBH63K3hBVoztCPCA36zcWhXFUGywQJTjYBfpxk"
, sdBytes = "kot"
, sdSignature = "p2sigRmXDp38VNVaEQH28LYukfLPn8QB5hPEberhvQrrUpRscDZJrrApbRh2u46PTVTwKXjxTLKNN9dyLhPQU6U6jWPGxe4d9v"
, sdValid = False
}
]
parsePublicKeySample :: Text -> Expectation
parsePublicKeySample publicKeyText =
parsePublicKey publicKeyText `shouldSatisfy` isRight
parsePublicKeyInvalid :: Text -> Expectation
parsePublicKeyInvalid invalidPublicKeyText =
parsePublicKey invalidPublicKeyText `shouldSatisfy` isLeft
parseSignatureSample :: Text -> Expectation
parseSignatureSample publicKeyText =
parseSignature publicKeyText `shouldSatisfy` isRight
parseSignatureInvalid :: Text -> Expectation
parseSignatureInvalid invalidSignatureText =
parseSignature invalidSignatureText `shouldSatisfy` isLeft
checkSignatureSample :: SignatureData -> Assertion
checkSignatureSample sd =
checkSignature publicKey signature (sdBytes sd) @?= sdValid sd
where
publicKey = partialParse parsePublicKey (sdPublicKey sd)
signature = partialParse parseSignature (sdSignature sd)
----------------------------------------------------------------------------
-- Key hashing
----------------------------------------------------------------------------
unit_Key_Hashing :: Assertion
unit_Key_Hashing = mapM_ hashKeySample sampleKeyHashes
sampleKeyHashes :: [(Text, Text)]
sampleKeyHashes =
[ ( "edpkupH22qrz1sNQt5HSvWfRJFfyJ9dhNbZLptE6GR4JbMoBcACZZH"
, "tz1NaZzLvdDBLfV2LWC6F4SJfNV2jHdZJXkJ"
)
, ( "edpkuwTWKgQNnhR5v17H2DYHbfcxYepARyrPGbf1tbMoGQAj8Ljr3V"
, "tz1Yz3VPaCNB5FjhdEVnSoN8Xv3ZM8g2LYhw"
)
, ( "sppk7cdA7Afj8MvuBFrP6KsTLfbM5DtH9GwYaRZwCf5tBVCz6UKGQFR"
, "tz2EfqCbLmpfv7mNiLcMmhxAwdgHtPTcwR4W"
)
, ( "sppk7Ze7NMs6EHF2uB8qq8GrEgJvE9PWYkUijN3LcesafzQuGyniHBD"
, "tz2Darj3LyQzekU98ZK8diHvuyn1YYjcHpc6"
)
, ( "p2pk67K1dwkDFPB63RZU5H3SoMCvmJdKZDZszc7U4FiGKN2YypKdDCB"
, "tz3S7wbUwQV581kroR81fYbgDBskFicZ6czW"
)
, ( "p2pk68C6tJr7pNLvgBH63K3hBVoztCPCA36zcWhXFUGywQJTjYBfpxk"
, "tz3QEbmdCdsMcnUo2rNjXdbKwg5tyack3goN"
)
]
hashKeySample :: (Text, Text) -> Assertion
hashKeySample (pkText, keyHashText) = hashKey pk @?= keyHash
where
pk = partialParse parsePublicKey pkText
keyHash = partialParse parseKeyHash keyHashText
----------------------------------------------------------------------------
-- Utils
----------------------------------------------------------------------------
-- If passed textual data is invalid, it's a programmer mistake.
partialParse :: (Text -> Either CryptoParseError a) -> Text -> a
partialParse parse = either (error . pretty) id . parse