Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

assetseed cli app #1324

Merged
merged 1 commit into from Dec 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -21,6 +21,7 @@ dist/
node_modules/
client/cmd/dexc/dexc
client/cmd/dexcctl/dexcctl
client/cmd/assetseed/assetseed
docs/examples/rpcclient/rpcclient
wiki
dex/testing/loadbot/loadbot
Expand Down
43 changes: 43 additions & 0 deletions client/cmd/assetseed/main.go
@@ -0,0 +1,43 @@
// This code is available on the terms of the project LICENSE.md file,
// also available online at https://blueoakcouncil.org/license/1.0.0.

package main

import (
"encoding/hex"
"flag"
"fmt"
"os"

"decred.org/dcrdex/client/core"
)

func main() {
var appSeed string
flag.StringVar(&appSeed, "seed", "", "DEX client application seed (128 hexadecimal characters)")
var assetID uint
flag.UintVar(&assetID, "asset", 0, "Asset ID. BIP-0044 coin type (integer).\n"+
"See https://github.com/satoshilabs/slips/blob/master/slip-0044.md")
flag.Parse()

if appSeed == "" {
flag.Usage()
os.Exit(1)
}

appSeedB, err := hex.DecodeString(appSeed)
if err != nil {
fmt.Fprintf(os.Stderr, "bad app seed: %v\n", err)
os.Exit(1)
}

if len(appSeedB) != 64 {
fmt.Fprintf(os.Stderr, "app seed is %d bytes, expected 64\n", len(appSeedB))
os.Exit(1)
}

seed, _ := core.AssetSeedAndPass(uint32(assetID), appSeedB)
fmt.Printf("%x\n", seed)

os.Exit(0)
}
8 changes: 6 additions & 2 deletions client/core/core.go
Expand Up @@ -1832,11 +1832,15 @@ func (c *Core) assetSeedAndPass(assetID uint32, crypter encrypt.Crypter) (seed,
return nil, nil, fmt.Errorf("app seed decryption error: %w", err)
}

seed, pass = assetSeedAndPass(assetID, appSeed)
seed, pass = AssetSeedAndPass(assetID, appSeed)
return seed, pass, nil
}

func assetSeedAndPass(assetID uint32, appSeed []byte) ([]byte, []byte) {
// AssetSeedAndPass derives the wallet seed and password that would be used to
// create a native wallet for a particular asset and application seed. Depending
// on external wallet software and their key derivation paths, this seed may be
// usable for accessing funds outside of DEX applications, e.g. btcwallet.
func AssetSeedAndPass(assetID uint32, appSeed []byte) ([]byte, []byte) {
b := make([]byte, len(appSeed)+4)
copy(b, appSeed)
binary.BigEndian.PutUint32(b[len(appSeed):], assetID)
Expand Down
4 changes: 2 additions & 2 deletions client/core/core_test.go
Expand Up @@ -7287,7 +7287,7 @@ func TestCredentialHandling(t *testing.T) {
// Decred wallet"
}

func TestCore_assetSeedAndPass(t *testing.T) {
func TestCoreAssetSeedAndPass(t *testing.T) {
// This test ensures the derived wallet seed and password are deterministic
// and depend on both asset ID and app seed.

Expand Down Expand Up @@ -7339,7 +7339,7 @@ func TestCore_assetSeedAndPass(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
seed, pass := assetSeedAndPass(tt.assetID, tt.appSeed)
seed, pass := AssetSeedAndPass(tt.assetID, tt.appSeed)
if !bytes.Equal(pass, tt.wantPass) {
t.Errorf("pass not as expected, got %#v", pass)
}
Expand Down