Replaced legacy `*.orly` module imports with `next.orly.dev/pkg` paths across the codebase for consistency. Removed legacy `go.mod` files from sub-packages, consolidating dependency management. Added Dockerfiles and configurations for benchmarking environments.
494 lines
18 KiB
Go
494 lines
18 KiB
Go
// Copyright (c) 2013-2016 The btcsuite developers
|
|
// Copyright (c) 2015-2020 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 (
|
|
"errors"
|
|
"testing"
|
|
|
|
"next.orly.dev/pkg/utils"
|
|
)
|
|
|
|
// TestParsePubKey ensures that public keys are properly parsed according
|
|
// to the spec including both the positive and negative cases.
|
|
func TestParsePubKey(t *testing.T) {
|
|
tests := []struct {
|
|
name string // test description
|
|
key string // hex encoded public key
|
|
err error // expected error
|
|
wantX string // expected x coordinate
|
|
wantY string // expected y coordinate
|
|
}{
|
|
{
|
|
name: "uncompressed ok",
|
|
key: "04" +
|
|
"11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" +
|
|
"b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
err: nil,
|
|
wantX: "11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c",
|
|
wantY: "b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
}, {
|
|
name: "uncompressed x changed (not on curve)",
|
|
key: "04" +
|
|
"15db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" +
|
|
"b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
err: ErrPubKeyNotOnCurve,
|
|
}, {
|
|
name: "uncompressed y changed (not on curve)",
|
|
key: "04" +
|
|
"11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" +
|
|
"b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a4",
|
|
err: ErrPubKeyNotOnCurve,
|
|
}, {
|
|
name: "uncompressed claims compressed",
|
|
key: "03" +
|
|
"11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" +
|
|
"b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
err: ErrPubKeyInvalidFormat,
|
|
}, {
|
|
name: "uncompressed as hybrid ok (ybit = 0)",
|
|
key: "06" +
|
|
"11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" +
|
|
"4d1f1522047b33068bbb9b07d1e9f40564749b062b3fc0666479bc08a94be98c",
|
|
err: nil,
|
|
wantX: "11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c",
|
|
wantY: "4d1f1522047b33068bbb9b07d1e9f40564749b062b3fc0666479bc08a94be98c",
|
|
}, {
|
|
name: "uncompressed as hybrid ok (ybit = 1)",
|
|
key: "07" +
|
|
"11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" +
|
|
"b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
err: nil,
|
|
wantX: "11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c",
|
|
wantY: "b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
}, {
|
|
name: "uncompressed as hybrid wrong oddness",
|
|
key: "06" +
|
|
"11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" +
|
|
"b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
err: ErrPubKeyMismatchedOddness,
|
|
}, {
|
|
name: "compressed ok (ybit = 0)",
|
|
key: "02" +
|
|
"ce0b14fb842b1ba549fdd675c98075f12e9c510f8ef52bd021a9a1f4809d3b4d",
|
|
err: nil,
|
|
wantX: "ce0b14fb842b1ba549fdd675c98075f12e9c510f8ef52bd021a9a1f4809d3b4d",
|
|
wantY: "0890ff84d7999d878a57bee170e19ef4b4803b4bdede64503a6ac352b03c8032",
|
|
}, {
|
|
name: "compressed ok (ybit = 1)",
|
|
key: "03" +
|
|
"2689c7c2dab13309fb143e0e8fe396342521887e976690b6b47f5b2a4b7d448e",
|
|
err: nil,
|
|
wantX: "2689c7c2dab13309fb143e0e8fe396342521887e976690b6b47f5b2a4b7d448e",
|
|
wantY: "499dd7852849a38aa23ed9f306f07794063fe7904e0f347bc209fdddaf37691f",
|
|
}, {
|
|
name: "compressed claims uncompressed (ybit = 0)",
|
|
key: "04" +
|
|
"ce0b14fb842b1ba549fdd675c98075f12e9c510f8ef52bd021a9a1f4809d3b4d",
|
|
err: ErrPubKeyInvalidFormat,
|
|
}, {
|
|
name: "compressed claims uncompressed (ybit = 1)",
|
|
key: "04" +
|
|
"2689c7c2dab13309fb143e0e8fe396342521887e976690b6b47f5b2a4b7d448e",
|
|
err: ErrPubKeyInvalidFormat,
|
|
}, {
|
|
name: "compressed claims hybrid (ybit = 0)",
|
|
key: "06" +
|
|
"ce0b14fb842b1ba549fdd675c98075f12e9c510f8ef52bd021a9a1f4809d3b4d",
|
|
err: ErrPubKeyInvalidFormat,
|
|
}, {
|
|
name: "compressed claims hybrid (ybit = 1)",
|
|
key: "07" +
|
|
"2689c7c2dab13309fb143e0e8fe396342521887e976690b6b47f5b2a4b7d448e",
|
|
err: ErrPubKeyInvalidFormat,
|
|
}, {
|
|
name: "compressed with invalid x coord (ybit = 0)",
|
|
key: "03" +
|
|
"ce0b14fb842b1ba549fdd675c98075f12e9c510f8ef52bd021a9a1f4809d3b4c",
|
|
err: ErrPubKeyNotOnCurve,
|
|
}, {
|
|
name: "compressed with invalid x coord (ybit = 1)",
|
|
key: "03" +
|
|
"2689c7c2dab13309fb143e0e8fe396342521887e976690b6b47f5b2a4b7d448d",
|
|
err: ErrPubKeyNotOnCurve,
|
|
}, {
|
|
name: "empty",
|
|
key: "",
|
|
err: ErrPubKeyInvalidLen,
|
|
}, {
|
|
name: "wrong length",
|
|
key: "05",
|
|
err: ErrPubKeyInvalidLen,
|
|
}, {
|
|
name: "uncompressed x == p",
|
|
key: "04" +
|
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f" +
|
|
"b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
err: ErrPubKeyXTooBig,
|
|
}, {
|
|
// The y coordinate produces a valid point for x == 1 (mod p), but it
|
|
// should fail to parse instead of wrapping around.
|
|
name: "uncompressed x > p (p + 1 -- aka 1)",
|
|
key: "04" +
|
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30" +
|
|
"bde70df51939b94c9c24979fa7dd04ebd9b3572da7802290438af2a681895441",
|
|
err: ErrPubKeyXTooBig,
|
|
}, {
|
|
name: "uncompressed y == p",
|
|
key: "04" +
|
|
"11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" +
|
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
|
|
err: ErrPubKeyYTooBig,
|
|
}, {
|
|
// The x coordinate produces a valid point for y == 1 (mod p), but it
|
|
// should fail to parse instead of wrapping around.
|
|
name: "uncompressed y > p (p + 1 -- aka 1)",
|
|
key: "04" +
|
|
"1fe1e5ef3fceb5c135ab7741333ce5a6e80d68167653f6b2b24bcbcfaaaff507" +
|
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
|
|
err: ErrPubKeyYTooBig,
|
|
}, {
|
|
name: "compressed x == p (ybit = 0)",
|
|
key: "02" +
|
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
|
|
err: ErrPubKeyXTooBig,
|
|
}, {
|
|
name: "compressed x == p (ybit = 1)",
|
|
key: "03" +
|
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
|
|
err: ErrPubKeyXTooBig,
|
|
}, {
|
|
// This would be valid for x == 2 (mod p), but it should fail to parse
|
|
// instead of wrapping around.
|
|
name: "compressed x > p (p + 2 -- aka 2) (ybit = 0)",
|
|
key: "02" +
|
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc31",
|
|
err: ErrPubKeyXTooBig,
|
|
}, {
|
|
// This would be valid for x == 1 (mod p), but it should fail to parse
|
|
// instead of wrapping around.
|
|
name: "compressed x > p (p + 1 -- aka 1) (ybit = 1)",
|
|
key: "03" +
|
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
|
|
err: ErrPubKeyXTooBig,
|
|
}, {
|
|
name: "hybrid x == p (ybit = 1)",
|
|
key: "07" +
|
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f" +
|
|
"b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
err: ErrPubKeyXTooBig,
|
|
}, {
|
|
// The y coordinate produces a valid point for x == 1 (mod p), but it
|
|
// should fail to parse instead of wrapping around.
|
|
name: "hybrid x > p (p + 1 -- aka 1) (ybit = 0)",
|
|
key: "06" +
|
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30" +
|
|
"bde70df51939b94c9c24979fa7dd04ebd9b3572da7802290438af2a681895441",
|
|
err: ErrPubKeyXTooBig,
|
|
}, {
|
|
name: "hybrid y == p (ybit = 0 when mod p)",
|
|
key: "06" +
|
|
"11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" +
|
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
|
|
err: ErrPubKeyYTooBig,
|
|
}, {
|
|
// The x coordinate produces a valid point for y == 1 (mod p), but it
|
|
// should fail to parse instead of wrapping around.
|
|
name: "hybrid y > p (p + 1 -- aka 1) (ybit = 1 when mod p)",
|
|
key: "07" +
|
|
"1fe1e5ef3fceb5c135ab7741333ce5a6e80d68167653f6b2b24bcbcfaaaff507" +
|
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
|
|
err: ErrPubKeyYTooBig,
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
pubKeyBytes := hexToBytes(test.key)
|
|
pubKey, err := ParsePubKey(pubKeyBytes)
|
|
if !errors.Is(err, test.err) {
|
|
t.Errorf(
|
|
"%s mismatched e -- got %v, want %v", test.name, err,
|
|
test.err,
|
|
)
|
|
continue
|
|
}
|
|
if err != nil {
|
|
continue
|
|
}
|
|
// Ensure the x and y coordinates match the expected values upon
|
|
// successful parse.
|
|
wantX, wantY := hexToFieldVal(test.wantX), hexToFieldVal(test.wantY)
|
|
if !pubKey.x.Equals(wantX) {
|
|
t.Errorf(
|
|
"%s: mismatched x coordinate -- got %v, want %v",
|
|
test.name, pubKey.x, wantX,
|
|
)
|
|
continue
|
|
}
|
|
if !pubKey.y.Equals(wantY) {
|
|
t.Errorf(
|
|
"%s: mismatched y coordinate -- got %v, want %v",
|
|
test.name, pubKey.y, wantY,
|
|
)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestPubKeySerialize ensures that serializing public keys works as expected
|
|
// for both the compressed and uncompressed cases.
|
|
func TestPubKeySerialize(t *testing.T) {
|
|
tests := []struct {
|
|
name string // test description
|
|
pubX string // hex encoded x coordinate for pubkey to serialize
|
|
pubY string // hex encoded y coordinate for pubkey to serialize
|
|
compress bool // whether to serialize compressed or uncompressed
|
|
expected string // hex encoded expected pubkey serialization
|
|
}{
|
|
{
|
|
name: "uncompressed (ybit = 0)",
|
|
pubX: "11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c",
|
|
pubY: "4d1f1522047b33068bbb9b07d1e9f40564749b062b3fc0666479bc08a94be98c",
|
|
compress: false,
|
|
expected: "04" +
|
|
"11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" +
|
|
"4d1f1522047b33068bbb9b07d1e9f40564749b062b3fc0666479bc08a94be98c",
|
|
}, {
|
|
name: "uncompressed (ybit = 1)",
|
|
pubX: "11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c",
|
|
pubY: "b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
compress: false,
|
|
expected: "04" +
|
|
"11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" +
|
|
"b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
}, {
|
|
// It's invalid to parse pubkeys that are not on the curve, however it
|
|
// is possible to manually create them and they should serialize
|
|
// correctly.
|
|
name: "uncompressed not on the curve due to x coord",
|
|
pubX: "15db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c",
|
|
pubY: "b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
compress: false,
|
|
expected: "04" +
|
|
"15db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" +
|
|
"b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
}, {
|
|
// It's invalid to parse pubkeys that are not on the curve, however it
|
|
// is possible to manually create them and they should serialize
|
|
// correctly.
|
|
name: "uncompressed not on the curve due to y coord",
|
|
pubX: "15db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c",
|
|
pubY: "b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a4",
|
|
compress: false,
|
|
expected: "04" +
|
|
"15db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" +
|
|
"b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a4",
|
|
}, {
|
|
name: "compressed (ybit = 0)",
|
|
pubX: "ce0b14fb842b1ba549fdd675c98075f12e9c510f8ef52bd021a9a1f4809d3b4d",
|
|
pubY: "0890ff84d7999d878a57bee170e19ef4b4803b4bdede64503a6ac352b03c8032",
|
|
compress: true,
|
|
expected: "02" +
|
|
"ce0b14fb842b1ba549fdd675c98075f12e9c510f8ef52bd021a9a1f4809d3b4d",
|
|
}, {
|
|
name: "compressed (ybit = 1)",
|
|
pubX: "2689c7c2dab13309fb143e0e8fe396342521887e976690b6b47f5b2a4b7d448e",
|
|
pubY: "499dd7852849a38aa23ed9f306f07794063fe7904e0f347bc209fdddaf37691f",
|
|
compress: true,
|
|
expected: "03" +
|
|
"2689c7c2dab13309fb143e0e8fe396342521887e976690b6b47f5b2a4b7d448e",
|
|
}, {
|
|
// It's invalid to parse pubkeys that are not on the curve, however it
|
|
// is possible to manually create them and they should serialize
|
|
// correctly.
|
|
name: "compressed not on curve (ybit = 0)",
|
|
pubX: "ce0b14fb842b1ba549fdd675c98075f12e9c510f8ef52bd021a9a1f4809d3b4c",
|
|
pubY: "0890ff84d7999d878a57bee170e19ef4b4803b4bdede64503a6ac352b03c8032",
|
|
compress: true,
|
|
expected: "02" +
|
|
"ce0b14fb842b1ba549fdd675c98075f12e9c510f8ef52bd021a9a1f4809d3b4c",
|
|
}, {
|
|
// It's invalid to parse pubkeys that are not on the curve, however it
|
|
// is possible to manually create them and they should serialize
|
|
// correctly.
|
|
name: "compressed not on curve (ybit = 1)",
|
|
pubX: "2689c7c2dab13309fb143e0e8fe396342521887e976690b6b47f5b2a4b7d448d",
|
|
pubY: "499dd7852849a38aa23ed9f306f07794063fe7904e0f347bc209fdddaf37691f",
|
|
compress: true,
|
|
expected: "03" +
|
|
"2689c7c2dab13309fb143e0e8fe396342521887e976690b6b47f5b2a4b7d448d",
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
// Parse the test data.
|
|
x, y := hexToFieldVal(test.pubX), hexToFieldVal(test.pubY)
|
|
pubKey := NewPublicKey(x, y)
|
|
// Serialize with the correct method and ensure the result matches the
|
|
// expected value.
|
|
var serialized []byte
|
|
if test.compress {
|
|
serialized = pubKey.SerializeCompressed()
|
|
} else {
|
|
serialized = pubKey.SerializeUncompressed()
|
|
}
|
|
expected := hexToBytes(test.expected)
|
|
if !utils.FastEqual(serialized, expected) {
|
|
t.Errorf(
|
|
"%s: mismatched serialized public key -- got %x, want %x",
|
|
test.name, serialized, expected,
|
|
)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestPublicKeyIsEqual ensures that equality testing between two public keys
|
|
// works as expected.
|
|
func TestPublicKeyIsEqual(t *testing.T) {
|
|
pubKey1 := &PublicKey{
|
|
x: *hexToFieldVal("2689c7c2dab13309fb143e0e8fe396342521887e976690b6b47f5b2a4b7d448e"),
|
|
y: *hexToFieldVal("499dd7852849a38aa23ed9f306f07794063fe7904e0f347bc209fdddaf37691f"),
|
|
}
|
|
pubKey1Copy := &PublicKey{
|
|
x: *hexToFieldVal("2689c7c2dab13309fb143e0e8fe396342521887e976690b6b47f5b2a4b7d448e"),
|
|
y: *hexToFieldVal("499dd7852849a38aa23ed9f306f07794063fe7904e0f347bc209fdddaf37691f"),
|
|
}
|
|
pubKey2 := &PublicKey{
|
|
x: *hexToFieldVal("ce0b14fb842b1ba549fdd675c98075f12e9c510f8ef52bd021a9a1f4809d3b4d"),
|
|
y: *hexToFieldVal("0890ff84d7999d878a57bee170e19ef4b4803b4bdede64503a6ac352b03c8032"),
|
|
}
|
|
|
|
if !pubKey1.IsEqual(pubKey1) {
|
|
t.Fatalf(
|
|
"bad self public key equality check: (%v, %v)", pubKey1.x,
|
|
pubKey1.y,
|
|
)
|
|
}
|
|
if !pubKey1.IsEqual(pubKey1Copy) {
|
|
t.Fatalf(
|
|
"bad public key equality check: (%v, %v) == (%v, %v)",
|
|
pubKey1.x, pubKey1.y, pubKey1Copy.x, pubKey1Copy.y,
|
|
)
|
|
}
|
|
|
|
if pubKey1.IsEqual(pubKey2) {
|
|
t.Fatalf(
|
|
"bad public key equality check: (%v, %v) != (%v, %v)",
|
|
pubKey1.x, pubKey1.y, pubKey2.x, pubKey2.y,
|
|
)
|
|
}
|
|
}
|
|
|
|
// TestPublicKeyAsJacobian ensures converting a public key to a jacobian point
|
|
// with a Z coordinate of 1 works as expected.
|
|
func TestPublicKeyAsJacobian(t *testing.T) {
|
|
tests := []struct {
|
|
name string // test description
|
|
pubKey string // hex encoded serialized compressed pubkey
|
|
wantX string // hex encoded expected X coordinate
|
|
wantY string // hex encoded expected Y coordinate
|
|
}{
|
|
{
|
|
name: "public key for secret key 0x01",
|
|
pubKey: "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
|
|
wantX: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
|
|
wantY: "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
|
|
}, {
|
|
name: "public for secret key 0x03",
|
|
pubKey: "02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9",
|
|
wantX: "f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9",
|
|
wantY: "388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672",
|
|
}, {
|
|
name: "public for secret key 0x06",
|
|
pubKey: "03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556",
|
|
wantX: "fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556",
|
|
wantY: "ae12777aacfbb620f3be96017f45c560de80f0f6518fe4a03c870c36b075f297",
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
// Parse the test data.
|
|
pubKeyBytes := hexToBytes(test.pubKey)
|
|
wantX := hexToFieldVal(test.wantX)
|
|
wantY := hexToFieldVal(test.wantY)
|
|
pubKey, err := ParsePubKey(pubKeyBytes)
|
|
if err != nil {
|
|
t.Errorf("%s: failed to parse public key: %v", test.name, err)
|
|
continue
|
|
}
|
|
// Convert the public key to a jacobian point and ensure the coordinates
|
|
// match the expected values.
|
|
var point JacobianPoint
|
|
pubKey.AsJacobian(&point)
|
|
if !point.Z.IsOne() {
|
|
t.Errorf(
|
|
"%s: invalid Z coordinate -- got %v, want 1", test.name,
|
|
point.Z,
|
|
)
|
|
continue
|
|
}
|
|
if !point.X.Equals(wantX) {
|
|
t.Errorf(
|
|
"%s: invalid X coordinate - got %v, want %v", test.name,
|
|
point.X, wantX,
|
|
)
|
|
continue
|
|
}
|
|
if !point.Y.Equals(wantY) {
|
|
t.Errorf(
|
|
"%s: invalid Y coordinate - got %v, want %v", test.name,
|
|
point.Y, wantY,
|
|
)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestPublicKeyIsOnCurve ensures testing if a public key is on the curve works
|
|
// as expected.
|
|
func TestPublicKeyIsOnCurve(t *testing.T) {
|
|
tests := []struct {
|
|
name string // test description
|
|
pubX string // hex encoded x coordinate for pubkey to serialize
|
|
pubY string // hex encoded y coordinate for pubkey to serialize
|
|
want bool // expected result
|
|
}{
|
|
{
|
|
name: "valid with even y",
|
|
pubX: "11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c",
|
|
pubY: "4d1f1522047b33068bbb9b07d1e9f40564749b062b3fc0666479bc08a94be98c",
|
|
want: true,
|
|
}, {
|
|
name: "valid with odd y",
|
|
pubX: "11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c",
|
|
pubY: "b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
want: true,
|
|
}, {
|
|
name: "invalid due to x coord",
|
|
pubX: "15db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c",
|
|
pubY: "b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
|
|
want: false,
|
|
}, {
|
|
name: "invalid due to y coord",
|
|
pubX: "15db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c",
|
|
pubY: "b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a4",
|
|
want: false,
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
// Parse the test data.
|
|
x, y := hexToFieldVal(test.pubX), hexToFieldVal(test.pubY)
|
|
pubKey := NewPublicKey(x, y)
|
|
|
|
result := pubKey.IsOnCurve()
|
|
if result != test.want {
|
|
t.Errorf(
|
|
"%s: mismatched is on curve result -- got %v, want %v",
|
|
test.name, result, test.want,
|
|
)
|
|
continue
|
|
}
|
|
}
|
|
}
|