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 "crypto/internal/rand"
24 cryptorand "crypto/rand"
25 "crypto/subtle"
26 "errors"
27 "internal/godebug"
28 "io"
29 "strconv"
30 )
31
32 const (
33
34 PublicKeySize = 32
35
36 PrivateKeySize = 64
37
38 SignatureSize = 64
39
40 SeedSize = 32
41 )
42
43
44 type PublicKey []byte
45
46
47
48
49
50 func (pub PublicKey) Equal(x crypto.PublicKey) bool {
51 xx, ok := x.(PublicKey)
52 if !ok {
53 return false
54 }
55 return subtle.ConstantTimeCompare(pub, xx) == 1
56 }
57
58
59 type PrivateKey []byte
60
61
62 func (priv PrivateKey) Public() crypto.PublicKey {
63 publicKey := make([]byte, PublicKeySize)
64 copy(publicKey, priv[32:])
65 return PublicKey(publicKey)
66 }
67
68
69 func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
70 xx, ok := x.(PrivateKey)
71 if !ok {
72 return false
73 }
74 return subtle.ConstantTimeCompare(priv, xx) == 1
75 }
76
77
78
79
80 func (priv PrivateKey) Seed() []byte {
81 return append(make([]byte, 0, SeedSize), priv[:SeedSize]...)
82 }
83
84
85
86 var privateKeyCache fips140cache.Cache[byte, ed25519.PrivateKey]
87
88
89
90
91
92
93
94
95
96
97 func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
98 k, err := privateKeyCache.Get(&priv[0], func() (*ed25519.PrivateKey, error) {
99 return ed25519.NewPrivateKey(priv)
100 }, func(k *ed25519.PrivateKey) bool {
101 return subtle.ConstantTimeCompare(priv, k.Bytes()) == 1
102 })
103 if err != nil {
104 return nil, err
105 }
106 hash := opts.HashFunc()
107 context := ""
108 if opts, ok := opts.(*Options); ok {
109 context = opts.Context
110 }
111 switch {
112 case hash == crypto.SHA512:
113 return ed25519.SignPH(k, message, context)
114 case hash == crypto.Hash(0) && context != "":
115 if fips140only.Enforced() {
116 return nil, errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
117 }
118 return ed25519.SignCtx(k, message, context)
119 case hash == crypto.Hash(0):
120 return ed25519.Sign(k, message), nil
121 default:
122 return nil, errors.New("ed25519: expected opts.HashFunc() zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
123 }
124 }
125
126
127
128 type Options struct {
129
130 Hash crypto.Hash
131
132
133
134 Context string
135 }
136
137
138 func (o *Options) HashFunc() crypto.Hash { return o.Hash }
139
140 var cryptocustomrand = godebug.New("cryptocustomrand")
141
142
143
144
145
146
147
148
149
150
151 func GenerateKey(random io.Reader) (PublicKey, PrivateKey, error) {
152 if random == nil {
153 if cryptocustomrand.Value() == "1" {
154 random = cryptorand.Reader
155 if !rand.IsDefaultReader(random) {
156 cryptocustomrand.IncNonDefault()
157 }
158 } else {
159 random = rand.Reader
160 }
161 }
162
163 seed := make([]byte, SeedSize)
164 if _, err := io.ReadFull(random, seed); err != nil {
165 return nil, nil, err
166 }
167
168 privateKey := NewKeyFromSeed(seed)
169 publicKey := privateKey.Public().(PublicKey)
170 return publicKey, privateKey, nil
171 }
172
173
174
175
176
177 func NewKeyFromSeed(seed []byte) PrivateKey {
178
179 privateKey := make([]byte, PrivateKeySize)
180 newKeyFromSeed(privateKey, seed)
181 return privateKey
182 }
183
184 func newKeyFromSeed(privateKey, seed []byte) {
185 k, err := ed25519.NewPrivateKeyFromSeed(seed)
186 if err != nil {
187
188 panic("ed25519: bad seed length: " + strconv.Itoa(len(seed)))
189 }
190 copy(privateKey, k.Bytes())
191 }
192
193
194
195 func Sign(privateKey PrivateKey, message []byte) []byte {
196
197
198 signature := make([]byte, SignatureSize)
199 sign(signature, privateKey, message)
200 return signature
201 }
202
203 func sign(signature []byte, privateKey PrivateKey, message []byte) {
204 k, err := privateKeyCache.Get(&privateKey[0], func() (*ed25519.PrivateKey, error) {
205 return ed25519.NewPrivateKey(privateKey)
206 }, func(k *ed25519.PrivateKey) bool {
207 return subtle.ConstantTimeCompare(privateKey, k.Bytes()) == 1
208 })
209 if err != nil {
210 panic("ed25519: bad private key: " + err.Error())
211 }
212 sig := ed25519.Sign(k, message)
213 copy(signature, sig)
214 }
215
216
217
218
219
220
221 func Verify(publicKey PublicKey, message, sig []byte) bool {
222 return VerifyWithOptions(publicKey, message, sig, &Options{Hash: crypto.Hash(0)}) == nil
223 }
224
225
226
227
228
229
230
231
232
233
234
235
236 func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) error {
237 if l := len(publicKey); l != PublicKeySize {
238 panic("ed25519: bad public key length: " + strconv.Itoa(l))
239 }
240 k, err := ed25519.NewPublicKey(publicKey)
241 if err != nil {
242 return err
243 }
244 switch {
245 case opts.Hash == crypto.SHA512:
246 return ed25519.VerifyPH(k, message, sig, opts.Context)
247 case opts.Hash == crypto.Hash(0) && opts.Context != "":
248 if fips140only.Enforced() {
249 return errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
250 }
251 return ed25519.VerifyCtx(k, message, sig, opts.Context)
252 case opts.Hash == crypto.Hash(0):
253 return ed25519.Verify(k, message, sig)
254 default:
255 return errors.New("ed25519: expected opts.Hash zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
256 }
257 }
258
View as plain text