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