Skip to content

Commit

Permalink
feat: support Secp256k1 format private keys import (#357)
Browse files Browse the repository at this point in the history
* feat: support eip712 private keys import

* fix: rename

* fix: typo

* fix: handle error
  • Loading branch information
j75689 authored Nov 9, 2023
1 parent cfdba88 commit ddd4ce0
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 12 deletions.
67 changes: 55 additions & 12 deletions client/keys/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,82 @@ package keys

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

"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/input"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keys/eth/ethsecp256k1"
)

const (
flagSecp256k1PrivateKey = "secp256k1-private-key"
)

// ImportKeyCommand imports private keys from a keyfile.
func ImportKeyCommand() *cobra.Command {
return &cobra.Command{
Use: "import <name> <keyfile>",
cmd := &cobra.Command{
Use: "import <name> <keyfile>/<privateKey>",
Short: "Import private keys into the local keybase",
Long: "Import a ASCII armored private key into the local keybase.",
Long: "Import a ASCII armored/Secp256k1 private key into the local keybase.",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
buf := bufio.NewReader(clientCtx.Input)

bz, err := os.ReadFile(args[1])
if err != nil {
return err
}
isSecp256k1, _ := cmd.Flags().GetBool(flagSecp256k1PrivateKey)

passphrase, err := input.GetPassword("Enter passphrase to decrypt your key:", buf)
if err != nil {
return err
if !isSecp256k1 {
return importASCIIArmored(clientCtx, args)
}

return clientCtx.Keyring.ImportPrivKey(args[0], string(bz), passphrase)
return importSecp256k1(clientCtx, args)
},
}

cmd.Flags().Bool(flagSecp256k1PrivateKey, false, "import Secp256k1 format private key")

return cmd
}

func importASCIIArmored(clientCtx client.Context, args []string) error {
buf := bufio.NewReader(clientCtx.Input)

bz, err := os.ReadFile(args[1])
if err != nil {
return err
}

passphrase, err := input.GetPassword("Enter passphrase to decrypt your key:", buf)
if err != nil {
return err
}

return clientCtx.Keyring.ImportPrivKey(args[0], string(bz), passphrase)
}

func importSecp256k1(clientCtx client.Context, args []string) error {
keyName := args[0]
keyBytes, err := hex.DecodeString(args[1])
if err != nil {
return err
}
if len(keyBytes) != 32 {
return fmt.Errorf("len of keybytes is not equal to 32")
}
var keyBytesArray [32]byte
copy(keyBytesArray[:], keyBytes[:32])
privKey := hd.EthSecp256k1.Generate()(keyBytesArray[:]).(*ethsecp256k1.PrivKey)

_, err = clientCtx.Keyring.WriteLocalKey(keyName, privKey)
if err != nil {
return err
}
return nil
}
8 changes: 8 additions & 0 deletions crypto/keyring/keyring.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ type Importer interface {

// ImportPubKey imports ASCII armored public keys.
ImportPubKey(uid string, armor string) error

// WriteLocalKey persists a private key object into storage.
WriteLocalKey(name string, privKey types.PrivKey) (*Record, error)
}

// Migrator is implemented by key stores and enables migration of keys from amino to proto
Expand Down Expand Up @@ -757,6 +760,11 @@ func newRealPrompt(dir string, buf io.Reader) func(string) (string, error) {
}
}

// WriteLocalKey persists a local key to the keyring.
func (ks keystore) WriteLocalKey(name string, privKey types.PrivKey) (*Record, error) {
return ks.writeLocalKey(name, privKey)
}

func (ks keystore) writeLocalKey(name string, privKey types.PrivKey) (*Record, error) {
k, err := NewLocalRecord(name, privKey, privKey.PubKey())
if err != nil {
Expand Down

0 comments on commit ddd4ce0

Please sign in to comment.