1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package ed25519
17
18 import (
19 "crypto"
20 "crypto/internal/fips140/ed25519"
21 "crypto/internal/fips140cache"
22 "crypto/internal/fips140only"
23 cryptorand "crypto/rand"
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 append(make([]byte, 0, SeedSize), priv[:SeedSize]...)
80 }
81
82
83
84 var privateKeyCache fips140cache.Cache[byte, ed25519.PrivateKey]
85
86
87
88
89
90
91
92
93
94
95 func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
96 k, err := privateKeyCache.Get(&priv[0], func() (*ed25519.PrivateKey, error) {
97 return ed25519.NewPrivateKey(priv)
98 }, func(k *ed25519.PrivateKey) bool {
99 return subtle.ConstantTimeCompare(priv, k.Bytes()) == 1
100 })
101 if err != nil {
102 return nil, err
103 }
104 hash := opts.HashFunc()
105 context := ""
106 if opts, ok := opts.(*Options); ok {
107 context = opts.Context
108 }
109 switch {
110 case hash == crypto.SHA512:
111 return ed25519.SignPH(k, message, context)
112 case hash == crypto.Hash(0) && context != "":
113 if fips140only.Enabled {
114 return nil, errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
115 }
116 return ed25519.SignCtx(k, message, context)
117 case hash == crypto.Hash(0):
118 return ed25519.Sign(k, message), nil
119 default:
120 return nil, errors.New("ed25519: expected opts.HashFunc() zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
121 }
122 }
123
124
125
126 type Options struct {
127
128 Hash crypto.Hash
129
130
131
132 Context string
133 }
134
135
136 func (o *Options) HashFunc() crypto.Hash { return o.Hash }
137
138
139
140
141
142
143 func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
144 if rand == nil {
145 rand = cryptorand.Reader
146 }
147
148 seed := make([]byte, SeedSize)
149 if _, err := io.ReadFull(rand, seed); err != nil {
150 return nil, nil, err
151 }
152
153 privateKey := NewKeyFromSeed(seed)
154 publicKey := privateKey.Public().(PublicKey)
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 k, err := ed25519.NewPrivateKeyFromSeed(seed)
171 if err != nil {
172
173 panic("ed25519: bad seed length: " + strconv.Itoa(len(seed)))
174 }
175 copy(privateKey, k.Bytes())
176 }
177
178
179
180 func Sign(privateKey PrivateKey, message []byte) []byte {
181
182
183 signature := make([]byte, SignatureSize)
184 sign(signature, privateKey, message)
185 return signature
186 }
187
188 func sign(signature []byte, privateKey PrivateKey, message []byte) {
189 k, err := privateKeyCache.Get(&privateKey[0], func() (*ed25519.PrivateKey, error) {
190 return ed25519.NewPrivateKey(privateKey)
191 }, func(k *ed25519.PrivateKey) bool {
192 return subtle.ConstantTimeCompare(privateKey, k.Bytes()) == 1
193 })
194 if err != nil {
195 panic("ed25519: bad private key: " + err.Error())
196 }
197 sig := ed25519.Sign(k, message)
198 copy(signature, sig)
199 }
200
201
202
203
204
205
206 func Verify(publicKey PublicKey, message, sig []byte) bool {
207 return VerifyWithOptions(publicKey, message, sig, &Options{Hash: crypto.Hash(0)}) == nil
208 }
209
210
211
212
213
214
215
216
217
218
219
220
221 func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) error {
222 if l := len(publicKey); l != PublicKeySize {
223 panic("ed25519: bad public key length: " + strconv.Itoa(l))
224 }
225 k, err := ed25519.NewPublicKey(publicKey)
226 if err != nil {
227 return err
228 }
229 switch {
230 case opts.Hash == crypto.SHA512:
231 return ed25519.VerifyPH(k, message, sig, opts.Context)
232 case opts.Hash == crypto.Hash(0) && opts.Context != "":
233 if fips140only.Enabled {
234 return errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
235 }
236 return ed25519.VerifyCtx(k, message, sig, opts.Context)
237 case opts.Hash == crypto.Hash(0):
238 return ed25519.Verify(k, message, sig)
239 default:
240 return errors.New("ed25519: expected opts.Hash zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
241 }
242 }
243
View as plain text