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