Add functions to serialize an ecdsa public key.

This commit is contained in:
Josh Rickmar 2013-09-10 23:14:30 -04:00
parent abfd6b44af
commit 961636c764
5 changed files with 85 additions and 9 deletions

11
internal_test.go Normal file
View file

@ -0,0 +1,11 @@
// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcec
const (
TstPubkeyUncompressed = pubkeyUncompressed
TstPubkeyCompressed = pubkeyCompressed
TstPubkeyHybrid = pubkeyHybrid
)

View file

@ -16,8 +16,8 @@ func isOdd(a *big.Int) bool {
const (
pubkeyCompressed byte = 0x2 // y_bit + x coord
pubkeyUncompressed = 0x4 // x coord + y coord
pubkeyHybrid = 0x6 // y_bit + x coord + y coord
pubkeyUncompressed byte = 0x4 // x coord + y coord
pubkeyHybrid byte = 0x6 // y_bit + x coord + y coord
)
// ParsePubKey parses a public key for a koblitz curve from a bytestring into a
@ -88,3 +88,42 @@ func ParsePubKey(pubKeyStr []byte, curve *KoblitzCurve) (key *ecdsa.PublicKey, e
}
return &pubkey, nil
}
// PublicKey is an ecdsa.PublicKey with additional functions to
// serialize in uncompressed, compressed, and hybrid formats.
type PublicKey ecdsa.PublicKey
// SerializeUncompressed serializes a public key in a 65-byte uncompressed
// format.
func (p *PublicKey) SerializeUncompressed() []byte {
b := make([]byte, 65)
b[0] = pubkeyUncompressed
copy(b[1:33], p.X.Bytes())
copy(b[33:], p.Y.Bytes())
return b
}
// SerializeCompressed serializes a public key in a 33-byte compressed format.
func (p *PublicKey) SerializeCompressed() []byte {
b := make([]byte, 33)
format := pubkeyCompressed
if isOdd(p.Y) {
format |= 0x1
}
b[0] = format
copy(b[1:33], p.X.Bytes())
return b
}
// SerializeHybrid serializes a public key in a 65-byte hybrid format.
func (p *PublicKey) SerializeHybrid() []byte {
b := make([]byte, 65)
format := pubkeyHybrid
if isOdd(p.Y) {
format |= 0x1
}
b[0] = format
copy(b[1:33], p.X.Bytes())
copy(b[33:], p.Y.Bytes())
return b
}

View file

