1// Copyright 2012 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/rand" 12 "encoding/hex" 13 "io" 14 "os" 15 "strings" 16 "testing" 17 18 "github.com/agl/ed25519/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 if !A.FromBytes(pub) { 35 t.Fatalf("ExtendedGroupElement.FromBytes failed") 36 } 37 38 var pub2 [32]byte 39 A.ToBytes(&pub2) 40 41 if *pub != pub2 { 42 t.Errorf("FromBytes(%v)->ToBytes does not round-trip, got %x\n", *pub, pub2) 43 } 44} 45 46func TestSignVerify(t *testing.T) { 47 var zero zeroReader 48 public, private, _ := GenerateKey(zero) 49 50 message := []byte("test message") 51 sig := Sign(private, message) 52 if !Verify(public, message, sig) { 53 t.Errorf("valid signature rejected") 54 } 55 56 wrongMessage := []byte("wrong message") 57 if Verify(public, wrongMessage, sig) { 58 t.Errorf("signature of different message accepted") 59 } 60} 61 62func TestGolden(t *testing.T) { 63 // sign.input.gz is a selection of test cases from 64 // http://ed25519.cr.yp.to/python/sign.input 65 testDataZ, err := os.Open("testdata/sign.input.gz") 66 if err != nil { 67 t.Fatal(err) 68 } 69 defer testDataZ.Close() 70 testData, err := gzip.NewReader(testDataZ) 71 if err != nil { 72 t.Fatal(err) 73 } 74 defer testData.Close() 75 76 in := bufio.NewReaderSize(testData, 1<<12) 77 lineNo := 0 78 for { 79 lineNo++ 80 lineBytes, isPrefix, err := in.ReadLine() 81 if isPrefix { 82 t.Fatal("bufio buffer too small") 83 } 84 if err != nil { 85 if err == io.EOF { 86 break 87 } 88 t.Fatalf("error reading test data: %s", err) 89 } 90 91 line := string(lineBytes) 92 parts := strings.Split(line, ":") 93 if len(parts) != 5 { 94 t.Fatalf("bad number of parts on line %d", lineNo) 95 } 96 97 privBytes, _ := hex.DecodeString(parts[0]) 98 pubKeyBytes, _ := hex.DecodeString(parts[1]) 99 msg, _ := hex.DecodeString(parts[2]) 100 sig, _ := hex.DecodeString(parts[3]) 101 // The signatures in the test vectors also include the message 102 // at the end, but we just want R and S. 103 sig = sig[:SignatureSize] 104 105 if l := len(pubKeyBytes); l != PublicKeySize { 106 t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l) 107 } 108 109 var priv [PrivateKeySize]byte 110 copy(priv[:], privBytes) 111 copy(priv[32:], pubKeyBytes) 112 113 sig2 := Sign(&priv, msg) 114 if !bytes.Equal(sig, sig2[:]) { 115 t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2) 116 } 117 118 var pubKey [PublicKeySize]byte 119 copy(pubKey[:], pubKeyBytes) 120 if !Verify(&pubKey, msg, sig2) { 121 t.Errorf("signature failed to verify on line %d", lineNo) 122 } 123 } 124} 125 126func BenchmarkKeyGeneration(b *testing.B) { 127 var zero zeroReader 128 for i := 0; i < b.N; i++ { 129 if _, _, err := GenerateKey(zero); err != nil { 130 b.Fatal(err) 131 } 132 } 133} 134 135func BenchmarkSigning(b *testing.B) { 136 var zero zeroReader 137 _, priv, err := GenerateKey(zero) 138 if err != nil { 139 b.Fatal(err) 140 } 141 message := []byte("Hello, world!") 142 b.ResetTimer() 143 for i := 0; i < b.N; i++ { 144 Sign(priv, message) 145 } 146} 147 148func BenchmarkVerification(b *testing.B) { 149 var zero zeroReader 150 pub, priv, err := GenerateKey(zero) 151 if err != nil { 152 b.Fatal(err) 153 } 154 message := []byte("Hello, world!") 155 signature := Sign(priv, message) 156 b.ResetTimer() 157 for i := 0; i < b.N; i++ { 158 Verify(pub, message, signature) 159 } 160} 161