|  | // Copyright 2016 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package ed25519 | 
|  |  | 
|  | import ( | 
|  | "bufio" | 
|  | "bytes" | 
|  | "compress/gzip" | 
|  | "crypto" | 
|  | "crypto/ed25519/internal/edwards25519" | 
|  | "crypto/rand" | 
|  | "encoding/hex" | 
|  | "os" | 
|  | "strings" | 
|  | "testing" | 
|  | ) | 
|  |  | 
|  | type zeroReader struct{} | 
|  |  | 
|  | func (zeroReader) Read(buf []byte) (int, error) { | 
|  | for i := range buf { | 
|  | buf[i] = 0 | 
|  | } | 
|  | return len(buf), nil | 
|  | } | 
|  |  | 
|  | // signGenericWrapper is identical to Sign except that it unconditionally calls signGeneric directly | 
|  | // rather than going through the sign function that might call assembly code. | 
|  | func signGenericWrapper(privateKey PrivateKey, msg []byte) []byte { | 
|  | sig := make([]byte, SignatureSize) | 
|  | signGeneric(sig, privateKey, msg) | 
|  | return sig | 
|  | } | 
|  |  | 
|  | func TestUnmarshalMarshal(t *testing.T) { | 
|  | pub, _, _ := GenerateKey(rand.Reader) | 
|  |  | 
|  | var A edwards25519.ExtendedGroupElement | 
|  | var pubBytes [32]byte | 
|  | copy(pubBytes[:], pub) | 
|  | if !A.FromBytes(&pubBytes) { | 
|  | t.Fatalf("ExtendedGroupElement.FromBytes failed") | 
|  | } | 
|  |  | 
|  | var pub2 [32]byte | 
|  | A.ToBytes(&pub2) | 
|  |  | 
|  | if pubBytes != pub2 { | 
|  | t.Errorf("FromBytes(%v)->ToBytes does not round-trip, got %x\n", pubBytes, pub2) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestSignVerify(t *testing.T) { | 
|  | t.Run("Generic", func(t *testing.T) { testSignVerify(t, signGenericWrapper, verifyGeneric) }) | 
|  | t.Run("Native", func(t *testing.T) { testSignVerify(t, Sign, Verify) }) | 
|  | } | 
|  |  | 
|  | func testSignVerify(t *testing.T, signImpl func(privateKey PrivateKey, message []byte) []byte, | 
|  | verifyImpl func(publicKey PublicKey, message, sig []byte) bool) { | 
|  | var zero zeroReader | 
|  | public, private, _ := GenerateKey(zero) | 
|  |  | 
|  | message := []byte("test message") | 
|  | sig := signImpl(private, message) | 
|  | if !verifyImpl(public, message, sig) { | 
|  | t.Errorf("valid signature rejected") | 
|  | } | 
|  |  | 
|  | wrongMessage := []byte("wrong message") | 
|  | if verifyImpl(public, wrongMessage, sig) { | 
|  | t.Errorf("signature of different message accepted") | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestCryptoSigner(t *testing.T) { | 
|  | t.Run("Generic", func(t *testing.T) { testCryptoSigner(t, verifyGeneric) }) | 
|  | t.Run("Native", func(t *testing.T) { testCryptoSigner(t, Verify) }) | 
|  | } | 
|  |  | 
|  | func testCryptoSigner(t *testing.T, verifyImpl func(publicKey PublicKey, message, sig []byte) bool) { | 
|  | var zero zeroReader | 
|  | public, private, _ := GenerateKey(zero) | 
|  |  | 
|  | signer := crypto.Signer(private) | 
|  |  | 
|  | publicInterface := signer.Public() | 
|  | public2, ok := publicInterface.(PublicKey) | 
|  | if !ok { | 
|  | t.Fatalf("expected PublicKey from Public() but got %T", publicInterface) | 
|  | } | 
|  |  | 
|  | if !bytes.Equal(public, public2) { | 
|  | t.Errorf("public keys do not match: original:%x vs Public():%x", public, public2) | 
|  | } | 
|  |  | 
|  | message := []byte("message") | 
|  | var noHash crypto.Hash | 
|  | signature, err := signer.Sign(zero, message, noHash) | 
|  | if err != nil { | 
|  | t.Fatalf("error from Sign(): %s", err) | 
|  | } | 
|  |  | 
|  | if !verifyImpl(public, message, signature) { | 
|  | t.Errorf("Verify failed on signature from Sign()") | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestEqual(t *testing.T) { | 
|  | public, private, _ := GenerateKey(rand.Reader) | 
|  |  | 
|  | if !public.Equal(public) { | 
|  | t.Errorf("public key is not equal to itself: %q", public) | 
|  | } | 
|  | if !public.Equal(crypto.Signer(private).Public()) { | 
|  | t.Errorf("private.Public() is not Equal to public: %q", public) | 
|  | } | 
|  | if !private.Equal(private) { | 
|  | t.Errorf("private key is not equal to itself: %q", private) | 
|  | } | 
|  |  | 
|  | otherPub, otherPriv, _ := GenerateKey(rand.Reader) | 
|  | if public.Equal(otherPub) { | 
|  | t.Errorf("different public keys are Equal") | 
|  | } | 
|  | if private.Equal(otherPriv) { | 
|  | t.Errorf("different private keys are Equal") | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestGolden(t *testing.T) { | 
|  | t.Run("Generic", func(t *testing.T) { testGolden(t, signGenericWrapper, verifyGeneric) }) | 
|  | t.Run("Native", func(t *testing.T) { testGolden(t, Sign, Verify) }) | 
|  | } | 
|  |  | 
|  | func testGolden(t *testing.T, signImpl func(privateKey PrivateKey, message []byte) []byte, | 
|  | verifyImpl func(publicKey PublicKey, message, sig []byte) bool) { | 
|  | // sign.input.gz is a selection of test cases from | 
|  | // https://ed25519.cr.yp.to/python/sign.input | 
|  | testDataZ, err := os.Open("testdata/sign.input.gz") | 
|  | if err != nil { | 
|  | t.Fatal(err) | 
|  | } | 
|  | defer testDataZ.Close() | 
|  | testData, err := gzip.NewReader(testDataZ) | 
|  | if err != nil { | 
|  | t.Fatal(err) | 
|  | } | 
|  | defer testData.Close() | 
|  |  | 
|  | scanner := bufio.NewScanner(testData) | 
|  | lineNo := 0 | 
|  |  | 
|  | for scanner.Scan() { | 
|  | lineNo++ | 
|  |  | 
|  | line := scanner.Text() | 
|  | parts := strings.Split(line, ":") | 
|  | if len(parts) != 5 { | 
|  | t.Fatalf("bad number of parts on line %d", lineNo) | 
|  | } | 
|  |  | 
|  | privBytes, _ := hex.DecodeString(parts[0]) | 
|  | pubKey, _ := hex.DecodeString(parts[1]) | 
|  | msg, _ := hex.DecodeString(parts[2]) | 
|  | sig, _ := hex.DecodeString(parts[3]) | 
|  | // The signatures in the test vectors also include the message | 
|  | // at the end, but we just want R and S. | 
|  | sig = sig[:SignatureSize] | 
|  |  | 
|  | if l := len(pubKey); l != PublicKeySize { | 
|  | t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l) | 
|  | } | 
|  |  | 
|  | var priv [PrivateKeySize]byte | 
|  | copy(priv[:], privBytes) | 
|  | copy(priv[32:], pubKey) | 
|  |  | 
|  | sig2 := signImpl(priv[:], msg) | 
|  | if !bytes.Equal(sig, sig2[:]) { | 
|  | t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2) | 
|  | } | 
|  |  | 
|  | if !verifyImpl(pubKey, msg, sig2) { | 
|  | t.Errorf("signature failed to verify on line %d", lineNo) | 
|  | } | 
|  |  | 
|  | priv2 := NewKeyFromSeed(priv[:32]) | 
|  | if !bytes.Equal(priv[:], priv2) { | 
|  | t.Errorf("recreating key pair gave different private key on line %d: %x vs %x", lineNo, priv[:], priv2) | 
|  | } | 
|  |  | 
|  | if pubKey2 := priv2.Public().(PublicKey); !bytes.Equal(pubKey, pubKey2) { | 
|  | t.Errorf("recreating key pair gave different public key on line %d: %x vs %x", lineNo, pubKey, pubKey2) | 
|  | } | 
|  |  | 
|  | if seed := priv2.Seed(); !bytes.Equal(priv[:32], seed) { | 
|  | t.Errorf("recreating key pair gave different seed on line %d: %x vs %x", lineNo, priv[:32], seed) | 
|  | } | 
|  | } | 
|  |  | 
|  | if err := scanner.Err(); err != nil { | 
|  | t.Fatalf("error reading test data: %s", err) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestMalleability(t *testing.T) { | 
|  | t.Run("Generic", func(t *testing.T) { testMalleability(t, verifyGeneric) }) | 
|  | t.Run("Native", func(t *testing.T) { testMalleability(t, Verify) }) | 
|  | } | 
|  |  | 
|  | func testMalleability(t *testing.T, verifyImpl func(publicKey PublicKey, message, sig []byte) bool) { | 
|  | // https://tools.ietf.org/html/rfc8032#section-5.1.7 adds an additional test | 
|  | // that s be in [0, order). This prevents someone from adding a multiple of | 
|  | // order to s and obtaining a second valid signature for the same message. | 
|  | msg := []byte{0x54, 0x65, 0x73, 0x74} | 
|  | sig := []byte{ | 
|  | 0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a, | 
|  | 0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b, | 
|  | 0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67, | 
|  | 0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d, | 
|  | 0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33, | 
|  | 0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d, | 
|  | } | 
|  | publicKey := []byte{ | 
|  | 0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5, | 
|  | 0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34, | 
|  | 0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa, | 
|  | } | 
|  |  | 
|  | if verifyImpl(publicKey, msg, sig) { | 
|  | t.Fatal("non-canonical signature accepted") | 
|  | } | 
|  | } | 
|  |  | 
|  | func BenchmarkKeyGeneration(b *testing.B) { | 
|  | var zero zeroReader | 
|  | for i := 0; i < b.N; i++ { | 
|  | if _, _, err := GenerateKey(zero); err != nil { | 
|  | b.Fatal(err) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func BenchmarkNewKeyFromSeed(b *testing.B) { | 
|  | seed := make([]byte, SeedSize) | 
|  | b.ReportAllocs() | 
|  | for i := 0; i < b.N; i++ { | 
|  | _ = NewKeyFromSeed(seed) | 
|  | } | 
|  | } | 
|  |  | 
|  | func BenchmarkSigning(b *testing.B) { | 
|  | var zero zeroReader | 
|  | _, priv, err := GenerateKey(zero) | 
|  | if err != nil { | 
|  | b.Fatal(err) | 
|  | } | 
|  | message := []byte("Hello, world!") | 
|  | b.ReportAllocs() | 
|  | b.ResetTimer() | 
|  | for i := 0; i < b.N; i++ { | 
|  | Sign(priv, message) | 
|  | } | 
|  | } | 
|  |  | 
|  | func BenchmarkVerification(b *testing.B) { | 
|  | var zero zeroReader | 
|  | pub, priv, err := GenerateKey(zero) | 
|  | if err != nil { | 
|  | b.Fatal(err) | 
|  | } | 
|  | message := []byte("Hello, world!") | 
|  | signature := Sign(priv, message) | 
|  | b.ResetTimer() | 
|  | for i := 0; i < b.N; i++ { | 
|  | Verify(pub, message, signature) | 
|  | } | 
|  | } |