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

Add priv keys import/export interfaces (CMW-611) #68

Merged
merged 1 commit into from
Nov 1, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions tests/types/keypair/private_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@ func Test_SECPKey_From_PemFile(t *testing.T) {
assert.Equal(t, "0203c90c0ee375abc85da81a982507d1f8258a380af2058b63c37abdb9c7045940f4", privateKeyData.PublicKey().ToHex())
}

func Test_SECPKey_ToPemFile(t *testing.T) {
privateKeyData, err := keypair.NewPrivateKeySECP256K1("../../data/keys/account_test_SECP_secret_key.pem")
require.NoError(t, err)
data, err := privateKeyData.ToPem()
require.NoError(t, err)
privateKeyData2, err := keypair.NewPrivateKeyFromPEM(data, keypair.SECP256K1)
require.NoError(t, err)
assert.Equal(t, privateKeyData.PublicKey().Bytes(), privateKeyData2.PublicKey().Bytes())
}

func Test_ED25519_PrivateKey_ToPemFile(t *testing.T) {
privateKeyData, err := keypair.NewPrivateKeyED25518("../../data/keys/account_test_ED25519_secret_key.pem")
require.NoError(t, err)
data, err := privateKeyData.ToPem()
require.NoError(t, err)
privateKeyData2, err := keypair.NewPrivateKeyFromPEM(data, keypair.ED25519)
require.NoError(t, err)
assert.Equal(t, privateKeyData.PublicKey().Bytes(), privateKeyData2.PublicKey().Bytes())
}

