{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} module Test.Cardano.Crypto.Wallet.SignSpec (tests) where import qualified Data.ByteString as BS import Foreign.C.Types (CInt (..), CSize (..)) import Foreign.Ptr (Ptr, castPtr) import System.IO.Unsafe (unsafePerformIO) import Test.Hspec import Cardano.Crypto.WalletHD.Encrypted foreign import ccall "cardano_crypto_ed25519_sign_open" c_ed25519_sign_open :: Ptr a -> CSize -> Ptr a -> Ptr a -> IO CInt verifySignature :: BS.ByteString -> BS.ByteString -> Signature -> Bool verifySignature :: ByteString -> ByteString -> Signature -> Bool verifySignature ByteString pub ByteString msg (Signature ByteString sig) = IO Bool -> Bool forall a. IO a -> a unsafePerformIO (IO Bool -> Bool) -> IO Bool -> Bool forall a b. (a -> b) -> a -> b $ ByteString -> (CStringLen -> IO Bool) -> IO Bool forall a. ByteString -> (CStringLen -> IO a) -> IO a BS.useAsCStringLen ByteString msg ((CStringLen -> IO Bool) -> IO Bool) -> (CStringLen -> IO Bool) -> IO Bool forall a b. (a -> b) -> a -> b $ \(Ptr CChar mp, Int ml) -> ByteString -> (Ptr CChar -> IO Bool) -> IO Bool forall a. ByteString -> (Ptr CChar -> IO a) -> IO a BS.useAsCString ByteString pub ((Ptr CChar -> IO Bool) -> IO Bool) -> (Ptr CChar -> IO Bool) -> IO Bool forall a b. (a -> b) -> a -> b $ \Ptr CChar pkp -> ByteString -> (Ptr CChar -> IO Bool) -> IO Bool forall a. ByteString -> (Ptr CChar -> IO a) -> IO a BS.useAsCString ByteString sig ((Ptr CChar -> IO Bool) -> IO Bool) -> (Ptr CChar -> IO Bool) -> IO Bool forall a b. (a -> b) -> a -> b $ \Ptr CChar sigp -> (CInt -> CInt -> Bool forall a. Eq a => a -> a -> Bool == CInt 0) (CInt -> Bool) -> IO CInt -> IO Bool forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Ptr Any -> CSize -> Ptr Any -> Ptr Any -> IO CInt forall a. Ptr a -> CSize -> Ptr a -> Ptr a -> IO CInt c_ed25519_sign_open (Ptr CChar -> Ptr Any forall a b. Ptr a -> Ptr b castPtr Ptr CChar mp) (forall a b. (Integral a, Num b) => a -> b fromIntegral @Int @CSize Int ml) (Ptr CChar -> Ptr Any forall a b. Ptr a -> Ptr b castPtr Ptr CChar pkp) (Ptr CChar -> Ptr Any forall a b. Ptr a -> Ptr b castPtr Ptr CChar sigp) testSeed :: BS.ByteString testSeed :: ByteString testSeed = Int -> Word8 -> ByteString BS.replicate Int 32 Word8 0x02 testCC :: BS.ByteString testCC :: ByteString testCC = Int -> Word8 -> ByteString BS.replicate Int 32 Word8 0xAB testPass :: BS.ByteString testPass :: ByteString testPass = Int -> Word8 -> ByteString BS.replicate Int 32 Word8 0x42 testMsg :: BS.ByteString testMsg :: ByteString testMsg = ByteString "cardano transaction body hash" tests :: Spec tests :: Spec tests = [Char] -> Spec -> Spec forall a. HasCallStack => [Char] -> SpecWith a -> SpecWith a describe [Char] "Sign" (Spec -> Spec) -> Spec -> Spec forall a b. (a -> b) -> a -> b $ do [Char] -> IO () -> SpecWith (Arg (IO ())) forall a. (HasCallStack, Example a) => [Char] -> a -> SpecWith (Arg a) it [Char] "encryptedSign produces a verifiable signature" (IO () -> SpecWith (Arg (IO ()))) -> IO () -> SpecWith (Arg (IO ())) forall a b. (a -> b) -> a -> b $ do Either XPrvError EncryptedKey res <- ByteString -> ByteString -> ByteString -> IO (Either XPrvError EncryptedKey) forall passphrase secret cc. (ByteArrayAccess passphrase, ByteArrayAccess secret, ByteArrayAccess cc) => secret -> passphrase -> cc -> IO (Either XPrvError EncryptedKey) encryptedCreate ByteString testSeed ByteString testPass ByteString testCC case Either XPrvError EncryptedKey res of Left XPrvError err -> HasCallStack => [Char] -> IO () [Char] -> IO () expectationFailure ([Char] -> IO ()) -> [Char] -> IO () forall a b. (a -> b) -> a -> b $ [Char] "encryptedCreate failed: " [Char] -> [Char] -> [Char] forall a. [a] -> [a] -> [a] ++ XPrvError -> [Char] forall a. Show a => a -> [Char] show XPrvError err Right EncryptedKey key -> do Either XPrvError Signature res' <- EncryptedKey -> ByteString -> ByteString -> IO (Either XPrvError Signature) forall passphrase msg. (ByteArrayAccess passphrase, ByteArrayAccess msg) => EncryptedKey -> passphrase -> msg -> IO (Either XPrvError Signature) encryptedSign EncryptedKey key ByteString testPass ByteString testMsg case Either XPrvError Signature res' of Left XPrvError err -> HasCallStack => [Char] -> IO () [Char] -> IO () expectationFailure ([Char] -> IO ()) -> [Char] -> IO () forall a b. (a -> b) -> a -> b $ [Char] "encryptedSign failed: " [Char] -> [Char] -> [Char] forall a. [a] -> [a] -> [a] ++ XPrvError -> [Char] forall a. Show a => a -> [Char] show XPrvError err Right Signature sig -> ByteString -> ByteString -> Signature -> Bool verifySignature (EncryptedKey -> ByteString encryptedPublic EncryptedKey key) ByteString testMsg Signature sig Bool -> Bool -> IO () forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO () `shouldBe` Bool True [Char] -> IO () -> SpecWith (Arg (IO ())) forall a. (HasCallStack, Example a) => [Char] -> a -> SpecWith (Arg a) it [Char] "encryptedSign fails with wrong passphrase" (IO () -> SpecWith (Arg (IO ()))) -> IO () -> SpecWith (Arg (IO ())) forall a b. (a -> b) -> a -> b $ do Either XPrvError EncryptedKey res <- ByteString -> ByteString -> ByteString -> IO (Either XPrvError EncryptedKey) forall passphrase secret cc. (ByteArrayAccess passphrase, ByteArrayAccess secret, ByteArrayAccess cc) => secret -> passphrase -> cc -> IO (Either XPrvError EncryptedKey) encryptedCreate ByteString testSeed ByteString testPass ByteString testCC case Either XPrvError EncryptedKey res of Left XPrvError err -> HasCallStack => [Char] -> IO () [Char] -> IO () expectationFailure ([Char] -> IO ()) -> [Char] -> IO () forall a b. (a -> b) -> a -> b $ [Char] "encryptedCreate failed: " [Char] -> [Char] -> [Char] forall a. [a] -> [a] -> [a] ++ XPrvError -> [Char] forall a. Show a => a -> [Char] show XPrvError err Right EncryptedKey key -> do Either XPrvError Signature r <- EncryptedKey -> ByteString -> ByteString -> IO (Either XPrvError Signature) forall passphrase msg. (ByteArrayAccess passphrase, ByteArrayAccess msg) => EncryptedKey -> passphrase -> msg -> IO (Either XPrvError Signature) encryptedSign EncryptedKey key (Int -> Word8 -> ByteString BS.replicate Int 32 Word8 0x00) ByteString testMsg Either XPrvError Signature r Either XPrvError Signature -> Either XPrvError Signature -> IO () forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO () `shouldBe` XPrvError -> Either XPrvError Signature forall a b. a -> Either a b Left XPrvError XPrvAuthenticationFailed [Char] -> IO () -> SpecWith (Arg (IO ())) forall a. (HasCallStack, Example a) => [Char] -> a -> SpecWith (Arg a) it [Char] "encryptedSign produces a 64-byte signature" (IO () -> SpecWith (Arg (IO ()))) -> IO () -> SpecWith (Arg (IO ())) forall a b. (a -> b) -> a -> b $ do Either XPrvError EncryptedKey res <- ByteString -> ByteString -> ByteString -> IO (Either XPrvError EncryptedKey) forall passphrase secret cc. (ByteArrayAccess passphrase, ByteArrayAccess secret, ByteArrayAccess cc) => secret -> passphrase -> cc -> IO (Either XPrvError EncryptedKey) encryptedCreate ByteString testSeed ByteString testPass ByteString testCC case Either XPrvError EncryptedKey res of Left XPrvError err -> HasCallStack => [Char] -> IO () [Char] -> IO () expectationFailure ([Char] -> IO ()) -> [Char] -> IO () forall a b. (a -> b) -> a -> b $ [Char] "encryptedCreate failed: " [Char] -> [Char] -> [Char] forall a. [a] -> [a] -> [a] ++ XPrvError -> [Char] forall a. Show a => a -> [Char] show XPrvError err Right EncryptedKey key -> do Either XPrvError Signature res' <- EncryptedKey -> ByteString -> ByteString -> IO (Either XPrvError Signature) forall passphrase msg. (ByteArrayAccess passphrase, ByteArrayAccess msg) => EncryptedKey -> passphrase -> msg -> IO (Either XPrvError Signature) encryptedSign EncryptedKey key ByteString testPass ByteString testMsg case Either XPrvError Signature res' of Left XPrvError err -> HasCallStack => [Char] -> IO () [Char] -> IO () expectationFailure ([Char] -> IO ()) -> [Char] -> IO () forall a b. (a -> b) -> a -> b $ [Char] "encryptedSign failed: " [Char] -> [Char] -> [Char] forall a. [a] -> [a] -> [a] ++ XPrvError -> [Char] forall a. Show a => a -> [Char] show XPrvError err Right (Signature ByteString s) -> ByteString -> Int BS.length ByteString s Int -> Int -> IO () forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO () `shouldBe` Int 64 [Char] -> IO () -> SpecWith (Arg (IO ())) forall a. (HasCallStack, Example a) => [Char] -> a -> SpecWith (Arg a) it [Char] "encryptedSign after passphrase change produces a verifiable signature" (IO () -> SpecWith (Arg (IO ()))) -> IO () -> SpecWith (Arg (IO ())) forall a b. (a -> b) -> a -> b $ do Either XPrvError EncryptedKey res <- ByteString -> ByteString -> ByteString -> IO (Either XPrvError EncryptedKey) forall passphrase secret cc. (ByteArrayAccess passphrase, ByteArrayAccess secret, ByteArrayAccess cc) => secret -> passphrase -> cc -> IO (Either XPrvError EncryptedKey) encryptedCreate ByteString testSeed ByteString testPass ByteString testCC case Either XPrvError EncryptedKey res of Left XPrvError err -> HasCallStack => [Char] -> IO () [Char] -> IO () expectationFailure ([Char] -> IO ()) -> [Char] -> IO () forall a b. (a -> b) -> a -> b $ [Char] "encryptedCreate failed: " [Char] -> [Char] -> [Char] forall a. [a] -> [a] -> [a] ++ XPrvError -> [Char] forall a. Show a => a -> [Char] show XPrvError err Right EncryptedKey key -> do let newPass :: ByteString newPass = Int -> Word8 -> ByteString BS.replicate Int 32 Word8 0xFF Either XPrvError EncryptedKey res' <- ByteString -> ByteString -> EncryptedKey -> IO (Either XPrvError EncryptedKey) forall oldPassPhrase newPassPhrase. (ByteArrayAccess oldPassPhrase, ByteArrayAccess newPassPhrase) => oldPassPhrase -> newPassPhrase -> EncryptedKey -> IO (Either XPrvError EncryptedKey) encryptedChangePass ByteString testPass ByteString newPass EncryptedKey key case Either XPrvError EncryptedKey res' of Left XPrvError err -> HasCallStack => [Char] -> IO () [Char] -> IO () expectationFailure ([Char] -> IO ()) -> [Char] -> IO () forall a b. (a -> b) -> a -> b $ [Char] "encryptedChangePass failed: " [Char] -> [Char] -> [Char] forall a. [a] -> [a] -> [a] ++ XPrvError -> [Char] forall a. Show a => a -> [Char] show XPrvError err Right EncryptedKey key' -> do Either XPrvError Signature res'' <- EncryptedKey -> ByteString -> ByteString -> IO (Either XPrvError Signature) forall passphrase msg. (ByteArrayAccess passphrase, ByteArrayAccess msg) => EncryptedKey -> passphrase -> msg -> IO (Either XPrvError Signature) encryptedSign EncryptedKey key' ByteString newPass ByteString testMsg case Either XPrvError Signature res'' of Left XPrvError err -> HasCallStack => [Char] -> IO () [Char] -> IO () expectationFailure ([Char] -> IO ()) -> [Char] -> IO () forall a b. (a -> b) -> a -> b $ [Char] "encryptedSign after changePass failed: " [Char] -> [Char] -> [Char] forall a. [a] -> [a] -> [a] ++ XPrvError -> [Char] forall a. Show a => a -> [Char] show XPrvError err Right Signature sig -> ByteString -> ByteString -> Signature -> Bool verifySignature (EncryptedKey -> ByteString encryptedPublic EncryptedKey key') ByteString testMsg Signature sig Bool -> Bool -> IO () forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO () `shouldBe` Bool True [Char] -> IO () -> SpecWith (Arg (IO ())) forall a. (HasCallStack, Example a) => [Char] -> a -> SpecWith (Arg a) it [Char] "signature from original key verifies against public key preserved by passphrase change" (IO () -> SpecWith (Arg (IO ()))) -> IO () -> SpecWith (Arg (IO ())) forall a b. (a -> b) -> a -> b $ do Either XPrvError EncryptedKey res <- ByteString -> ByteString -> ByteString -> IO (Either XPrvError EncryptedKey) forall passphrase secret cc. (ByteArrayAccess passphrase, ByteArrayAccess secret, ByteArrayAccess cc) => secret -> passphrase -> cc -> IO (Either XPrvError EncryptedKey) encryptedCreate ByteString testSeed ByteString testPass ByteString testCC case Either XPrvError EncryptedKey res of Left XPrvError err -> HasCallStack => [Char] -> IO () [Char] -> IO () expectationFailure ([Char] -> IO ()) -> [Char] -> IO () forall a b. (a -> b) -> a -> b $ [Char] "encryptedCreate failed: " [Char] -> [Char] -> [Char] forall a. [a] -> [a] -> [a] ++ XPrvError -> [Char] forall a. Show a => a -> [Char] show XPrvError err Right EncryptedKey key -> do Either XPrvError Signature res' <- EncryptedKey -> ByteString -> ByteString -> IO (Either XPrvError Signature) forall passphrase msg. (ByteArrayAccess passphrase, ByteArrayAccess msg) => EncryptedKey -> passphrase -> msg -> IO (Either XPrvError Signature) encryptedSign EncryptedKey key ByteString testPass ByteString testMsg case Either XPrvError Signature res' of Left XPrvError err -> HasCallStack => [Char] -> IO () [Char] -> IO () expectationFailure ([Char] -> IO ()) -> [Char] -> IO () forall a b. (a -> b) -> a -> b $ [Char] "encryptedSign failed: " [Char] -> [Char] -> [Char] forall a. [a] -> [a] -> [a] ++ XPrvError -> [Char] forall a. Show a => a -> [Char] show XPrvError err Right Signature sig -> do let newPass :: ByteString newPass = Int -> Word8 -> ByteString BS.replicate Int 32 Word8 0xFF Either XPrvError EncryptedKey res'' <- ByteString -> ByteString -> EncryptedKey -> IO (Either XPrvError EncryptedKey) forall oldPassPhrase newPassPhrase. (ByteArrayAccess oldPassPhrase, ByteArrayAccess newPassPhrase) => oldPassPhrase -> newPassPhrase -> EncryptedKey -> IO (Either XPrvError EncryptedKey) encryptedChangePass ByteString testPass ByteString newPass EncryptedKey key case Either XPrvError EncryptedKey res'' of Left XPrvError err -> HasCallStack => [Char] -> IO () [Char] -> IO () expectationFailure ([Char] -> IO ()) -> [Char] -> IO () forall a b. (a -> b) -> a -> b $ [Char] "encryptedChangePass failed: " [Char] -> [Char] -> [Char] forall a. [a] -> [a] -> [a] ++ XPrvError -> [Char] forall a. Show a => a -> [Char] show XPrvError err Right EncryptedKey key' -> ByteString -> ByteString -> Signature -> Bool verifySignature (EncryptedKey -> ByteString encryptedPublic EncryptedKey key') ByteString testMsg Signature sig Bool -> Bool -> IO () forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO () `shouldBe` Bool True