cardano-addresses-4.0.1: test/Cardano/Address/Style/ByronSpec.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# OPTIONS_GHC -fno-warn-deprecations #-}
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
module Cardano.Address.Style.ByronSpec
( spec
) where
import Prelude
import Cardano.Address.Derivation
( Depth (..)
, DerivationType (..)
, GenMasterKey (..)
, HardDerivation (..)
, Index
, XPrv
, xprvFromBytes
)
import Cardano.Address.Style.Byron
( Byron (..), minSeedLengthBytes )
import Cardano.Mnemonic
( SomeMnemonic (..) )
import Control.Monad
( (<=<) )
import Data.ByteArray
( ByteArrayAccess, ScrubbedBytes )
import Data.ByteArray.Encoding
( Base (Base16), convertFromBase )
import Data.ByteString
( ByteString )
import Data.Text
( Text )
import Test.Arbitrary
( unsafeMkEnglishMnemonic )
import Test.Hspec
( Expectation, Spec, describe, it, shouldBe )
import Test.QuickCheck
( Arbitrary (..), Property, choose, property, vector )
import qualified Data.ByteArray as BA
import qualified Data.ByteString as BS
spec :: Spec
spec = do
goldenSpec
describe "Random Address Derivation Properties" $ do
it "Key derivation from seed works for various indexes" $
property prop_keyDerivationFromSeed
it "Key derivation from master key works for various indexes" $
property prop_keyDerivationFromXPrv
{-------------------------------------------------------------------------------
Properties
-------------------------------------------------------------------------------}
prop_keyDerivationFromSeed
:: SomeMnemonic
-> Index 'WholeDomain 'AccountK
-> Index 'WholeDomain 'PaymentK
-> Property
prop_keyDerivationFromSeed mw accIx addrIx =
addrXPrv `seq` property ()
where
rootXPrv = genMasterKeyFromMnemonic mw () :: Byron 'RootK XPrv
accXPrv = deriveAccountPrivateKey rootXPrv accIx
addrXPrv = deriveAddressPrivateKey accXPrv () addrIx
prop_keyDerivationFromXPrv
:: XPrv
-> Index 'WholeDomain 'AccountK
-> Index 'WholeDomain 'PaymentK
-> Property
prop_keyDerivationFromXPrv xprv accIx addrIx =
addrXPrv `seq` property ()
where
rootXPrv = genMasterKeyFromXPrv xprv :: Byron 'RootK XPrv
accXPrv = deriveAccountPrivateKey rootXPrv accIx
addrXPrv = deriveAddressPrivateKey accXPrv () addrIx
{-------------------------------------------------------------------------------
Golden tests
-------------------------------------------------------------------------------}
goldenSpec :: Spec
goldenSpec = describe "Golden tests" $ do
it "unsafeGenerateKeyFromSeed - no passphrase" $
generateTest generateTest1
{-------------------------------------------------------------------------------
Golden tests for generateKeyFromSeed
-------------------------------------------------------------------------------}
data GenerateKeyFromSeed = GenerateKeyFromSeed
{ mnem :: [Text]
, rootKey :: Byron 'RootK XPrv
}
generateTest :: GenerateKeyFromSeed -> Expectation
generateTest (GenerateKeyFromSeed mnemonic rootXPrv) =
getKey masterKey `shouldBe` getKey rootXPrv
where
mw = SomeMnemonic $ unsafeMkEnglishMnemonic @12 mnemonic
masterKey = genMasterKeyFromMnemonic mw () :: Byron 'RootK XPrv
generateTest1 :: GenerateKeyFromSeed
generateTest1 = GenerateKeyFromSeed
{ mnem = defMnemonic
, rootKey = xprv16
"b84d0b6db447911a98a3ade98145c0e8323e106f07bc17a99c2104c2688bb752\
\8310902a3cec7e262ded6a4369ec1f48966a6b48b1ee90aa00e61b95417949f8\
\a4762129a6c83acfda5b257eaeb73ec5fee1518b6674fdc7891fe23f06174421"
}
-- | This is the mnemonic that provides the 'Default' instance in cardano-sl
defMnemonic :: [Text]
defMnemonic =
[ "squirrel", "material", "silly", "twice", "direct", "slush"
, "pistol", "razor", "become", "junk", "kingdom", "flee" ]
{-------------------------------------------------------------------------------
Utils
-------------------------------------------------------------------------------}
-- | Get a private key from a hex string, without error checking.
xprv16 :: ByteString -> Byron 'RootK XPrv
xprv16 hex = genMasterKeyFromXPrv prv
where
Just prv = (xprvFromBytes <=< fromHexText) hex
fromHexText :: ByteString -> Maybe ByteString
fromHexText = either (const Nothing) Just . convertFromBase Base16
{-------------------------------------------------------------------------------
Arbitrary Instances
-------------------------------------------------------------------------------}
newtype Passphrase = Passphrase ScrubbedBytes
deriving stock (Eq, Show)
deriving newtype (ByteArrayAccess)
-- This generator will only produce valid (@>= minSeedLengthBytes@) passphrases
-- because 'generateKeyFromSeed' is a partial function.
instance {-# OVERLAPS #-} Arbitrary Passphrase where
arbitrary = do
n <- choose (minSeedLengthBytes, 64)
bytes <- BS.pack <$> vector n
return $ Passphrase $ BA.convert bytes