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

View as plain text