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