Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changes/depend-on-cardano-keys.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
project: cardano-api
pr: 1332
kind:
- breaking
- refactoring
description: |
The key types, their hashes and the raw-bytes, hex, CBOR, bech32 and text-envelope serialisations now come from the `cardano-keys` package. The module names, the exported names and `Cardano.Api`'s re-exports are unchanged, so most code needs no edit. Three things did change: `HasTextEnvelope` instances now define `textEnvelopeTypes :: AsType a -> NonEmpty TextEnvelopeType` instead of `textEnvelopeType` (the head of that list is the type written when serialising, the whole list is accepted when reading, and `textEnvelopeType` remains available as a free function); `getKesPeriod` returns a `KESPeriod` rather than a `Word`; and the error types that moved carry `render...` functions in `cardano-keys`, with the `Error` instances kept here.
1 change: 1 addition & 0 deletions .github/master-check-exceptions.list
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://github.com/IntersectMBO/cardano-keys
12 changes: 12 additions & 0 deletions cabal.project
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ semaphore: True
constraints:
-- haskell.nix patch does not work for 1.6.8
, any.crypton-x509-system < 1.6.8
-- cardano-crypto-class (in cardano-api and in the cardano-keys dependency)
-- requires crypton < 1.1; without this the GHC 9.14 solver greedily picks
-- crypton 1.1.4 and then cannot resolve cardano-crypto-class.
, crypton < 1.1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be behind GHC version check


-- Temporary, until cardano-keys has its first CHaP release.
source-repository-package
type: git
location: https://github.com/IntersectMBO/cardano-keys
tag: df20ae67e89920fdc65cd3c30a720dbcbf9e5344
subdir: cardano-keys
--sha256: sha256-TILlrhcfUOgVkrG5vi6QL8sjTaFvBKJIrnPvURG94A4=


-- WASM compilation specific
Expand Down
2 changes: 1 addition & 1 deletion cardano-api/cardano-api.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ library
cardano-crypto-wrapper ^>=1.7,
cardano-data >=1.0,
cardano-diffusion:{api, cardano-diffusion} ^>=1.1,
cardano-keys ^>=11.0,
cardano-ledger-allegra >=1.7,
cardano-ledger-alonzo >=1.15,
cardano-ledger-api ^>=1.14,
Expand Down Expand Up @@ -187,7 +188,6 @@ library
prettyprinter,
prettyprinter-ansi-terminal,
prettyprinter-configurable ^>=1.36,
random,
resource-registry ^>=0.3,
safe-exceptions,
scientific,
Expand Down
297 changes: 4 additions & 293 deletions cardano-api/src/Cardano/Api/Byron/Internal/Key.hs
Original file line number Diff line number Diff line change
@@ -1,298 +1,9 @@
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}

