commit 9ff305c910884bf715f8dfb697a55554d1a260b4
parent 9aca927703f4ea6735e796474fb588597a51b769
Author: Jared Tobin <jared@jtobin.io>
Date:   Thu, 20 Feb 2025 18:25:19 +0400
lib: xpub, xprv, tpub, tprv functions
Diffstat:
1 file changed, 57 insertions(+), 35 deletions(-)
diff --git a/lib/Crypto/HDKey/BIP32.hs b/lib/Crypto/HDKey/BIP32.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE NumericUnderscores #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards #-}
@@ -103,13 +104,13 @@ _master seed@(BI.PS _ _ l)
 
 -- private parent key -> private child key
 ckd_priv :: XPrv -> Word32 -> XPrv
-ckd_priv xprv@(XPrv (X sec cod)) i =
+ckd_priv _xprv@(XPrv (X sec cod)) i =
     let l = SHA512.hmac cod dat
         (il, ci) = BS.splitAt 32 l
         pil = parse256 il
         ki  = Secp256k1.modQ (pil + sec)
     in  if   pil >= Secp256k1._CURVE_Q || ki == 0 -- negl
-        then ckd_priv xprv (succ i)
+        then ckd_priv _xprv (succ i)
         else XPrv (X ki ci)
   where
     dat | hardened i = BS.singleton 0x00 <> ser256 sec <> ser32 i
@@ -119,7 +120,7 @@ ckd_priv xprv@(XPrv (X sec cod)) i =
 
 -- public parent key -> public child key
 ckd_pub :: XPub -> Word32 -> Maybe XPub
-ckd_pub xpub@(XPub (X pub cod)) i
+ckd_pub _xpub@(XPub (X pub cod)) i
   | hardened i = Nothing
   | otherwise = do
       let dat = Secp256k1.serialize_point pub <> ser32 i
@@ -128,7 +129,7 @@ ckd_pub xpub@(XPub (X pub cod)) i
           pil = parse256 il
           ki = Secp256k1.mul_unsafe Secp256k1._CURVE_G pil `Secp256k1.add` pub
       if   pil >= Secp256k1._CURVE_Q || ki == Secp256k1._CURVE_ZERO -- negl
-      then ckd_pub xpub (succ i)
+      then ckd_pub _xpub (succ i)
       else pure (XPub (X ki ci))
 
 -- private parent key -> public child key
@@ -175,49 +176,71 @@ master_pub seed = do
 derive_priv :: HDKey -> Word32 -> Maybe HDKey
 derive_priv HDKey {..} i = case ek_key of
   Left _ -> Nothing
-  Right xprv -> pure $!
-    let key   = Right (ckd_priv xprv i)
+  Right _xprv -> pure $!
+    let key   = Right (ckd_priv _xprv i)
         depth = ek_depth + 1
-        parent = Just (fingerprint xprv)
+        parent = Just (fingerprint _xprv)
         child = ser32 i
     in  HDKey key depth parent child
 
 derive_pub :: HDKey -> Word32 -> Maybe HDKey
 derive_pub HDKey {..} i = do
   (key, parent) <- case ek_key of
-    Left xpub  -> do
-      pub <- ckd_pub xpub i
-      pure (pub, fingerprint xpub)
-    Right xprv ->
-      let pub = n (ckd_priv xprv i)
-      in  pure (pub, fingerprint xprv)
+    Left _xpub  -> do
+      pub <- ckd_pub _xpub i
+      pure (pub, fingerprint _xpub)
+    Right _xprv ->
+      let pub = n (ckd_priv _xprv i)
+      in  pure (pub, fingerprint _xprv)
   let depth = ek_depth + 1
       child = ser32 i
   pure $ HDKey (Left key) depth (Just parent) child
 
 -- serialization --------------------------------------------------------------
 
-serialize_mainnet :: HDKey -> BS.ByteString
-serialize_mainnet x@HDKey {..} =
-    let pay = BS.toStrict . BSB.toLazyByteString $ case ek_key of
-          Left _  -> _serialize _MAINNET_PUBLIC x
-          Right _ -> _serialize _MAINNET_PRIVATE x
-        kek = BS.take 4 (SHA256.hash (SHA256.hash pay))
-    in  B58.encode (pay <> kek)
-  where
-    _MAINNET_PUBLIC  = 0x0488B21E
-    _MAINNET_PRIVATE = 0x0488ADE4
-
-serialize_testnet :: HDKey -> BS.ByteString
-serialize_testnet x@HDKey {..} =
-    let pay = BS.toStrict . BSB.toLazyByteString $ case ek_key of
-          Left _  -> _serialize _TESTNET_PUBLIC x
-          Right _ -> _serialize _TESTNET_PRIVATE x
-        kek = BS.take 4 (SHA256.hash (SHA256.hash pay))
-    in  B58.encode (pay <> kek)
-  where
-    _TESTNET_PUBLIC = 0x043587CF
-    _TESTNET_PRIVATE = 0x04358394
+xpub :: HDKey -> BS.ByteString
+xpub x@HDKey {..} =
+  let _MAINNET_PUBLIC  = 0x0488B21E
+      pay = BS.toStrict . BSB.toLazyByteString $ case ek_key of
+        Left _  -> _serialize _MAINNET_PUBLIC x
+        Right e -> _serialize _MAINNET_PUBLIC HDKey {
+            ek_key = Left (n e)
+          , ..
+          }
+      kek = BS.take 4 (SHA256.hash (SHA256.hash pay))
+  in  B58.encode (pay <> kek)
+
+-- XX make safer?
+
+xprv :: HDKey -> BS.ByteString
+xprv x@HDKey {..} =
+  let _MAINNET_PRIVATE = 0x0488ADE4
+      pay = BS.toStrict . BSB.toLazyByteString $ case ek_key of
+        Left _  -> error "ppad-bip32 (xprv): no private key"
+        Right _ -> _serialize _MAINNET_PRIVATE x
+      kek = BS.take 4 (SHA256.hash (SHA256.hash pay))
+  in  B58.encode (pay <> kek)
+
+tpub :: HDKey -> BS.ByteString
+tpub x@HDKey {..} =
+  let _TESTNET_PUBLIC = 0x043587CF
+      pay = BS.toStrict . BSB.toLazyByteString $ case ek_key of
+        Left _  -> _serialize _TESTNET_PUBLIC x
+        Right e -> _serialize _TESTNET_PUBLIC HDKey {
+            ek_key = Left (n e)
+          , ..
+          }
+      kek = BS.take 4 (SHA256.hash (SHA256.hash pay))
+  in  B58.encode (pay <> kek)
+
+tprv :: HDKey -> BS.ByteString
+tprv x@HDKey {..} =
+  let _TESTNET_PRIVATE = 0x04358394
+      pay = BS.toStrict . BSB.toLazyByteString $ case ek_key of
+        Left _  -> error "ppad-bip32 (tprv): no private key"
+        Right _ -> _serialize _TESTNET_PRIVATE x
+      kek = BS.take 4 (SHA256.hash (SHA256.hash pay))
+  in  B58.encode (pay <> kek)
 
 _serialize :: Word32 -> HDKey -> BSB.Builder
 _serialize version HDKey {..} =
@@ -236,4 +259,3 @@ _serialize version HDKey {..} =
          <> BSB.word8 0x00
          <> BSB.byteString (ser256 sec)
 
-