-
Notifications
You must be signed in to change notification settings - Fork 3.7k
/
ed25519.go
216 lines (175 loc) · 5.94 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
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
package ed25519
import (
"crypto/ed25519"
"crypto/subtle"
"fmt"
"io"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/cosmos/cosmos-sdk/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/types/errors"
)
//-------------------------------------
const (
PrivKeyName = "tendermint/PrivKeyEd25519"
PubKeyName = "tendermint/PubKeyEd25519"
// PubKeySize is is the size, in bytes, of public keys as used in this package.
PubKeySize = 32
// PrivKeySize is the size, in bytes, of private keys as used in this package.
PrivKeySize = 64
// Size of an Edwards25519 signature. Namely the size of a compressed
// Edwards25519 point, and a field element. Both of which are 32 bytes.
SignatureSize = 64
// SeedSize is the size, in bytes, of private key seeds. These are the
// private key representations used by RFC 8032.
SeedSize = 32
keyType = "ed25519"
)
var _ cryptotypes.PrivKey = &PrivKey{}
var _ codec.AminoMarshaler = &PrivKey{}
// Bytes returns the privkey byte format.
func (privKey *PrivKey) Bytes() []byte {
return privKey.Key
}
// Sign produces a signature on the provided message.
// This assumes the privkey is wellformed in the golang format.
// The first 32 bytes should be random,
// corresponding to the normal ed25519 private key.
// The latter 32 bytes should be the compressed public key.
// If these conditions aren't met, Sign will panic or produce an
// incorrect signature.
func (privKey *PrivKey) Sign(msg []byte) ([]byte, error) {
return ed25519.Sign(privKey.Key, msg), nil
}
// PubKey gets the corresponding public key from the private key.
//
// Panics if the private key is not initialized.
func (privKey *PrivKey) PubKey() cryptotypes.PubKey {
// If the latter 32 bytes of the privkey are all zero, privkey is not
// initialized.
initialized := false
for _, v := range privKey.Key[32:] {
if v != 0 {
initialized = true
break
}
}
if !initialized {
panic("Expected ed25519 PrivKey to include concatenated pubkey bytes")
}
pubkeyBytes := make([]byte, PubKeySize)
copy(pubkeyBytes, privKey.Key[32:])
return &PubKey{Key: pubkeyBytes}
}
// Equals - you probably don't need to use this.
// Runs in constant time based on length of the keys.
func (privKey *PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool {
if privKey.Type() != other.Type() {
return false
}
return subtle.ConstantTimeCompare(privKey.Bytes(), other.Bytes()) == 1
}
func (privKey *PrivKey) Type() string {
return keyType
}
// MarshalAmino overrides Amino binary marshalling.
func (privKey PrivKey) MarshalAmino() ([]byte, error) {
return privKey.Key, nil
}
// UnmarshalAmino overrides Amino binary marshalling.
func (privKey *PrivKey) UnmarshalAmino(bz []byte) error {
if len(bz) != PrivKeySize {
return fmt.Errorf("invalid privkey size")
}
privKey.Key = bz
return nil
}
// MarshalAminoJSON overrides Amino JSON marshalling.
func (privKey PrivKey) MarshalAminoJSON() ([]byte, error) {
// When we marshal to Amino JSON, we don't marshal the "key" field itself,
// just its contents (i.e. the key bytes).
return privKey.MarshalAmino()
}
// UnmarshalAminoJSON overrides Amino JSON marshalling.
func (privKey *PrivKey) UnmarshalAminoJSON(bz []byte) error {
return privKey.UnmarshalAmino(bz)
}
// GenPrivKey generates a new ed25519 private key.
// It uses OS randomness in conjunction with the current global random seed
// in tendermint/libs/common to generate the private key.
func GenPrivKey() *PrivKey {
return genPrivKey(crypto.CReader())
}
// genPrivKey generates a new ed25519 private key using the provided reader.
func genPrivKey(rand io.Reader) *PrivKey {
seed := make([]byte, SeedSize)
_, err := io.ReadFull(rand, seed)
if err != nil {
panic(err)
}
return &PrivKey{Key: ed25519.NewKeyFromSeed(seed)}
}
// GenPrivKeyFromSecret hashes the secret with SHA2, and uses
// that 32 byte output to create the private key.
// NOTE: secret should be the output of a KDF like bcrypt,
// if it's derived from user input.
func GenPrivKeyFromSecret(secret []byte) *PrivKey {
seed := crypto.Sha256(secret) // Not Ripemd160 because we want 32 bytes.
return &PrivKey{Key: ed25519.NewKeyFromSeed(seed)}
}
//-------------------------------------
var _ cryptotypes.PubKey = &PubKey{}
var _ codec.AminoMarshaler = &PubKey{}
// Address is the SHA256-20 of the raw pubkey bytes.
func (pubKey *PubKey) Address() crypto.Address {
if len(pubKey.Key) != PubKeySize {
panic("pubkey is incorrect size")
}
return crypto.Address(tmhash.SumTruncated(pubKey.Key))
}
// Bytes returns the PubKey byte format.
func (pubKey *PubKey) Bytes() []byte {
return pubKey.Key
}
func (pubKey *PubKey) VerifySignature(msg []byte, sig []byte) bool {
// make sure we use the same algorithm to sign
if len(sig) != SignatureSize {
return false
}
return ed25519.Verify(pubKey.Key, msg, sig)
}
func (pubKey *PubKey) String() string {
return fmt.Sprintf("PubKeyEd25519{%X}", pubKey.Key)
}
func (pubKey *PubKey) Type() string {
return keyType
}
func (pubKey *PubKey) Equals(other cryptotypes.PubKey) bool {
if pubKey.Type() != other.Type() {
return false
}
return subtle.ConstantTimeCompare(pubKey.Bytes(), other.Bytes()) == 1
}
// MarshalAmino overrides Amino binary marshalling.
func (pubKey PubKey) MarshalAmino() ([]byte, error) {
return pubKey.Key, nil
}
// UnmarshalAmino overrides Amino binary marshalling.
func (pubKey *PubKey) UnmarshalAmino(bz []byte) error {
if len(bz) != PubKeySize {
return errors.Wrap(errors.ErrInvalidPubKey, "invalid pubkey size")
}
pubKey.Key = bz
return nil
}
// MarshalAminoJSON overrides Amino JSON marshalling.
func (pubKey PubKey) MarshalAminoJSON() ([]byte, error) {
// When we marshal to Amino JSON, we don't marshal the "key" field itself,
// just its contents (i.e. the key bytes).
return pubKey.MarshalAmino()
}
// UnmarshalAminoJSON overrides Amino JSON marshalling.
func (pubKey *PubKey) UnmarshalAminoJSON(bz []byte) error {
return pubKey.UnmarshalAmino(bz)
}