...

Source file src/github.com/decred/dcrd/dcrec/secp256k1/v4/privkey_test.go

Documentation: github.com/decred/dcrd/dcrec/secp256k1/v4

     1  // Copyright (c) 2013-2016 The btcsuite developers
     2  // Copyright (c) 2015-2023 The Decred developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package secp256k1
     7  
     8  import (
     9  	"bytes"
    10  	cryptorand "crypto/rand"
    11  	"errors"
    12  	"math/big"
    13  	"testing"
    14  )
    15  
    16  // TestGeneratePrivateKey ensures the key generation works as expected.
    17  func TestGeneratePrivateKey(t *testing.T) {
    18  	priv, err := GeneratePrivateKey()
    19  	if err != nil {
    20  		t.Errorf("failed to generate private key: %s", err)
    21  		return
    22  	}
    23  	pub := priv.PubKey()
    24  	if !isOnCurve(&pub.x, &pub.y) {
    25  		t.Error("public key is not on the curve")
    26  	}
    27  }
    28  
    29  // TestGeneratePrivateKeyFromRand ensures generating a private key from a random
    30  // entropy source works as expected.
    31  func TestGeneratePrivateKeyFromRand(t *testing.T) {
    32  	priv, err := GeneratePrivateKeyFromRand(cryptorand.Reader)
    33  	if err != nil {
    34  		t.Errorf("failed to generate private key: %s", err)
    35  		return
    36  	}
    37  	pub := priv.PubKey()
    38  	if !isOnCurve(&pub.x, &pub.y) {
    39  		t.Error("public key is not on the curve")
    40  	}
    41  }
    42  
    43  // mockPrivateKeyReaderFunc is an adapter to allow the use of an ordinary
    44  // function as an io.Reader.
    45  type mockPrivateKeyReaderFunc func([]byte) (int, error)
    46  
    47  // Read calls the function with the provided parameter and returns the result.
    48  func (f mockPrivateKeyReaderFunc) Read(p []byte) (int, error) {
    49  	return f(p)
    50  }
    51  
    52  // TestGeneratePrivateKeyCorners ensures random values that private key
    53  // generation correctly handles entropy values that are invalid for use as
    54  // private keys by creating a fake source of randomness to inject known bad
    55  // values.
    56  func TestGeneratePrivateKeyCorners(t *testing.T) {
    57  	// Create a mock reader that returns the following sequence of values:
    58  	// 1st invocation: 0
    59  	// 2nd invocation: The curve order
    60  	// 3rd invocation: The curve order + 1
    61  	// 4th invocation: 1 (32-byte big endian)
    62  	oneModN := hexToModNScalar("01")
    63  	var numReads int
    64  	mockReader := mockPrivateKeyReaderFunc(func(p []byte) (int, error) {
    65  		numReads++
    66  		switch numReads {
    67  		case 1:
    68  			return copy(p, bytes.Repeat([]byte{0x00}, len(p))), nil
    69  		case 2:
    70  			return copy(p, curveParams.N.Bytes()), nil
    71  		case 3:
    72  			nPlusOne := new(big.Int).Add(curveParams.N, big.NewInt(1))
    73  			return copy(p, nPlusOne.Bytes()), nil
    74  		}
    75  		oneModNBytes := oneModN.Bytes()
    76  		return copy(p, oneModNBytes[:]), nil
    77  	})
    78  
    79  	// Generate a private key using the mock reader and ensure the resulting key
    80  	// is the expected one.  It should be the value "1" since the other values
    81  	// the sequence produces are invalid and thus should be rejected.
    82  	priv, err := GeneratePrivateKeyFromRand(mockReader)
    83  	if err != nil {
    84  		t.Errorf("failed to generate private key: %s", err)
    85  		return
    86  	}
    87  	if !priv.Key.Equals(oneModN) {
    88  		t.Fatalf("unexpected private key -- got: %x, want %x", priv.Serialize(),
    89  			oneModN.Bytes())
    90  	}
    91  }
    92  
    93  // TestGeneratePrivateKeyError ensures the private key generation properly
    94  // handles errors when attempting to read from the source of randomness.
    95  func TestGeneratePrivateKeyError(t *testing.T) {
    96  	// Create a mock reader that returns an error.
    97  	errDisabled := errors.New("disabled")
    98  	mockReader := mockPrivateKeyReaderFunc(func(p []byte) (int, error) {
    99  		return 0, errDisabled
   100  	})
   101  
   102  	// Generate a private key using the mock reader and ensure the expected
   103  	// error is returned.
   104  	_, err := GeneratePrivateKeyFromRand(mockReader)
   105  	if !errors.Is(err, errDisabled) {
   106  		t.Fatalf("mismatched err -- got %v, want %v", err, errDisabled)
   107  		return
   108  	}
   109  }
   110  
   111  // TestPrivKeys ensures a private key created from bytes produces both the
   112  // correct associated public key as well serializes back to the original bytes.
   113  func TestPrivKeys(t *testing.T) {
   114  	tests := []struct {
   115  		name string
   116  		priv string // hex encoded private key to test
   117  		pub  string // expected hex encoded serialized compressed public key
   118  	}{{
   119  		name: "random private key 1",
   120  		priv: "eaf02ca348c524e6392655ba4d29603cd1a7347d9d65cfe93ce1ebffdca22694",
   121  		pub:  "025ceeba2ab4a635df2c0301a3d773da06ac5a18a7c3e0d09a795d7e57d233edf1",
   122  	}, {
   123  		name: "random private key 2",
   124  		priv: "24b860d0651db83feba821e7a94ba8b87162665509cefef0cbde6a8fbbedfe7c",
   125  		pub:  "032a6e51bf218085647d330eac2fafaeee07617a777ad9e8e7141b4cdae92cb637",
   126  	}}
   127  
   128  	for _, test := range tests {
   129  		// Parse test data.
   130  		privKeyBytes := hexToBytes(test.priv)
   131  		wantPubKeyBytes := hexToBytes(test.pub)
   132  
   133  		priv := PrivKeyFromBytes(privKeyBytes)
   134  		pub := priv.PubKey()
   135  
   136  		serializedPubKey := pub.SerializeCompressed()
   137  		if !bytes.Equal(serializedPubKey, wantPubKeyBytes) {
   138  			t.Errorf("%s unexpected serialized public key - got: %x, want: %x",
   139  				test.name, serializedPubKey, wantPubKeyBytes)
   140  		}
   141  
   142  		serializedPrivKey := priv.Serialize()
   143  		if !bytes.Equal(serializedPrivKey, privKeyBytes) {
   144  			t.Errorf("%s unexpected serialized private key - got: %x, want: %x",
   145  				test.name, serializedPrivKey, privKeyBytes)
   146  		}
   147  	}
   148  }
   149  
   150  // TestPrivateKeyZero ensures that zeroing a private key clears the memory
   151  // associated with it.
   152  func TestPrivateKeyZero(t *testing.T) {
   153  	// Create a new private key and zero the initial key material that is now
   154  	// copied into the private key.
   155  	key := new(ModNScalar).SetHex("eaf02ca348c524e6392655ba4d29603cd1a7347d9d65cfe93ce1ebffdca22694")
   156  	privKey := NewPrivateKey(key)
   157  	key.Zero()
   158  
   159  	// Ensure the private key is non zero.
   160  	if privKey.Key.IsZero() {
   161  		t.Fatal("private key is zero when it should be non zero")
   162  	}
   163  
   164  	// Zero the private key and ensure it was properly zeroed.
   165  	privKey.Zero()
   166  	if !privKey.Key.IsZero() {
   167  		t.Fatal("private key is non zero when it should be zero")
   168  	}
   169  }
   170  

View as plain text