如何在Golang中从助记词派生以太坊账户的公私钥?
解决Golang从助记词派生以太坊公私钥的问题
你当前的代码只生成了master密钥,还没按照BIP-44路径m/44'/60'/0'/0/0派生出对应以太坊账户的子密钥。下面是完整的实现步骤和修改后的代码:
关键步骤说明
- 解析派生路径:将BIP路径拆分为多个层级,区分普通索引和hardened索引(带
'的索引需要加上0x80000000)。 - 逐层派生子密钥:从masterKey开始,依次派生每个层级的子密钥。
- 生成以太坊地址:用派生后的公钥(去掉开头的
0x04字节)计算Keccak256哈希,取最后20字节作为地址并添加0x前缀。 - 格式化公私钥:将私钥和公钥转换为十六进制字符串,添加
0x前缀。
修改后的完整代码
package generator import ( "encoding/hex" "fmt" "strconv" "strings" "github.com/tyler-smith/go-bip32" "github.com/tyler-smith/go-bip39" "golang.org/x/crypto/sha3" ) type HDWallet struct{} const BIP_PATH = "m/44'/60'/0'/0/0" func (wallet *HDWallet) GenerateAddressAndPrivateKey(seedPhrase string) (string, string, error) { // 从助记词生成seed seed, err := bip39.NewSeedWithErrorChecking(seedPhrase, "") if err != nil { return "", "", err } // 生成master密钥 masterKey, err := bip32.NewMasterKey(seed) if err != nil { return "", "", err } // 解析BIP路径并派生子密钥 parts := strings.Split(BIP_PATH, "/") currentKey := masterKey // 跳过第一个"m"部分 for _, part := range parts[1:] { // 处理hardened索引(带') isHardened := strings.HasSuffix(part, "'") if isHardened { part = strings.TrimSuffix(part, "'") } // 转换为整数索引 index, err := strconv.ParseUint(part, 10, 32) if err != nil { return "", "", fmt.Errorf("invalid path part: %s, err: %w", part, err) } // hardened索引需要加上0x80000000 if isHardened { index += 0x80000000 } // 派生子密钥 currentKey, err = currentKey.Child(uint32(index)) if err != nil { return "", "", fmt.Errorf("failed to derive child key: %w", err) } } // 获取私钥并格式化为十六进制字符串(带0x前缀) privateKeyHex := "0x" + hex.EncodeToString(currentKey.Key) // 获取公钥(去掉开头的0x04字节,以太坊用非压缩公钥) publicKey := currentKey.PublicKey().Key[1:] // 计算Keccak256哈希 hash := sha3.NewLegacyKeccak256() hash.Write(publicKey) hashBytes := hash.Sum(nil) // 取最后20字节作为以太坊地址,添加0x前缀 address := "0x" + hex.EncodeToString(hashBytes[12:]) return address, privateKeyHex, nil }
代码说明
- 路径解析:通过拆分路径字符串,逐个处理每个层级的索引,区分hardened类型并转换为正确的索引值。
- 子密钥派生:使用
currentKey.Child()方法逐层派生,最终得到对应以太坊账户的子密钥。 - 地址生成:以太坊地址基于公钥的Keccak256哈希生成,需去掉公钥开头的
0x04标识位,再取哈希的后20字节。 - 公私钥格式化:将原始字节数组转换为十六进制字符串,并添加以太坊标准的
0x前缀。
内容的提问来源于stack exchange,提问作者Gervasius Twinklewinkleson
相关产品推荐
相关产品推荐

