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 5 package ed25519 6 7 import ( 8 "bufio" 9 "bytes" 10 "compress/gzip" 11 "crypto" 12 "crypto/rand" 13 "encoding/hex" 14 "os" 15 "strings" 16 "testing" 17 18 "boringssl.googlesource.com/boringssl/ssl/test/runner/ed25519/internal/edwards25519" 19 ) 20 21 type zeroReader struct{} 22 23 func (zeroReader) Read(buf []byte) (int, error) { 24 for i := range buf { 25 buf[i] = 0 26 } 27 return len(buf), nil 28 } 29 30 func 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 48 func 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 64 func 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 92 func 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 162 func 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 186 func 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 195 func 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 208 func 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