Skip to content

Commit

Permalink
feat: support bip39 mnemonic for importing ecdsa keys (#212)
Browse files Browse the repository at this point in the history
* feat: support bip39 mnemonic for importing keys

* remove unused code
  • Loading branch information
shrimalmadhur authored Sep 12, 2024
1 parent 9c15fe9 commit 11fe204
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 35 deletions.
26 changes: 14 additions & 12 deletions pkg/keys/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ This command will create keys in $HOME/.eigenlayer/operator_keys/ location

switch keyType {
case KeyTypeECDSA:
privateKey, mnemonic, err := generateEcdsaKeyWithMnemonic()
// Passing empty string to generate a new mnemonic
privateKey, mnemonic, err := generateEcdsaKeyWithMnemonic("")
if err != nil {
return err
}
Expand All @@ -98,17 +99,18 @@ This command will create keys in $HOME/.eigenlayer/operator_keys/ location
return createCmd
}

func generateEcdsaKeyWithMnemonic() (*ecdsa.PrivateKey, string, error) {
// Generate entropy for mnemonic
entropy, err := bip39.NewEntropy(128)
if err != nil {
return nil, "", fmt.Errorf("failed to generate entropy: %v", err)
}

// Generate mnemonic
mnemonic, err := bip39.NewMnemonic(entropy)
if err != nil {
return nil, "", fmt.Errorf("failed to generate mnemonic: %v", err)
func generateEcdsaKeyWithMnemonic(mnemonic string) (*ecdsa.PrivateKey, string, error) {
if mnemonic == "" {
// Generate entropy for mnemonic
entropy, err := bip39.NewEntropy(128)
if err != nil {
return nil, "", fmt.Errorf("failed to generate entropy: %v", err)
}
// Generate mnemonic
mnemonic, err = bip39.NewMnemonic(entropy)
if err != nil {
return nil, "", fmt.Errorf("failed to generate mnemonic: %v", err)
}
}

// Create HD wallet
Expand Down
3 changes: 3 additions & 0 deletions pkg/keys/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ var (
ErrInvalidKeyType = errors.New("invalid key type. key type must be either 'ecdsa' or 'bls'")
ErrInvalidPassword = errors.New("invalid password")
ErrInvalidHexPrivateKey = errors.New("invalid hex private key")
ErrInvalidKeyFormat = errors.New(
"invalid key format. Please provide a single hex encoded private key or a 12-word mnemonic",
)
)
42 changes: 22 additions & 20 deletions pkg/keys/import.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package keys

import (
"crypto/ecdsa"
"fmt"
"math/big"
"regexp"
"strings"

"github.com/Layr-Labs/eigenlayer-cli/pkg/internal/common"
"github.com/Layr-Labs/eigenlayer-cli/pkg/telemetry"
Expand Down Expand Up @@ -53,8 +54,13 @@ This command will import keys in $HOME/.eigenlayer/operator_keys/ location
}

privateKey := args.Get(1)
if err := validatePrivateKey(privateKey); err != nil {
return err
if privateKey == "" {
return ErrEmptyPrivateKey
}

pkSlice := strings.Split(privateKey, " ")
if len(pkSlice) != 1 && len(pkSlice) != 12 {
return ErrInvalidKeyFormat
}

// Check if input is available in the pipe and read the password from it
Expand All @@ -65,12 +71,20 @@ This command will import keys in $HOME/.eigenlayer/operator_keys/ location

switch keyType {
case KeyTypeECDSA:
privateKey = common.Trim0x(privateKey)
privateKeyPair, err := crypto.HexToECDSA(privateKey)
if err != nil {
return err
var privateKeyPair *ecdsa.PrivateKey
var err error
if len(pkSlice) == 1 {
privateKey = common.Trim0x(privateKey)
privateKeyPair, err = crypto.HexToECDSA(privateKey)
if err != nil {
return err
}
} else {
privateKeyPair, _, err = generateEcdsaKeyWithMnemonic(privateKey)
if err != nil {
return err
}
}
// TODO: Add support for mnemonic imports
return saveEcdsaKey(keyName, p, privateKeyPair, insecure, stdInPassword, readFromPipe, "")
case KeyTypeBLS:
privateKeyBigInt := new(big.Int)
Expand Down Expand Up @@ -105,15 +119,3 @@ This command will import keys in $HOME/.eigenlayer/operator_keys/ location
}
return importCmd
}

func validatePrivateKey(pk string) error {
if len(pk) == 0 {
return ErrEmptyPrivateKey
}

if match, _ := regexp.MatchString("\\s", pk); match {
return ErrPrivateKeyContainsWhitespaces
}

return nil
}
21 changes: 18 additions & 3 deletions pkg/keys/import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/Layr-Labs/eigensdk-go/crypto/bls"

"github.com/Layr-Labs/eigenlayer-cli/pkg/internal/common"
prompterMock "github.com/Layr-Labs/eigenlayer-cli/pkg/utils/mocks"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -67,7 +66,7 @@ func TestImportCmd(t *testing.T) {
{
name: "keyname with whitespaces",
args: []string{"--key-type", "ecdsa", "hello", "hello world"},
err: ErrPrivateKeyContainsWhitespaces,
err: ErrInvalidKeyFormat,
},
{
name: "invalid key type",
Expand Down Expand Up @@ -127,6 +126,22 @@ func TestImportCmd(t *testing.T) {
expectedPrivKey: "6842fb8f5fa574d0482818b8a825a15c4d68f542693197f2c2497e3562f335f6",
keyPath: filepath.Join(homePath, OperatorKeystoreSubFolder, "/test.ecdsa.key.json"),
},
{
name: "valid ecdsa key import with mnemonic",
args: []string{
"--key-type",
"ecdsa",
"test",
"kidney various problem toe ready mass exhibit volume shuffle must glue sketch",
},
err: nil,
promptMock: func(p *prompterMock.MockPrompter) {
p.EXPECT().InputHiddenString(gomock.Any(), gomock.Any(), gomock.Any()).Return("", nil)
p.EXPECT().InputHiddenString(gomock.Any(), gomock.Any(), gomock.Any()).Return("", nil)
},
expectedPrivKey: "aee7f88721a86c9e269f50ba9a8675609ee8eef54947827fcdce818d8aafd3b1",
keyPath: filepath.Join(homePath, OperatorKeystoreSubFolder, "/test.ecdsa.key.json"),
},
{
name: "valid bls key import",
args: []string{
Expand Down Expand Up @@ -202,7 +217,7 @@ func TestImportCmd(t *testing.T) {
if tt.args[1] == KeyTypeECDSA {
key, err := GetECDSAPrivateKey(tt.keyPath, "")
assert.NoError(t, err)
assert.Equal(t, common.Trim0x(tt.args[3]), hex.EncodeToString(key.D.Bytes()))
assert.Equal(t, tt.expectedPrivKey, hex.EncodeToString(key.D.Bytes()))
} else if tt.args[1] == KeyTypeBLS {
key, err := bls.ReadPrivateKeyFromFile(tt.keyPath, "")
assert.NoError(t, err)
Expand Down

0 comments on commit 11fe204

Please sign in to comment.