You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
5.4 KiB
179 lines
5.4 KiB
// Copyright (c) 2013-2016 The btcsuite developers |
|
// Copyright (c) 2015-2023 The Decred developers |
|
// Use of this source code is governed by an ISC |
|
// license that can be found in the LICENSE file. |
|
|
|
package secp256k1 |
|
|
|
import ( |
|
"bytes" |
|
"crypto/rand" |
|
"errors" |
|
"math/big" |
|
"testing" |
|
|
|
"next.orly.dev/pkg/utils" |
|
) |
|
|
|
// TestGenerateSecretKey ensures the key generation works as expected. |
|
func TestGenerateSecretKey(t *testing.T) { |
|
sec, err := GenerateSecretKey() |
|
if err != nil { |
|
t.Errorf("failed to generate secret key: %s", err) |
|
return |
|
} |
|
pub := sec.PubKey() |
|
if !isOnCurve(&pub.x, &pub.y) { |
|
t.Error("public key is not on the curve") |
|
} |
|
} |
|
|
|
// TestGenerateSecretKeyFromRand ensures generating a secret key from a random |
|
// entropy source works as expected. |
|
func TestGenerateSecretKeyFromRand(t *testing.T) { |
|
sec, err := GenerateSecretKeyFromRand(rand.Reader) |
|
if err != nil { |
|
t.Errorf("failed to generate secret key: %s", err) |
|
return |
|
} |
|
pub := sec.PubKey() |
|
if !isOnCurve(&pub.x, &pub.y) { |
|
t.Error("public key is not on the curve") |
|
} |
|
} |
|
|
|
// mockSecretKeyReaderFunc is an adapter to allow the use of an ordinary |
|
// function as an io.Reader. |
|
type mockSecretKeyReaderFunc func([]byte) (int, error) |
|
|
|
// Read calls the function with the provided parameter and returns the result. |
|
func (f mockSecretKeyReaderFunc) Read(p []byte) (int, error) { |
|
return f(p) |
|
} |
|
|
|
// TestGenerateSecretKeyCorners ensures random values that secret key |
|
// generation correctly handles entropy values that are invalid for use as |
|
// secret keys by creating a fake source of randomness to inject known bad |
|
// values. |
|
func TestGenerateSecretKeyCorners(t *testing.T) { |
|
// Create a mock reader that returns the following sequence of values: |
|
// 1st invocation: 0 |
|
// 2nd invocation: The curve order |
|
// 3rd invocation: The curve order + 1 |
|
// 4th invocation: 1 (32-byte big endian) |
|
oneModN := hexToModNScalar("01") |
|
var numReads int |
|
mockReader := mockSecretKeyReaderFunc( |
|
func(p []byte) (int, error) { |
|
numReads++ |
|
switch numReads { |
|
case 1: |
|
return copy(p, bytes.Repeat([]byte{0x00}, len(p))), nil |
|
case 2: |
|
return copy(p, curveParams.N.Bytes()), nil |
|
case 3: |
|
nPlusOne := new(big.Int).Add(curveParams.N, big.NewInt(1)) |
|
return copy(p, nPlusOne.Bytes()), nil |
|
} |
|
oneModNBytes := oneModN.Bytes() |
|
return copy(p, oneModNBytes[:]), nil |
|
}, |
|
) |
|
// Generate a secret key using the mock reader and ensure the resulting key |
|
// is the expected one. It should be the value "1" since the other values |
|
// the sequence produces are invalid and thus should be rejected. |
|
sec, err := GenerateSecretKeyFromRand(mockReader) |
|
if err != nil { |
|
t.Errorf("failed to generate secret key: %s", err) |
|
return |
|
} |
|
if !sec.Key.Equals(oneModN) { |
|
t.Fatalf( |
|
"unexpected secret key -- got: %x, want %x", sec.Serialize(), |
|
oneModN.Bytes(), |
|
) |
|
} |
|
} |
|
|
|
// TestGenerateSecretKeyError ensures the secret key generation properly |
|
// handles errors when attempting to read from the source of randomness. |
|
func TestGenerateSecretKeyError(t *testing.T) { |
|
// Create a mock reader that returns an error. |
|
errDisabled := errors.New("disabled") |
|
mockReader := mockSecretKeyReaderFunc( |
|
func(p []byte) (int, error) { |
|
return 0, errDisabled |
|
}, |
|
) |
|
// Generate a secret key using the mock reader and ensure the expected |
|
// error is returned. |
|
_, err := GenerateSecretKeyFromRand(mockReader) |
|
if !errors.Is(err, errDisabled) { |
|
t.Fatalf("mismatched err -- got %v, want %v", err, errDisabled) |
|
return |
|
} |
|
} |
|
|
|
// TestSecKeys ensures a secret key created from bytes produces both the |
|
// correct associated public key as well serializes back to the original bytes. |
|
func TestSecKeys(t *testing.T) { |
|
tests := []struct { |
|
name string |
|
sec string // hex encoded secret key to test |
|
pub string // expected hex encoded serialized compressed public key |
|
}{ |
|
{ |
|
name: "random secret key 1", |
|
sec: "eaf02ca348c524e6392655ba4d29603cd1a7347d9d65cfe93ce1ebffdca22694", |
|
pub: "025ceeba2ab4a635df2c0301a3d773da06ac5a18a7c3e0d09a795d7e57d233edf1", |
|
}, { |
|
name: "random secret key 2", |
|
sec: "24b860d0651db83feba821e7a94ba8b87162665509cefef0cbde6a8fbbedfe7c", |
|
pub: "032a6e51bf218085647d330eac2fafaeee07617a777ad9e8e7141b4cdae92cb637", |
|
}, |
|
} |
|
|
|
for _, test := range tests { |
|
// Parse test data. |
|
secKeyBytes := hexToBytes(test.sec) |
|
wantPubKeyBytes := hexToBytes(test.pub) |
|
|
|
sec := SecKeyFromBytes(secKeyBytes) |
|
pub := sec.PubKey() |
|
|
|
serializedPubKey := pub.SerializeCompressed() |
|
if !utils.FastEqual(serializedPubKey, wantPubKeyBytes) { |
|
t.Errorf( |
|
"%s unexpected serialized public key - got: %x, want: %x", |
|
test.name, serializedPubKey, wantPubKeyBytes, |
|
) |
|
} |
|
|
|
serializedSecKey := sec.Serialize() |
|
if !utils.FastEqual(serializedSecKey, secKeyBytes) { |
|
t.Errorf( |
|
"%s unexpected serialized secret key - got: %x, want: %x", |
|
test.name, serializedSecKey, secKeyBytes, |
|
) |
|
} |
|
} |
|
} |
|
|
|
// TestSecretKeyZero ensures that zeroing a secret key clears the memory |
|
// associated with it. |
|
func TestSecretKeyZero(t *testing.T) { |
|
// Create a new secret key and zero the initial key material that is now |
|
// copied into the secret key. |
|
key := new(ModNScalar).SetHex("eaf02ca348c524e6392655ba4d29603cd1a7347d9d65cfe93ce1ebffdca22694") |
|
secKey := NewSecretKey(key) |
|
key.Zero() |
|
// Ensure the secret key is non zero. |
|
if secKey.Key.IsZero() { |
|
t.Fatal("secret key is zero when it should be non zero") |
|
} |
|
// Zero the secret key and ensure it was properly zeroed. |
|
secKey.Zero() |
|
if !secKey.Key.IsZero() { |
|
t.Fatal("secret key is non zero when it should be zero") |
|
} |
|
}
|
|
|