keys: add support for uncompressed serialization in PublicKey

This commit is contained in:
Roman Khimov 2020-06-10 19:14:13 +03:00
parent 6031c8a087
commit 7e2e5e1879
2 changed files with 48 additions and 16 deletions

View file

@ -1,7 +1,6 @@
package keys package keys
import ( import (
"bytes"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
"crypto/x509" "crypto/x509"
@ -19,6 +18,9 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// coordLen is the number of bytes in serialized X or Y coordinate.
const coordLen = 32
// PublicKeys is a list of public keys. // PublicKeys is a list of public keys.
type PublicKeys []*PublicKey type PublicKeys []*PublicKey
@ -106,23 +108,49 @@ func NewPublicKeyFromBytes(b []byte) (*PublicKey, error) {
return pubKey, nil return pubKey, nil
} }
// Bytes returns the byte array representation of the public key. // getBytes serializes X and Y using compressed or uncompressed format.
func (p *PublicKey) Bytes() []byte { func (p *PublicKey) getBytes(compressed bool) []byte {
if p.IsInfinity() { if p.IsInfinity() {
return []byte{0x00} return []byte{0x00}
} }
var ( var resLen = 1 + coordLen
x = p.X.Bytes() if !compressed {
paddedX = append(bytes.Repeat([]byte{0x00}, 32-len(x)), x...) resLen += coordLen
prefix = byte(0x03)
)
if p.Y.Bit(0) == 0 {
prefix = byte(0x02)
} }
var res = make([]byte, resLen)
var prefix byte
return append([]byte{prefix}, paddedX...) xBytes := p.X.Bytes()
copy(res[1+coordLen-len(xBytes):], xBytes)
if compressed {
if p.Y.Bit(0) == 0 {
prefix = 0x02
} else {
prefix = 0x03
}
} else {
prefix = 0x04
yBytes := p.Y.Bytes()
copy(res[1+coordLen+coordLen-len(yBytes):], yBytes)
}
res[0] = prefix
return res
}
// Bytes returns byte array representation of the public key in compressed
// form (33 bytes with 0x02 or 0x03 prefix, except infinity which is always 0).
func (p *PublicKey) Bytes() []byte {
return p.getBytes(true)
}
// UncompressedBytes returns byte array representation of the public key in
// uncompressed form (65 bytes with 0x04 prefix, except infinity which is
// always 0).
func (p *PublicKey) UncompressedBytes() []byte {
return p.getBytes(false)
} }
// NewPublicKeyFromASN1 returns a NEO PublicKey from the ASN.1 serialized key. // NewPublicKeyFromASN1 returns a NEO PublicKey from the ASN.1 serialized key.

View file

@ -95,10 +95,14 @@ func TestPubkeyToAddress(t *testing.T) {
func TestDecodeBytes(t *testing.T) { func TestDecodeBytes(t *testing.T) {
pubKey := getPubKey(t) pubKey := getPubKey(t)
decodedPubKey := &PublicKey{} var testBytesFunction = func(t *testing.T, bytesFunction func() []byte) {
err := decodedPubKey.DecodeBytes(pubKey.Bytes()) decodedPubKey := &PublicKey{}
require.NoError(t, err) err := decodedPubKey.DecodeBytes(bytesFunction())
require.Equal(t, pubKey, decodedPubKey) require.NoError(t, err)
require.Equal(t, pubKey, decodedPubKey)
}
t.Run("compressed", func(t *testing.T) { testBytesFunction(t, pubKey.Bytes) })
t.Run("uncompressed", func(t *testing.T) { testBytesFunction(t, pubKey.UncompressedBytes) })
} }
func TestSort(t *testing.T) { func TestSort(t *testing.T) {