Source file src/crypto/ed25519/ed25519_test.go

     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/internal/cryptotest"
    13  	"crypto/rand"
    14  	"crypto/sha512"
    15  	"encoding/hex"
    16  	"log"
    17  	"os"
    18  	"strings"
    19  	"testing"
    20  )
    21  
    22  func Example_ed25519ctx() {
    23  	pub, priv, err := GenerateKey(nil)
    24  	if err != nil {
    25  		log.Fatal(err)
    26  	}
    27  
    28  	msg := []byte("The quick brown fox jumps over the lazy dog")
    29  
    30  	sig, err := priv.Sign(nil, msg, &Options{
    31  		Context: "Example_ed25519ctx",
    32  	})
    33  	if err != nil {
    34  		log.Fatal(err)
    35  	}
    36  
    37  	if err := VerifyWithOptions(pub, msg, sig, &Options{
    38  		Context: "Example_ed25519ctx",
    39  	}); err != nil {
    40  		log.Fatal("invalid signature")
    41  	}
    42  }
    43  
    44  func TestGenerateKey(t *testing.T) {
    45  	// nil is like using crypto/rand.Reader.
    46  	public, private, err := GenerateKey(nil)
    47  	if err != nil {
    48  		t.Fatal(err)
    49  	}
    50  
    51  	if len(public) != PublicKeySize {
    52  		t.Errorf("public key has the wrong size: %d", len(public))
    53  	}
    54  	if len(private) != PrivateKeySize {
    55  		t.Errorf("private key has the wrong size: %d", len(private))
    56  	}
    57  	if !bytes.Equal(private.Public().(PublicKey), public) {
    58  		t.Errorf("public key doesn't match private key")
    59  	}
    60  	fromSeed := NewKeyFromSeed(private.Seed())
    61  	if !bytes.Equal(private, fromSeed) {
    62  		t.Errorf("recreating key pair from seed gave different private key")
    63  	}
    64  
    65  	_, k2, err := GenerateKey(nil)
    66  	if err != nil {
    67  		t.Fatal(err)
    68  	}
    69  	if bytes.Equal(private, k2) {
    70  		t.Errorf("GenerateKey returned the same private key twice")
    71  	}
    72  
    73  	_, k3, err := GenerateKey(rand.Reader)
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  	if bytes.Equal(private, k3) {
    78  		t.Errorf("GenerateKey returned the same private key twice")
    79  	}
    80  
    81  	// GenerateKey is documented to be the same as NewKeyFromSeed.
    82  	seed := make([]byte, SeedSize)
    83  	rand.Read(seed)
    84  	_, k4, err := GenerateKey(bytes.NewReader(seed))
    85  	if err != nil {
    86  		t.Fatal(err)
    87  	}
    88  	k4n := NewKeyFromSeed(seed)
    89  	if !bytes.Equal(k4, k4n) {
    90  		t.Errorf("GenerateKey with seed gave different private key")
    91  	}
    92  }
    93  
    94  type zeroReader struct{}
    95  
    96  func (zeroReader) Read(buf []byte) (int, error) {
    97  	clear(buf)
    98  	return len(buf), nil
    99  }
   100  
   101  func TestSignVerify(t *testing.T) {
   102  	var zero zeroReader
   103  	public, private, _ := GenerateKey(zero)
   104  
   105  	message := []byte("test message")
   106  	sig := Sign(private, message)
   107  	if !Verify(public, message, sig) {
   108  		t.Errorf("valid signature rejected")
   109  	}
   110  
   111  	wrongMessage := []byte("wrong message")
   112  	if Verify(public, wrongMessage, sig) {
   113  		t.Errorf("signature of different message accepted")
   114  	}
   115  }
   116  
   117  func TestSignVerifyHashed(t *testing.T) {
   118  	// From RFC 8032, Section 7.3
   119  	key, _ := hex.DecodeString("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf")
   120  	expectedSig, _ := hex.DecodeString("98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406")
   121  	message, _ := hex.DecodeString("616263")
   122  
   123  	private := PrivateKey(key)
   124  	public := private.Public().(PublicKey)
   125  	hash := sha512.Sum512(message)
   126  	sig, err := private.Sign(nil, hash[:], crypto.SHA512)
   127  	if err != nil {
   128  		t.Fatal(err)
   129  	}
   130  	if !bytes.Equal(sig, expectedSig) {
   131  		t.Error("signature doesn't match test vector")
   132  	}
   133  	sig, err = private.Sign(nil, hash[:], &Options{Hash: crypto.SHA512})
   134  	if err != nil {
   135  		t.Fatal(err)
   136  	}
   137  	if !bytes.Equal(sig, expectedSig) {
   138  		t.Error("signature doesn't match test vector")
   139  	}
   140  	if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}); err != nil {
   141  		t.Errorf("valid signature rejected: %v", err)
   142  	}
   143  
   144  	if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA256}); err == nil {
   145  		t.Errorf("expected error for wrong hash")
   146  	}
   147  
   148  	wrongHash := sha512.Sum512([]byte("wrong message"))
   149  	if VerifyWithOptions(public, wrongHash[:], sig, &Options{Hash: crypto.SHA512}) == nil {
   150  		t.Errorf("signature of different message accepted")
   151  	}
   152  
   153  	sig[0] ^= 0xff
   154  	if VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}) == nil {
   155  		t.Errorf("invalid signature accepted")
   156  	}
   157  	sig[0] ^= 0xff
   158  	sig[SignatureSize-1] ^= 0xff
   159  	if VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}) == nil {
   160  		t.Errorf("invalid signature accepted")
   161  	}
   162  
   163  	// The RFC provides no test vectors for Ed25519ph with context, so just sign
   164  	// and verify something.
   165  	sig, err = private.Sign(nil, hash[:], &Options{Hash: crypto.SHA512, Context: "123"})
   166  	if err != nil {
   167  		t.Fatal(err)
   168  	}
   169  	if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512, Context: "123"}); err != nil {
   170  		t.Errorf("valid signature rejected: %v", err)
   171  	}
   172  	if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512, Context: "321"}); err == nil {
   173  		t.Errorf("expected error for wrong context")
   174  	}
   175  	if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA256, Context: "123"}); err == nil {
   176  		t.Errorf("expected error for wrong hash")
   177  	}
   178  }
   179  
   180  func TestSignVerifyContext(t *testing.T) {
   181  	// From RFC 8032, Section 7.2
   182  	key, _ := hex.DecodeString("0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292")
   183  	expectedSig, _ := hex.DecodeString("55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d")
   184  	message, _ := hex.DecodeString("f726936d19c800494e3fdaff20b276a8")
   185  	context := "foo"
   186  
   187  	private := PrivateKey(key)
   188  	public := private.Public().(PublicKey)
   189  	sig, err := private.Sign(nil, message, &Options{Context: context})
   190  	if err != nil {
   191  		t.Fatal(err)
   192  	}
   193  	if !bytes.Equal(sig, expectedSig) {
   194  		t.Error("signature doesn't match test vector")
   195  	}
   196  	if err := VerifyWithOptions(public, message, sig, &Options{Context: context}); err != nil {
   197  		t.Errorf("valid signature rejected: %v", err)
   198  	}
   199  
   200  	if VerifyWithOptions(public, []byte("bar"), sig, &Options{Context: context}) == nil {
   201  		t.Errorf("signature of different message accepted")
   202  	}
   203  	if VerifyWithOptions(public, message, sig, &Options{Context: "bar"}) == nil {
   204  		t.Errorf("signature with different context accepted")
   205  	}
   206  
   207  	sig[0] ^= 0xff
   208  	if VerifyWithOptions(public, message, sig, &Options{Context: context}) == nil {
   209  		t.Errorf("invalid signature accepted")
   210  	}
   211  	sig[0] ^= 0xff
   212  	sig[SignatureSize-1] ^= 0xff
   213  	if VerifyWithOptions(public, message, sig, &Options{Context: context}) == nil {
   214  		t.Errorf("invalid signature accepted")
   215  	}
   216  }
   217  
   218  func TestCryptoSigner(t *testing.T) {
   219  	var zero zeroReader
   220  	public, private, _ := GenerateKey(zero)
   221  
   222  	signer := crypto.Signer(private)
   223  
   224  	publicInterface := signer.Public()
   225  	public2, ok := publicInterface.(PublicKey)
   226  	if !ok {
   227  		t.Fatalf("expected PublicKey from Public() but got %T", publicInterface)
   228  	}
   229  
   230  	if !bytes.Equal(public, public2) {
   231  		t.Errorf("public keys do not match: original:%x vs Public():%x", public, public2)
   232  	}
   233  
   234  	message := []byte("message")
   235  	var noHash crypto.Hash
   236  	signature, err := signer.Sign(zero, message, noHash)
   237  	if err != nil {
   238  		t.Fatalf("error from Sign(): %s", err)
   239  	}
   240  
   241  	signature2, err := signer.Sign(zero, message, &Options{Hash: noHash})
   242  	if err != nil {
   243  		t.Fatalf("error from Sign(): %s", err)
   244  	}
   245  	if !bytes.Equal(signature, signature2) {
   246  		t.Errorf("signatures keys do not match")
   247  	}
   248  
   249  	if !Verify(public, message, signature) {
   250  		t.Errorf("Verify failed on signature from Sign()")
   251  	}
   252  }
   253  
   254  func TestEqual(t *testing.T) {
   255  	public, private, _ := GenerateKey(rand.Reader)
   256  
   257  	if !public.Equal(public) {
   258  		t.Errorf("public key is not equal to itself: %q", public)
   259  	}
   260  	if !public.Equal(crypto.Signer(private).Public()) {
   261  		t.Errorf("private.Public() is not Equal to public: %q", public)
   262  	}
   263  	if !private.Equal(private) {
   264  		t.Errorf("private key is not equal to itself: %q", private)
   265  	}
   266  
   267  	otherPub, otherPriv, _ := GenerateKey(rand.Reader)
   268  	if public.Equal(otherPub) {
   269  		t.Errorf("different public keys are Equal")
   270  	}
   271  	if private.Equal(otherPriv) {
   272  		t.Errorf("different private keys are Equal")
   273  	}
   274  }
   275  
   276  func TestGolden(t *testing.T) {
   277  	// sign.input.gz is a selection of test cases from
   278  	// https://ed25519.cr.yp.to/python/sign.input
   279  	testDataZ, err := os.Open("testdata/sign.input.gz")
   280  	if err != nil {
   281  		t.Fatal(err)
   282  	}
   283  	defer testDataZ.Close()
   284  	testData, err := gzip.NewReader(testDataZ)
   285  	if err != nil {
   286  		t.Fatal(err)
   287  	}
   288  	defer testData.Close()
   289  
   290  	scanner := bufio.NewScanner(testData)
   291  	lineNo := 0
   292  
   293  	for scanner.Scan() {
   294  		lineNo++
   295  
   296  		line := scanner.Text()
   297  		parts := strings.Split(line, ":")
   298  		if len(parts) != 5 {
   299  			t.Fatalf("bad number of parts on line %d", lineNo)
   300  		}
   301  
   302  		privBytes, _ := hex.DecodeString(parts[0])
   303  		pubKey, _ := hex.DecodeString(parts[1])
   304  		msg, _ := hex.DecodeString(parts[2])
   305  		sig, _ := hex.DecodeString(parts[3])
   306  		// The signatures in the test vectors also include the message
   307  		// at the end, but we just want R and S.
   308  		sig = sig[:SignatureSize]
   309  
   310  		if l := len(pubKey); l != PublicKeySize {
   311  			t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l)
   312  		}
   313  
   314  		var priv [PrivateKeySize]byte
   315  		copy(priv[:], privBytes)
   316  		copy(priv[32:], pubKey)
   317  
   318  		sig2 := Sign(priv[:], msg)
   319  		if !bytes.Equal(sig, sig2[:]) {
   320  			t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2)
   321  		}
   322  
   323  		if !Verify(pubKey, msg, sig2) {
   324  			t.Errorf("signature failed to verify on line %d", lineNo)
   325  		}
   326  
   327  		priv2 := NewKeyFromSeed(priv[:32])
   328  		if !bytes.Equal(priv[:], priv2) {
   329  			t.Errorf("recreating key pair gave different private key on line %d: %x vs %x", lineNo, priv[:], priv2)
   330  		}
   331  
   332  		if pubKey2 := priv2.Public().(PublicKey); !bytes.Equal(pubKey, pubKey2) {
   333  			t.Errorf("recreating key pair gave different public key on line %d: %x vs %x", lineNo, pubKey, pubKey2)
   334  		}
   335  
   336  		if seed := priv2.Seed(); !bytes.Equal(priv[:32], seed) {
   337  			t.Errorf("recreating key pair gave different seed on line %d: %x vs %x", lineNo, priv[:32], seed)
   338  		}
   339  	}
   340  
   341  	if err := scanner.Err(); err != nil {
   342  		t.Fatalf("error reading test data: %s", err)
   343  	}
   344  }
   345  
   346  func TestMalleability(t *testing.T) {
   347  	// https://tools.ietf.org/html/rfc8032#section-5.1.7 adds an additional test
   348  	// that s be in [0, order). This prevents someone from adding a multiple of
   349  	// order to s and obtaining a second valid signature for the same message.
   350  	msg := []byte{0x54, 0x65, 0x73, 0x74}
   351  	sig := []byte{
   352  		0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a,
   353  		0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b,
   354  		0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67,
   355  		0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d,
   356  		0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33,
   357  		0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d,
   358  	}
   359  	publicKey := []byte{
   360  		0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5,
   361  		0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34,
   362  		0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
   363  	}
   364  
   365  	if Verify(publicKey, msg, sig) {
   366  		t.Fatal("non-canonical signature accepted")
   367  	}
   368  }
   369  
   370  func TestAllocations(t *testing.T) {
   371  	cryptotest.SkipTestAllocations(t)
   372  	if allocs := testing.AllocsPerRun(100, func() {
   373  		seed := make([]byte, SeedSize)
   374  		message := []byte("Hello, world!")
   375  		priv := NewKeyFromSeed(seed)
   376  		pub := priv.Public().(PublicKey)
   377  		signature := Sign(priv, message)
   378  		if !Verify(pub, message, signature) {
   379  			t.Fatal("signature didn't verify")
   380  		}
   381  	}); allocs > 0 {
   382  		t.Errorf("expected zero allocations, got %0.1f", allocs)
   383  	}
   384  }
   385  
   386  func BenchmarkKeyGeneration(b *testing.B) {
   387  	var zero zeroReader
   388  	for i := 0; i < b.N; i++ {
   389  		if _, _, err := GenerateKey(zero); err != nil {
   390  			b.Fatal(err)
   391  		}
   392  	}
   393  }
   394  
   395  func BenchmarkNewKeyFromSeed(b *testing.B) {
   396  	seed := make([]byte, SeedSize)
   397  	for i := 0; i < b.N; i++ {
   398  		_ = NewKeyFromSeed(seed)
   399  	}
   400  }
   401  
   402  func BenchmarkSigning(b *testing.B) {
   403  	var zero zeroReader
   404  	_, priv, err := GenerateKey(zero)
   405  	if err != nil {
   406  		b.Fatal(err)
   407  	}
   408  	message := []byte("Hello, world!")
   409  	b.ResetTimer()
   410  	for i := 0; i < b.N; i++ {
   411  		Sign(priv, message)
   412  	}
   413  }
   414  
   415  func BenchmarkVerification(b *testing.B) {
   416  	var zero zeroReader
   417  	pub, priv, err := GenerateKey(zero)
   418  	if err != nil {
   419  		b.Fatal(err)
   420  	}
   421  	message := []byte("Hello, world!")
   422  	signature := Sign(priv, message)
   423  	b.ResetTimer()
   424  	for i := 0; i < b.N; i++ {
   425  		Verify(pub, message, signature)
   426  	}
   427  }
   428  

View as plain text