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