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