diff --git a/cardano-crypto-wallet/CHANGELOG.md b/cardano-crypto-wallet/CHANGELOG.md index 5cb314893..89e8ea26e 100644 --- a/cardano-crypto-wallet/CHANGELOG.md +++ b/cardano-crypto-wallet/CHANGELOG.md @@ -1,8 +1,10 @@ # Changelog for cardano-crypto-wallet -## 0.1.0.1 +## 0.2.0.0 -* +* Breaking: `encryptedDerivePublic` now returns `Either XPrvError (PublicKey, ChainCode)` + instead of throwing on hardened indices. +* Breaking: `XPrvHardenedDerivationUnsupported` constructor added to `XPrvError`. ## 0.1.0.0 diff --git a/cardano-crypto-wallet/cardano-crypto-wallet.cabal b/cardano-crypto-wallet/cardano-crypto-wallet.cabal index 3d7f8dab4..8e00cd372 100644 --- a/cardano-crypto-wallet/cardano-crypto-wallet.cabal +++ b/cardano-crypto-wallet/cardano-crypto-wallet.cabal @@ -1,6 +1,6 @@ cabal-version: 3.0 name: cardano-crypto-wallet -version: 0.1.0.0 +version: 0.2.0.0 synopsis: Authenticated v2 envelope for HD wallet keys description: Provides authenticated encryption and key derivation for HD wallet keys, diff --git a/cardano-crypto-wallet/src/Cardano/Crypto/WalletHD/Encrypted.hs b/cardano-crypto-wallet/src/Cardano/Crypto/WalletHD/Encrypted.hs index 556a733d1..0968ed929 100644 --- a/cardano-crypto-wallet/src/Cardano/Crypto/WalletHD/Encrypted.hs +++ b/cardano-crypto-wallet/src/Cardano/Crypto/WalletHD/Encrypted.hs @@ -427,6 +427,7 @@ data XPrvError | XPrvInvalidChainCode | XPrvPublicKeyMismatch | XPrvInternalError + | XPrvHardenedDerivationUnsupported deriving (Eq, Show) newtype EncryptedKey = EncryptedKey ByteString @@ -673,16 +674,15 @@ encryptedDerivePublic :: DerivationScheme -> (PublicKey, ChainCode) -> DerivationIndex -> - (PublicKey, ChainCode) + Either XPrvError (PublicKey, ChainCode) encryptedDerivePublic dscheme (publicKey, cc) childIndex - | childIndex >= 0x80000000 = - error "encryptedDerivePublic: cannot derive hardened key from public key" - | otherwise = unsafePerformIO $ do - fmap (first PublicKey) $ psbCreateResult $ \publicKeyPtrOut -> - fmap ChainCode $ psbCreate $ \ccOutPtr -> - withPublicKeyPtr publicKey $ \publicKeyPtr -> - withChainCodePtr cc $ \chainCodePtr -> do - r <- + | childIndex >= 0x80000000 = Left XPrvHardenedDerivationUnsupported + | otherwise = unsafePerformIO $ + withPublicKeyPtr publicKey $ \publicKeyPtr -> + withChainCodePtr cc $ \chainCodePtr -> do + (pubKeyBytes, (ccBytes, r)) <- + psbCreateResult $ \publicKeyPtrOut -> + psbCreateResult $ \ccOutPtr -> wallet_derive_public publicKeyPtr chainCodePtr @@ -690,9 +690,10 @@ encryptedDerivePublic dscheme (publicKey, cc) childIndex (PublicKeyPtr publicKeyPtrOut) (ChainCodePtr ccOutPtr) (dschemeToC dscheme) - if r /= 0 - then error "encryptedDerivePublic: hardened index check failed" - else pure () + pure $ + if r /= 0 + then Left XPrvInternalError + else Right (PublicKey pubKeyBytes, ChainCode ccBytes) encryptedPublic :: HasCallStack => EncryptedKey -> PublicKey encryptedPublic eKey@(EncryptedKey eKeyBytes) = diff --git a/cardano-crypto-wallet/test/Test/Cardano/Crypto/Wallet/RoundTripSpec.hs b/cardano-crypto-wallet/test/Test/Cardano/Crypto/Wallet/RoundTripSpec.hs index 6e4cdf93a..db1ea868e 100644 --- a/cardano-crypto-wallet/test/Test/Cardano/Crypto/Wallet/RoundTripSpec.hs +++ b/cardano-crypto-wallet/test/Test/Cardano/Crypto/Wallet/RoundTripSpec.hs @@ -82,8 +82,9 @@ tests = describe "RoundTrip" $ do case res' of Left err -> expectationFailure $ "derivePrivate failed: " ++ show err Right child -> - let (derivedPub, _) = encryptedDerivePublic DerivationScheme2 (pub, cc) idx - in encryptedPublic child `shouldBe` derivedPub + case encryptedDerivePublic DerivationScheme2 (pub, cc) idx of + Left err -> expectationFailure $ "derivePublic failed: " ++ show err + Right (derivedPub, _) -> encryptedPublic child `shouldBe` derivedPub it "encryptedDerivePublic is consistent for both schemes" $ do res <- encryptedCreate testSeed testPass testCC @@ -92,9 +93,12 @@ tests = describe "RoundTrip" $ do Right key -> do let pub = encryptedPublic key cc = encryptedChainCode key - (pub1, _) = encryptedDerivePublic DerivationScheme1 (pub, cc) 0 - (pub2, _) = encryptedDerivePublic DerivationScheme2 (pub, cc) 0 - pub1 `shouldNotBe` pub2 + case ( encryptedDerivePublic DerivationScheme1 (pub, cc) 0 + , encryptedDerivePublic DerivationScheme2 (pub, cc) 0 + ) of + (Right (pub1, _), Right (pub2, _)) -> pub1 `shouldNotBe` pub2 + (Left err, _) -> expectationFailure $ "derivePublic scheme1 failed: " ++ show err + (_, Left err) -> expectationFailure $ "derivePublic scheme2 failed: " ++ show err prop "mkEncryptedKey . unEncryptedKey is identity" $ \(key :: EncryptedKey) ->