update EncodePrivateKey and DecodePrivateKey to take a btcnet parameter
This commit is contained in:
parent
7e3c9c1aed
commit
cefb048288
2 changed files with 49 additions and 14 deletions
56
addrconvs.go
56
addrconvs.go
|
@ -20,6 +20,11 @@ var ErrUnknownNet = errors.New("unrecognized bitcoin network")
|
||||||
// a non-matching checksum.
|
// a non-matching checksum.
|
||||||
var ErrMalformedAddress = errors.New("malformed address")
|
var ErrMalformedAddress = errors.New("malformed address")
|
||||||
|
|
||||||
|
// ErrMalformedPrivateKey describes an error where an address is improperly
|
||||||
|
// formatted, either due to an incorrect length of the private key or
|
||||||
|
// a non-matching checksum.
|
||||||
|
var ErrMalformedPrivateKey = errors.New("malformed private key")
|
||||||
|
|
||||||
// Constants used to specify which network a payment address belongs
|
// Constants used to specify which network a payment address belongs
|
||||||
// to. Mainnet address cannot be used on the Testnet, and vice versa.
|
// to. Mainnet address cannot be used on the Testnet, and vice versa.
|
||||||
const (
|
const (
|
||||||
|
@ -28,6 +33,12 @@ const (
|
||||||
|
|
||||||
// TestNetAddr is the address identifier for TestNet
|
// TestNetAddr is the address identifier for TestNet
|
||||||
TestNetAddr = 0x6f
|
TestNetAddr = 0x6f
|
||||||
|
|
||||||
|
// MainNetKey is the key identifier for MainNet
|
||||||
|
MainNetKey = 0x80
|
||||||
|
|
||||||
|
// TestNetKey is the key identifier for TestNet
|
||||||
|
TestNetKey = 0xef
|
||||||
)
|
)
|
||||||
|
|
||||||
// EncodeAddress takes a 20-byte raw payment address (hash160 of a pubkey)
|
// EncodeAddress takes a 20-byte raw payment address (hash160 of a pubkey)
|
||||||
|
@ -96,20 +107,30 @@ func DecodeAddress(addr string) (addrHash []byte, net btcwire.BitcoinNet, err er
|
||||||
return addrHash, net, nil
|
return addrHash, net, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodePrivateKey takes a 32-byte raw private key address and encodes
|
// EncodePrivateKey takes a 32-byte private key and encodes it into the
|
||||||
// it into the Wallet Import Format (WIF)
|
// Wallet Import Format (WIF).
|
||||||
func EncodePrivateKey(privKey []byte) (string, error) {
|
func EncodePrivateKey(privKey []byte, net btcwire.BitcoinNet) (string, error) {
|
||||||
if len(privKey) != 32 {
|
if len(privKey) != 32 {
|
||||||
return "", ErrMalformedAddress
|
return "", ErrMalformedPrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
tosum := append([]byte{0x80}, privKey...)
|
var netID byte
|
||||||
|
switch net {
|
||||||
|
case btcwire.MainNet:
|
||||||
|
netID = MainNetKey
|
||||||
|
case btcwire.TestNet3:
|
||||||
|
netID = TestNetKey
|
||||||
|
default:
|
||||||
|
return "", ErrUnknownNet
|
||||||
|
}
|
||||||
|
|
||||||
|
tosum := append([]byte{netID}, privKey...)
|
||||||
cksum := btcwire.DoubleSha256(tosum)
|
cksum := btcwire.DoubleSha256(tosum)
|
||||||
|
|
||||||
// Address before base58 encoding is 1 byte for 0x80 (5), 32 bytes for
|
// Private key before base58 encoding is 1 byte for netID, 32 bytes for
|
||||||
// privKey, plus 4 bytes of checksum.
|
// privKey, plus 4 bytes of checksum.
|
||||||
a := make([]byte, 37, 37)
|
a := make([]byte, 37, 37)
|
||||||
a[0] = 0x80
|
a[0] = netID
|
||||||
copy(a[1:], privKey)
|
copy(a[1:], privKey)
|
||||||
copy(a[32+1:], cksum[:4])
|
copy(a[32+1:], cksum[:4])
|
||||||
|
|
||||||
|
@ -118,23 +139,36 @@ func EncodePrivateKey(privKey []byte) (string, error) {
|
||||||
|
|
||||||
// DecodePrivateKey takes a Wallet Import Format (WIF) string and
|
// DecodePrivateKey takes a Wallet Import Format (WIF) string and
|
||||||
// decodes into a 32-byte private key.
|
// decodes into a 32-byte private key.
|
||||||
func DecodePrivateKey(wif string) ([]byte, error) {
|
func DecodePrivateKey(wif string) ([]byte, btcwire.BitcoinNet, error) {
|
||||||
decoded := Base58Decode(wif)
|
decoded := Base58Decode(wif)
|
||||||
|
|
||||||
// Length of decoded privkey must be 32 bytes + 1 byte for 0x80
|
// Length of decoded privkey must be 32 bytes + 1 byte for 0x80
|
||||||
// + 4 bytes of checksum
|
// + 4 bytes of checksum
|
||||||
if len(decoded) != 32+5 {
|
if len(decoded) != 32+5 {
|
||||||
return nil, ErrMalformedAddress
|
return nil, 0, ErrMalformedPrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var net btcwire.BitcoinNet
|
||||||
|
switch decoded[0] {
|
||||||
|
case MainNetKey:
|
||||||
|
net = btcwire.MainNet
|
||||||
|
case TestNetKey:
|
||||||
|
net = btcwire.TestNet3
|
||||||
|
default:
|
||||||
|
return nil, 0, ErrUnknownNet
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checksum is first four bytes of double SHA256 of the identifier byte
|
||||||
|
// and privKey. Verify this matches the final 4 bytes of the decoded
|
||||||
|
// private key.
|
||||||
tosum := decoded[:32+1]
|
tosum := decoded[:32+1]
|
||||||
cksum := btcwire.DoubleSha256(tosum)[:4]
|
cksum := btcwire.DoubleSha256(tosum)[:4]
|
||||||
if !bytes.Equal(cksum, decoded[len(decoded)-4:]) {
|
if !bytes.Equal(cksum, decoded[len(decoded)-4:]) {
|
||||||
return nil, ErrMalformedAddress
|
return nil, 0, ErrMalformedPrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
privKey := make([]byte, 32, 32)
|
privKey := make([]byte, 32, 32)
|
||||||
copy(privKey[:], decoded[1:32+1])
|
copy(privKey[:], decoded[1:32+1])
|
||||||
|
|
||||||
return privKey, nil
|
return privKey, net, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
var encodePrivateKeyTests = []struct {
|
var encodePrivateKeyTests = []struct {
|
||||||
in []byte
|
in []byte
|
||||||
|
net btcwire.BitcoinNet
|
||||||
out string
|
out string
|
||||||
}{
|
}{
|
||||||
{[]byte{
|
{[]byte{
|
||||||
|
@ -20,7 +21,7 @@ var encodePrivateKeyTests = []struct {
|
||||||
0x60, 0x0b, 0x2f, 0xe5, 0x0b, 0x7c, 0xae, 0x11,
|
0x60, 0x0b, 0x2f, 0xe5, 0x0b, 0x7c, 0xae, 0x11,
|
||||||
0xec, 0x86, 0xd3, 0xbf, 0x1f, 0xbe, 0x47, 0x1b,
|
0xec, 0x86, 0xd3, 0xbf, 0x1f, 0xbe, 0x47, 0x1b,
|
||||||
0xe8, 0x98, 0x27, 0xe1, 0x9d, 0x72, 0xaa, 0x1d,
|
0xe8, 0x98, 0x27, 0xe1, 0x9d, 0x72, 0xaa, 0x1d,
|
||||||
}, "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ"},
|
}, btcwire.MainNet, "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ"},
|
||||||
}
|
}
|
||||||
|
|
||||||
var encodeTests = []struct {
|
var encodeTests = []struct {
|
||||||
|
@ -106,7 +107,7 @@ func TestDecodeAddresses(t *testing.T) {
|
||||||
|
|
||||||
func TestEncodeDecodePrivateKey(t *testing.T) {
|
func TestEncodeDecodePrivateKey(t *testing.T) {
|
||||||
for _, test := range encodePrivateKeyTests {
|
for _, test := range encodePrivateKeyTests {
|
||||||
wif, err := btcutil.EncodePrivateKey(test.in)
|
wif, err := btcutil.EncodePrivateKey(test.in, test.net)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
continue
|
continue
|
||||||
|
@ -117,7 +118,7 @@ func TestEncodeDecodePrivateKey(t *testing.T) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := btcutil.DecodePrivateKey(test.out)
|
key, _, err := btcutil.DecodePrivateKey(test.out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
continue
|
continue
|
||||||
|
|
Loading…
Reference in a new issue