@ -5,13 +5,16 @@
package btcec_test
import (
"bytes"
"github.com/conformal/btcec"
"github.com/davecgh/go-spew/spew"
"testing"
)
type pubKeyTest struct {
name string
key []byte
format byte
isValid bool
}
@ -30,6 +33,7 @@ var pubKeyTests = []pubKeyTest{
0xb4, 0x12, 0xa3,
},
isValid: true,
format: btcec.TstPubkeyUncompressed,
},
pubKeyTest{
name: "uncompressed x changed",
@ -82,6 +86,7 @@ var pubKeyTests = []pubKeyTest{
0xb4, 0x12, 0xa3,
},
isValid: true,
format: btcec.TstPubkeyHybrid,
},
pubKeyTest{
name: "uncompressed as hybrid wrong",
@ -105,6 +110,7 @@ var pubKeyTests = []pubKeyTest{
0xa9, 0xa1, 0xf4, 0x80, 0x9d, 0x3b, 0x4d,
},
isValid: true,
format: btcec.TstPubkeyCompressed,
},
// from tx fdeb8e72524e8dab0da507ddbaf5f88fe4a933eb10a66bc4745bb0aa11ea393c
pubKeyTest{
@ -115,6 +121,7 @@ var pubKeyTests = []pubKeyTest{
0x7f, 0x5b, 0x2a, 0x4b, 0x7d, 0x44, 0x8e,
},
isValid: true,
format: btcec.TstPubkeyCompressed,
},
pubKeyTest{
name: "compressed claims uncompressed (ybit = 0)",
@ -195,7 +202,7 @@ var pubKeyTests = []pubKeyTest{
func TestPubKeys(t *testing.T) {
for _, test := range pubKeyTests {
_, err := btcec.ParsePubKey(test.key, btcec.S256())
pk, err := btcec.ParsePubKey(test.key, btcec.S256())
if err != nil {
if test.isValid {
t.Errorf("%s pubkey failed when shouldn't %v",
@ -206,6 +213,22 @@ func TestPubKeys(t *testing.T) {
if !test.isValid {
t.Errorf("%s counted as valid when it should fail",
test.name)
continue
}
var pkStr []byte
switch test.format {
case btcec.TstPubkeyUncompressed:
pkStr = (*btcec.PublicKey)(pk).SerializeUncompressed()
case btcec.TstPubkeyCompressed:
pkStr = (*btcec.PublicKey)(pk).SerializeCompressed()
case btcec.TstPubkeyHybrid:
pkStr = (*btcec.PublicKey)(pk).SerializeHybrid()
}
if !bytes.Equal(test.key, pkStr) {
t.Errorf("%s pubkey: serialized keys do not match.",
test.name)
spew.Dump(test.key)
spew.Dump(pkStr)
}
}
}

View file

@ -154,7 +154,7 @@ var signatureTests = []signatureTest{
// This test is now passing (used to be failing) because there
// are signatures in the blockchain that have trailing zero
// bytes before the hashtype. So ParseSignature was fixed to
// bytes before the hashtype. So ParseSignature was fixed to
// permit buffers with trailing nonsense after the actual
// signature.
isValid: true,

View file

@ -2,19 +2,22 @@
github.com/conformal/btcec/signature.go ParseSignature 100.00% (41/41)
github.com/conformal/btcec/btcec.go KoblitzCurve.doubleJacobian 100.00% (21/21)
github.com/conformal/btcec/btcec.go KoblitzCurve.ScalarMult 100.00% (9/9)
github.com/conformal/btcec/btcec.go initS256 100.00% (7/7)
github.com/conformal/btcec/pubkey.go PublicKey.SerializeHybrid 100.00% (8/8)
github.com/conformal/btcec/btcec.go KoblitzCurve.IsOnCurve 100.00% (7/7)
github.com/conformal/btcec/pubkey.go PublicKey.SerializeCompressed 100.00% (7/7)
github.com/conformal/btcec/btcec.go initS256 100.00% (7/7)
github.com/conformal/btcec/pubkey.go PublicKey.SerializeUncompressed 100.00% (5/5)
github.com/conformal/btcec/btcec.go zForAffine 100.00% (4/4)
github.com/conformal/btcec/btcec.go KoblitzCurve.Add 100.00% (3/3)
github.com/conformal/btcec/btcec.go KoblitzCurve.QPlus1Div4 100.00% (3/3)
github.com/conformal/btcec/btcec.go KoblitzCurve.Add 100.00% (3/3)
github.com/conformal/btcec/btcec.go S256 100.00% (2/2)
github.com/conformal/btcec/btcec.go KoblitzCurve.Params 100.00% (1/1)
github.com/conformal/btcec/btcec.go KoblitzCurve.ScalarBaseMult 100.00% (1/1)
github.com/conformal/btcec/btcec.go initAll 100.00% (1/1)
github.com/conformal/btcec/pubkey.go isOdd 100.00% (1/1)
github.com/conformal/btcec/btcec.go initAll 100.00% (1/1)
github.com/conformal/btcec/btcec.go KoblitzCurve.Params 100.00% (1/1)
github.com/conformal/btcec/pubkey.go ParsePubKey 96.88% (31/32)
github.com/conformal/btcec/btcec.go KoblitzCurve.addJacobian 91.67% (55/60)
github.com/conformal/btcec/btcec.go KoblitzCurve.affineFromJacobian 90.00% (9/10)
github.com/conformal/btcec/btcec.go KoblitzCurve.Double 0.00% (0/2)
github.com/conformal/btcec ------------------------------- 95.61% (196/205)
github.com/conformal/btcec ------------------------------- 96.00% (216/225)