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/rand"
13	"encoding/hex"
14	"os"
15	"runtime"
16	"strings"
17	"testing"
18)
19
20type zeroReader struct{}
21
22func (zeroReader) Read(buf []byte) (int, error) {
23	for i := range buf {
24		buf[i] = 0
25	}
26	return len(buf), nil
27}
28
29func TestSignVerify(t *testing.T) {
30	var zero zeroReader
31	public, private, _ := GenerateKey(zero)
32
33	message := []byte("test message")
34	sig := Sign(private, message)
35	if !Verify(public, message, sig) {
36		t.Errorf("valid signature rejected")
37	}
38
39	wrongMessage := []byte("wrong message")
40	if Verify(public, wrongMessage, sig) {
41		t.Errorf("signature of different message accepted")
42	}
43}
44
45func TestCryptoSigner(t *testing.T) {
46	var zero zeroReader
47	public, private, _ := GenerateKey(zero)
48
49	signer := crypto.Signer(private)
50
51	publicInterface := signer.Public()
52	public2, ok := publicInterface.(PublicKey)
53	if !ok {
54		t.Fatalf("expected PublicKey from Public() but got %T", publicInterface)
55	}
56
57	if !bytes.Equal(public, public2) {
58		t.Errorf("public keys do not match: original:%x vs Public():%x", public, public2)
59	}
60
61	message := []byte("message")
62	var noHash crypto.Hash
63	signature, err := signer.Sign(zero, message, noHash)
64	if err != nil {
65		t.Fatalf("error from Sign(): %s", err)
66	}
67
68	if !Verify(public, message, signature) {
69		t.Errorf("Verify failed on signature from Sign()")
70	}
71}
72
73func TestEqual(t *testing.T) {
74	public, private, _ := GenerateKey(rand.Reader)
75
76	if !public.Equal(public) {
77		t.Errorf("public key is not equal to itself: %q", public)
78	}
79	if !public.Equal(crypto.Signer(private).Public()) {
80		t.Errorf("private.Public() is not Equal to public: %q", public)
81	}
82	if !private.Equal(private) {
83		t.Errorf("private key is not equal to itself: %q", private)
84	}
85
86	otherPub, otherPriv, _ := GenerateKey(rand.Reader)
87	if public.Equal(otherPub) {
88		t.Errorf("different public keys are Equal")
89	}
90	if private.Equal(otherPriv) {
91		t.Errorf("different private keys are Equal")
92	}
93}
94
95func TestGolden(t *testing.T) {
96	// sign.input.gz is a selection of test cases from
97	// https://ed25519.cr.yp.to/python/sign.input
98	testDataZ, err := os.Open("testdata/sign.input.gz")
99	if err != nil {
100		t.Fatal(err)
101	}
102	defer testDataZ.Close()
103	testData, err := gzip.NewReader(testDataZ)
104	if err != nil {
105		t.Fatal(err)
106	}
107	defer testData.Close()
108
109	scanner := bufio.NewScanner(testData)
110	lineNo := 0
111
112	for scanner.Scan() {
113		lineNo++
114
115		line := scanner.Text()
116		parts := strings.Split(line, ":")
117		if len(parts) != 5 {
118			t.Fatalf("bad number of parts on line %d", lineNo)
119		}
120
121		privBytes, _ := hex.DecodeString(parts[0])
122		pubKey, _ := hex.DecodeString(parts[1])
123		msg, _ := hex.DecodeString(parts[2])
124		sig, _ := hex.DecodeString(parts[3])
125		// The signatures in the test vectors also include the message
126		// at the end, but we just want R and S.
127		sig = sig[:SignatureSize]
128
129		if l := len(pubKey); l != PublicKeySize {
130			t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l)
131		}
132
133		var priv [PrivateKeySize]byte
134		copy(priv[:], privBytes)
135		copy(priv[32:], pubKey)
136
137		sig2 := Sign(priv[:], msg)
138		if !bytes.Equal(sig, sig2[:]) {
139			t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2)
140		}
141
142		if !Verify(pubKey, msg, sig2) {
143			t.Errorf("signature failed to verify on line %d", lineNo)
144		}
145
146		priv2 := NewKeyFromSeed(priv[:32])
147		if !bytes.Equal(priv[:], priv2) {
148			t.Errorf("recreating key pair gave different private key on line %d: %x vs %x", lineNo, priv[:], priv2)
149		}
150
151		if pubKey2 := priv2.Public().(PublicKey); !bytes.Equal(pubKey, pubKey2) {
152			t.Errorf("recreating key pair gave different public key on line %d: %x vs %x", lineNo, pubKey, pubKey2)
153		}
154
155		if seed := priv2.Seed(); !bytes.Equal(priv[:32], seed) {
156			t.Errorf("recreating key pair gave different seed on line %d: %x vs %x", lineNo, priv[:32], seed)
157		}
158	}
159
160	if err := scanner.Err(); err != nil {
161		t.Fatalf("error reading test data: %s", err)
162	}
163}
164
165func TestMalleability(t *testing.T) {
166	// https://tools.ietf.org/html/rfc8032#section-5.1.7 adds an additional test
167	// that s be in [0, order). This prevents someone from adding a multiple of
168	// order to s and obtaining a second valid signature for the same message.
169	msg := []byte{0x54, 0x65, 0x73, 0x74}
170	sig := []byte{
171		0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a,
172		0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b,
173		0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67,
174		0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d,
175		0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33,
176		0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d,
177	}
178	publicKey := []byte{
179		0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5,
180		0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34,
181		0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
182	}
183
184	if Verify(publicKey, msg, sig) {
185		t.Fatal("non-canonical signature accepted")
186	}
187}
188
189func TestAllocations(t *testing.T) {
190	if runtime.Compiler == "gccgo" {
191		t.Skip("gofronted escape analysis not good enough")
192	}
193	if strings.HasSuffix(os.Getenv("GO_BUILDER_NAME"), "-noopt") {
194		t.Skip("skipping allocations test without relevant optimizations")
195	}
196	if allocs := testing.AllocsPerRun(100, func() {
197		seed := make([]byte, SeedSize)
198		message := []byte("Hello, world!")
199		priv := NewKeyFromSeed(seed)
200		pub := priv.Public().(PublicKey)
201		signature := Sign(priv, message)
202		if !Verify(pub, message, signature) {
203			t.Fatal("signature didn't verify")
204		}
205	}); allocs > 0 {
206		t.Errorf("expected zero allocations, got %0.1v", allocs)
207	}
208}
209
210func BenchmarkKeyGeneration(b *testing.B) {
211	var zero zeroReader
212	for i := 0; i < b.N; i++ {
213		if _, _, err := GenerateKey(zero); err != nil {
214			b.Fatal(err)
215		}
216	}
217}
218
219func BenchmarkNewKeyFromSeed(b *testing.B) {
220	seed := make([]byte, SeedSize)
221	for i := 0; i < b.N; i++ {
222		_ = NewKeyFromSeed(seed)
223	}
224}
225
226func BenchmarkSigning(b *testing.B) {
227	var zero zeroReader
228	_, priv, err := GenerateKey(zero)
229	if err != nil {
230		b.Fatal(err)
231	}
232	message := []byte("Hello, world!")
233	b.ResetTimer()
234	for i := 0; i < b.N; i++ {
235		Sign(priv, message)
236	}
237}
238
239func BenchmarkVerification(b *testing.B) {
240	var zero zeroReader
241	pub, priv, err := GenerateKey(zero)
242	if err != nil {
243		b.Fatal(err)
244	}
245	message := []byte("Hello, world!")
246	signature := Sign(priv, message)
247	b.ResetTimer()
248	for i := 0; i < b.N; i++ {
249		Verify(pub, message, signature)
250	}
251}
252