forked from ckousik/go-libp2p
/
ed25519.go
156 lines (130 loc) · 3.89 KB
/
ed25519.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package crypto
import (
"bytes"
"crypto/ed25519"
"crypto/subtle"
"errors"
"fmt"
"io"
pb "github.com/John-LittleBearLabs/go-libp2p/core/crypto/pb"
"github.com/John-LittleBearLabs/go-libp2p/core/internal/catch"
)
// Ed25519PrivateKey is an ed25519 private key.
type Ed25519PrivateKey struct {
k ed25519.PrivateKey
}
// Ed25519PublicKey is an ed25519 public key.
type Ed25519PublicKey struct {
k ed25519.PublicKey
}
// GenerateEd25519Key generates a new ed25519 private and public key pair.
func GenerateEd25519Key(src io.Reader) (PrivKey, PubKey, error) {
pub, priv, err := ed25519.GenerateKey(src)
if err != nil {
return nil, nil, err
}
return &Ed25519PrivateKey{
k: priv,
},
&Ed25519PublicKey{
k: pub,
},
nil
}
// Type of the private key (Ed25519).
func (k *Ed25519PrivateKey) Type() pb.KeyType {
return pb.KeyType_Ed25519
}
// Raw private key bytes.
func (k *Ed25519PrivateKey) Raw() ([]byte, error) {
// The Ed25519 private key contains two 32-bytes curve points, the private
// key and the public key.
// It makes it more efficient to get the public key without re-computing an
// elliptic curve multiplication.
buf := make([]byte, len(k.k))
copy(buf, k.k)
return buf, nil
}
func (k *Ed25519PrivateKey) pubKeyBytes() []byte {
return k.k[ed25519.PrivateKeySize-ed25519.PublicKeySize:]
}
// Equals compares two ed25519 private keys.
func (k *Ed25519PrivateKey) Equals(o Key) bool {
edk, ok := o.(*Ed25519PrivateKey)
if !ok {
return basicEquals(k, o)
}
return subtle.ConstantTimeCompare(k.k, edk.k) == 1
}
// GetPublic returns an ed25519 public key from a private key.
func (k *Ed25519PrivateKey) GetPublic() PubKey {
return &Ed25519PublicKey{k: k.pubKeyBytes()}
}
// Sign returns a signature from an input message.
func (k *Ed25519PrivateKey) Sign(msg []byte) (res []byte, err error) {
defer func() { catch.HandlePanic(recover(), &err, "ed15519 signing") }()
return ed25519.Sign(k.k, msg), nil
}
// Type of the public key (Ed25519).
func (k *Ed25519PublicKey) Type() pb.KeyType {
return pb.KeyType_Ed25519
}
// Raw public key bytes.
func (k *Ed25519PublicKey) Raw() ([]byte, error) {
return k.k, nil
}
// Equals compares two ed25519 public keys.
func (k *Ed25519PublicKey) Equals(o Key) bool {
edk, ok := o.(*Ed25519PublicKey)
if !ok {
return basicEquals(k, o)
}
return bytes.Equal(k.k, edk.k)
}
// Verify checks a signature agains the input data.
func (k *Ed25519PublicKey) Verify(data []byte, sig []byte) (success bool, err error) {
defer func() {
catch.HandlePanic(recover(), &err, "ed15519 signature verification")
// To be safe.
if err != nil {
success = false
}
}()
return ed25519.Verify(k.k, data, sig), nil
}
// UnmarshalEd25519PublicKey returns a public key from input bytes.
func UnmarshalEd25519PublicKey(data []byte) (PubKey, error) {
if len(data) != 32 {
return nil, errors.New("expect ed25519 public key data size to be 32")
}
return &Ed25519PublicKey{
k: ed25519.PublicKey(data),
}, nil
}
// UnmarshalEd25519PrivateKey returns a private key from input bytes.
func UnmarshalEd25519PrivateKey(data []byte) (PrivKey, error) {
switch len(data) {
case ed25519.PrivateKeySize + ed25519.PublicKeySize:
// Remove the redundant public key. See issue #36.
redundantPk := data[ed25519.PrivateKeySize:]
pk := data[ed25519.PrivateKeySize-ed25519.PublicKeySize : ed25519.PrivateKeySize]
if subtle.ConstantTimeCompare(pk, redundantPk) == 0 {
return nil, errors.New("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, got %d",
ed25519.PrivateKeySize,
ed25519.PrivateKeySize+ed25519.PublicKeySize,
len(data),
)
}
return &Ed25519PrivateKey{
k: ed25519.PrivateKey(data),
}, nil
}