secp256k1: Add AsJacobian method to pubkey.

This add a new method to the PublicKey type named AsJacobian which
converts the public key into a Jacobian point with Z=1.  This allows the
public key to be treated a Jacobian point in the secp256k1 group in
calculations.

It also adds an associated test to ensure proper functionality.
This commit is contained in:
Dave Collins 2020-03-23 19:48:43 -05:00
parent b9695b4828
commit 990076ec2e
No known key found for this signature in database
GPG Key ID: B8904D9D9C93D1F2
2 changed files with 74 additions and 8 deletions

View File

@ -134,6 +134,16 @@ func ParsePubKey(pubKeyStr []byte) (key *PublicKey, err error) {
return &pubkey, nil
}
// paddedAppend appends the src byte slice to dst, returning the new slice.
// If the length of the source is smaller than the passed size, leading zero
// bytes are appended to the dst slice before appending src.
func paddedAppend(size uint, dst, src []byte) []byte {
for i := 0; i < int(size)-len(src); i++ {
dst = append(dst, 0)
}
return append(dst, src...)
}
// SerializeUncompressed serializes a public key in a 65-byte uncompressed
// format.
func (p PublicKey) SerializeUncompressed() []byte {
@ -161,12 +171,9 @@ func (p *PublicKey) IsEqual(otherPubKey *PublicKey) bool {
return p.x.Cmp(otherPubKey.x) == 0 && p.y.Cmp(otherPubKey.y) == 0
}
// paddedAppend appends the src byte slice to dst, returning the new slice.
// If the length of the source is smaller than the passed size, leading zero
// bytes are appended to the dst slice before appending src.
func paddedAppend(size uint, dst, src []byte) []byte {
for i := 0; i < int(size)-len(src); i++ {
dst = append(dst, 0)
}
return append(dst, src...)
// AsJacobian converts the public key into a Jacobian point with Z=1 and stores
// the result in the provided result param. This allows the public key to be
// treated a Jacobian point in the secp256k1 group in calculations.
func (p *PublicKey) AsJacobian(result *JacobianPoint) {
bigAffineToJacobian(p.x, p.y, result)
}

View File

@ -277,3 +277,62 @@ func TestPublicKeyIsEqual(t *testing.T) {
"equal to %v", pubKey1, pubKey2)
}
}
// 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 private key 0x01",
pubKey: "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
wantX: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
wantY: "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
}, {
name: "public for private key 0x03",
pubKey: "02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9",
wantX: "f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9",
wantY: "388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672",
}, {
name: "public for private 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
}
}
}