module Utils
( RandomSecretKey(..)
, RandomChainCode(..)
, HardIdx(..)
, SoftIdx(..)
-- * Functions helper
, makeXprv
, rskToScalar
, dumpRaw
) where
import Data.Word
import Data.Bits
import qualified Data.ByteString as B
import Control.Monad
import qualified Crypto.Math.Edwards25519 as Edwards25519
import Cardano.Crypto.Wallet (XPrv, xprv)
import Foundation.Check
-- | Randomly generated ED25519 Extended secret key (64 bytes with a special structure)
newtype RandomSecretKey = RandomSecretKey B.ByteString
deriving (Eq)
instance Show RandomSecretKey where
show (RandomSecretKey bs) = "RandomSecretKey " ++ (dumpRaw $ B.unpack bs)
instance Arbitrary RandomSecretKey where
arbitrary = do
{-
high <- toHigh <$> pure 0
middle <- replicateM 30 (pure 0)
low <- toLow <$> pure 0
extended <- replicateM 32 (pure 0)
-}
high <- toHigh <$> arbitrary
middle <- replicateM 30 arbitrary
low <- toLow <$> arbitrary
extended <- replicateM 32 arbitrary
pure $ RandomSecretKey $ B.pack $ [low] ++ middle ++ [high] ++ extended
where
toHigh w = w `clearBit` 7 `clearBit` 5 `setBit` 6
toLow w = w `clearBit` 0 `clearBit` 1 `clearBit` 2
-- | Randomly generate chain code (32 bytes)
newtype RandomChainCode = RandomChainCode B.ByteString
deriving (Eq)
instance Show RandomChainCode where
show (RandomChainCode bs) = "RandomChainCode " ++ (dumpRaw $ B.unpack bs)
instance Arbitrary RandomChainCode where
arbitrary = RandomChainCode . B.pack <$> {-pure (replicate 32 0) <$>-} replicateM 32 arbitrary
newtype HardIdx = HardIdx Word32
deriving (Show,Eq)
instance Arbitrary HardIdx where
arbitrary = HardIdx . setBit 31 <$> arbitrary
newtype SoftIdx = SoftIdx Word32
deriving (Show,Eq)
instance Arbitrary SoftIdx where
arbitrary = SoftIdx . clearBit 31 <$> arbitrary
makeXprv :: RandomSecretKey -> RandomChainCode -> XPrv
makeXprv (RandomSecretKey k) (RandomChainCode cc) =
let (s1,s2) = B.splitAt 32 k
scalar = Edwards25519.scalar s1
pub = Edwards25519.scalarToPoint scalar
xprvData = k `B.append` Edwards25519.unPointCompressed pub `B.append` cc
in either (error "makeXprv: invalid") id $ xprv xprvData
rskToScalar :: RandomSecretKey -> Edwards25519.Scalar
rskToScalar (RandomSecretKey rsk) = Edwards25519.scalar (B.take 32 rsk)
hex :: Int -> Char
hex 0 = '0'
hex 1 = '1'
hex 2 = '2'
hex 3 = '3'
hex 4 = '4'
hex 5 = '5'
hex 6 = '6'
hex 7 = '7'
hex 8 = '8'
hex 9 = '9'
hex 10 = 'a'
hex 11 = 'b'
hex 12 = 'c'
hex 13 = 'd'
hex 14 = 'e'
hex 15 = 'f'
hex _ = ' '
{-# INLINE hexBytes #-}
hexBytes :: Word8 -> (Char, Char)
hexBytes w = (hex h, hex l) where (h,l) = (fromIntegral w) `divMod` 16
-- | Dump one byte into a 2 hexadecimal characters.
hexString :: Word8 -> String
hexString i = [h,l] where (h,l) = hexBytes i
-- | Dump a list of word8 into a raw string of hex value
dumpRaw :: [Word8] -> String
dumpRaw = concatMap hexString