package bip32 import ( "encoding/hex" "testing" "code.luxferre.top/luxferre/kisstron/base58" "code.luxferre.top/luxferre/kisstron/bip39" "code.luxferre.top/luxferre/kisstron/keccak" "code.luxferre.top/luxferre/kisstron/secp256k1" ) // addressOf computes the TRON base58check address for an uncompressed 64-byte // public key (x || y). func addressOf(pub64 []byte) string { h := keccak.Sum256(pub64) payload := append([]byte{0x41}, h[12:]...) return base58.CheckEncode(payload) } // TestKnownDerivations locks the BIP-32 CKDpriv implementation to vectors // produced by tronpy's HDPath on the standard "abandon ... about" mnemonic. func TestKnownDerivations(t *testing.T) { const mn = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" seed := bip39.Seed(mn, "") if got := hex.EncodeToString(seed); got != "5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4" { t.Fatalf("seed = %s", got) } cases := []struct { path string key string addr string }{ {"m/44'/195'/0'/0/0", "b5a4cea271ff424d7c31dc12a3e43e401df7a40d7412a15750f3f0b6b5449a28", "TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH"}, {"m/44'/195'/0'/0/1", "edb728e259afca2ddcc428459e7681b8414668649aedbc8d25c0872da219b2e6", "TSeJkUh4Qv67VNFwY8LaAxERygNdy6NQZK"}, {"m/44'/195'/1'/0/0", "fe06186947bc68444a097c97cce54cbc6ec8344313173346f1fc6d1f68876cd9", "TLrpNTBuCpGMrB9TyVwgEhNVRhtWEQPHh4"}, } for _, tc := range cases { t.Run(tc.path, func(t *testing.T) { key, err := DerivePath(seed, tc.path) if err != nil { t.Fatalf("DerivePath: %v", err) } if got := hex.EncodeToString(key); got != tc.key { t.Fatalf("key = %s, want %s", got, tc.key) } point, err := secp256k1.PublicKey(key) if err != nil { t.Fatalf("PublicKey: %v", err) } raw := make([]byte, 64) point.X.FillBytes(raw[0:32]) point.Y.FillBytes(raw[32:64]) if got := addressOf(raw); got != tc.addr { t.Fatalf("addr = %s, want %s", got, tc.addr) } }) } } func TestSeedWithPassphrase(t *testing.T) { const mn = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" seed := bip39.Seed(mn, "TREZOR") if got := hex.EncodeToString(seed); got != "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04" { t.Fatalf("seed = %s", got) } } func TestParsePath(t *testing.T) { idx, err := ParsePath("m/44'/195'/0'/0/0") if err != nil { t.Fatalf("ParsePath: %v", err) } want := []uint32{0x8000002c, 0x800000c3, 0x80000000, 0, 0} if len(idx) != len(want) { t.Fatalf("len = %d want %d", len(idx), len(want)) } for i := range want { if idx[i] != want[i] { t.Fatalf("idx[%d] = %#x want %#x", i, idx[i], want[i]) } } if _, err := ParsePath("44/195"); err == nil { t.Fatalf("expected error for path without m") } if _, err := ParsePath("m/x"); err == nil { t.Fatalf("expected error for non-numeric node") } }