func Test_SECPKey_CreateAndValidateSignature(t *testing.T) {
secretMessage := []byte("Enigmatic Shadows Concealing Ancient Whispers")
privateKeyData, err := keypair.GeneratePrivateKey(keypair.SECP256K1)
Expand Down
43 changes: 43 additions & 0 deletions types/keypair/ed25519/pem_parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package ed25519

import (
"crypto/ed25519"
"encoding/pem"
)

const PemFramePrivateKeyPrefixSize = 16

func PrivateKeyToPem(priv ed25519.PrivateKey) ([]byte, error) {
// Extract the seed (first 32 bytes of the private key)
seed := priv[:32]

// Create the prefix for the seed
prefix := make([]byte, PemFramePrivateKeyPrefixSize)

// Combine the prefix and the seed to match the original format
fullKey := append(prefix, seed...)

return pem.EncodeToMemory(
&pem.Block{
Type: "PRIVATE KEY",
Bytes: fullKey,
},
), nil
}

func NewPrivateKeyFromPEM(content []byte) (PrivateKey, error) {
block, _ := pem.Decode(content)
// Trim PEM prefix
data := block.Bytes[PemFramePrivateKeyPrefixSize:]
// Use only last 32 bytes of private Key
privateKeySize := len(data)
if privateKeySize > 32 {
data = data[privateKeySize%32:]
}

privateEdDSA := ed25519.NewKeyFromSeed(data)

return PrivateKey{
key: privateEdDSA,
}, nil
}
35 changes: 4 additions & 31 deletions types/keypair/ed25519/private_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@ package ed25519

import (
"crypto/ed25519"
"encoding/pem"
"errors"
"os"
)

const PemFramePrivateKeyPrefixSize = 16

type PrivateKey struct {
key ed25519.PrivateKey
}
Expand All @@ -21,6 +16,10 @@ func (k PrivateKey) Sign(mes []byte) ([]byte, error) {
return ed25519.Sign(k.key, mes), nil
}

func (k PrivateKey) ToPem() ([]byte, error) {
return PrivateKeyToPem(k.key)
}

func GeneratePrivateKey() (PrivateKey, error) {
_, priv, err := ed25519.GenerateKey(nil)
if err != nil {
Expand All @@ -30,29 +29,3 @@ func GeneratePrivateKey() (PrivateKey, error) {
key: priv,
}, nil
}

func NewPrivateKeyFromPEMFile(path string) (PrivateKey, error) {
content, err := os.ReadFile(path)
if err != nil {
return PrivateKey{}, errors.New("can't read file")
}

return NewPrivateKeyFromPEM(content)
}

func NewPrivateKeyFromPEM(content []byte) (PrivateKey, error) {
block, _ := pem.Decode(content)
// Trim PEM prefix
data := block.Bytes[PemFramePrivateKeyPrefixSize:]
// Use only last 32 bytes of private Key
privateKeySize := len(data)
if privateKeySize > 32 {
data = data[privateKeySize%32:]
}

privateEdDSA := ed25519.NewKeyFromSeed(data)

return PrivateKey{
key: privateEdDSA,
}, nil
}
18 changes: 16 additions & 2 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"
"os"

"github.com/make-software/casper-go-sdk/types/keypair/ed25519"
"github.com/make-software/casper-go-sdk/types/keypair/secp256k1"
Expand All @@ -10,6 +11,7 @@ import (
type PrivateKeyInternal interface {
PublicKeyBytes() []byte
Sign(mes []byte) ([]byte, error)
ToPem() ([]byte, error)
Volodymyr-Kuchinskyi marked this conversation as resolved.
Show resolved Hide resolved
}

type PrivateKey struct {
Expand All @@ -22,6 +24,10 @@ func (v PrivateKey) PublicKey() PublicKey {
return v.pub
}

func (v PrivateKey) ToPem() ([]byte, error) {
return v.priv.ToPem()
}

// Sign creates a Casper compatible cryptographic signature, including the algorithm tag prefix
func (v PrivateKey) Sign(msg []byte) ([]byte, error) {
sign, err := v.priv.Sign(msg)
Expand All @@ -46,16 +52,24 @@ func NewPrivateKeySECP256K1(path string) (PrivateKey, error) {
}

func NewPrivateKeyFromFile(path string, algorithm keyAlgorithm) (PrivateKey, error) {
content, err := os.ReadFile(path)
if err != nil {
return PrivateKey{}, errors.New("can't read file")
}
return NewPrivateKeyFromPEM(content, algorithm)
}

func NewPrivateKeyFromPEM(content []byte, algorithm keyAlgorithm) (PrivateKey, error) {
var priv PrivateKeyInternal
var err error
switch algorithm {
case ED25519:
priv, err = ed25519.NewPrivateKeyFromPEMFile(path)
priv, err = ed25519.NewPrivateKeyFromPEM(content)
if err != nil {
return PrivateKey{}, err
}
case SECP256K1:
priv, err = secp256k1.NewPrivateKeyFromPemFile(path)
priv, err = secp256k1.NewPrivateKeyFromPem(content)
if err != nil {
return PrivateKey{}, err
}
Expand Down
4 changes: 2 additions & 2 deletions types/keypair/secp256k1/pem_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ func PrivateKeyToPem(priv *secp256k1.PrivateKey) ([]byte, error) {
), nil
}

func PemToPrivateKey(priv []byte) (*secp256k1.PrivateKey, error) {
block, _ := pem.Decode(priv)
func PemToPrivateKey(content []byte) (*secp256k1.PrivateKey, error) {
block, _ := pem.Decode(content)
if block == nil {
return nil, fmt.Errorf("key not found")
}
Expand Down
10 changes: 2 additions & 8 deletions types/keypair/secp256k1/private_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package secp256k1

import (
"crypto/sha256"
"errors"
"os"

"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
Expand All @@ -23,12 +21,8 @@ func (v PrivateKey) Sign(mes []byte) ([]byte, error) {
return ecdsa.SignCompact(v.key, hash[:], false)[1:], nil
}

func NewPrivateKeyFromPemFile(path string) (PrivateKey, error) {
content, err := os.ReadFile(path)
if err != nil {
return PrivateKey{}, errors.New("can't read file")
}
return NewPrivateKeyFromPem(content)
func (v PrivateKey) ToPem() ([]byte, error) {
return PrivateKeyToPem(v.key)
}

func NewPrivateKeyFromPem(content []byte) (PrivateKey, error) {
Expand Down