1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package ed25519
17
18 import (
19 "bytes"
20 "crypto"
21 "crypto/internal/edwards25519"
22 cryptorand "crypto/rand"
23 "crypto/sha512"
24 "crypto/subtle"
25 "errors"
26 "io"
27 "strconv"
28 )
29
30 const (
31
32 PublicKeySize = 32
33
34 PrivateKeySize = 64
35
36 SignatureSize = 64
37
38 SeedSize = 32
39 )
40
41
42 type PublicKey []byte
43
44
45
46
47
48 func (pub PublicKey) Equal(x crypto.PublicKey) bool {
49 xx, ok := x.(PublicKey)
50 if !ok {
51 return false
52 }
53 return subtle.ConstantTimeCompare(pub, xx) == 1
54 }
55
56
57 type PrivateKey []byte
58
59
60 func (priv PrivateKey) Public() crypto.PublicKey {
61 publicKey := make([]byte, PublicKeySize)
62 copy(publicKey, priv[32:])
63 return PublicKey(publicKey)
64 }
65
66
67 func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
68 xx, ok := x.(PrivateKey)
69 if !ok {
70 return false
71 }
72 return subtle.ConstantTimeCompare(priv, xx) == 1
73 }
74
75
76
77
78 func (priv PrivateKey) Seed() []byte {
79 return bytes.Clone(priv[:SeedSize])
80 }
81
82
83
84
85
86
87
88
89
90
91 func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
92 hash := opts.HashFunc()
93 context := ""
94 if opts, ok := opts.(*Options); ok {
95 context = opts.Context
96 }
97 switch {
98 case hash == crypto.SHA512:
99 if l := len(message); l != sha512.Size {
100 return nil, errors.New("ed25519: bad Ed25519ph message hash length: " + strconv.Itoa(l))
101 }
102 if l := len(context); l > 255 {
103 return nil, errors.New("ed25519: bad Ed25519ph context length: " + strconv.Itoa(l))
104 }
105 signature := make([]byte, SignatureSize)
106 sign(signature, priv, message, domPrefixPh, context)
107 return signature, nil
108 case hash == crypto.Hash(0) && context != "":
109 if l := len(context); l > 255 {
110 return nil, errors.New("ed25519: bad Ed25519ctx context length: " + strconv.Itoa(l))
111 }
112 signature := make([]byte, SignatureSize)
113 sign(signature, priv, message, domPrefixCtx, context)
114 return signature, nil
115 case hash == crypto.Hash(0):
116 return Sign(priv, message), nil
117 default:
118 return nil, errors.New("ed25519: expected opts.HashFunc() zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
119 }
120 }
121
122
123
124 type Options struct {
125
126 Hash crypto.Hash
127
128
129
130 Context string
131 }
132
133
134 func (o *Options) HashFunc() crypto.Hash { return o.Hash }
135
136
137
138
139
140
141 func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
142 if rand == nil {
143 rand = cryptorand.Reader
144 }
145
146 seed := make([]byte, SeedSize)
147 if _, err := io.ReadFull(rand, seed); err != nil {
148 return nil, nil, err
149 }
150
151 privateKey := NewKeyFromSeed(seed)
152 publicKey := make([]byte, PublicKeySize)
153 copy(publicKey, privateKey[32:])
154
155 return publicKey, privateKey, nil
156 }
157
158
159
160
161
162 func NewKeyFromSeed(seed []byte) PrivateKey {
163
164 privateKey := make([]byte, PrivateKeySize)
165 newKeyFromSeed(privateKey, seed)
166 return privateKey
167 }
168
169 func newKeyFromSeed(privateKey, seed []byte) {
170 if l := len(seed); l != SeedSize {
171 panic("ed25519: bad seed length: " + strconv.Itoa(l))
172 }
173
174 h := sha512.Sum512(seed)
175 s, err := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
176 if err != nil {
177 panic("ed25519: internal error: setting scalar failed")
178 }
179 A := (&edwards25519.Point{}).ScalarBaseMult(s)
180
181 publicKey := A.Bytes()
182
183 copy(privateKey, seed)
184 copy(privateKey[32:], publicKey)
185 }
186
187
188
189 func Sign(privateKey PrivateKey, message []byte) []byte {
190
191
192 signature := make([]byte, SignatureSize)
193 sign(signature, privateKey, message, domPrefixPure, "")
194 return signature
195 }
196
197
198
199 const (
200
201 domPrefixPure = ""
202
203
204 domPrefixPh = "SigEd25519 no Ed25519 collisions\x01"
205
206
207 domPrefixCtx = "SigEd25519 no Ed25519 collisions\x00"
208 )
209
210 func sign(signature, privateKey, message []byte, domPrefix, context string) {
211 if l := len(privateKey); l != PrivateKeySize {
212 panic("ed25519: bad private key length: " + strconv.Itoa(l))
213 }
214 seed, publicKey := privateKey[:SeedSize], privateKey[SeedSize:]
215
216 h := sha512.Sum512(seed)
217 s, err := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
218 if err != nil {
219 panic("ed25519: internal error: setting scalar failed")
220 }
221 prefix := h[32:]
222
223 mh := sha512.New()
224 if domPrefix != domPrefixPure {
225 mh.Write([]byte(domPrefix))
226 mh.Write([]byte{byte(len(context))})
227 mh.Write([]byte(context))
228 }
229 mh.Write(prefix)
230 mh.Write(message)
231 messageDigest := make([]byte, 0, sha512.Size)
232 messageDigest = mh.Sum(messageDigest)
233 r, err := edwards25519.NewScalar().SetUniformBytes(messageDigest)
234 if err != nil {
235 panic("ed25519: internal error: setting scalar failed")
236 }
237
238 R := (&edwards25519.Point{}).ScalarBaseMult(r)
239
240 kh := sha512.New()
241 if domPrefix != domPrefixPure {
242 kh.Write([]byte(domPrefix))
243 kh.Write([]byte{byte(len(context))})
244 kh.Write([]byte(context))
245 }
246 kh.Write(R.Bytes())
247 kh.Write(publicKey)
248 kh.Write(message)
249 hramDigest := make([]byte, 0, sha512.Size)
250 hramDigest = kh.Sum(hramDigest)
251 k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)
252 if err != nil {
253 panic("ed25519: internal error: setting scalar failed")
254 }
255
256 S := edwards25519.NewScalar().MultiplyAdd(k, s, r)
257
258 copy(signature[:32], R.Bytes())
259 copy(signature[32:], S.Bytes())
260 }
261
262
263
264
265
266
267 func Verify(publicKey PublicKey, message, sig []byte) bool {
268 return verify(publicKey, message, sig, domPrefixPure, "")
269 }
270
271
272
273
274
275
276
277
278
279
280
281
282 func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) error {
283 switch {
284 case opts.Hash == crypto.SHA512:
285 if l := len(message); l != sha512.Size {
286 return errors.New("ed25519: bad Ed25519ph message hash length: " + strconv.Itoa(l))
287 }
288 if l := len(opts.Context); l > 255 {
289 return errors.New("ed25519: bad Ed25519ph context length: " + strconv.Itoa(l))
290 }
291 if !verify(publicKey, message, sig, domPrefixPh, opts.Context) {
292 return errors.New("ed25519: invalid signature")
293 }
294 return nil
295 case opts.Hash == crypto.Hash(0) && opts.Context != "":
296 if l := len(opts.Context); l > 255 {
297 return errors.New("ed25519: bad Ed25519ctx context length: " + strconv.Itoa(l))
298 }
299 if !verify(publicKey, message, sig, domPrefixCtx, opts.Context) {
300 return errors.New("ed25519: invalid signature")
301 }
302 return nil
303 case opts.Hash == crypto.Hash(0):
304 if !verify(publicKey, message, sig, domPrefixPure, "") {
305 return errors.New("ed25519: invalid signature")
306 }
307 return nil
308 default:
309 return errors.New("ed25519: expected opts.Hash zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
310 }
311 }
312
313 func verify(publicKey PublicKey, message, sig []byte, domPrefix, context string) bool {
314 if l := len(publicKey); l != PublicKeySize {
315 panic("ed25519: bad public key length: " + strconv.Itoa(l))
316 }
317
318 if len(sig) != SignatureSize || sig[63]&224 != 0 {
319 return false
320 }
321
322 A, err := (&edwards25519.Point{}).SetBytes(publicKey)
323 if err != nil {
324 return false
325 }
326
327 kh := sha512.New()
328 if domPrefix != domPrefixPure {
329 kh.Write([]byte(domPrefix))
330 kh.Write([]byte{byte(len(context))})
331 kh.Write([]byte(context))
332 }
333 kh.Write(sig[:32])
334 kh.Write(publicKey)
335 kh.Write(message)
336 hramDigest := make([]byte, 0, sha512.Size)
337 hramDigest = kh.Sum(hramDigest)
338 k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)
339 if err != nil {
340 panic("ed25519: internal error: setting scalar failed")
341 }
342
343 S, err := edwards25519.NewScalar().SetCanonicalBytes(sig[32:])
344 if err != nil {
345 return false
346 }
347
348
349 minusA := (&edwards25519.Point{}).Negate(A)
350 R := (&edwards25519.Point{}).VarTimeDoubleScalarBaseMult(k, minusA, S)
351
352 return bytes.Equal(sig[:32], R.Bytes())
353 }
354
View as plain text