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

View as plain text