Skip to content

Commit

Permalink
Add support for loading private key from hex string (#118)
Browse files Browse the repository at this point in the history
* Add support for loading private key from hex string
---------

Signed-off-by: Saurabh Singh <[email protected]>
  • Loading branch information
saurabh-router authored Oct 4, 2024
1 parent 7230165 commit ed9af41
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 0 deletions.
38 changes: 38 additions & 0 deletions tests/types/keypair/private_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,41 @@ func Test_ED25Key_CreateAndValidateRawSignature(t *testing.T) {
err = privateKeyData.PublicKey().VerifyRawSignature(secretMessage, signature)
assert.NoError(t, err)
}

func Test_NewPrivateKeyFromHex(t *testing.T) {
t.Run("Valid ED25519 key", func(t *testing.T) {
// This is a sample ED25519 private key in hex format
hexKey := "dda433e404770ebbe9cec28cd7623770ce4222c4961dc4508b076145126c200ece69876ad8154b3c4ec5c2a6ca250e88efda5008cef9ca5ec6767045ee006b53"
privateKey, err := keypair.NewPrivateKeyFromHex(hexKey, keypair.ED25519)

require.NoError(t, err)
assert.NotNil(t, privateKey.PublicKey())
assert.Equal(t, "01ce69876ad8154b3c4ec5c2a6ca250e88efda5008cef9ca5ec6767045ee006b53", privateKey.PublicKey().ToHex())
assert.NotNil(t, privateKey)
})

t.Run("Valid SECP256K1 key", func(t *testing.T) {
// This is a sample SECP256K1 private key in hex format
hexKey := "1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd"
privateKey, err := keypair.NewPrivateKeyFromHex(hexKey, keypair.SECP256K1)

require.NoError(t, err)
assert.NotNil(t, privateKey.PublicKey())
})

t.Run("Invalid hex for ED25519", func(t *testing.T) {
hexKey := "invalid_hex"
_, err := keypair.NewPrivateKeyFromHex(hexKey, keypair.ED25519)

assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to create private key")
})

t.Run("Invalid hex for SECP256K1", func(t *testing.T) {
hexKey := "invalid_hex"
_, err := keypair.NewPrivateKeyFromHex(hexKey, keypair.SECP256K1)

assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to create private key")
})
}
35 changes: 35 additions & 0 deletions types/keypair/ed25519/hex_parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package ed25519

import (
"crypto/ed25519"
"encoding/hex"
"fmt"
)

// NewPrivateKeyFromBytes creates an ED25519 PrivateKey from raw bytes
func NewPrivateKeyFromBytes(key []byte) (PrivateKey, error) {
// Check if the key size matches the expected ED25519 private key size
if len(key) != ed25519.PrivateKeySize {
return PrivateKey{}, fmt.Errorf("wrong key size: expected %v bytes, got %v bytes", ed25519.PrivateKeySize, len(key))
}

privateKey := ed25519.PrivateKey(key)
return PrivateKey{
key: privateKey,
}, nil
}

// NewPrivateKeyFromHex creates an ED25519 PrivateKey from a hex string
func NewPrivateKeyFromHex(key string) (PrivateKey, error) {
// Validate hex string length (128 hex characters = 64 bytes for ED25519 private key)
if len(key) != ed25519.PrivateKeySize*2 {
return PrivateKey{}, fmt.Errorf("invalid hex string length: expected %v characters, got %v", ed25519.PrivateKeySize*2, len(key))
}

b, err := hex.DecodeString(key)
if err != nil {
return PrivateKey{}, fmt.Errorf("failed to decode hex string: %v", err)
}

return NewPrivateKeyFromBytes(b)
}
30 changes: 30 additions & 0 deletions types/keypair/private_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keypair

import (
"errors"
"fmt"
"os"

"github.com/make-software/casper-go-sdk/v2/types/keypair/ed25519"
Expand Down Expand Up @@ -113,3 +114,32 @@ func GeneratePrivateKey(algorithm keyAlgorithm) (PrivateKey, error) {
priv: priv,
}, nil
}

func NewPrivateKeyFromHex(key string, algorithm keyAlgorithm) (PrivateKey, error) {
var priv PrivateKeyInternal
var err error

switch algorithm {
case ED25519:
priv, err = ed25519.NewPrivateKeyFromHex(key)
case SECP256K1:
priv, err = secp256k1.NewPrivateKeyFromHex(key)
default:
return PrivateKey{}, fmt.Errorf("unsupported key algorithm: %v", algorithm)
}

if err != nil {
return PrivateKey{}, fmt.Errorf("failed to create private key: %w", err)
}

publicKey, err := NewPublicKeyFromBytes(append([]byte{byte(algorithm)}, priv.PublicKeyBytes()...))
if err != nil {
return PrivateKey{}, fmt.Errorf("failed to create public key: %w", err)
}

return PrivateKey{
alg: algorithm,
pub: publicKey,
priv: priv,
}, nil
}
38 changes: 38 additions & 0 deletions types/keypair/secp256k1/hex_parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package secp256k1

import (
"encoding/hex"
"fmt"

"github.com/decred/dcrd/dcrec/secp256k1/v4"
)

// NewPrivateKeyFromBytes creates a secp256k1 PrivateKey from raw bytes
func NewPrivateKeyFromBytes(key []byte) (PrivateKey, error) {
// Validate key length (32 bytes for secp256k1)
if len(key) != 32 {
return PrivateKey{}, fmt.Errorf("invalid private key length: expected 32 bytes, got %d", len(key))
}

privateKey := secp256k1.PrivKeyFromBytes(key)

return PrivateKey{
key: privateKey,
}, nil
}

// NewPrivateKeyFromHex creates a secp256k1 PrivateKey from a hex string
func NewPrivateKeyFromHex(key string) (PrivateKey, error) {
// Validate hex string length (64 hex characters for secp256k1)
if len(key) != 64 {
return PrivateKey{}, fmt.Errorf("invalid private key hex length: expected 64 characters, got %d", len(key))
}

// Decode the hex string into bytes
b, err := hex.DecodeString(key)
if err != nil {
return PrivateKey{}, fmt.Errorf("failed to decode hex: %v", err)
}

return NewPrivateKeyFromBytes(b)
}

0 comments on commit ed9af41

Please sign in to comment.