如何使用 cosmos sdk 生成给定种子短语的高清钱包密钥和地址?
How to generate hd wallet keys & addresses given seed phrase with cosmos sdk?
我正在尝试使用 cosmos sdk 生成高清钱包私钥,public 密钥和地址。下面是 python 中的等效实现,它按预期生成密钥、地址,但是当尝试使用 cosmos sdk 在 golang
中生成时,它不会生成相同的密钥。非常感谢 python 实现的等效 golang 版本的任何输入。谢谢。
Python
seed = Mnemonic.to_seed("blast about old claw current first paste risk involve victory edit current", passphrase="")
print("Seed: ", seed.hex())
purpose = 44
coinType = 118
account = 0
change = 0
hdwallet = HDWallet()
hdwallet.from_seed(seed=seed.hex())
for addressIndex in range(1):
hdwallet.clean_derivation()
hdwallet.from_index(purpose, hardened=True)
hdwallet.from_index(coinType, hardened=True)
hdwallet.from_index(account, hardened=True)
hdwallet.from_index(change)
hdwallet.from_index(addressIndex, hardened=True)
print("---")
print("Derivation Path: ", hdwallet.path())
print("Private Key: ", hdwallet.private_key())
print("Public Key: ", hdwallet.public_key())
readdr_bytes = b"\x04" + bytearray.fromhex(hdwallet.public_key())
readdr_bytes5 = bech32.convertbits(readdr_bytes, 8, 5)
wallet_addr = bech32.bech32_encode("atom", readdr_bytes5)
print("Wallet Address: ", wallet_addr)
OUTPUT
Derivation Path: m/44'/118'/0'/0/0'
Private Key: 69668f2378b43009b16b5c6eb5e405d9224ca2a326a65a17919e567105fa4e5a
Public Key: 03de79435cbc8a799efc24cdce7d3b180fb014d5f19949fb8d61de3f21b9f6c1f8
Wallet Address: atom1qspau72rtj7g57v7lsjvmnna8vvqlvq56hcejj0m34sau0eph8mvr7qgl9avu
GoLang ( Gernerating differnt keys )
import (
"github.com/tendermint/tendermint/crypto/secp256k1"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/go-bip39"
"github.com/decred/dcrd/bech32"
)
path := hd.BIP44Params{
Purpose: 44,
CoinType: 118,
Account: 0,
Change: false,
AddressIndex: 0,
}
seed := bip39.NewSeed("blast about old claw current first paste risk involve victory edit current","")
master, ch := hd.ComputeMastersFromSeed(seed)
priv, err := hd.DerivePrivateKeyForPath(master, ch, path.String())
if err != nil {
log.Fatal(err)
}
var privKey = secp256k1.GenPrivKeySecp256k1(priv)
pubKey := privKey.PubKey()
fmt.Println(hex.EncodeToString(pubKey.Bytes()))
decodeString, _ := hex.DecodeString(fmt.Sprintf("04%x", pubKey.Bytes()))
// Convert test data to base32:
conv, err := bech32.ConvertBits(decodeString, 8, 5, true)
if err != nil {
fmt.Println("Error:", err)
}
encoded, err := bech32.Encode("atom", conv)
if err != nil {
fmt.Println("Error:", err)
}
// Show the encoded data.
fmt.Println("Atom address:", encoded)
OUTPUT
Derivation Path: m/44'/1022'/0'/0/0'
Private Key: 84925813eac8c1dc39f170e93b3bebe0bf961ac9c46507e858ce178a1a715c26
Public Key: 0204a0bad86cafed2daf1b4080a3e908afcf524e2a9c24e20817920c478d537cc1
Wallet Address: atom1qsp3yaurlt463pl6pekgae4yudlcwk2dhxt93cxz5d5ymw3j8xmngaqef5j7p
两个代码的结果因两个问题而不同:
Go代码中私钥导出错误:
在 Python 代码中,使用了路径 m/44'/118'/0'/0/0'
,如 hdwallet.path()
的输出所示。相反,在 Go 代码中,使用路径 m/44'/118'/0'/0/0
,如 path.String()
.
的输出所示
要在Go代码中使用Python代码的路径,路径可以是例如直接指定。为此,行:
priv, err := hd.DerivePrivateKeyForPath(master, ch, path.String())
必须替换为:
priv, err := hd.DerivePrivateKeyForPath(master, ch, "m/44'/118'/0'/0/0'")
并且可以删除 path
变量。
通过此更改,Go 代码提供与 Python 代码相同的私钥。
Go代码中,私钥导入错误。因此,public键被错误确定。要解决此问题,行:
var privKey = secp256k1.GenPrivKeySecp256k1(priv)
必须替换为:
var privKey = secp256k1.PrivKey(priv)
通过此更改,Go 代码提供与 Python 代码相同的 public 键。
Go 代码的其余部分在功能上等同于 Python 代码,因此 Go 代码生成与 Python 代码相同的地址。
完整的 Go 代码为:
package main
import (
"encoding/hex"
"fmt"
"log"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/go-bip39"
"github.com/decred/dcrd/bech32"
"github.com/tendermint/tendermint/crypto/secp256k1"
)
func main() {
seed := bip39.NewSeed("blast about old claw current first paste risk involve victory edit current", "")
fmt.Println("Seed: ", hex.EncodeToString(seed)) // Seed: dd5ffa7088c0fa4c665085bca7096a61e42ba92e7243a8ad7fbc6975a4aeea1845c6b668ebacd024fd2ca215c6cd510be7a9815528016af3a5e6f47d1cca30dd
master, ch := hd.ComputeMastersFromSeed(seed)
path := "m/44'/118'/0'/0/0'"
priv, err := hd.DerivePrivateKeyForPath(master, ch, path)
if err != nil {
log.Fatal(err)
}
fmt.Println("Derivation Path: ", path) // Derivation Path: m/44'/118'/0'/0/0'
fmt.Println("Private Key: ", hex.EncodeToString(priv)) // Private Key: 69668f2378b43009b16b5c6eb5e405d9224ca2a326a65a17919e567105fa4e5a
var privKey = secp256k1.PrivKey(priv)
pubKey := privKey.PubKey()
fmt.Println("Public Key: ", hex.EncodeToString(pubKey.Bytes())) // Public Key: 03de79435cbc8a799efc24cdce7d3b180fb014d5f19949fb8d61de3f21b9f6c1f8
decodeString, err := hex.DecodeString(fmt.Sprintf("04%x", pubKey.Bytes()))
if err != nil {
log.Fatal(err)
}
// Convert test data to base32:
conv, err := bech32.ConvertBits(decodeString, 8, 5, true)
if err != nil {
fmt.Println("Error:", err)
}
encoded, err := bech32.Encode("atom", conv)
if err != nil {
fmt.Println("Error:", err)
}
// Show the encoded data.
fmt.Println("Wallet Address:", encoded) // Wallet Address: atom1qspau72rtj7g57v7lsjvmnna8vvqlvq56hcejj0m34sau0eph8mvr7qgl9avu
}
我正在尝试使用 cosmos sdk 生成高清钱包私钥,public 密钥和地址。下面是 python 中的等效实现,它按预期生成密钥、地址,但是当尝试使用 cosmos sdk 在 golang
中生成时,它不会生成相同的密钥。非常感谢 python 实现的等效 golang 版本的任何输入。谢谢。
Python
seed = Mnemonic.to_seed("blast about old claw current first paste risk involve victory edit current", passphrase="")
print("Seed: ", seed.hex())
purpose = 44
coinType = 118
account = 0
change = 0
hdwallet = HDWallet()
hdwallet.from_seed(seed=seed.hex())
for addressIndex in range(1):
hdwallet.clean_derivation()
hdwallet.from_index(purpose, hardened=True)
hdwallet.from_index(coinType, hardened=True)
hdwallet.from_index(account, hardened=True)
hdwallet.from_index(change)
hdwallet.from_index(addressIndex, hardened=True)
print("---")
print("Derivation Path: ", hdwallet.path())
print("Private Key: ", hdwallet.private_key())
print("Public Key: ", hdwallet.public_key())
readdr_bytes = b"\x04" + bytearray.fromhex(hdwallet.public_key())
readdr_bytes5 = bech32.convertbits(readdr_bytes, 8, 5)
wallet_addr = bech32.bech32_encode("atom", readdr_bytes5)
print("Wallet Address: ", wallet_addr)
OUTPUT
Derivation Path: m/44'/118'/0'/0/0' Private Key: 69668f2378b43009b16b5c6eb5e405d9224ca2a326a65a17919e567105fa4e5a Public Key: 03de79435cbc8a799efc24cdce7d3b180fb014d5f19949fb8d61de3f21b9f6c1f8 Wallet Address: atom1qspau72rtj7g57v7lsjvmnna8vvqlvq56hcejj0m34sau0eph8mvr7qgl9avu
GoLang ( Gernerating differnt keys )
import (
"github.com/tendermint/tendermint/crypto/secp256k1"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/go-bip39"
"github.com/decred/dcrd/bech32"
)
path := hd.BIP44Params{
Purpose: 44,
CoinType: 118,
Account: 0,
Change: false,
AddressIndex: 0,
}
seed := bip39.NewSeed("blast about old claw current first paste risk involve victory edit current","")
master, ch := hd.ComputeMastersFromSeed(seed)
priv, err := hd.DerivePrivateKeyForPath(master, ch, path.String())
if err != nil {
log.Fatal(err)
}
var privKey = secp256k1.GenPrivKeySecp256k1(priv)
pubKey := privKey.PubKey()
fmt.Println(hex.EncodeToString(pubKey.Bytes()))
decodeString, _ := hex.DecodeString(fmt.Sprintf("04%x", pubKey.Bytes()))
// Convert test data to base32:
conv, err := bech32.ConvertBits(decodeString, 8, 5, true)
if err != nil {
fmt.Println("Error:", err)
}
encoded, err := bech32.Encode("atom", conv)
if err != nil {
fmt.Println("Error:", err)
}
// Show the encoded data.
fmt.Println("Atom address:", encoded)
OUTPUT
Derivation Path: m/44'/1022'/0'/0/0' Private Key: 84925813eac8c1dc39f170e93b3bebe0bf961ac9c46507e858ce178a1a715c26 Public Key: 0204a0bad86cafed2daf1b4080a3e908afcf524e2a9c24e20817920c478d537cc1 Wallet Address: atom1qsp3yaurlt463pl6pekgae4yudlcwk2dhxt93cxz5d5ymw3j8xmngaqef5j7p
两个代码的结果因两个问题而不同:
Go代码中私钥导出错误:
在 Python 代码中,使用了路径
的输出所示m/44'/118'/0'/0/0'
,如hdwallet.path()
的输出所示。相反,在 Go 代码中,使用路径m/44'/118'/0'/0/0
,如path.String()
.要在Go代码中使用Python代码的路径,路径可以是例如直接指定。为此,行:
priv, err := hd.DerivePrivateKeyForPath(master, ch, path.String())
必须替换为:
priv, err := hd.DerivePrivateKeyForPath(master, ch, "m/44'/118'/0'/0/0'")
并且可以删除
path
变量。通过此更改,Go 代码提供与 Python 代码相同的私钥。
Go代码中,私钥导入错误。因此,public键被错误确定。要解决此问题,行:
var privKey = secp256k1.GenPrivKeySecp256k1(priv)
必须替换为:
var privKey = secp256k1.PrivKey(priv)
通过此更改,Go 代码提供与 Python 代码相同的 public 键。
Go 代码的其余部分在功能上等同于 Python 代码,因此 Go 代码生成与 Python 代码相同的地址。
完整的 Go 代码为:
package main
import (
"encoding/hex"
"fmt"
"log"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/go-bip39"
"github.com/decred/dcrd/bech32"
"github.com/tendermint/tendermint/crypto/secp256k1"
)
func main() {
seed := bip39.NewSeed("blast about old claw current first paste risk involve victory edit current", "")
fmt.Println("Seed: ", hex.EncodeToString(seed)) // Seed: dd5ffa7088c0fa4c665085bca7096a61e42ba92e7243a8ad7fbc6975a4aeea1845c6b668ebacd024fd2ca215c6cd510be7a9815528016af3a5e6f47d1cca30dd
master, ch := hd.ComputeMastersFromSeed(seed)
path := "m/44'/118'/0'/0/0'"
priv, err := hd.DerivePrivateKeyForPath(master, ch, path)
if err != nil {
log.Fatal(err)
}
fmt.Println("Derivation Path: ", path) // Derivation Path: m/44'/118'/0'/0/0'
fmt.Println("Private Key: ", hex.EncodeToString(priv)) // Private Key: 69668f2378b43009b16b5c6eb5e405d9224ca2a326a65a17919e567105fa4e5a
var privKey = secp256k1.PrivKey(priv)
pubKey := privKey.PubKey()
fmt.Println("Public Key: ", hex.EncodeToString(pubKey.Bytes())) // Public Key: 03de79435cbc8a799efc24cdce7d3b180fb014d5f19949fb8d61de3f21b9f6c1f8
decodeString, err := hex.DecodeString(fmt.Sprintf("04%x", pubKey.Bytes()))
if err != nil {
log.Fatal(err)
}
// Convert test data to base32:
conv, err := bech32.ConvertBits(decodeString, 8, 5, true)
if err != nil {
fmt.Println("Error:", err)
}
encoded, err := bech32.Encode("atom", conv)
if err != nil {
fmt.Println("Error:", err)
}
// Show the encoded data.
fmt.Println("Wallet Address:", encoded) // Wallet Address: atom1qspau72rtj7g57v7lsjvmnna8vvqlvq56hcejj0m34sau0eph8mvr7qgl9avu
}