From 8cf1f86c47d4e9ecf617971159562c9d48659636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E6=98=BE=E6=9D=BE?= Date: Fri, 20 Nov 2020 19:06:32 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9ERawKey=20=E7=BB=99=E5=87=BA?= =?UTF-8?q?=E5=8E=9F=E5=A7=8B=E7=A7=81=E9=92=A5/=E5=85=AC=E9=92=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/cli/Makefile | 3 ++ cmd/cli/main.go | 49 ++++++++++++++++++++++++++++ core/bbc/internal/bip44.go | 4 +-- core/bbc/internal/coin.go | 17 ++++++++++ core/btc/internal/btc.go | 12 +++++++ core/eth/internalized/eth.go | 62 ++++++++++++++++++++++-------------- core/trx/trx.go | 12 +++++++ core/type.go | 2 ++ core/util.go | 8 +++++ wallet/interface.go | 9 ++++++ wallet/interface_test.go | 22 +++++++++++++ 11 files changed, 173 insertions(+), 27 deletions(-) create mode 100644 cmd/cli/Makefile create mode 100644 cmd/cli/main.go create mode 100644 core/util.go diff --git a/cmd/cli/Makefile b/cmd/cli/Makefile new file mode 100644 index 0000000..b96430e --- /dev/null +++ b/cmd/cli/Makefile @@ -0,0 +1,3 @@ +build: + GOOS=windows GOARCH=amd64 go build -o wcli.exe + go build -o wcli \ No newline at end of file diff --git a/cmd/cli/main.go b/cmd/cli/main.go new file mode 100644 index 0000000..7ce0ef9 --- /dev/null +++ b/cmd/cli/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "flag" + "fmt" + + "github.com/dabankio/wallet-core/bip44" + "github.com/dabankio/wallet-core/wallet" +) + +var pass string +var mne string + +func init() { + flag.StringVar(&pass, "pass", "", "-pass xxx") + flag.StringVar(&mne, "mne", "", "-mne xxx") + flag.Parse() +} + +func main() { + const s = "BBC" + + options := &wallet.WalletOptions{} + options.Add(wallet.WithPathFormat(bip44.FullPathFormat)) //m/44'/%d'/0'/0/0, 确保兼容imToken + options.Add(wallet.WithPassword(pass)) //确保兼容imToken + options.Add(wallet.WithShareAccountWithParentChain(true)) //USDT BTC共用地址 + options.Add(wallet.WithFlag(wallet.FlagBBCUseStandardBip44ID)) //BBC使用标准bip44 ID + options.Add(wallet.WithFlag(wallet.FlagMKFUseBBCBip44ID)) //MKF 和BBC共用地址 + + w, err := wallet.BuildWalletFromMnemonic(mne, true, options) + pe(err) + + privk, err := w.DerivePrivateKey(s) + pe(err) + pubk, err := w.DerivePublicKey(s) + pe(err) + address, err := w.DeriveAddress(s) + pe(err) + + fmt.Println("addr", address) + fmt.Println("pubk", pubk) + fmt.Println("prvk", privk) +} + +func pe(e error) { + if e != nil { + panic(e) + } +} diff --git a/core/bbc/internal/bip44.go b/core/bbc/internal/bip44.go index f68724a..7e9611f 100644 --- a/core/bbc/internal/bip44.go +++ b/core/bbc/internal/bip44.go @@ -23,8 +23,6 @@ func init() { } const ( - ed25519SeedSize = 32 - // RecommendedSeedLen is the recommended length in bytes for a seed // to a master node. RecommendedSeedLen = 32 // 256 bits @@ -279,7 +277,7 @@ func (k *ExtendedKey) Child(i uint32) (*ExtendedKey, error) { ilNum.Mod(ilNum, ed25519L) childKey = ilNum.Bytes() - if len(childKey) != ed25519SeedSize { + if len(childKey) != ed25519.SeedSize { _s := blake2b.Sum256(childKey) childKey = _s[:] } diff --git a/core/bbc/internal/coin.go b/core/bbc/internal/coin.go index 55d5283..2e221bd 100644 --- a/core/bbc/internal/coin.go +++ b/core/bbc/internal/coin.go @@ -1,6 +1,8 @@ package internal import ( + "crypto/ed25519" + "github.com/dabankio/gobbc" "github.com/dabankio/wallet-core/bip44" "github.com/dabankio/wallet-core/core" @@ -143,6 +145,21 @@ func (c *Wallet) Sign(msg, privateKey string) (string, error) { return c.SignTemplate(msg, "", privateKey) } +// RawKey 32+32 +func (c *Wallet) RawKey() ([]byte, error) { + child, err := c.derive() + if err != nil { + return nil, err + } + b := make([]byte, 0) + b = core.PaddedAppend(ed25519.SeedSize, b, child.key) + pubk, err := gobbc.Seed2pubk(child.key) + if err != nil { + return nil, err + } + return append(b, pubk...), nil +} + // VerifySignature verifies rawTx's signature is intact func (c *Wallet) VerifySignature(pubKey, msg, signature string) error { return errors.New("verify signature not supported for BBC currently") diff --git a/core/btc/internal/btc.go b/core/btc/internal/btc.go index 1b5b944..b39c0cc 100644 --- a/core/btc/internal/btc.go +++ b/core/btc/internal/btc.go @@ -205,6 +205,18 @@ func (c *BTC) Sign(rawTx, privateKeyWif string) (signedRawTx string, err error) return } +// 32 + 33 (format+pubk) +func (c *BTC) RawKey() ([]byte, error) { + privk, err := c.derivePrivateKey() + if err != nil { + return nil, err + } + b := make([]byte, 0) + b = core.PaddedAppend(btcec.PrivKeyBytesLen, b, privk.D.Bytes()) + b = append(b, privk.PubKey().SerializeCompressed()...) + return b, nil +} + // VerifySignature verifies rawTx's signature is intact // If signedRawTx is not signed by pubKey, an error will raise. func (c *BTC) VerifySignature(pubKey, rawTx, signedRawTx string) error { diff --git a/core/eth/internalized/eth.go b/core/eth/internalized/eth.go index 6d7fb7c..a044d49 100644 --- a/core/eth/internalized/eth.go +++ b/core/eth/internalized/eth.go @@ -22,6 +22,8 @@ const ( symbol = "ETH" ) +var _ core.Coin = (*eth)(nil) + type eth struct { core.CoinInfo } @@ -86,40 +88,24 @@ func (c *eth) DeriveAddress() (address string, err error) { } func (c *eth) DerivePublicKey() (publicKey string, err error) { - privateKeyECDSA, err := c.DerivePrivateKey() + ecPrivk, err := c.deriveECPrivateKey() if err != nil { - return + return "", err } - - privateKey, err := crypto.HexToECDSA(privateKeyECDSA) - if err != nil { - return - } - - public := privateKey.Public() - publicKeyECDSA, ok := public.(*ecdsa.PublicKey) + ecdsaPublicKey, ok := ecPrivk.Public().(*ecdsa.PublicKey) if !ok { - err = errors.New("failed to get public key") - return + return "", errors.New("failed to get public key") } - publicKey = hex.EncodeToString(crypto.FromECDSAPub(publicKeyECDSA)) + publicKey = hex.EncodeToString(crypto.FromECDSAPub(ecdsaPublicKey)) return } func (c *eth) DerivePrivateKey() (privateKey string, err error) { - childKey := c.MasterKey - for _, childNum := range c.DerivationPath { - childKey, err = childKey.Child(childNum) - if err != nil { - return "", err - } - } - - ECPrivateKey, err := childKey.ECPrivKey() + ecPrivk, err := c.deriveECPrivateKey() if err != nil { - return + return "", err } - privateKey = hex.EncodeToString(crypto.FromECDSA(ECPrivateKey.ToECDSA())) + privateKey = hex.EncodeToString(crypto.FromECDSA(ecPrivk)) return } @@ -219,6 +205,34 @@ func (c *eth) Sign(msg, privateKey string) (sig string, err error) { return } +func (c *eth) deriveECPrivateKey() (*ecdsa.PrivateKey, error) { + var err error + childKey := c.MasterKey + for _, childNum := range c.DerivationPath { + childKey, err = childKey.Child(childNum) + if err != nil { + return nil, err + } + } + ecPrivateKey, err := childKey.ECPrivKey() + if err != nil { + return nil, err + } + return ecPrivateKey.ToECDSA(), nil +} + +func (c *eth) RawKey() ([]byte, error) { + ecPrivk, err := c.deriveECPrivateKey() + if err != nil { + return nil, err + } + ecdsaPublicKey, ok := ecPrivk.Public().(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("failed to get public key") + } + return append(crypto.FromECDSA(ecPrivk), crypto.FromECDSAPub(ecdsaPublicKey)...), nil +} + // pubkey is eth address func (c *eth) VerifySignature(address, msg, signature string) (err error) { if !common.IsHexAddress(address) { diff --git a/core/trx/trx.go b/core/trx/trx.go index 218b68c..6fc19bc 100644 --- a/core/trx/trx.go +++ b/core/trx/trx.go @@ -78,6 +78,18 @@ func (c *trx) derivePrivateKey() (privateKey *ecdsa.PrivateKey, err error) { return priKey.ToECDSA(), nil } +func (c *trx) RawKey() ([]byte, error) { + ecPrivk, err := c.derivePrivateKey() + if err != nil { + return nil, err + } + ecdsaPublicKey, ok := ecPrivk.Public().(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("failed to get public key") + } + return append(crypto.FromECDSA(ecPrivk), crypto.FromECDSAPub(ecdsaPublicKey)...), nil +} + func (c *trx) DerivePrivateKey() (privateKey string, err error) { priKey, err := c.derivePrivateKey() if err != nil { diff --git a/core/type.go b/core/type.go index dce7ddb..b3962fc 100644 --- a/core/type.go +++ b/core/type.go @@ -27,6 +27,8 @@ type Coin interface { Sign(msg, privateKey string) (sig string, err error) // VerifySignature verifies rawTx's signature is intact VerifySignature(pubKey, msg, signature string) error + // RawKey return raw private key, public key + RawKey() ([]byte, error) } type HasParentChain interface { diff --git a/core/util.go b/core/util.go new file mode 100644 index 0000000..7eb3cde --- /dev/null +++ b/core/util.go @@ -0,0 +1,8 @@ +package core + +func PaddedAppend(size uint, dst, src []byte) []byte { + for i := 0; i < int(size)-len(src); i++ { + dst = append(dst, 0) + } + return append(dst, src...) +} diff --git a/wallet/interface.go b/wallet/interface.go index 777d31b..b60afc2 100644 --- a/wallet/interface.go +++ b/wallet/interface.go @@ -117,6 +117,15 @@ func (c Wallet) DerivePrivateKey(symbol string) (privateKey string, err error) { return coin.DerivePrivateKey() } +// RawKey 给出原始 私钥+公钥 +func (c Wallet) RawKey(symbol string) ([]byte, error) { + coin, err := c.initCoin(symbol) + if err != nil { + return nil, err + } + return coin.RawKey() +} + // DecodeTx 解析交易数据 // return: json 数据 func (c Wallet) DecodeTx(symbol, msg string) (tx string, err error) { diff --git a/wallet/interface_test.go b/wallet/interface_test.go index 0e6a56f..450eec0 100644 --- a/wallet/interface_test.go +++ b/wallet/interface_test.go @@ -41,6 +41,28 @@ func TestBTCSegwit(t *testing.T) { } +func ExampleDerive(t *testing.T) { + mnemonic := "connect auto goose panda extend ozone absent climb abstract doll west crazy" + var options WalletOptions + options.Add(WithPassword("")) + options.Add(WithPathFormat(bip44.FullPathFormat)) + // options.Add(WithFlag(FlagBTCUseSegWitFormat)) + w, err := BuildWalletFromMnemonic( + mnemonic, + false, + &options, + ) + assert.NoError(t, err) + + for _, s := range []string{"BTC", "BBC", "ETH", "TRX"} { + fmt.Println(s) + key, err := w.RawKey(s) + assert.NoError(t, err) + fmt.Println(len(key), key) + } + +} + // 该测试验证不同的通用参数推导出不同的地址,以确保path/password确实生效 func TestCoin_DeriveAddressOptions(t *testing.T) { const mnemonic = "lecture leg select like delay limit spread retire toward west grape bachelor"