91 lines
3.1 KiB
Go
91 lines
3.1 KiB
Go
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")
|
||
|
|
}
|
||
|
|
}
|