From ab5121a1910dc5b1d27940f1c4eaf16ec00db356 Mon Sep 17 00:00:00 2001 From: Luke Nadur <19835357+intricate@users.noreply.github.com> Date: Tue, 8 Sep 2020 12:38:16 -0400 Subject: [PATCH 1/3] Add command for converting cardano-address signing keys --- .../src/Cardano/CLI/Shelley/Commands.hs | 11 ++ .../src/Cardano/CLI/Shelley/Parsers.hs | 31 ++++ .../src/Cardano/CLI/Shelley/Run/Key.hs | 146 +++++++++++++++++- 3 files changed, 184 insertions(+), 4 deletions(-) diff --git a/cardano-cli/src/Cardano/CLI/Shelley/Commands.hs b/cardano-cli/src/Cardano/CLI/Shelley/Commands.hs index ab4b4b126bc..72f0f188e0c 100644 --- a/cardano-cli/src/Cardano/CLI/Shelley/Commands.hs +++ b/cardano-cli/src/Cardano/CLI/Shelley/Commands.hs @@ -22,6 +22,7 @@ module Cardano.CLI.Shelley.Commands , AddressKeyType (..) , ByronKeyType (..) , ByronKeyFormat (..) + , CardanoAddressKeyType (..) , GenesisDir (..) , TxInCount (..) , TxOutCount (..) @@ -136,6 +137,7 @@ data KeyCmd | KeyConvertITNStakeKey SomeKeyFile OutputFile | KeyConvertITNExtendedToStakeKey SomeKeyFile OutputFile | KeyConvertITNBip32ToStakeKey SomeKeyFile OutputFile + | KeyConvertCardanoAddressSigningKey CardanoAddressKeyType SigningKeyFile OutputFile deriving (Eq, Show) renderKeyCmd :: KeyCmd -> Text @@ -148,6 +150,7 @@ renderKeyCmd cmd = KeyConvertITNStakeKey {} -> "key convert-itn-key" KeyConvertITNExtendedToStakeKey {} -> "key convert-itn-extended-key" KeyConvertITNBip32ToStakeKey {} -> "key convert-itn-bip32-key" + KeyConvertCardanoAddressSigningKey {} -> "key convert-cardano-address-signing-key" data TransactionCmd = TxBuildRaw @@ -395,6 +398,14 @@ data ByronKeyFormat = NonLegacyByronKeyFormat | LegacyByronKeyFormat deriving (Eq, Show) +-- | The type of @cardano-address@ key. +data CardanoAddressKeyType + = CardanoAddressShelleyPaymentKey + | CardanoAddressShelleyStakeKey + | CardanoAddressIcarusPaymentKey + | CardanoAddressByronPaymentKey + deriving (Eq, Show) + newtype OpCertCounterFile = OpCertCounterFile FilePath deriving (Eq, Show) diff --git a/cardano-cli/src/Cardano/CLI/Shelley/Parsers.hs b/cardano-cli/src/Cardano/CLI/Shelley/Parsers.hs index 8fe9288a4fa..7ee7669c3a0 100644 --- a/cardano-cli/src/Cardano/CLI/Shelley/Parsers.hs +++ b/cardano-cli/src/Cardano/CLI/Shelley/Parsers.hs @@ -273,6 +273,11 @@ pKeyCmd = Opt.progDesc $ "Convert an Incentivized Testnet (ITN) BIP32 " ++ "(Ed25519Bip32) signing key to a corresponding " ++ "Shelley stake signing key" + + , Opt.command "convert-cardano-address-key" $ + Opt.info pKeyConvertCardanoAddressSigningKey $ + Opt.progDesc $ "Convert a cardano-address extended signing key " + ++ "to a corresponding Shelley-format key." ] where pKeyGetVerificationKey :: Parser KeyCmd @@ -411,6 +416,32 @@ pKeyCmd = <> Opt.completer (Opt.bashCompleter "file") ) + pKeyConvertCardanoAddressSigningKey :: Parser KeyCmd + pKeyConvertCardanoAddressSigningKey = + KeyConvertCardanoAddressSigningKey + <$> pCardanoAddressKeyType + <*> pSigningKeyFile Input + <*> pOutputFile + + pCardanoAddressKeyType :: Parser CardanoAddressKeyType + pCardanoAddressKeyType = + Opt.flag' CardanoAddressShelleyPaymentKey + ( Opt.long "shelley-payment-key" + <> Opt.help "Use a Shelley-era extended payment key." + ) + <|> Opt.flag' CardanoAddressShelleyStakeKey + ( Opt.long "shelley-stake-key" + <> Opt.help "Use a Shelley-era extended stake key." + ) + <|> Opt.flag' CardanoAddressIcarusPaymentKey + ( Opt.long "icarus-payment-key" + <> Opt.help "Use a Byron-era extended payment key formatted in the Icarus style." + ) + <|> Opt.flag' CardanoAddressByronPaymentKey + ( Opt.long "byron-payment-key" + <> Opt.help "Use a Byron-era extended payment key formatted in the deprecated Byron style." + ) + pTransaction :: Parser TransactionCmd pTransaction = Opt.subparser $ diff --git a/cardano-cli/src/Cardano/CLI/Shelley/Run/Key.hs b/cardano-cli/src/Cardano/CLI/Shelley/Run/Key.hs index 45a704a9aa7..a8b739a0d21 100644 --- a/cardano-cli/src/Cardano/CLI/Shelley/Run/Key.hs +++ b/cardano-cli/src/Cardano/CLI/Shelley/Run/Key.hs @@ -32,7 +32,7 @@ import qualified Cardano.Crypto.Signing as Byron import qualified Shelley.Spec.Ledger.Keys as Shelley import Cardano.Api.Shelley.ITN (xprvFromBytes) -import Cardano.Api.Typed hiding (Bech32DecodeError (..)) +import Cardano.Api.Typed import Cardano.CLI.Byron.Key (CardanoEra (..)) import qualified Cardano.CLI.Byron.Key as Byron @@ -53,6 +53,8 @@ data ShelleyKeyCmdError -- error type isn't exported. | ShelleyKeyCmdItnKeyConvError !ConversionError | ShelleyKeyCmdWrongKeyTypeError + | ShelleyKeyCmdCardanoAddressSigningKeyFileError + !(FileError CardanoAddressSigningKeyConversionError) deriving Show renderShelleyKeyCmdError :: ShelleyKeyCmdError -> Text @@ -66,6 +68,8 @@ renderShelleyKeyCmdError err = ShelleyKeyCmdItnKeyConvError convErr -> renderConversionError convErr ShelleyKeyCmdWrongKeyTypeError -> Text.pack "Please use a signing key file \ \when converting ITN BIP32 or Extended keys" + ShelleyKeyCmdCardanoAddressSigningKeyFileError fileErr -> + Text.pack (displayError fileErr) runKeyCmd :: KeyCmd -> ExceptT ShelleyKeyCmdError IO () runKeyCmd cmd = @@ -89,6 +93,8 @@ runKeyCmd cmd = KeyConvertITNBip32ToStakeKey itnPrivKeyFile outFile -> runConvertITNBip32ToStakeKey itnPrivKeyFile outFile + KeyConvertCardanoAddressSigningKey keyType skfOld skfNew -> + runConvertCardanoAddressSigningKey keyType skfOld skfNew runGetVerificationKey :: SigningKeyFile -> VerificationKeyFile @@ -439,7 +445,7 @@ runConvertITNBip32ToStakeKey (ASigningKeyFile (SigningKeyFile sk)) (OutputFile o $ writeFileTextEnvelope outFile Nothing skey data ConversionError - = Bech32DecodingError + = Bech32KeyDecodingError -- ^ Bech32 key !Text !Bech32.DecodingError @@ -453,7 +459,7 @@ data ConversionError renderConversionError :: ConversionError -> Text renderConversionError err = case err of - Bech32DecodingError key decErr -> + Bech32KeyDecodingError key decErr -> "Error decoding Bech32 key: " <> key <> " Error: " <> textShow decErr Bech32ErrorExtractingByes dp -> "Unable to extract bytes from: " <> Bech32.dataPartToText dp @@ -510,7 +516,7 @@ decodeBech32Key :: Text (Bech32.HumanReadablePart, Bech32.DataPart, ByteString) decodeBech32Key key = case Bech32.decodeLenient key of - Left err -> Left $ Bech32DecodingError key err + Left err -> Left $ Bech32KeyDecodingError key err Right (hRpart, dataPart) -> case Bech32.dataPartToBytes dataPart of Nothing -> Left $ ITNError hRpart dataPart Just bs -> Right (hRpart, dataPart, bs) @@ -521,3 +527,135 @@ readFileITNKey fp = do case eStr of Left e -> return . Left $ Bech32ReadError fp e Right str -> return . Right . Text.concat $ Text.words str + +-------------------------------------------------------------------------------- +-- `cardano-address` extended signing key conversions +-------------------------------------------------------------------------------- + +runConvertCardanoAddressSigningKey + :: CardanoAddressKeyType + -> SigningKeyFile + -> OutputFile + -> ExceptT ShelleyKeyCmdError IO () +runConvertCardanoAddressSigningKey keyType skFile (OutputFile outFile) = do + sKey <- firstExceptT ShelleyKeyCmdCardanoAddressSigningKeyFileError + . newExceptT + $ readSomeCardanoAddressSigningKeyFile keyType skFile + firstExceptT ShelleyKeyCmdWriteFileError . newExceptT + $ writeSomeCardanoAddressSigningKeyFile outFile sKey + +-- | Some kind of signing key that was converted from a @cardano-address@ +-- signing key. +data SomeCardanoAddressSigningKey + = ACardanoAddrShelleyPaymentSigningKey !(SigningKey PaymentExtendedKey) + | ACardanoAddrShelleyStakeSigningKey !(SigningKey StakeExtendedKey) + | ACardanoAddrByronSigningKey !(SigningKey ByronKey) + +-- | An error that can occur while converting a @cardano-address@ extended +-- signing key. +data CardanoAddressSigningKeyConversionError + = CardanoAddressSigningKeyBech32DecodeError !Bech32DecodeError + -- ^ There was an error in decoding the string as Bech32. + | CardanoAddressSigningKeyDeserialisationError !ByteString + -- ^ There was an error in converting the @cardano-address@ extended signing + -- key. + deriving (Show, Eq) + +instance Error CardanoAddressSigningKeyConversionError where + displayError = Text.unpack . renderCardanoAddressSigningKeyConversionError + +-- | Render an error message for a 'CardanoAddressSigningKeyConversionError'. +renderCardanoAddressSigningKeyConversionError + :: CardanoAddressSigningKeyConversionError + -> Text +renderCardanoAddressSigningKeyConversionError err = + case err of + CardanoAddressSigningKeyBech32DecodeError decErr -> + Text.pack (displayError decErr) + CardanoAddressSigningKeyDeserialisationError _bs -> + -- Sensitive data, such as the signing key, is purposely not included in + -- the error message. + "Error deserialising cardano-address signing key." + +-- | Decode a Bech32-encoded string. +decodeBech32 + :: Text + -> Either Bech32DecodeError (Bech32.HumanReadablePart, Bech32.DataPart, ByteString) +decodeBech32 bech32Str = + case Bech32.decodeLenient bech32Str of + Left err -> Left (Bech32DecodingError err) + Right (hrPart, dataPart) -> + case Bech32.dataPartToBytes dataPart of + Nothing -> + Left $ Bech32DataPartToBytesError (Bech32.dataPartToText dataPart) + Just bs -> Right (hrPart, dataPart, bs) + +-- | Convert a Ed25519 BIP32 extended signing key (96 bytes) to a @cardano-crypto@ +-- style extended signing key. +-- +-- Note that both the ITN and @cardano-address@ use this key format. +convertBip32SigningKey + :: ByteString + -> Either CardanoAddressSigningKeyConversionError Crypto.XPrv +convertBip32SigningKey signingKeyBs = + case xprvFromBytes signingKeyBs of + Just xPrv -> Right xPrv + Nothing -> + Left $ CardanoAddressSigningKeyDeserialisationError signingKeyBs + +-- | Read a file containing a Bech32-encoded Ed25519 BIP32 extended signing +-- key. +readBech32Bip32SigningKeyFile + :: SigningKeyFile + -> IO (Either (FileError CardanoAddressSigningKeyConversionError) Crypto.XPrv) +readBech32Bip32SigningKeyFile (SigningKeyFile fp) = do + eStr <- Exception.try $ readFile fp + case eStr of + Left e -> pure . Left $ FileIOError fp e + Right str -> + case decodeBech32 (Text.concat $ Text.words str) of + Left err -> + pure $ Left $ + FileError fp (CardanoAddressSigningKeyBech32DecodeError err) + Right (_hrPart, _dataPart, bs) -> + pure $ first (FileError fp) (convertBip32SigningKey bs) + +-- | Read a file containing a Bech32-encoded @cardano-address@ extended +-- signing key. +readSomeCardanoAddressSigningKeyFile + :: CardanoAddressKeyType + -> SigningKeyFile + -> IO (Either (FileError CardanoAddressSigningKeyConversionError) SomeCardanoAddressSigningKey) +readSomeCardanoAddressSigningKeyFile keyType skFile = do + xPrv <- readBech32Bip32SigningKeyFile skFile + pure (toSomeCardanoAddressSigningKey <$> xPrv) + where + toSomeCardanoAddressSigningKey :: Crypto.XPrv -> SomeCardanoAddressSigningKey + toSomeCardanoAddressSigningKey xPrv = + case keyType of + CardanoAddressShelleyPaymentKey -> + ACardanoAddrShelleyPaymentSigningKey + (PaymentExtendedSigningKey xPrv) + CardanoAddressShelleyStakeKey -> + ACardanoAddrShelleyStakeSigningKey (StakeExtendedSigningKey xPrv) + CardanoAddressIcarusPaymentKey -> + ACardanoAddrByronSigningKey $ + ByronSigningKey (Byron.SigningKey xPrv) + CardanoAddressByronPaymentKey -> + ACardanoAddrByronSigningKey $ + ByronSigningKey (Byron.SigningKey xPrv) + +-- | Write a text envelope formatted file containing a @cardano-address@ +-- extended signing key, but converted to a format supported by @cardano-cli@. +writeSomeCardanoAddressSigningKeyFile + :: FilePath + -> SomeCardanoAddressSigningKey + -> IO (Either (FileError ()) ()) +writeSomeCardanoAddressSigningKeyFile outFile skey = + case skey of + ACardanoAddrShelleyPaymentSigningKey sk -> + writeFileTextEnvelope outFile Nothing sk + ACardanoAddrShelleyStakeSigningKey sk -> + writeFileTextEnvelope outFile Nothing sk + ACardanoAddrByronSigningKey sk -> + writeFileTextEnvelope outFile Nothing sk From fae5d35e1a3c9b6267dd17a6b8bbbcb426d22d4a Mon Sep 17 00:00:00 2001 From: Luke Nadur <19835357+intricate@users.noreply.github.com> Date: Tue, 8 Sep 2020 13:28:37 -0400 Subject: [PATCH 2/3] Minor refactoring of ITN key conversion command code --- .../src/Cardano/CLI/Shelley/Run/Key.hs | 86 ++++++++----------- cardano-cli/test/Test/Cli/ITN.hs | 8 +- 2 files changed, 39 insertions(+), 55 deletions(-) diff --git a/cardano-cli/src/Cardano/CLI/Shelley/Run/Key.hs b/cardano-cli/src/Cardano/CLI/Shelley/Run/Key.hs index a8b739a0d21..44274242f94 100644 --- a/cardano-cli/src/Cardano/CLI/Shelley/Run/Key.hs +++ b/cardano-cli/src/Cardano/CLI/Shelley/Run/Key.hs @@ -7,7 +7,7 @@ module Cardano.CLI.Shelley.Run.Key , runKeyCmd -- * Exports for testing - , decodeBech32Key + , decodeBech32 ) where import Cardano.Prelude @@ -51,7 +51,7 @@ data ShelleyKeyCmdError !Text -- ^ Text representation of the parse error. Unfortunately, the actual -- error type isn't exported. - | ShelleyKeyCmdItnKeyConvError !ConversionError + | ShelleyKeyCmdItnKeyConvError !ItnKeyConversionError | ShelleyKeyCmdWrongKeyTypeError | ShelleyKeyCmdCardanoAddressSigningKeyFileError !(FileError CardanoAddressSigningKeyConversionError) @@ -444,88 +444,72 @@ runConvertITNBip32ToStakeKey (ASigningKeyFile (SigningKeyFile sk)) (OutputFile o firstExceptT ShelleyKeyCmdWriteFileError . newExceptT $ writeFileTextEnvelope outFile Nothing skey -data ConversionError - = Bech32KeyDecodingError - -- ^ Bech32 key - !Text - !Bech32.DecodingError - | Bech32ErrorExtractingByes !Bech32.DataPart - | Bech32ReadError !FilePath !IOException - | ITNError !Bech32.HumanReadablePart !Bech32.DataPart - | SigningKeyDeserializationError !ByteString - | VerificationKeyDeserializationError !ByteString +-- | An error that can occur while converting an Incentivized Testnet (ITN) +-- key. +data ItnKeyConversionError + = ItnKeyBech32DecodeError !Bech32DecodeError + | ItnReadBech32FileError !FilePath !IOException + | ItnSigningKeyDeserialisationError !ByteString + | ItnVerificationKeyDeserialisationError !ByteString deriving Show -renderConversionError :: ConversionError -> Text +-- | Render an error message for an 'ItnKeyConversionError'. +renderConversionError :: ItnKeyConversionError -> Text renderConversionError err = case err of - Bech32KeyDecodingError key decErr -> - "Error decoding Bech32 key: " <> key <> " Error: " <> textShow decErr - Bech32ErrorExtractingByes dp -> - "Unable to extract bytes from: " <> Bech32.dataPartToText dp - Bech32ReadError fp readErr -> - "Error reading bech32 key at: " <> textShow fp + ItnKeyBech32DecodeError decErr -> + "Error decoding Bech32 key: " <> Text.pack (displayError decErr) + ItnReadBech32FileError fp readErr -> + "Error reading Bech32 key at: " <> textShow fp <> " Error: " <> Text.pack (displayException readErr) - ITNError hRpart dp -> - "Error extracting a ByteString from DataPart: " <> Bech32.dataPartToText dp <> - " With human readable part: " <> Bech32.humanReadablePartToText hRpart - SigningKeyDeserializationError sKey -> - "Error deserialising signing key: " <> textShow (BSC.unpack sKey) - VerificationKeyDeserializationError vKey -> + ItnSigningKeyDeserialisationError _sKey -> + -- Sensitive data, such as the signing key, is purposely not included in + -- the error message. + "Error deserialising signing key." + ItnVerificationKeyDeserialisationError vKey -> "Error deserialising verification key: " <> textShow (BSC.unpack vKey) -- | Convert public ed25519 key to a Shelley stake verification key -convertITNVerificationKey :: Text -> Either ConversionError (VerificationKey StakeKey) +convertITNVerificationKey :: Text -> Either ItnKeyConversionError (VerificationKey StakeKey) convertITNVerificationKey pubKey = do - (_, _, keyBS) <- decodeBech32Key pubKey + (_, _, keyBS) <- first ItnKeyBech32DecodeError (decodeBech32 pubKey) case DSIGN.rawDeserialiseVerKeyDSIGN keyBS of Just verKey -> Right . StakeVerificationKey $ Shelley.VKey verKey - Nothing -> Left $ VerificationKeyDeserializationError keyBS + Nothing -> Left $ ItnVerificationKeyDeserialisationError keyBS -- | Convert private ed22519 key to a Shelley signing key. -convertITNSigningKey :: Text -> Either ConversionError (SigningKey StakeKey) +convertITNSigningKey :: Text -> Either ItnKeyConversionError (SigningKey StakeKey) convertITNSigningKey privKey = do - (_, _, keyBS) <- decodeBech32Key privKey + (_, _, keyBS) <- first ItnKeyBech32DecodeError (decodeBech32 privKey) case DSIGN.rawDeserialiseSignKeyDSIGN keyBS of Just signKey -> Right $ StakeSigningKey signKey - Nothing -> Left $ SigningKeyDeserializationError keyBS + Nothing -> Left $ ItnSigningKeyDeserialisationError keyBS -- | Convert extended private ed22519 key to a Shelley signing key -- Extended private key = 64 bytes, -- Public key = 32 bytes. -convertITNExtendedSigningKey :: Text -> Either ConversionError (SigningKey StakeExtendedKey) +convertITNExtendedSigningKey :: Text -> Either ItnKeyConversionError (SigningKey StakeExtendedKey) convertITNExtendedSigningKey privKey = do - (_, _, privkeyBS) <- decodeBech32Key privKey + (_, _, privkeyBS) <- first ItnKeyBech32DecodeError (decodeBech32 privKey) let dummyChainCode = BS.replicate 32 0 case xprvFromBytes $ BS.concat [privkeyBS, dummyChainCode] of Just xprv -> Right $ StakeExtendedSigningKey xprv - Nothing -> Left $ SigningKeyDeserializationError privkeyBS + Nothing -> Left $ ItnSigningKeyDeserialisationError privkeyBS -- BIP32 Private key = 96 bytes (64 bytes extended private key + 32 bytes chaincode) -- BIP32 Public Key = 64 Bytes -convertITNBIP32SigningKey :: Text -> Either ConversionError (SigningKey StakeExtendedKey) +convertITNBIP32SigningKey :: Text -> Either ItnKeyConversionError (SigningKey StakeExtendedKey) convertITNBIP32SigningKey privKey = do - (_, _, privkeyBS) <- decodeBech32Key privKey + (_, _, privkeyBS) <- first ItnKeyBech32DecodeError (decodeBech32 privKey) case xprvFromBytes privkeyBS of Just xprv -> Right $ StakeExtendedSigningKey xprv - Nothing -> Left $ SigningKeyDeserializationError privkeyBS - --- | Convert ITN Bech32 public or private keys to 'ByteString's -decodeBech32Key :: Text - -> Either ConversionError - (Bech32.HumanReadablePart, Bech32.DataPart, ByteString) -decodeBech32Key key = - case Bech32.decodeLenient key of - Left err -> Left $ Bech32KeyDecodingError key err - Right (hRpart, dataPart) -> case Bech32.dataPartToBytes dataPart of - Nothing -> Left $ ITNError hRpart dataPart - Just bs -> Right (hRpart, dataPart, bs) - -readFileITNKey :: FilePath -> IO (Either ConversionError Text) + Nothing -> Left $ ItnSigningKeyDeserialisationError privkeyBS + +readFileITNKey :: FilePath -> IO (Either ItnKeyConversionError Text) readFileITNKey fp = do eStr <- Exception.try $ readFile fp case eStr of - Left e -> return . Left $ Bech32ReadError fp e + Left e -> return . Left $ ItnReadBech32FileError fp e Right str -> return . Right . Text.concat $ Text.words str -------------------------------------------------------------------------------- diff --git a/cardano-cli/test/Test/Cli/ITN.hs b/cardano-cli/test/Test/Cli/ITN.hs index 991a6ccd055..af9ba7aa187 100644 --- a/cardano-cli/test/Test/Cli/ITN.hs +++ b/cardano-cli/test/Test/Cli/ITN.hs @@ -4,7 +4,7 @@ module Test.Cli.ITN ( tests ) where -import Cardano.CLI.Shelley.Run.Key (decodeBech32Key) +import Cardano.CLI.Shelley.Run.Key (decodeBech32) import Cardano.Prelude import Hedgehog (Property, (===)) import Test.OptParse @@ -112,14 +112,14 @@ prop_convertITNBIP32SigningKey = propertyOnce . moduleWorkspace "tmp" $ \tempDir -- Check for existence of the converted ITN keys assertFilesExist [outputHaskellSignKeyFp] --- | We check our 'decodeBech32Key' outputs against https://slowli.github.io/bech32-buffer/ +-- | We check our 'decodeBech32' outputs against https://slowli.github.io/bech32-buffer/ -- using 'itnVerKey' & 'itnSignKey' as inputs. golden_bech32Decode :: Property golden_bech32Decode = propertyOnce $ do - (vHumReadPart, vDataPart , _) <- H.evalEither $ decodeBech32Key itnVerKey + (vHumReadPart, vDataPart , _) <- H.evalEither $ decodeBech32 itnVerKey Just vDataPartBase16 <- pure (dataPartToBase16 vDataPart) - (sHumReadPart, sDataPart , _) <- H.evalEither $ decodeBech32Key itnSignKey + (sHumReadPart, sDataPart , _) <- H.evalEither $ decodeBech32 itnSignKey Just sDataPartBase16 <- pure (dataPartToBase16 sDataPart) -- Based on https://slowli.github.io/bech32-buffer/ which are in Base16 From 289de30d3ef38f12d891ec01e12cdf46abfc698a Mon Sep 17 00:00:00 2001 From: Luke Nadur <19835357+intricate@users.noreply.github.com> Date: Mon, 14 Sep 2020 15:25:19 -0400 Subject: [PATCH 3/3] Add CLI golden tests for new cardano-address key conversion command --- cardano-cli/cardano-cli.cabal | 1 + cardano-cli/test/Test/Golden/Shelley.hs | 16 ++ .../Shelley/Key/ConvertCardanoAddressKey.hs | 190 ++++++++++++++++++ cardano-cli/test/cardano-cli-golden.hs | 1 + .../byron_signing_key | 5 + .../icarus_signing_key | 5 + .../shelley_payment_signing_key | 5 + .../shelley_stake_signing_key | 5 + 8 files changed, 228 insertions(+) create mode 100644 cardano-cli/test/Test/Golden/Shelley/Key/ConvertCardanoAddressKey.hs create mode 100644 cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/byron_signing_key create mode 100644 cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/icarus_signing_key create mode 100644 cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/shelley_payment_signing_key create mode 100644 cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/shelley_stake_signing_key diff --git a/cardano-cli/cardano-cli.cabal b/cardano-cli/cardano-cli.cabal index 6e1dfd4ab77..e4ccfb52656 100644 --- a/cardano-cli/cardano-cli.cabal +++ b/cardano-cli/cardano-cli.cabal @@ -235,6 +235,7 @@ test-suite cardano-cli-golden Test.Golden.Shelley.Genesis.KeyGenGenesis Test.Golden.Shelley.Genesis.KeyGenUtxo Test.Golden.Shelley.Genesis.KeyHash + Test.Golden.Shelley.Key.ConvertCardanoAddressKey Test.Golden.Shelley.Node.IssueOpCert Test.Golden.Shelley.Node.KeyGen Test.Golden.Shelley.Node.KeyGenKes diff --git a/cardano-cli/test/Test/Golden/Shelley.hs b/cardano-cli/test/Test/Golden/Shelley.hs index fe1a347a228..ed5343ba0ce 100644 --- a/cardano-cli/test/Test/Golden/Shelley.hs +++ b/cardano-cli/test/Test/Golden/Shelley.hs @@ -3,6 +3,7 @@ module Test.Golden.Shelley ( keyTests , certificateTests + , keyConversionTests , metaDatatests , multiSigTests , txTests @@ -19,6 +20,11 @@ import Test.Golden.Shelley.Genesis.KeyGenDelegate (golden_shelleyGenes import Test.Golden.Shelley.Genesis.KeyGenGenesis (golden_shelleyGenesisKeyGenGenesis) import Test.Golden.Shelley.Genesis.KeyGenUtxo (golden_shelleyGenesisKeyGenUtxo) import Test.Golden.Shelley.Genesis.KeyHash (golden_shelleyGenesisKeyHash) +import Test.Golden.Shelley.Key.ConvertCardanoAddressKey + (golden_convertCardanoAddressByronSigningKey, + golden_convertCardanoAddressIcarusSigningKey, + golden_convertCardanoAddressShelleyPaymentSigningKey, + golden_convertCardanoAddressShelleyStakeSigningKey) import Test.Golden.Shelley.Node.IssueOpCert (golden_shelleyNodeIssueOpCert) import Test.Golden.Shelley.Node.KeyGen (golden_shelleyNodeKeyGen) import Test.Golden.Shelley.Node.KeyGenKes (golden_shelleyNodeKeyGenKes) @@ -126,6 +132,16 @@ certificateTests = , ("golden_shelleyGenesisKeyDelegationCertificate", golden_shelleyGenesisKeyDelegationCertificate) ] +keyConversionTests :: IO Bool +keyConversionTests = + H.checkSequential + $ H.Group "Key Conversion Goldens" + [ ("golden_convertCardanoAddressByronSigningKey", golden_convertCardanoAddressByronSigningKey) + , ("golden_convertCardanoAddressIcarusSigningKey", golden_convertCardanoAddressIcarusSigningKey) + , ("golden_convertCardanoAddressShelleyPaymentSigningKey", golden_convertCardanoAddressShelleyPaymentSigningKey) + , ("golden_convertCardanoAddressShelleyStakeSigningKey", golden_convertCardanoAddressShelleyStakeSigningKey) + ] + metaDatatests :: IO Bool metaDatatests = H.checkSequential diff --git a/cardano-cli/test/Test/Golden/Shelley/Key/ConvertCardanoAddressKey.hs b/cardano-cli/test/Test/Golden/Shelley/Key/ConvertCardanoAddressKey.hs new file mode 100644 index 00000000000..ec4e41c1aa4 --- /dev/null +++ b/cardano-cli/test/Test/Golden/Shelley/Key/ConvertCardanoAddressKey.hs @@ -0,0 +1,190 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Test.Golden.Shelley.Key.ConvertCardanoAddressKey + ( golden_convertCardanoAddressByronSigningKey + , golden_convertCardanoAddressIcarusSigningKey + , golden_convertCardanoAddressShelleyPaymentSigningKey + , golden_convertCardanoAddressShelleyStakeSigningKey + ) where + +import Cardano.Prelude hiding (readFile) + +import Hedgehog (Property, (===)) + +import Test.OptParse + +{- HLINT ignore "Use camelCase" -} + +-- | An example signing key generated by @cardano-address@ using the +-- deprecated Byron style. +exampleByronSigningKey :: Text +exampleByronSigningKey = + "xprv1pp72a64en2vf568jywe9azlgrqe3p2jjf9gxxeejn2fex8g889x54w6emg2egkaz2rxyc" + <> "560fp0hrv8y0hzpuzu27zhhhgwc8t5tvrczz2jnhhjwdnd6cdjx4dxehrsr2pr406rchw" + <> "ctfwrgpc9r7nmakvaegyz9" + +-- | An example signing key generated by @cardano-address@ using the Icarus +-- style. +exampleIcarusSigningKey :: Text +exampleIcarusSigningKey = + "xprv1yq7c6nlmxncg7txy0z6lqf3fww4vm20m60lrxttx5lr4qmkvh395m3p59v8fn4ku9mzyc" + <> "g2rkxatgwm86uc3pvrt06e43afya6rm0s2azlpnc9yrhygl2heckeyhhtgad08c0zljpn" + <> "c6fse2ldzyx9c86yvddxjw" + +-- | An example signing key generated by @cardano-address@ using the Shelley +-- style. +exampleShelleySigningKey :: Text +exampleShelleySigningKey = + "xprv1yq7c6nlmxncg7txy0z6lqf3fww4vm20m60lrxttx5lr4qmkvh395m3p59v8fn4ku9mzyc" + <> "g2rkxatgwm86uc3pvrt06e43afya6rm0s2azlpnc9yrhygl2heckeyhhtgad08c0zljpn" + <> "c6fse2ldzyx9c86yvddxjw" + +-- | Test that converting a @cardano-address@ Byron signing key yields the +-- expected result. +golden_convertCardanoAddressByronSigningKey :: Property +golden_convertCardanoAddressByronSigningKey = + propertyOnce . moduleWorkspace "tmp" $ \tempDir -> do + + -- `cardano-address` signing key filepath + signingKeyFp <- noteTempFile tempDir "cardano-address-byron.skey" + + -- Converted signing key filepath + convertedSigningKeyFp <- + noteTempFile tempDir "converted-cardano-address-byron.skey" + + -- Write `cardano-address` signing key to disk + liftIO $ writeFile signingKeyFp exampleByronSigningKey + assertFilesExist [signingKeyFp] + + -- Convert the `cardano-address` signing key + void $ execCardanoCLI + [ "shelley","key","convert-cardano-address-key" + , "--byron-payment-key" + , "--signing-key-file", signingKeyFp + , "--out-file", convertedSigningKeyFp + ] + + -- Check for existence of the converted signing key file + assertFilesExist [convertedSigningKeyFp] + + -- Check that the contents of the converted signing key file match that of + -- the golden file. + actualConvertedSigningKey <- readFile convertedSigningKeyFp + expectedConvertedSigningKey <- + readFile $ + "test/data/golden/shelley/keys/converted_cardano-address_keys/" + <> "byron_signing_key" + expectedConvertedSigningKey === actualConvertedSigningKey + +-- | Test that converting a @cardano-address@ Icarus signing key yields the +-- expected result. +golden_convertCardanoAddressIcarusSigningKey :: Property +golden_convertCardanoAddressIcarusSigningKey = + propertyOnce . moduleWorkspace "tmp" $ \tempDir -> do + + -- `cardano-address` signing key filepath + signingKeyFp <- noteTempFile tempDir "cardano-address-icarus.skey" + + -- Converted signing key filepath + convertedSigningKeyFp <- + noteTempFile tempDir "converted-cardano-address-icarus.skey" + + -- Write `cardano-address` signing key to disk + liftIO $ writeFile signingKeyFp exampleIcarusSigningKey + assertFilesExist [signingKeyFp] + + -- Convert the `cardano-address` signing key + void $ execCardanoCLI + [ "shelley","key","convert-cardano-address-key" + , "--icarus-payment-key" + , "--signing-key-file", signingKeyFp + , "--out-file", convertedSigningKeyFp + ] + + -- Check for existence of the converted signing key file + assertFilesExist [convertedSigningKeyFp] + + -- Check that the contents of the converted signing key file match that of + -- the golden file. + actualConvertedSigningKey <- readFile convertedSigningKeyFp + expectedConvertedSigningKey <- + readFile $ + "test/data/golden/shelley/keys/converted_cardano-address_keys/" + <> "icarus_signing_key" + expectedConvertedSigningKey === actualConvertedSigningKey + +-- | Test that converting a @cardano-address@ Shelley payment signing key +-- yields the expected result. +golden_convertCardanoAddressShelleyPaymentSigningKey :: Property +golden_convertCardanoAddressShelleyPaymentSigningKey = + propertyOnce . moduleWorkspace "tmp" $ \tempDir -> do + + -- `cardano-address` signing key filepath + signingKeyFp <- + noteTempFile tempDir "cardano-address-shelley-payment.skey" + + -- Converted signing key filepath + convertedSigningKeyFp <- + noteTempFile tempDir "converted-cardano-address-shelley-payment.skey" + + -- Write `cardano-address` signing key to disk + liftIO $ writeFile signingKeyFp exampleShelleySigningKey + assertFilesExist [signingKeyFp] + + -- Convert the `cardano-address` signing key + void $ execCardanoCLI + [ "shelley","key","convert-cardano-address-key" + , "--shelley-payment-key" + , "--signing-key-file", signingKeyFp + , "--out-file", convertedSigningKeyFp + ] + + -- Check for existence of the converted signing key file + assertFilesExist [convertedSigningKeyFp] + + -- Check that the contents of the converted signing key file match that of + -- the golden file. + actualConvertedSigningKey <- readFile convertedSigningKeyFp + expectedConvertedSigningKey <- + readFile $ + "test/data/golden/shelley/keys/converted_cardano-address_keys/" + <> "shelley_payment_signing_key" + expectedConvertedSigningKey === actualConvertedSigningKey + +-- | Test that converting a @cardano-address@ Shelley stake signing key yields +-- the expected result. +golden_convertCardanoAddressShelleyStakeSigningKey :: Property +golden_convertCardanoAddressShelleyStakeSigningKey = + propertyOnce . moduleWorkspace "tmp" $ \tempDir -> do + + -- `cardano-address` signing key filepath + signingKeyFp <- + noteTempFile tempDir "cardano-address-shelley-stake.skey" + + -- Converted signing key filepath + convertedSigningKeyFp <- + noteTempFile tempDir "converted-cardano-address-shelley-stake.skey" + + -- Write `cardano-address` signing key to disk + liftIO $ writeFile signingKeyFp exampleShelleySigningKey + assertFilesExist [signingKeyFp] + + -- Convert the `cardano-address` signing key + void $ execCardanoCLI + [ "shelley","key","convert-cardano-address-key" + , "--shelley-stake-key" + , "--signing-key-file", signingKeyFp + , "--out-file", convertedSigningKeyFp + ] + + -- Check for existence of the converted signing key file + assertFilesExist [convertedSigningKeyFp] + + -- Check that the contents of the converted signing key file match that of + -- the golden file. + actualConvertedSigningKey <- readFile convertedSigningKeyFp + expectedConvertedSigningKey <- + readFile $ + "test/data/golden/shelley/keys/converted_cardano-address_keys/" + <> "shelley_stake_signing_key" + expectedConvertedSigningKey === actualConvertedSigningKey diff --git a/cardano-cli/test/cardano-cli-golden.hs b/cardano-cli/test/cardano-cli-golden.hs index 1737d504abe..190ca25a374 100644 --- a/cardano-cli/test/cardano-cli-golden.hs +++ b/cardano-cli/test/cardano-cli-golden.hs @@ -9,6 +9,7 @@ main = defaultMain [ Test.Golden.Shelley.keyTests , Test.Golden.Shelley.certificateTests + , Test.Golden.Shelley.keyConversionTests , Test.Golden.Shelley.metaDatatests , Test.Golden.Shelley.multiSigTests , Test.Golden.Shelley.txTests diff --git a/cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/byron_signing_key b/cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/byron_signing_key new file mode 100644 index 00000000000..ef892403416 --- /dev/null +++ b/cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/byron_signing_key @@ -0,0 +1,5 @@ +{ + "type": "PaymentSigningKeyByron_ed25519_bip32", + "description": "", + "cborHex": "5880087caeeab99a989a68f223b25e8be8183310aa5249506367329a93931d07394d4abb59da15945ba250cc4c534f485f71b0e47dc41e0b8af0af7ba1d83ae8b60f975e5b024cda7923bacc4c25cca498b9e67380dfe588764b614d8e7a37656dfd0212a53bde4e6cdbac3646ab4d9b8e03504757e878bbb0b4b8680e0a3f4f7db3" +} diff --git a/cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/icarus_signing_key b/cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/icarus_signing_key new file mode 100644 index 00000000000..2d1ce496105 --- /dev/null +++ b/cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/icarus_signing_key @@ -0,0 +1,5 @@ +{ + "type": "PaymentSigningKeyByron_ed25519_bip32", + "description": "", + "cborHex": "5880203d8d4ffb34f08f2cc478b5f0262973aacda9fbd3fe332d66a7c7506eccbc4b4dc4342b0e99d6dc2ec44c2143b1bab43b67d73110b06b7eb358f524ee87b7c13ceae36bc0e1fbaacbcb259f9342c322459015ea351bc0f644d93de7d0099a735d17c33c1483b911f55f38b6497bad1d6bcf878bf20cf1a4c32afb44431707d1" +} diff --git a/cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/shelley_payment_signing_key b/cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/shelley_payment_signing_key new file mode 100644 index 00000000000..a6b4a4dc80a --- /dev/null +++ b/cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/shelley_payment_signing_key @@ -0,0 +1,5 @@ +{ + "type": "PaymentExtendedSigningKeyShelley_ed25519_bip32", + "description": "", + "cborHex": "5880203d8d4ffb34f08f2cc478b5f0262973aacda9fbd3fe332d66a7c7506eccbc4b4dc4342b0e99d6dc2ec44c2143b1bab43b67d73110b06b7eb358f524ee87b7c13ceae36bc0e1fbaacbcb259f9342c322459015ea351bc0f644d93de7d0099a735d17c33c1483b911f55f38b6497bad1d6bcf878bf20cf1a4c32afb44431707d1" +} diff --git a/cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/shelley_stake_signing_key b/cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/shelley_stake_signing_key new file mode 100644 index 00000000000..b490299a814 --- /dev/null +++ b/cardano-cli/test/data/golden/shelley/keys/converted_cardano-address_keys/shelley_stake_signing_key @@ -0,0 +1,5 @@ +{ + "type": "StakeExtendedSigningKeyShelley_ed25519_bip32", + "description": "", + "cborHex": "5880203d8d4ffb34f08f2cc478b5f0262973aacda9fbd3fe332d66a7c7506eccbc4b4dc4342b0e99d6dc2ec44c2143b1bab43b67d73110b06b7eb358f524ee87b7c13ceae36bc0e1fbaacbcb259f9342c322459015ea351bc0f644d93de7d0099a735d17c33c1483b911f55f38b6497bad1d6bcf878bf20cf1a4c32afb44431707d1" +}