module Bitcoin.BIP32.DetDerive ( module Bitcoin.BIP32.DetDerive , module Bitcoin.BIP32.Types ) where import Bitcoin.Internal.Types import Bitcoin.BIP32.Types import Data.Serialize as Bin import Data.Serialize.Get as BinGet import qualified Network.Haskoin.Crypto as HC import Network.Haskoin.Crypto (DerivPathI(..)) class DerivationSeed a where toDerivSeed :: a -> ByteString -- | Deterministically derive a ChildKey from a sourceKey and a 'DerivationSeed' detDerive :: forall a sourceKey t k derivPath. ( DerivationSeed a , DerivPathElem Word32 derivPath , IsChildKey sourceKey t k derivPath ) => sourceKey -> a -> t k detDerive sourceKey seed = mkChild sourceKey path where path :: derivPath path = toDerivPath (to128bitSeed seed) to128bitSeed :: DerivationSeed a => a -> (Word32, Word32, Word32, Word32) to128bitSeed a = either (\e -> error $ "to128bitSeed bug: " ++ e) id $ BinGet.runGet getWords (Bin.encode . HC.hash256 . toDerivSeed $ a) where getWords = do w1 <- BinGet.getWord32be w2 <- BinGet.getWord32be w3 <- BinGet.getWord32be w4 <- BinGet.getWord32be return (w1,w2,w3,w4) -- ######## -- ### Internal --newtype KeyIndex = KeyIndex Word32 class DerivPathElem i derivPath where derivBegin :: i -> derivPath (/:|) :: derivPath -> i -> derivPath instance DerivPathElem Word32 HC.SoftPath where derivBegin i = Deriv :/ cap31Bit i (/:|) p i = p :/ cap31Bit i instance DerivPathElem Word32 HC.HardPath where derivBegin i = Deriv :| cap31Bit i (/:|) p i = p :| cap31Bit i cap31Bit :: Word32 -> Word32 cap31Bit = (`mod` (0x80000000 :: Word32)) class AsDerivePath t derivPath where toDerivPath :: t -> derivPath instance DerivPathElem i derivPath => AsDerivePath (i, i, i, i) derivPath where toDerivPath (w1,w2,w3,w4) = derivBegin w1 /:| w2 /:| w3 /:| w4