Skip to content
This repository has been archived by the owner on Dec 7, 2019. It is now read-only.

Commit

Permalink
Merge pull request #38 from libp2p/fix/17
Browse files Browse the repository at this point in the history
switch to the go-crypto ed25519 implementation
  • Loading branch information
Stebalien authored Aug 11, 2018
2 parents c001d46 + f6f8063 commit 137c71c
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 84 deletions.
89 changes: 41 additions & 48 deletions ed25519.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ import (
"fmt"
"io"

"github.com/agl/ed25519"
extra "github.com/agl/ed25519/extra25519"
pb "github.com/libp2p/go-libp2p-crypto/pb"
"golang.org/x/crypto/ed25519"
)

type Ed25519PrivateKey struct {
sk *[64]byte
pk *[32]byte
k ed25519.PrivateKey
}

type Ed25519PublicKey struct {
k *[32]byte
k ed25519.PublicKey
}

func GenerateEd25519Key(src io.Reader) (PrivKey, PubKey, error) {
Expand All @@ -26,8 +24,7 @@ func GenerateEd25519Key(src io.Reader) (PrivKey, PubKey, error) {
}

return &Ed25519PrivateKey{
sk: priv,
pk: pub,
k: priv,
},
&Ed25519PublicKey{
k: pub,
Expand All @@ -44,35 +41,35 @@ func (k *Ed25519PrivateKey) Bytes() ([]byte, error) {
}

func (k *Ed25519PrivateKey) Raw() ([]byte, error) {
buf := make([]byte, 96)
copy(buf, k.sk[:])
copy(buf[64:], k.pk[:])
// Intentionally redundant for backwards compatibility.
// Issue: #36
// TODO: Remove the second copy of the public key at some point in the future.
buf := make([]byte, len(k.k)+ed25519.PublicKeySize)
copy(buf, k.k)
copy(buf[len(k.k):], k.pubKeyBytes())

return buf, nil
}

func (k *Ed25519PrivateKey) pubKeyBytes() []byte {
return k.k[ed25519.PrivateKeySize-ed25519.PublicKeySize:]
}

func (k *Ed25519PrivateKey) Equals(o Key) bool {
edk, ok := o.(*Ed25519PrivateKey)
if !ok {
return false
}

return bytes.Equal((*k.sk)[:], (*edk.sk)[:]) && bytes.Equal((*k.pk)[:], (*edk.pk)[:])
return bytes.Equal(k.k, edk.k)
}

func (k *Ed25519PrivateKey) GetPublic() PubKey {
return &Ed25519PublicKey{k.pk}
return &Ed25519PublicKey{k: k.pubKeyBytes()}
}

func (k *Ed25519PrivateKey) Sign(msg []byte) ([]byte, error) {
out := ed25519.Sign(k.sk, msg)
return (*out)[:], nil
}

func (k *Ed25519PrivateKey) ToCurve25519() *[32]byte {
var sk [32]byte
extra.PrivateKeyToCurve25519(&sk, k.sk)
return &sk
return ed25519.Sign(k.k, msg), nil
}

func (k *Ed25519PublicKey) Type() pb.KeyType {
Expand All @@ -84,7 +81,7 @@ func (k *Ed25519PublicKey) Bytes() ([]byte, error) {
}

func (k *Ed25519PublicKey) Raw() ([]byte, error) {
return (*k.k)[:], nil
return k.k, nil
}

func (k *Ed25519PublicKey) Equals(o Key) bool {
Expand All @@ -93,48 +90,44 @@ func (k *Ed25519PublicKey) Equals(o Key) bool {
return false
}

return bytes.Equal((*k.k)[:], (*edk.k)[:])
return bytes.Equal(k.k, edk.k)
}

func (k *Ed25519PublicKey) Verify(data []byte, sig []byte) (bool, error) {
var asig [64]byte
copy(asig[:], sig)
return ed25519.Verify(k.k, data, &asig), nil
}

func (k *Ed25519PublicKey) ToCurve25519() (*[32]byte, error) {
var pk [32]byte
success := extra.PublicKeyToCurve25519(&pk, k.k)
if !success {
return nil, fmt.Errorf("Error converting ed25519 pubkey to curve25519 pubkey")
}
return &pk, nil
return ed25519.Verify(k.k, data, sig), nil
}

func UnmarshalEd25519PublicKey(data []byte) (PubKey, error) {
if len(data) != 32 {
return nil, fmt.Errorf("expect ed25519 public key data size to be 32")
}

var pub [32]byte
copy(pub[:], data)

return &Ed25519PublicKey{
k: &pub,
k: ed25519.PublicKey(data),
}, nil
}

func UnmarshalEd25519PrivateKey(data []byte) (PrivKey, error) {
if len(data) != 96 {
return nil, fmt.Errorf("expected ed25519 data size to be 96")
switch len(data) {
case ed25519.PrivateKeySize + ed25519.PublicKeySize:
// Remove the redundant public key. See issue #36.
redundantPk := data[ed25519.PrivateKeySize:]
if !bytes.Equal(data[len(data)-ed25519.PublicKeySize:], redundantPk) {
return nil, fmt.Errorf("expected redundant ed25519 public key to be redundant")
}

// No point in storing the extra data.
newKey := make([]byte, ed25519.PrivateKeySize)
copy(newKey, data[:ed25519.PrivateKeySize])
data = newKey
case ed25519.PrivateKeySize:
default:
return nil, fmt.Errorf(
"expected ed25519 data size to be %d or %d",
ed25519.PrivateKeySize,
ed25519.PublicKeySize+ed25519.PublicKeySize,
)
}
var priv [64]byte
var pub [32]byte
copy(priv[:], data)
copy(pub[:], data[64:])

return &Ed25519PrivateKey{
sk: &priv,
pk: &pub,
k: ed25519.PrivateKey(data),
}, nil
}
95 changes: 59 additions & 36 deletions ed25519_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package crypto
import (
"crypto/rand"
"testing"

pb "github.com/libp2p/go-libp2p-crypto/pb"

"golang.org/x/crypto/ed25519"
)

func TestBasicSignAndVerify(t *testing.T) {
Expand Down Expand Up @@ -59,47 +63,66 @@ func TestSignZero(t *testing.T) {
t.Fatal("signature didn't match")
}
}

func TestMarshalLoop(t *testing.T) {
priv, pub, err := GenerateEd25519Key(rand.Reader)
if err != nil {
t.Fatal(err)
}

privB, err := priv.Bytes()
if err != nil {
t.Fatal(err)
for name, f := range map[string]func() ([]byte, error){
"Bytes": priv.Bytes,
"Marshal": func() ([]byte, error) {
return MarshalPrivateKey(priv)
},
"NonRedundant": func() ([]byte, error) {
// Manually marshal a non-redundant private key to make sure it works!
pbmes := new(pb.PrivateKey)
pbmes.Type = priv.Type()
data, err := priv.Raw()
if err != nil {
t.Fatal(err)
}

pbmes.Data = data[:ed25519.PrivateKeySize]
return pbmes.Marshal()
},
} {
t.Run(name, func(t *testing.T) {
bts, err := f()
if err != nil {
t.Fatal(err)
}
privNew, err := UnmarshalPrivateKey(bts)
if err != nil {
t.Fatal(err)
}

if !priv.Equals(privNew) || !privNew.Equals(priv) {
t.Fatal("keys are not equal")
}
})
}

for name, f := range map[string]func() ([]byte, error){
"Bytes": pub.Bytes,
"Marshal": func() ([]byte, error) {
return MarshalPublicKey(pub)
},
} {
t.Run(name, func(t *testing.T) {
bts, err := f()
if err != nil {
t.Fatal(err)
}
pubNew, err := UnmarshalPublicKey(bts)
if err != nil {
t.Fatal(err)
}

if !pub.Equals(pubNew) || !pubNew.Equals(pub) {
t.Fatal("keys are not equal")
}
})
}

privNew, err := UnmarshalPrivateKey(privB)
if err != nil {
t.Fatal(err)
}

privB, err = MarshalPrivateKey(priv)
if err != nil {
t.Fatal(err)
}

privNew, err = UnmarshalPrivateKey(privB)
if err != nil {
t.Fatal(err)
}

if !priv.Equals(privNew) || !privNew.Equals(priv) {
t.Fatal("keys are not equal")
}

pubB, err := pub.Bytes()
if err != nil {
t.Fatal(err)
}
pubNew, err := UnmarshalPublicKey(pubB)
if err != nil {
t.Fatal(err)
}

if !pub.Equals(pubNew) || !pubNew.Equals(pub) {
t.Fatal("keys are not equal")
}

}

0 comments on commit 137c71c

Please sign in to comment.