cardano-addresses-4.0.0: test/Cardano/Codec/CborSpec.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# OPTIONS_GHC -fno-warn-deprecations #-}
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
module Cardano.Codec.CborSpec
( spec
) where
import Prelude
import Cardano.Address.Derivation
( Depth (..), GenMasterKey (..), XPrv )
import Cardano.Address.Style.Byron
( Byron (..) )
import Cardano.Codec.Cbor
( decodeAddressDerivationPath
, decodeAddressPayload
, decodeAllAttributes
, decodeDerivationPathAttr
, deserialiseCbor
, encodeAttributes
, encodeDerivationPathAttr
, toLazyByteString
, unsafeDeserialiseCbor
)
import Cardano.Mnemonic
( mkSomeMnemonic )
import Data.ByteArray
( ByteArrayAccess, ScrubbedBytes )
import Data.ByteString
( ByteString )
import Data.Text
( Text )
import Data.Word
( Word32 )
import Test.Arbitrary
( unsafeFromHex )
import Test.Hspec
( Expectation, Spec, describe, it, shouldBe )
import Test.QuickCheck
( Arbitrary (..), Property, conjoin, property, vector, (===), (==>) )
import qualified Data.ByteArray as BA
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
{- HLINT ignore "Use head" -}
spec :: Spec
spec = do
describe "decodeAddress <-> encodeAddress roundtrip" $ do
it "DerivationPath roundtrip" (property prop_derivationPathRoundTrip)
describe "Golden Tests for Byron Addresses w/ random scheme (Mainnet)" $ do
it "decodeDerivationPath - mainnet - initial account" $
decodeDerivationPathTest DecodeDerivationPath
{ mnem =
arbitraryMnemonic
, addr =
"82d818584283581ca08bcb9e5e8cd30d5aea6d434c46abd8604fe4907d\
\56b9730ca28ce5a101581e581c22e25f2464ec7295b556d86d0ec33bc1\
\a681e7656da92dbc0582f5e4001a3abe2aa5"
, accIndex =
2147483648
, addrIndex =
2147483648
}
it "decodeDerivationPath - mainnet - another account" $
decodeDerivationPathTest DecodeDerivationPath
{ mnem =
arbitraryMnemonic
, addr =
"82d818584283581cb039e80866203e82fc834b8e6a355b83ec6f8fd199\
\66078a40e6d6b2a101581e581c22e27fb12d08728073cd416dfbfcb8dc\
\0e760335d1d60f65e8740034001a4bce4d1a"
, accIndex =
2694138340
, addrIndex =
2512821145
}
describe "Golden Tests for Byron Addresses w/ random scheme (Testnet)" $ do
it "decodeDerivationPath - testnet - initial account" $
decodeDerivationPathTest DecodeDerivationPath
{ mnem =
arbitraryMnemonic
, addr =
"82d818584983581ca03d42af673855aabcef3059e21c37235ae706072d\
\38150dcefae9c6a201581e581c22e25f2464ec7295b556d86d0ec33bc1\
\a681e7656da92dbc0582f5e402451a4170cb17001a39a0b7b5"
, accIndex =
2147483648
, addrIndex =
2147483648
}
it "decodeDerivationPath - testnet - another account" $
decodeDerivationPathTest DecodeDerivationPath
{ mnem =
arbitraryMnemonic
, addr =
"82d818584983581c267b40902921c3afd73926a83a23ca08ae9626a64a\
\4b5616d14d6709a201581e581c22e219c90fb572d565134f6daeab650d\
\c871d130430afe594116f1ae02451a4170cb17001aee75f28a"
, accIndex =
3337448281
, addrIndex =
3234874775
}
{-------------------------------------------------------------------------------
Golden tests for Address derivation path
-------------------------------------------------------------------------------}
data DecodeDerivationPath = DecodeDerivationPath
{ mnem :: [Text]
, addr :: ByteString
, accIndex :: Word32
, addrIndex :: Word32
} deriving (Show, Eq)
-- An aribtrary mnemonic sentence for the tests
arbitraryMnemonic :: [Text]
arbitraryMnemonic =
[ "price", "whip", "bottom", "execute", "resist", "library"
, "entire", "purse", "assist", "clock", "still", "noble" ]
decodeDerivationPathTest :: DecodeDerivationPath -> Expectation
decodeDerivationPathTest DecodeDerivationPath{..} =
decoded `shouldBe` Right (Just (accIndex, addrIndex))
where
payload = unsafeDeserialiseCbor decodeAddressPayload $
BL.fromStrict (unsafeFromHex addr)
decoded = deserialiseCbor (decodeAddressDerivationPath pwd) payload
Right mw = mkSomeMnemonic @'[12] mnem
key = genMasterKeyFromMnemonic mw () :: Byron 'RootK XPrv
pwd = payloadPassphrase key
{-------------------------------------------------------------------------------
Derivation Path Roundtrip
-------------------------------------------------------------------------------}
prop_derivationPathRoundTrip
:: Passphrase
-> Passphrase
-> Word32
-> Word32
-> Property
prop_derivationPathRoundTrip (Passphrase pwd) (Passphrase pwd') acctIx addrIx =
let
encoded = toLazyByteString $ encodeAttributes
[ encodeDerivationPathAttr pwd acctIx addrIx ]
decoded = unsafeDeserialiseCbor
(decodeAllAttributes >>= decodeDerivationPathAttr pwd)
encoded
decoded' = unsafeDeserialiseCbor
(decodeAllAttributes >>= decodeDerivationPathAttr pwd')
encoded
in
conjoin
[ decoded === Just (acctIx, addrIx)
, pwd /= pwd' ==> decoded' === Nothing
]
{-------------------------------------------------------------------------------
Arbitrary Instances
-------------------------------------------------------------------------------}
newtype Passphrase = Passphrase ScrubbedBytes
deriving stock (Eq, Show)
deriving newtype (ByteArrayAccess)
instance Arbitrary Passphrase where
arbitrary = do
bytes <- BS.pack <$> vector 32
return $ Passphrase $ BA.convert bytes