This change removes the internal pad function in favor a more opimized paddedAppend function. Unlike pad, which would always alloate a new slice of the desired size and copy the bytes into it, paddedAppend only appends the leading padding when necesary, and uses the builtin append to copy the remaining source bytes. pad was also used in combination with another call to the builtin copy func to copy into a zeroed byte slice. As the slice is now created using make with an initial length of zero, this copy can also be removed. As confirmed by poking the bytes with the unsafe package, gc does not zero array elements between the len and cap when allocating slices with make(). In combination with the paddedAppend func, this results in only a single copy of each byte, with no unnecssary zeroing, when creating the serialized pubkeys. This has not been tested with other Go compilers (namely, gccgo and llgo), but the new behavior is still functionally correct regardless of compiler optimizations. The TestPad function has been removed as the pad func it tested has likewise been removed. ok @davecgh
264 lines
8.1 KiB
Go
264 lines
8.1 KiB
Go
// Copyright (c) 2013-2014 Conformal Systems LLC.
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package btcec_test
|
|
|
|
import (
|
|
"bytes"
|
|
"github.com/conformal/btcec"
|
|
"github.com/davecgh/go-spew/spew"
|
|
"testing"
|
|
)
|
|
|
|
type privKeyTest struct {
|
|
name string
|
|
key []byte
|
|
}
|
|
|
|
type pubKeyTest struct {
|
|
name string
|
|
key []byte
|
|
format byte
|
|
isValid bool
|
|
}
|
|
|
|
var privKeyTests = []privKeyTest{
|
|
{
|
|
name: "check curve",
|
|
key: []byte{
|
|
0xea, 0xf0, 0x2c, 0xa3, 0x48, 0xc5, 0x24, 0xe6,
|
|
0x39, 0x26, 0x55, 0xba, 0x4d, 0x29, 0x60, 0x3c,
|
|
0xd1, 0xa7, 0x34, 0x7d, 0x9d, 0x65, 0xcf, 0xe9,
|
|
0x3c, 0xe1, 0xeb, 0xff, 0xdc, 0xa2, 0x26, 0x94,
|
|
},
|
|
},
|
|
}
|
|
|
|
var pubKeyTests = []pubKeyTest{
|
|
// pubkey from bitcoin blockchain tx
|
|
// 0437cd7f8525ceed2324359c2d0ba26006d92d85
|
|
{
|
|
name: "uncompressed ok",
|
|
key: []byte{0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
|
|
0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
|
|
0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
|
|
0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
|
|
0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
|
|
0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
|
|
0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
|
|
0xb4, 0x12, 0xa3,
|
|
},
|
|
isValid: true,
|
|
format: btcec.TstPubkeyUncompressed,
|
|
},
|
|
{
|
|
name: "uncompressed x changed",
|
|
key: []byte{0x04, 0x15, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
|
|
0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
|
|
0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
|
|
0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
|
|
0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
|
|
0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
|
|
0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
|
|
0xb4, 0x12, 0xa3,
|
|
},
|
|
isValid: false,
|
|
},
|
|
{
|
|
name: "uncompressed y changed",
|
|
key: []byte{0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
|
|
0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
|
|
0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
|
|
0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
|
|
0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
|
|
0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
|
|
0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
|
|
0xb4, 0x12, 0xa4,
|
|
},
|
|
isValid: false,
|
|
},
|
|
{
|
|
name: "uncompressed claims compressed",
|
|
key: []byte{0x03, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
|
|
0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
|
|
0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
|
|
0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
|
|
0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
|
|
0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
|
|
0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
|
|
0xb4, 0x12, 0xa3,
|
|
},
|
|
isValid: false,
|
|
},
|
|
{
|
|
name: "uncompressed as hybrid ok",
|
|
key: []byte{0x07, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
|
|
0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
|
|
0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
|
|
0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
|
|
0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
|
|
0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
|
|
0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
|
|
0xb4, 0x12, 0xa3,
|
|
},
|
|
isValid: true,
|
|
format: btcec.TstPubkeyHybrid,
|
|
},
|
|
{
|
|
name: "uncompressed as hybrid wrong",
|
|
key: []byte{0x06, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
|
|
0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
|
|
0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
|
|
0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
|
|
0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
|
|
0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
|
|
0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
|
|
0xb4, 0x12, 0xa3,
|
|
},
|
|
isValid: false,
|
|
},
|
|
// from tx 0b09c51c51ff762f00fb26217269d2a18e77a4fa87d69b3c363ab4df16543f20
|
|
{
|
|
name: "compressed ok (ybit = 0)",
|
|
key: []byte{0x02, 0xce, 0x0b, 0x14, 0xfb, 0x84, 0x2b, 0x1b,
|
|
0xa5, 0x49, 0xfd, 0xd6, 0x75, 0xc9, 0x80, 0x75, 0xf1,
|
|
0x2e, 0x9c, 0x51, 0x0f, 0x8e, 0xf5, 0x2b, 0xd0, 0x21,
|
|
0xa9, 0xa1, 0xf4, 0x80, 0x9d, 0x3b, 0x4d,
|
|
},
|
|
isValid: true,
|
|
format: btcec.TstPubkeyCompressed,
|
|
},
|
|
// from tx fdeb8e72524e8dab0da507ddbaf5f88fe4a933eb10a66bc4745bb0aa11ea393c
|
|
{
|
|
name: "compressed ok (ybit = 1)",
|
|
key: []byte{0x03, 0x26, 0x89, 0xc7, 0xc2, 0xda, 0xb1, 0x33,
|
|
0x09, 0xfb, 0x14, 0x3e, 0x0e, 0x8f, 0xe3, 0x96, 0x34,
|
|
0x25, 0x21, 0x88, 0x7e, 0x97, 0x66, 0x90, 0xb6, 0xb4,
|
|
0x7f, 0x5b, 0x2a, 0x4b, 0x7d, 0x44, 0x8e,
|
|
},
|
|
isValid: true,
|
|
format: btcec.TstPubkeyCompressed,
|
|
},
|
|
{
|
|
name: "compressed claims uncompressed (ybit = 0)",
|
|
key: []byte{0x04, 0xce, 0x0b, 0x14, 0xfb, 0x84, 0x2b, 0x1b,
|
|
0xa5, 0x49, 0xfd, 0xd6, 0x75, 0xc9, 0x80, 0x75, 0xf1,
|
|
0x2e, 0x9c, 0x51, 0x0f, 0x8e, 0xf5, 0x2b, 0xd0, 0x21,
|
|
0xa9, 0xa1, 0xf4, 0x80, 0x9d, 0x3b, 0x4d,
|
|
},
|
|
isValid: false,
|
|
},
|
|
{
|
|
name: "compressed claims uncompressed (ybit = 1)",
|
|
key: []byte{0x05, 0x26, 0x89, 0xc7, 0xc2, 0xda, 0xb1, 0x33,
|
|
0x09, 0xfb, 0x14, 0x3e, 0x0e, 0x8f, 0xe3, 0x96, 0x34,
|
|
0x25, 0x21, 0x88, 0x7e, 0x97, 0x66, 0x90, 0xb6, 0xb4,
|
|
0x7f, 0x5b, 0x2a, 0x4b, 0x7d, 0x44, 0x8e,
|
|
},
|
|
isValid: false,
|
|
},
|
|
{
|
|
name: "wrong length)",
|
|
key: []byte{0x05},
|
|
isValid: false,
|
|
},
|
|
{
|
|
name: "X == P",
|
|
key: []byte{0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, 0xb2, 0xe0,
|
|
0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
|
|
0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
|
|
0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
|
|
0xb4, 0x12, 0xa3,
|
|
},
|
|
isValid: false,
|
|
},
|
|
{
|
|
name: "X > P",
|
|
key: []byte{0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFD, 0x2F, 0xb2, 0xe0,
|
|
0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
|
|
0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
|
|
0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
|
|
0xb4, 0x12, 0xa3,
|
|
},
|
|
isValid: false,
|
|
},
|
|
{
|
|
name: "Y == P",
|
|
key: []byte{0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
|
|
0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
|
|
0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
|
|
0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF,
|
|
0xFF, 0xFC, 0x2F,
|
|
},
|
|
isValid: false,
|
|
},
|
|
{
|
|
name: "Y > P",
|
|
key: []byte{0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
|
|
0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
|
|
0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
|
|
0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF,
|
|
0xFF, 0xFD, 0x2F,
|
|
},
|
|
isValid: false,
|
|
},
|
|
}
|
|
|
|
func TestPrivKeys(t *testing.T) {
|
|
for _, test := range privKeyTests {
|
|
_, pub := btcec.PrivKeyFromBytes(btcec.S256(), test.key)
|
|
|
|
_, err := btcec.ParsePubKey(
|
|
pub.SerializeUncompressed(), btcec.S256())
|
|
if err != nil {
|
|
t.Errorf("%s privkey: %v", test.name, err)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPubKeys(t *testing.T) {
|
|
for _, test := range pubKeyTests {
|
|
pk, err := btcec.ParsePubKey(test.key, btcec.S256())
|
|
if err != nil {
|
|
if test.isValid {
|
|
t.Errorf("%s pubkey failed when shouldn't %v",
|
|
test.name, err)
|
|
}
|
|
continue
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
}
|