1
2
3
4
5 package ed25519
6
7 import (
8 "bufio"
9 "bytes"
10 "compress/gzip"
11 "crypto"
12 "crypto/internal/boring"
13 "crypto/rand"
14 "crypto/sha512"
15 "encoding/hex"
16 "internal/testenv"
17 "log"
18 "os"
19 "strings"
20 "testing"
21 )
22
23 func Example_ed25519ctx() {
24 pub, priv, err := GenerateKey(nil)
25 if err != nil {
26 log.Fatal(err)
27 }
28
29 msg := []byte("The quick brown fox jumps over the lazy dog")
30
31 sig, err := priv.Sign(nil, msg, &Options{
32 Context: "Example_ed25519ctx",
33 })
34 if err != nil {
35 log.Fatal(err)
36 }
37
38 if err := VerifyWithOptions(pub, msg, sig, &Options{
39 Context: "Example_ed25519ctx",
40 }); err != nil {
41 log.Fatal("invalid signature")
42 }
43 }
44
45 type zeroReader struct{}
46
47 func (zeroReader) Read(buf []byte) (int, error) {
48 for i := range buf {
49 buf[i] = 0
50 }
51 return len(buf), nil
52 }
53
54 func TestSignVerify(t *testing.T) {
55 var zero zeroReader
56 public, private, _ := GenerateKey(zero)
57
58 message := []byte("test message")
59 sig := Sign(private, message)
60 if !Verify(public, message, sig) {
61 t.Errorf("valid signature rejected")
62 }
63
64 wrongMessage := []byte("wrong message")
65 if Verify(public, wrongMessage, sig) {
66 t.Errorf("signature of different message accepted")
67 }
68 }
69
70 func TestSignVerifyHashed(t *testing.T) {
71
72 key, _ := hex.DecodeString("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf")
73 expectedSig, _ := hex.DecodeString("98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406")
74 message, _ := hex.DecodeString("616263")
75
76 private := PrivateKey(key)
77 public := private.Public().(PublicKey)
78 hash := sha512.Sum512(message)
79 sig, err := private.Sign(nil, hash[:], crypto.SHA512)
80 if err != nil {
81 t.Fatal(err)
82 }
83 if !bytes.Equal(sig, expectedSig) {
84 t.Error("signature doesn't match test vector")
85 }
86 sig, err = private.Sign(nil, hash[:], &Options{Hash: crypto.SHA512})
87 if err != nil {
88 t.Fatal(err)
89 }
90 if !bytes.Equal(sig, expectedSig) {
91 t.Error("signature doesn't match test vector")
92 }
93 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}); err != nil {
94 t.Errorf("valid signature rejected: %v", err)
95 }
96
97 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA256}); err == nil {
98 t.Errorf("expected error for wrong hash")
99 }
100
101 wrongHash := sha512.Sum512([]byte("wrong message"))
102 if VerifyWithOptions(public, wrongHash[:], sig, &Options{Hash: crypto.SHA512}) == nil {
103 t.Errorf("signature of different message accepted")
104 }
105
106 sig[0] ^= 0xff
107 if VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}) == nil {
108 t.Errorf("invalid signature accepted")
109 }
110 sig[0] ^= 0xff
111 sig[SignatureSize-1] ^= 0xff
112 if VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}) == nil {
113 t.Errorf("invalid signature accepted")
114 }
115
116
117
118 sig, err = private.Sign(nil, hash[:], &Options{Hash: crypto.SHA512, Context: "123"})
119 if err != nil {
120 t.Fatal(err)
121 }
122 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512, Context: "123"}); err != nil {
123 t.Errorf("valid signature rejected: %v", err)
124 }
125 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512, Context: "321"}); err == nil {
126 t.Errorf("expected error for wrong context")
127 }
128 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA256, Context: "123"}); err == nil {
129 t.Errorf("expected error for wrong hash")
130 }
131 }
132
133 func TestSignVerifyContext(t *testing.T) {
134
135 key, _ := hex.DecodeString("0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292")
136 expectedSig, _ := hex.DecodeString("55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d")
137 message, _ := hex.DecodeString("f726936d19c800494e3fdaff20b276a8")
138 context := "foo"
139
140 private := PrivateKey(key)
141 public := private.Public().(PublicKey)
142 sig, err := private.Sign(nil, message, &Options{Context: context})
143 if err != nil {
144 t.Fatal(err)
145 }
146 if !bytes.Equal(sig, expectedSig) {
147 t.Error("signature doesn't match test vector")
148 }
149 if err := VerifyWithOptions(public, message, sig, &Options{Context: context}); err != nil {
150 t.Errorf("valid signature rejected: %v", err)
151 }
152
153 if VerifyWithOptions(public, []byte("bar"), sig, &Options{Context: context}) == nil {
154 t.Errorf("signature of different message accepted")
155 }
156 if VerifyWithOptions(public, message, sig, &Options{Context: "bar"}) == nil {
157 t.Errorf("signature with different context accepted")
158 }
159
160 sig[0] ^= 0xff
161 if VerifyWithOptions(public, message, sig, &Options{Context: context}) == nil {
162 t.Errorf("invalid signature accepted")
163 }
164 sig[0] ^= 0xff
165 sig[SignatureSize-1] ^= 0xff
166 if VerifyWithOptions(public, message, sig, &Options{Context: context}) == nil {
167 t.Errorf("invalid signature accepted")
168 }
169 }
170
171 func TestCryptoSigner(t *testing.T) {
172 var zero zeroReader
173 public, private, _ := GenerateKey(zero)
174
175 signer := crypto.Signer(private)
176
177 publicInterface := signer.Public()
178 public2, ok := publicInterface.(PublicKey)
179 if !ok {
180 t.Fatalf("expected PublicKey from Public() but got %T", publicInterface)
181 }
182
183 if !bytes.Equal(public, public2) {
184 t.Errorf("public keys do not match: original:%x vs Public():%x", public, public2)
185 }
186
187 message := []byte("message")
188 var noHash crypto.Hash
189 signature, err := signer.Sign(zero, message, noHash)
190 if err != nil {
191 t.Fatalf("error from Sign(): %s", err)
192 }
193
194 signature2, err := signer.Sign(zero, message, &Options{Hash: noHash})
195 if err != nil {
196 t.Fatalf("error from Sign(): %s", err)
197 }
198 if !bytes.Equal(signature, signature2) {
199 t.Errorf("signatures keys do not match")
200 }
201
202 if !Verify(public, message, signature) {
203 t.Errorf("Verify failed on signature from Sign()")
204 }
205 }
206
207 func TestEqual(t *testing.T) {
208 public, private, _ := GenerateKey(rand.Reader)
209
210 if !public.Equal(public) {
211 t.Errorf("public key is not equal to itself: %q", public)
212 }
213 if !public.Equal(crypto.Signer(private).Public()) {
214 t.Errorf("private.Public() is not Equal to public: %q", public)
215 }
216 if !private.Equal(private) {
217 t.Errorf("private key is not equal to itself: %q", private)
218 }
219
220 otherPub, otherPriv, _ := GenerateKey(rand.Reader)
221 if public.Equal(otherPub) {
222 t.Errorf("different public keys are Equal")
223 }
224 if private.Equal(otherPriv) {
225 t.Errorf("different private keys are Equal")
226 }
227 }
228
229 func TestGolden(t *testing.T) {
230
231
232 testDataZ, err := os.Open("testdata/sign.input.gz")
233 if err != nil {
234 t.Fatal(err)
235 }
236 defer testDataZ.Close()
237 testData, err := gzip.NewReader(testDataZ)
238 if err != nil {
239 t.Fatal(err)
240 }
241 defer testData.Close()
242
243 scanner := bufio.NewScanner(testData)
244 lineNo := 0
245
246 for scanner.Scan() {
247 lineNo++
248
249 line := scanner.Text()
250 parts := strings.Split(line, ":")
251 if len(parts) != 5 {
252 t.Fatalf("bad number of parts on line %d", lineNo)
253 }
254
255 privBytes, _ := hex.DecodeString(parts[0])
256 pubKey, _ := hex.DecodeString(parts[1])
257 msg, _ := hex.DecodeString(parts[2])
258 sig, _ := hex.DecodeString(parts[3])
259
260
261 sig = sig[:SignatureSize]
262
263 if l := len(pubKey); l != PublicKeySize {
264 t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l)
265 }
266
267 var priv [PrivateKeySize]byte
268 copy(priv[:], privBytes)
269 copy(priv[32:], pubKey)
270
271 sig2 := Sign(priv[:], msg)
272 if !bytes.Equal(sig, sig2[:]) {
273 t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2)
274 }
275
276 if !Verify(pubKey, msg, sig2) {
277 t.Errorf("signature failed to verify on line %d", lineNo)
278 }
279
280 priv2 := NewKeyFromSeed(priv[:32])
281 if !bytes.Equal(priv[:], priv2) {
282 t.Errorf("recreating key pair gave different private key on line %d: %x vs %x", lineNo, priv[:], priv2)
283 }
284
285 if pubKey2 := priv2.Public().(PublicKey); !bytes.Equal(pubKey, pubKey2) {
286 t.Errorf("recreating key pair gave different public key on line %d: %x vs %x", lineNo, pubKey, pubKey2)
287 }
288
289 if seed := priv2.Seed(); !bytes.Equal(priv[:32], seed) {
290 t.Errorf("recreating key pair gave different seed on line %d: %x vs %x", lineNo, priv[:32], seed)
291 }
292 }
293
294 if err := scanner.Err(); err != nil {
295 t.Fatalf("error reading test data: %s", err)
296 }
297 }
298
299 func TestMalleability(t *testing.T) {
300
301
302
303 msg := []byte{0x54, 0x65, 0x73, 0x74}
304 sig := []byte{
305 0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a,
306 0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b,
307 0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67,
308 0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d,
309 0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33,
310 0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d,
311 }
312 publicKey := []byte{
313 0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5,
314 0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34,
315 0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
316 }
317
318 if Verify(publicKey, msg, sig) {
319 t.Fatal("non-canonical signature accepted")
320 }
321 }
322
323 func TestAllocations(t *testing.T) {
324 if boring.Enabled {
325 t.Skip("skipping allocations test with BoringCrypto")
326 }
327 testenv.SkipIfOptimizationOff(t)
328
329 if allocs := testing.AllocsPerRun(100, func() {
330 seed := make([]byte, SeedSize)
331 message := []byte("Hello, world!")
332 priv := NewKeyFromSeed(seed)
333 pub := priv.Public().(PublicKey)
334 signature := Sign(priv, message)
335 if !Verify(pub, message, signature) {
336 t.Fatal("signature didn't verify")
337 }
338 }); allocs > 0 {
339 t.Errorf("expected zero allocations, got %0.1f", allocs)
340 }
341 }
342
343 func BenchmarkKeyGeneration(b *testing.B) {
344 var zero zeroReader
345 for i := 0; i < b.N; i++ {
346 if _, _, err := GenerateKey(zero); err != nil {
347 b.Fatal(err)
348 }
349 }
350 }
351
352 func BenchmarkNewKeyFromSeed(b *testing.B) {
353 seed := make([]byte, SeedSize)
354 for i := 0; i < b.N; i++ {
355 _ = NewKeyFromSeed(seed)
356 }
357 }
358
359 func BenchmarkSigning(b *testing.B) {
360 var zero zeroReader
361 _, priv, err := GenerateKey(zero)
362 if err != nil {
363 b.Fatal(err)
364 }
365 message := []byte("Hello, world!")
366 b.ResetTimer()
367 for i := 0; i < b.N; i++ {
368 Sign(priv, message)
369 }
370 }
371
372 func BenchmarkVerification(b *testing.B) {
373 var zero zeroReader
374 pub, priv, err := GenerateKey(zero)
375 if err != nil {
376 b.Fatal(err)
377 }
378 message := []byte("Hello, world!")
379 signature := Sign(priv, message)
380 b.ResetTimer()
381 for i := 0; i < b.N; i++ {
382 Verify(pub, message, signature)
383 }
384 }
385
View as plain text