Black Lives Matter. Support the Equal Justice Initiative.

Source file src/crypto/ed25519/ed25519_test.go

Documentation: crypto/ed25519

     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/rand"
    13  	"encoding/hex"
    14  	"os"
    15  	"strings"
    16  	"testing"
    17  )
    18  
    19  type zeroReader struct{}
    20  
    21  func (zeroReader) Read(buf []byte) (int, error) {
    22  	for i := range buf {
    23  		buf[i] = 0
    24  	}
    25  	return len(buf), nil
    26  }
    27  
    28  func TestSignVerify(t *testing.T) {
    29  	var zero zeroReader
    30  	public, private, _ := GenerateKey(zero)
    31  
    32  	message := []byte("test message")
    33  	sig := Sign(private, message)
    34  	if !Verify(public, message, sig) {
    35  		t.Errorf("valid signature rejected")
    36  	}
    37  
    38  	wrongMessage := []byte("wrong message")
    39  	if Verify(public, wrongMessage, sig) {
    40  		t.Errorf("signature of different message accepted")
    41  	}
    42  }
    43  
    44  func TestCryptoSigner(t *testing.T) {
    45  	var zero zeroReader
    46  	public, private, _ := GenerateKey(zero)
    47  
    48  	signer := crypto.Signer(private)
    49  
    50  	publicInterface := signer.Public()
    51  	public2, ok := publicInterface.(PublicKey)
    52  	if !ok {
    53  		t.Fatalf("expected PublicKey from Public() but got %T", publicInterface)
    54  	}
    55  
    56  	if !bytes.Equal(public, public2) {
    57  		t.Errorf("public keys do not match: original:%x vs Public():%x", public, public2)
    58  	}
    59  
    60  	message := []byte("message")
    61  	var noHash crypto.Hash
    62  	signature, err := signer.Sign(zero, message, noHash)
    63  	if err != nil {
    64  		t.Fatalf("error from Sign(): %s", err)
    65  	}
    66  
    67  	if !Verify(public, message, signature) {
    68  		t.Errorf("Verify failed on signature from Sign()")
    69  	}
    70  }
    71  
    72  func TestEqual(t *testing.T) {
    73  	public, private, _ := GenerateKey(rand.Reader)
    74  
    75  	if !public.Equal(public) {
    76  		t.Errorf("public key is not equal to itself: %q", public)
    77  	}
    78  	if !public.Equal(crypto.Signer(private).Public()) {
    79  		t.Errorf("private.Public() is not Equal to public: %q", public)
    80  	}
    81  	if !private.Equal(private) {
    82  		t.Errorf("private key is not equal to itself: %q", private)
    83  	}
    84  
    85  	otherPub, otherPriv, _ := GenerateKey(rand.Reader)
    86  	if public.Equal(otherPub) {
    87  		t.Errorf("different public keys are Equal")
    88  	}
    89  	if private.Equal(otherPriv) {
    90  		t.Errorf("different private keys are Equal")
    91  	}
    92  }
    93  
    94  func TestGolden(t *testing.T) {
    95  	// sign.input.gz is a selection of test cases from
    96  	// https://ed25519.cr.yp.to/python/sign.input
    97  	testDataZ, err := os.Open("testdata/sign.input.gz")
    98  	if err != nil {
    99  		t.Fatal(err)
   100  	}
   101  	defer testDataZ.Close()
   102  	testData, err := gzip.NewReader(testDataZ)
   103  	if err != nil {
   104  		t.Fatal(err)
   105  	}
   106  	defer testData.Close()
   107  
   108  	scanner := bufio.NewScanner(testData)
   109  	lineNo := 0
   110  
   111  	for scanner.Scan() {
   112  		lineNo++
   113  
   114  		line := scanner.Text()
   115  		parts := strings.Split(line, ":")
   116  		if len(parts) != 5 {
   117  			t.Fatalf("bad number of parts on line %d", lineNo)
   118  		}
   119  
   120  		privBytes, _ := hex.DecodeString(parts[0])
   121  		pubKey, _ := hex.DecodeString(parts[1])
   122  		msg, _ := hex.DecodeString(parts[2])
   123  		sig, _ := hex.DecodeString(parts[3])
   124  		// The signatures in the test vectors also include the message
   125  		// at the end, but we just want R and S.
   126  		sig = sig[:SignatureSize]
   127  
   128  		if l := len(pubKey); l != PublicKeySize {
   129  			t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l)
   130  		}
   131  
   132  		var priv [PrivateKeySize]byte
   133  		copy(priv[:], privBytes)
   134  		copy(priv[32:], pubKey)
   135  
   136  		sig2 := Sign(priv[:], msg)
   137  		if !bytes.Equal(sig, sig2[:]) {
   138  			t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2)
   139  		}
   140  
   141  		if !Verify(pubKey, msg, sig2) {
   142  			t.Errorf("signature failed to verify on line %d", lineNo)
   143  		}
   144  
   145  		priv2 := NewKeyFromSeed(priv[:32])
   146  		if !bytes.Equal(priv[:], priv2) {
   147  			t.Errorf("recreating key pair gave different private key on line %d: %x vs %x", lineNo, priv[:], priv2)
   148  		}
   149  
   150  		if pubKey2 := priv2.Public().(PublicKey); !bytes.Equal(pubKey, pubKey2) {
   151  			t.Errorf("recreating key pair gave different public key on line %d: %x vs %x", lineNo, pubKey, pubKey2)
   152  		}
   153  
   154  		if seed := priv2.Seed(); !bytes.Equal(priv[:32], seed) {
   155  			t.Errorf("recreating key pair gave different seed on line %d: %x vs %x", lineNo, priv[:32], seed)
   156  		}
   157  	}
   158  
   159  	if err := scanner.Err(); err != nil {
   160  		t.Fatalf("error reading test data: %s", err)
   161  	}
   162  }
   163  
   164  func TestMalleability(t *testing.T) {
   165  	// https://tools.ietf.org/html/rfc8032#section-5.1.7 adds an additional test
   166  	// that s be in [0, order). This prevents someone from adding a multiple of
   167  	// order to s and obtaining a second valid signature for the same message.
   168  	msg := []byte{0x54, 0x65, 0x73, 0x74}
   169  	sig := []byte{
   170  		0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a,
   171  		0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b,
   172  		0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67,
   173  		0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d,
   174  		0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33,
   175  		0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d,
   176  	}
   177  	publicKey := []byte{
   178  		0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5,
   179  		0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34,
   180  		0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
   181  	}
   182  
   183  	if Verify(publicKey, msg, sig) {
   184  		t.Fatal("non-canonical signature accepted")
   185  	}
   186  }
   187  
   188  func TestAllocations(t *testing.T) {
   189  	if strings.HasSuffix(os.Getenv("GO_BUILDER_NAME"), "-noopt") {
   190  		t.Skip("skipping allocations test without relevant optimizations")
   191  	}
   192  	if allocs := testing.AllocsPerRun(100, func() {
   193  		seed := make([]byte, SeedSize)
   194  		message := []byte("Hello, world!")
   195  		priv := NewKeyFromSeed(seed)
   196  		pub := priv.Public().(PublicKey)
   197  		signature := Sign(priv, message)
   198  		if !Verify(pub, message, signature) {
   199  			t.Fatal("signature didn't verify")
   200  		}
   201  	}); allocs > 0 {
   202  		t.Errorf("expected zero allocations, got %0.1v", allocs)
   203  	}
   204  }
   205  
   206  func BenchmarkKeyGeneration(b *testing.B) {
   207  	var zero zeroReader
   208  	for i := 0; i < b.N; i++ {
   209  		if _, _, err := GenerateKey(zero); err != nil {
   210  			b.Fatal(err)
   211  		}
   212  	}
   213  }
   214  
   215  func BenchmarkNewKeyFromSeed(b *testing.B) {
   216  	seed := make([]byte, SeedSize)
   217  	for i := 0; i < b.N; i++ {
   218  		_ = NewKeyFromSeed(seed)
   219  	}
   220  }
   221  
   222  func BenchmarkSigning(b *testing.B) {
   223  	var zero zeroReader
   224  	_, priv, err := GenerateKey(zero)
   225  	if err != nil {
   226  		b.Fatal(err)
   227  	}
   228  	message := []byte("Hello, world!")
   229  	b.ResetTimer()
   230  	for i := 0; i < b.N; i++ {
   231  		Sign(priv, message)
   232  	}
   233  }
   234  
   235  func BenchmarkVerification(b *testing.B) {
   236  	var zero zeroReader
   237  	pub, priv, err := GenerateKey(zero)
   238  	if err != nil {
   239  		b.Fatal(err)
   240  	}
   241  	message := []byte("Hello, world!")
   242  	signature := Sign(priv, message)
   243  	b.ResetTimer()
   244  	for i := 0; i < b.N; i++ {
   245  		Verify(pub, message, signature)
   246  	}
   247  }
   248  

View as plain text