forked from textileio/near-api-go
/
keypair.go
185 lines (166 loc) · 5.12 KB
/
keypair.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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package keys
import (
"crypto"
"crypto/ed25519"
"crypto/subtle"
"errors"
"fmt"
"strings"
"github.com/mr-tron/base58/base58"
)
// KeyType is the type of key.
type KeyType int
const (
// ED25519 represents an ed25519 key.
ED25519 KeyType = iota
)
// NewPublicKeyFromString creates a new public key from a base58 encoded string prefixed with the key type string.
func NewPublicKeyFromString(str string) (*PublicKey, error) {
parts := strings.Split(str, ":")
if len(parts) == 1 {
data, err := base58.Decode(parts[0])
if err != nil {
return nil, fmt.Errorf("decoding key string: %v", err)
}
return &PublicKey{Type: ED25519, Data: data}, nil
} else if len(parts) == 2 {
keyType, err := stringToKeyType(parts[0])
if err != nil {
return nil, fmt.Errorf("decoding key type string: %v", err)
}
data, err := base58.Decode(parts[1])
if err != nil {
return nil, fmt.Errorf("decoding key data: %v", err)
}
return &PublicKey{Type: keyType, Data: data}, nil
} else {
return nil, fmt.Errorf("invalid encoded key format, must be <curve>:<encoded key>")
}
}
// PublicKey represents a public key.
type PublicKey struct {
Type KeyType
Data []byte
}
// ToString creates a string representation of the public key of the form <curve>:<base58 encoded key>.
func (pk *PublicKey) ToString() (string, error) {
typeStr, err := keyTypeToString(pk.Type)
if err != nil {
return "", fmt.Errorf("converting key type to string: %v", err)
}
return fmt.Sprintf("%s:%s", typeStr, base58.Encode(pk.Data)), nil
}
func keyTypeToString(keyType KeyType) (string, error) {
switch keyType {
case ED25519:
return "ed25519", nil
default:
return "", fmt.Errorf("unknown key type: %v", keyType)
}
}
func stringToKeyType(str string) (KeyType, error) {
switch strings.ToLower(str) {
case "ed25519":
return ED25519, nil
default:
return -1, fmt.Errorf("unknown key type string: %s", str)
}
}
// KeyPair represents a public/private key pair.
type KeyPair interface {
fmt.Stringer
Sign(message []byte) ([]byte, error)
Verify(message, signature []byte) bool
GetPublicKey() PublicKey
}
// NewKeyPairFromRandom creates a random KeyPair using the specified curve.
func NewKeyPairFromRandom(curve string) (KeyPair, error) {
switch strings.ToUpper(curve) {
case "ED25519":
_, priv, err := ed25519.GenerateKey(nil)
if err != nil {
return nil, fmt.Errorf("generating random ed25519 key: %v", err)
}
return &KeyPairEd25519{privateKey: priv}, nil
default:
return nil, fmt.Errorf("unknown curve %s", curve)
}
}
// NewKeyPairFromString creates a new KeyPair from a optionally curve-prefixed base58 string.
func NewKeyPairFromString(secretKey string) (KeyPair, error) {
parts := strings.Split(secretKey, ":")
base58string := ""
if len(parts) == 1 {
base58string = parts[0]
} else if len(parts) == 2 {
switch strings.ToUpper(parts[0]) {
case "ED25519":
base58string = parts[1]
default:
return nil, fmt.Errorf("unknown curve %s", parts[0])
}
} else {
return nil, fmt.Errorf("Invalid encoded key format, must be <curve>:<encoded key>")
}
kp, err := keyPairEd25519FromString(base58string)
if err != nil {
return nil, fmt.Errorf("creating ed25519 key from string: %v", err)
}
return kp, nil
}
// KeyPairEd25519 is an ed25519 implementation of KeyPair.
type KeyPairEd25519 struct {
privateKey ed25519.PrivateKey
}
// Sign signs a message with the KeyPair's private key.
func (k *KeyPairEd25519) Sign(message []byte) ([]byte, error) {
res, err := k.privateKey.Sign(nil, message, crypto.Hash(0))
if err != nil {
return nil, fmt.Errorf("calling sign: %v", err)
}
return res, nil
}
// Verify reports whether signature is a valid signature of message by the KeyPair's public key.
func (k *KeyPairEd25519) Verify(message, signature []byte) bool {
return ed25519.Verify(k.privateKey.Public().(ed25519.PublicKey), message, signature)
}
// GetPublicKey returns the PublicKey corresponding to the KeyPair's private key.
func (k *KeyPairEd25519) GetPublicKey() PublicKey {
return PublicKey{
Type: ED25519,
Data: k.privateKey.Public().(ed25519.PublicKey),
}
}
func (k *KeyPairEd25519) String() string {
return string(k.privateKey)
}
func keyPairEd25519FromString(base58string string) (*KeyPairEd25519, error) {
data, err := base58.Decode(base58string)
if err != nil {
return nil, fmt.Errorf("decoding secret key: %v", err)
}
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 &KeyPairEd25519{
privateKey: ed25519.PrivateKey(data),
}, nil
}