update EncodePrivateKey and DecodePrivateKey to take a btcnet parameter

This commit is contained in:
David Hill 2013-11-01 00:45:38 -04:00
parent 7e3c9c1aed
commit cefb048288
2 changed files with 49 additions and 14 deletions

View file

@ -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
} }

View file

@ -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