英文:
How to generate hd wallet keys & addresses given seed phrase with cosmos sdk?
问题
我正在尝试使用 Cosmos SDK 生成 HD 钱包的私钥、公钥和地址。以下是在 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)
输出结果:
Derivation Path: m/44'/118'/0'/0/0'
Private Key: 69668f2378b43009b16b5c6eb5e405d9224ca2a326a65a17919e567105fa4e5a
Public Key: 03de79435cbc8a799efc24cdce7d3b180fb014d5f19949fb8d61de3f21b9f6c1f8
Wallet Address: atom1qspau72rtj7g57v7lsjvmnna8vvqlvq56hcejj0m34sau0eph8mvr7qgl9avu
> GoLang(生成不同的密钥)
```go
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)
输出结果:
---
Derivation Path: m/44'/1022'/0'/0/0'
Private Key: 84925813eac8c1dc39f170e93b3bebe0bf961ac9c46507e858ce178a1a715c26
Public Key: 0204a0bad86cafed2daf1b4080a3e908afcf524e2a9c24e20817920c478d537cc1
Wallet Address: atom1qsp3yaurlt463pl6pekgae4yudlcwk2dhxt93cxz5d5ymw3j8xmngaqef5j7p
英文:
I am trying to generate hd wallet private keys , public keys and addresess using cosmos sdk. Below is the equivalent implementation in python which generates the keys , address as expected but when trying to generated in golang
using cosmos sdk it won't generate same keys. Any inputs for equivalent golang version of the python implementation is much appreciated. Thank you.
> 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
答案1
得分: 4
两个代码的结果不同,原因有两个:
-
在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代码中,私钥的导入方式不正确。因此,公钥被错误地确定。要修复这个问题,需要将以下行:
var privKey = secp256k1.GenPrivKeySecp256k1(priv)
替换为:
var privKey = secp256k1.PrivKey(priv)
通过这个改变,Go代码给出与Python代码相同的公钥。
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
}
英文:
The results of both codes differ because of two issues:
-
In the Go Code, the private key is derived incorrectly:
In the Python code, the path
m/44'/118'/0'/0/0'
is used, as the output ofhdwallet.path()
shows. In the Go code, in contrast, the pathm/44'/118'/0'/0/0
is used, as shown by the output ofpath.String()
.To use the path of the Python code in the Go code, the path can be e.g. specified directly. For this the line:
priv, err := hd.DerivePrivateKeyForPath(master, ch, path.String())
has to be replaced by:
priv, err := hd.DerivePrivateKeyForPath(master, ch, "m/44'/118'/0'/0/0'")
and the
path
variable can be removed.With this change, the Go code provides the same private key as the Python code.
-
In the Go Code, the private key is imported incorrectly. Therefore, the public key is determined wrongly. To fix this, the line:
var privKey = secp256k1.GenPrivKeySecp256k1(priv)
must be replaced by:
var privKey = secp256k1.PrivKey(priv)
With this change, the Go code gives the same public key as the Python code.
The rest of the Go code is functionally equivalent to the Python code, so the Go code produces the same address as the Python code.
The complete Go code is:
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论