-- | Byron key types and their 'Key' class instances
--
-- This module now lives in the cardano-keys package; re-exported here for compatibility.
module Cardano.Api.Byron.Internal.Key
( -- * Key types
ByronKey
, ByronKeyLegacy

-- * Data family instances
, AsType (..)
, VerificationKey (..)
, SigningKey (..)
, Hash (..)

-- * Legacy format
, IsByronKey (..)
, ByronKeyFormat (..)
, SomeByronSigningKey (..)
, toByronSigningKey
( module Cardano.Keys.Byron
)
where

import Cardano.Api.HasTypeProxy
import Cardano.Api.Hash
import Cardano.Api.Key.Internal
import Cardano.Api.Key.Internal.Class
import Cardano.Api.Pretty
import Cardano.Api.Serialise.Cbor
import Cardano.Api.Serialise.Raw
import Cardano.Api.Serialise.SerialiseUsing
import Cardano.Api.Serialise.TextEnvelope.Internal

import Cardano.Binary (cborError, toStrictByteString)
import Cardano.Chain.Common qualified as Crypto
import Cardano.Crypto.DSIGN.Class qualified as Crypto
import Cardano.Crypto.Hashing qualified as Crypto
import Cardano.Crypto.Seed qualified as Crypto
import Cardano.Crypto.Signing qualified as Crypto
import Cardano.Crypto.Wallet qualified as Crypto.HD
import Cardano.Crypto.Wallet qualified as Wallet

import Codec.CBOR.Decoding qualified as CBOR
import Codec.CBOR.Read qualified as CBOR
import Control.Monad
import Data.Bifunctor
import Data.ByteString.Lazy qualified as LB
import Data.Either.Combinators
import Data.Text qualified as Text
import Formatting (build, formatToString)

-- | Byron-era payment keys. Used for Byron addresses and witnessing
-- transactions that spend from these addresses.
--
-- These use Ed25519 but with a 32byte \"chaincode\" used in HD derivation.
-- The inclusion of the chaincode is a design mistake but one that cannot
-- be corrected for the Byron era. The Shelley era 'PaymentKey's do not include
-- a chaincode. It is safe to use a zero or random chaincode for new Byron keys.
--
-- This is a type level tag, used with other interfaces like 'Key'.
data ByronKey

data ByronKeyLegacy

class IsByronKey key where
byronKeyFormat :: ByronKeyFormat key

data ByronKeyFormat key where
ByronLegacyKeyFormat :: ByronKeyFormat ByronKeyLegacy
ByronModernKeyFormat :: ByronKeyFormat ByronKey

data SomeByronSigningKey
= AByronSigningKeyLegacy (SigningKey ByronKeyLegacy)
| AByronSigningKey (SigningKey ByronKey)

toByronSigningKey :: SomeByronSigningKey -> Crypto.SigningKey
toByronSigningKey bWit =
case bWit of
AByronSigningKeyLegacy (ByronSigningKeyLegacy sKey) -> sKey
AByronSigningKey (ByronSigningKey sKey) -> sKey

--
-- Byron key
--

instance Key ByronKey where
newtype VerificationKey ByronKey
= ByronVerificationKey Crypto.VerificationKey
deriving stock Eq
deriving (Show, Pretty) via UsingRawBytesHex (VerificationKey ByronKey)
deriving newtype (ToCBOR, FromCBOR)
deriving anyclass SerialiseAsCBOR

newtype SigningKey ByronKey
= ByronSigningKey Crypto.SigningKey
deriving (Show, Pretty) via UsingRawBytesHex (SigningKey ByronKey)
deriving newtype (ToCBOR, FromCBOR)
deriving anyclass SerialiseAsCBOR

deterministicSigningKey :: AsType ByronKey -> Crypto.Seed -> SigningKey ByronKey
deterministicSigningKey AsByronKey seed =
ByronSigningKey (snd (Crypto.runMonadRandomWithSeed seed Crypto.keyGen))

deterministicSigningKeySeedSize :: AsType ByronKey -> Word
deterministicSigningKeySeedSize AsByronKey = 32

getVerificationKey :: SigningKey ByronKey -> VerificationKey ByronKey
getVerificationKey (ByronSigningKey sk) =
ByronVerificationKey (Crypto.toVerification sk)

verificationKeyHash :: VerificationKey ByronKey -> Hash ByronKey
verificationKeyHash (ByronVerificationKey vkey) =
ByronKeyHash (Crypto.hashKey vkey)

instance HasTypeProxy ByronKey where
data AsType ByronKey = AsByronKey
proxyToAsType _ = AsByronKey

instance HasTextEnvelope (VerificationKey ByronKey) where
textEnvelopeType _ = "PaymentVerificationKeyByron_ed25519_bip32"

instance HasTextEnvelope (SigningKey ByronKey) where
textEnvelopeType _ = "PaymentSigningKeyByron_ed25519_bip32"

instance SerialiseAsRawBytes (VerificationKey ByronKey) where
serialiseToRawBytes (ByronVerificationKey (Crypto.VerificationKey xvk)) =
Crypto.HD.unXPub xvk

deserialiseFromRawBytes (AsVerificationKey AsByronKey) bs =
first (\msg -> SerialiseAsRawBytesError ("Unable to deserialise VerificationKey ByronKey" ++ msg)) $
ByronVerificationKey . Crypto.VerificationKey <$> Crypto.HD.xpub bs

instance SerialiseAsRawBytes (SigningKey ByronKey) where
serialiseToRawBytes (ByronSigningKey sk) = toStrictByteString $ toCBOR sk

deserialiseFromRawBytes (AsSigningKey AsByronKey) bs =
first (\e -> SerialiseAsRawBytesError ("Unable to deserialise SigningKey ByronKey" ++ show e)) $
ByronSigningKey . snd <$> CBOR.deserialiseFromBytes fromCBOR (LB.fromStrict bs)

newtype instance Hash ByronKey = ByronKeyHash Crypto.KeyHash
deriving (Eq, Ord)
deriving (Show, Pretty) via UsingRawBytesHex (Hash ByronKey)
deriving (ToCBOR, FromCBOR) via UsingRawBytes (Hash ByronKey)
deriving anyclass SerialiseAsCBOR

instance SerialiseAsRawBytes (Hash ByronKey) where
serialiseToRawBytes (ByronKeyHash (Crypto.KeyHash vkh)) =
Crypto.abstractHashToBytes vkh

deserialiseFromRawBytes (AsHash AsByronKey) bs =
maybeToRight (SerialiseAsRawBytesError "Unable to deserialise Hash ByronKey") $
ByronKeyHash . Crypto.KeyHash <$> Crypto.abstractHashFromBytes bs

instance CastVerificationKeyRole ByronKey PaymentExtendedKey where
castVerificationKey (ByronVerificationKey vk) =
PaymentExtendedVerificationKey
(Crypto.unVerificationKey vk)

instance CastVerificationKeyRole ByronKey PaymentKey where
castVerificationKey =
( castVerificationKey
:: VerificationKey PaymentExtendedKey
-> VerificationKey PaymentKey
)
. ( castVerificationKey
:: VerificationKey ByronKey
-> VerificationKey PaymentExtendedKey
)

instance IsByronKey ByronKey where
byronKeyFormat = ByronModernKeyFormat

--
-- Legacy Byron key
--

instance Key ByronKeyLegacy where
newtype VerificationKey ByronKeyLegacy
= ByronVerificationKeyLegacy Crypto.VerificationKey
deriving stock Eq
deriving (Show, Pretty) via UsingRawBytesHex (VerificationKey ByronKeyLegacy)
deriving newtype (ToCBOR, FromCBOR)
deriving anyclass SerialiseAsCBOR

newtype SigningKey ByronKeyLegacy
= ByronSigningKeyLegacy Crypto.SigningKey
deriving (Show, Pretty) via UsingRawBytesHex (SigningKey ByronKeyLegacy)
deriving newtype (ToCBOR, FromCBOR)
deriving anyclass SerialiseAsCBOR

deterministicSigningKey :: AsType ByronKeyLegacy -> Crypto.Seed -> SigningKey ByronKeyLegacy
deterministicSigningKey _ _ = error "Please generate a non legacy Byron key instead"

deterministicSigningKeySeedSize :: AsType ByronKeyLegacy -> Word
deterministicSigningKeySeedSize AsByronKeyLegacy = 32

getVerificationKey :: SigningKey ByronKeyLegacy -> VerificationKey ByronKeyLegacy
getVerificationKey (ByronSigningKeyLegacy sk) =
ByronVerificationKeyLegacy (Crypto.toVerification sk)

verificationKeyHash :: VerificationKey ByronKeyLegacy -> Hash ByronKeyLegacy
verificationKeyHash (ByronVerificationKeyLegacy vkey) =
ByronKeyHashLegacy (Crypto.hashKey vkey)

instance HasTypeProxy ByronKeyLegacy where
data AsType ByronKeyLegacy = AsByronKeyLegacy
proxyToAsType _ = AsByronKeyLegacy

instance HasTextEnvelope (VerificationKey ByronKeyLegacy) where
textEnvelopeType _ = "PaymentVerificationKeyByronLegacy_ed25519_bip32"

instance HasTextEnvelope (SigningKey ByronKeyLegacy) where
textEnvelopeType _ = "PaymentSigningKeyByronLegacy_ed25519_bip32"

newtype instance Hash ByronKeyLegacy = ByronKeyHashLegacy Crypto.KeyHash
deriving (Eq, Ord)
deriving (Show, Pretty) via UsingRawBytesHex (Hash ByronKeyLegacy)
deriving (ToCBOR, FromCBOR) via UsingRawBytes (Hash ByronKeyLegacy)
deriving anyclass SerialiseAsCBOR

instance SerialiseAsRawBytes (Hash ByronKeyLegacy) where
serialiseToRawBytes (ByronKeyHashLegacy (Crypto.KeyHash vkh)) =
Crypto.abstractHashToBytes vkh

deserialiseFromRawBytes (AsHash AsByronKeyLegacy) bs =
maybeToRight (SerialiseAsRawBytesError "Unable to deserialise Hash ByronKeyLegacy") $
ByronKeyHashLegacy . Crypto.KeyHash <$> Crypto.abstractHashFromBytes bs

instance SerialiseAsRawBytes (VerificationKey ByronKeyLegacy) where
serialiseToRawBytes (ByronVerificationKeyLegacy (Crypto.VerificationKey xvk)) =
Crypto.HD.unXPub xvk

deserialiseFromRawBytes (AsVerificationKey AsByronKeyLegacy) bs =
first
(\msg -> SerialiseAsRawBytesError ("Unable to deserialise VerificationKey ByronKeyLegacy" ++ msg))
$ ByronVerificationKeyLegacy . Crypto.VerificationKey <$> Crypto.HD.xpub bs

instance SerialiseAsRawBytes (SigningKey ByronKeyLegacy) where
serialiseToRawBytes (ByronSigningKeyLegacy (Crypto.SigningKey xsk)) =
Crypto.HD.unXPrv xsk

deserialiseFromRawBytes (AsSigningKey AsByronKeyLegacy) bs =
first (\e -> SerialiseAsRawBytesError ("Unable to deserialise SigningKey ByronKeyLegacy" ++ show e)) $
ByronSigningKeyLegacy . snd <$> CBOR.deserialiseFromBytes decodeLegacyDelegateKey (LB.fromStrict bs)
where
-- Stolen from: cardano-sl/binary/src/Pos/Binary/Class/Core.hs
-- \| Enforces that the input size is the same as the decoded one, failing in
-- case it's not.
enforceSize :: Text -> Int -> CBOR.Decoder s ()
enforceSize lbl requestedSize = CBOR.decodeListLenCanonical >>= matchSize requestedSize lbl

-- Stolen from: cardano-sl/binary/src/Pos/Binary/Class/Core.hs
-- \| Compare two sizes, failing if they are not equal.
matchSize :: Int -> Text -> Int -> CBOR.Decoder s ()
matchSize requestedSize lbl actualSize =
when (actualSize /= requestedSize) $
cborError
( lbl
<> " failed the size check. Expected "
<> Text.pack (show requestedSize)
<> ", found "
<> Text.pack (show actualSize)
)

decodeXPrv :: CBOR.Decoder s Wallet.XPrv
decodeXPrv = CBOR.decodeBytesCanonical >>= either (fail . formatToString build) pure . Wallet.xprv

-- \| Decoder for a Byron/Classic signing key.
-- Lifted from cardano-sl legacy codebase.
decodeLegacyDelegateKey :: CBOR.Decoder s Crypto.SigningKey
decodeLegacyDelegateKey = do
enforceSize "UserSecret" 4
_ <- do
enforceSize "vss" 1
CBOR.decodeBytes
pkey <- do
enforceSize "pkey" 1
Crypto.SigningKey <$> decodeXPrv
_ <- do
CBOR.decodeListLenIndef
CBOR.decodeSequenceLenIndef (flip (:)) [] reverse CBOR.decodeNull
_ <- do
enforceSize "wallet" 0
pure pkey

instance CastVerificationKeyRole ByronKeyLegacy ByronKey where
castVerificationKey (ByronVerificationKeyLegacy vk) =
ByronVerificationKey vk

instance IsByronKey ByronKeyLegacy where
byronKeyFormat = ByronLegacyKeyFormat
import Cardano.Keys.Byron
Loading
Loading