mirror of
https://github.com/LBRYFoundation/lbcutil.git
synced 2025-08-23 17:47:30 +00:00
Consolidate remaining addrconvs.go to address.go.
Since all of the deprecated address conversion functions have been removed, consolidate the remaining private key funcs and tests into address.go and address_test.go, repectively.
This commit is contained in:
parent
d7ea478de2
commit
1c82527b3d
4 changed files with 171 additions and 194 deletions
136
addrconvs.go
136
addrconvs.go
|
@ -1,136 +0,0 @@
|
||||||
// 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 btcutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"github.com/conformal/btcwire"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrUnknownNet describes an error where the Bitcoin network is
|
|
||||||
// not recognized.
|
|
||||||
var ErrUnknownNet = errors.New("unrecognized bitcoin network")
|
|
||||||
|
|
||||||
// ErrMalformedAddress describes an error where an address is improperly
|
|
||||||
// formatted, either due to an incorrect length of the hashed pubkey or
|
|
||||||
// a non-matching checksum.
|
|
||||||
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
|
|
||||||
// to. Mainnet address cannot be used on the Testnet, and vice versa.
|
|
||||||
const (
|
|
||||||
// MainNetAddr is the address identifier for MainNet
|
|
||||||
MainNetAddr = 0x00
|
|
||||||
|
|
||||||
// TestNetAddr is the address identifier for TestNet
|
|
||||||
TestNetAddr = 0x6f
|
|
||||||
|
|
||||||
// MainNetKey is the key identifier for MainNet
|
|
||||||
MainNetKey = 0x80
|
|
||||||
|
|
||||||
// TestNetKey is the key identifier for TestNet
|
|
||||||
TestNetKey = 0xef
|
|
||||||
|
|
||||||
// MainNetScriptHash is the script hash identifier for MainNet
|
|
||||||
MainNetScriptHash = 0x05
|
|
||||||
|
|
||||||
// TestNetScriptHash is the script hash identifier for TestNet
|
|
||||||
TestNetScriptHash = 0xc4
|
|
||||||
)
|
|
||||||
|
|
||||||
// EncodePrivateKey takes a 32-byte private key and encodes it into the
|
|
||||||
// Wallet Import Format (WIF).
|
|
||||||
func EncodePrivateKey(privKey []byte, net btcwire.BitcoinNet, compressed bool) (string, error) {
|
|
||||||
if len(privKey) != 32 {
|
|
||||||
return "", ErrMalformedPrivateKey
|
|
||||||
}
|
|
||||||
|
|
||||||
var netID byte
|
|
||||||
switch net {
|
|
||||||
case btcwire.MainNet:
|
|
||||||
netID = MainNetKey
|
|
||||||
case btcwire.TestNet3:
|
|
||||||
netID = TestNetKey
|
|
||||||
default:
|
|
||||||
return "", ErrUnknownNet
|
|
||||||
}
|
|
||||||
|
|
||||||
tosum := append([]byte{netID}, privKey...)
|
|
||||||
if compressed {
|
|
||||||
tosum = append(tosum, 0x01)
|
|
||||||
}
|
|
||||||
cksum := btcwire.DoubleSha256(tosum)
|
|
||||||
|
|
||||||
// Private key before base58 encoding is 1 byte for netID, 32 bytes for
|
|
||||||
// privKey, plus an optional byte (0x01) if copressed, plus 4 bytes of checksum.
|
|
||||||
encodeLen := 37
|
|
||||||
if compressed {
|
|
||||||
encodeLen += 1
|
|
||||||
}
|
|
||||||
a := make([]byte, encodeLen, encodeLen)
|
|
||||||
a[0] = netID
|
|
||||||
copy(a[1:], privKey)
|
|
||||||
if compressed {
|
|
||||||
copy(a[32+1:], []byte{0x01})
|
|
||||||
copy(a[32+1+1:], cksum[:4])
|
|
||||||
} else {
|
|
||||||
copy(a[32+1:], cksum[:4])
|
|
||||||
}
|
|
||||||
return Base58Encode(a), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodePrivateKey takes a Wallet Import Format (WIF) string and
|
|
||||||
// decodes into a 32-byte private key.
|
|
||||||
func DecodePrivateKey(wif string) ([]byte, btcwire.BitcoinNet, bool, error) {
|
|
||||||
decoded := Base58Decode(wif)
|
|
||||||
decodedLen := len(decoded)
|
|
||||||
compressed := false
|
|
||||||
|
|
||||||
// Length of decoded privkey must be 32 bytes + an optional 1 byte (0x01)
|
|
||||||
// if compressed, plus 1 byte for netID + 4 bytes of checksum
|
|
||||||
if decodedLen == 32+6 {
|
|
||||||
compressed = true
|
|
||||||
if decoded[33] != 0x01 {
|
|
||||||
return nil, 0, compressed, ErrMalformedPrivateKey
|
|
||||||
}
|
|
||||||
} else if decodedLen != 32+5 {
|
|
||||||
return nil, 0, compressed, ErrMalformedPrivateKey
|
|
||||||
}
|
|
||||||
|
|
||||||
var net btcwire.BitcoinNet
|
|
||||||
switch decoded[0] {
|
|
||||||
case MainNetKey:
|
|
||||||
net = btcwire.MainNet
|
|
||||||
case TestNetKey:
|
|
||||||
net = btcwire.TestNet3
|
|
||||||
default:
|
|
||||||
return nil, 0, compressed, 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.
|
|
||||||
var tosum []byte
|
|
||||||
if compressed {
|
|
||||||
tosum = decoded[:32+1+1]
|
|
||||||
} else {
|
|
||||||
tosum = decoded[:32+1]
|
|
||||||
}
|
|
||||||
cksum := btcwire.DoubleSha256(tosum)[:4]
|
|
||||||
if !bytes.Equal(cksum, decoded[decodedLen-4:]) {
|
|
||||||
return nil, 0, compressed, ErrMalformedPrivateKey
|
|
||||||
}
|
|
||||||
|
|
||||||
privKey := make([]byte, 32, 32)
|
|
||||||
copy(privKey[:], decoded[1:32+1])
|
|
||||||
|
|
||||||
return privKey, net, compressed, nil
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
// 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 btcutil_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"github.com/conformal/btcutil"
|
|
||||||
"github.com/conformal/btcwire"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var encodePrivateKeyTests = []struct {
|
|
||||||
in []byte
|
|
||||||
net btcwire.BitcoinNet
|
|
||||||
compressed bool
|
|
||||||
out string
|
|
||||||
}{
|
|
||||||
{[]byte{
|
|
||||||
0x0c, 0x28, 0xfc, 0xa3, 0x86, 0xc7, 0xa2, 0x27,
|
|
||||||
0x60, 0x0b, 0x2f, 0xe5, 0x0b, 0x7c, 0xae, 0x11,
|
|
||||||
0xec, 0x86, 0xd3, 0xbf, 0x1f, 0xbe, 0x47, 0x1b,
|
|
||||||
0xe8, 0x98, 0x27, 0xe1, 0x9d, 0x72, 0xaa, 0x1d,
|
|
||||||
}, btcwire.MainNet, false, "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ"},
|
|
||||||
{[]byte{
|
|
||||||
0xdd, 0xa3, 0x5a, 0x14, 0x88, 0xfb, 0x97, 0xb6,
|
|
||||||
0xeb, 0x3f, 0xe6, 0xe9, 0xef, 0x2a, 0x25, 0x81,
|
|
||||||
0x4e, 0x39, 0x6f, 0xb5, 0xdc, 0x29, 0x5f, 0xe9,
|
|
||||||
0x94, 0xb9, 0x67, 0x89, 0xb2, 0x1a, 0x03, 0x98,
|
|
||||||
}, btcwire.TestNet3, true, "cV1Y7ARUr9Yx7BR55nTdnR7ZXNJphZtCCMBTEZBJe1hXt2kB684q"},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncodeDecodePrivateKey(t *testing.T) {
|
|
||||||
for x, test := range encodePrivateKeyTests {
|
|
||||||
wif, err := btcutil.EncodePrivateKey(test.in, test.net, test.compressed)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%x: %v", x, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if wif != test.out {
|
|
||||||
t.Errorf("TestEncodeDecodePrivateKey failed: want '%s', got '%s'",
|
|
||||||
test.out, wif)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
key, _, compressed, err := btcutil.DecodePrivateKey(test.out)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !bytes.Equal(key, test.in) || compressed != test.compressed {
|
|
||||||
t.Errorf("TestEncodeDecodePrivateKey failed: want '%x', got '%x'",
|
|
||||||
test.out, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
125
address.go
125
address.go
|
@ -14,6 +14,20 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// ErrUnknownNet describes an error where the Bitcoin network is
|
||||||
|
// not recognized.
|
||||||
|
ErrUnknownNet = errors.New("unrecognized bitcoin network")
|
||||||
|
|
||||||
|
// ErrMalformedAddress describes an error where an address is improperly
|
||||||
|
// formatted, either due to an incorrect length of the hashed pubkey or
|
||||||
|
// a non-matching checksum.
|
||||||
|
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.
|
||||||
|
ErrMalformedPrivateKey = errors.New("malformed private key")
|
||||||
|
|
||||||
// ErrChecksumMismatch describes an error where decoding failed due
|
// ErrChecksumMismatch describes an error where decoding failed due
|
||||||
// to a bad checksum.
|
// to a bad checksum.
|
||||||
ErrChecksumMismatch = errors.New("checksum mismatch")
|
ErrChecksumMismatch = errors.New("checksum mismatch")
|
||||||
|
@ -23,6 +37,28 @@ var (
|
||||||
ErrUnknownIdentifier = errors.New("unknown identifier byte")
|
ErrUnknownIdentifier = errors.New("unknown identifier byte")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Constants used to specify which network a payment address belongs
|
||||||
|
// to. Mainnet address cannot be used on the Testnet, and vice versa.
|
||||||
|
const (
|
||||||
|
// MainNetAddr is the address identifier for MainNet
|
||||||
|
MainNetAddr = 0x00
|
||||||
|
|
||||||
|
// TestNetAddr is the address identifier for TestNet
|
||||||
|
TestNetAddr = 0x6f
|
||||||
|
|
||||||
|
// MainNetKey is the key identifier for MainNet
|
||||||
|
MainNetKey = 0x80
|
||||||
|
|
||||||
|
// TestNetKey is the key identifier for TestNet
|
||||||
|
TestNetKey = 0xef
|
||||||
|
|
||||||
|
// MainNetScriptHash is the script hash identifier for MainNet
|
||||||
|
MainNetScriptHash = 0x05
|
||||||
|
|
||||||
|
// TestNetScriptHash is the script hash identifier for TestNet
|
||||||
|
TestNetScriptHash = 0xc4
|
||||||
|
)
|
||||||
|
|
||||||
// checkBitcoinNet returns an error if the bitcoin network is not supported.
|
// checkBitcoinNet returns an error if the bitcoin network is not supported.
|
||||||
func checkBitcoinNet(net btcwire.BitcoinNet) error {
|
func checkBitcoinNet(net btcwire.BitcoinNet) error {
|
||||||
// Check for a valid bitcoin network.
|
// Check for a valid bitcoin network.
|
||||||
|
@ -452,3 +488,92 @@ func (a *AddressPubKey) AddressPubKeyHash() *AddressPubKeyHash {
|
||||||
return addr
|
return addr
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncodePrivateKey takes a 32-byte private key and encodes it into the
|
||||||
|
// Wallet Import Format (WIF).
|
||||||
|
func EncodePrivateKey(privKey []byte, net btcwire.BitcoinNet, compressed bool) (string, error) {
|
||||||
|
if len(privKey) != 32 {
|
||||||
|
return "", ErrMalformedPrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
var netID byte
|
||||||
|
switch net {
|
||||||
|
case btcwire.MainNet:
|
||||||
|
netID = MainNetKey
|
||||||
|
case btcwire.TestNet3:
|
||||||
|
netID = TestNetKey
|
||||||
|
default:
|
||||||
|
return "", ErrUnknownNet
|
||||||
|
}
|
||||||
|
|
||||||
|
tosum := append([]byte{netID}, privKey...)
|
||||||
|
if compressed {
|
||||||
|
tosum = append(tosum, 0x01)
|
||||||
|
}
|
||||||
|
cksum := btcwire.DoubleSha256(tosum)
|
||||||
|
|
||||||
|
// Private key before base58 encoding is 1 byte for netID, 32 bytes for
|
||||||
|
// privKey, plus an optional byte (0x01) if copressed, plus 4 bytes of checksum.
|
||||||
|
encodeLen := 37
|
||||||
|
if compressed {
|
||||||
|
encodeLen += 1
|
||||||
|
}
|
||||||
|
a := make([]byte, encodeLen, encodeLen)
|
||||||
|
a[0] = netID
|
||||||
|
copy(a[1:], privKey)
|
||||||
|
if compressed {
|
||||||
|
copy(a[32+1:], []byte{0x01})
|
||||||
|
copy(a[32+1+1:], cksum[:4])
|
||||||
|
} else {
|
||||||
|
copy(a[32+1:], cksum[:4])
|
||||||
|
}
|
||||||
|
return Base58Encode(a), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodePrivateKey takes a Wallet Import Format (WIF) string and
|
||||||
|
// decodes into a 32-byte private key.
|
||||||
|
func DecodePrivateKey(wif string) ([]byte, btcwire.BitcoinNet, bool, error) {
|
||||||
|
decoded := Base58Decode(wif)
|
||||||
|
decodedLen := len(decoded)
|
||||||
|
compressed := false
|
||||||
|
|
||||||
|
// Length of decoded privkey must be 32 bytes + an optional 1 byte (0x01)
|
||||||
|
// if compressed, plus 1 byte for netID + 4 bytes of checksum
|
||||||
|
if decodedLen == 32+6 {
|
||||||
|
compressed = true
|
||||||
|
if decoded[33] != 0x01 {
|
||||||
|
return nil, 0, compressed, ErrMalformedPrivateKey
|
||||||
|
}
|
||||||
|
} else if decodedLen != 32+5 {
|
||||||
|
return nil, 0, compressed, ErrMalformedPrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
var net btcwire.BitcoinNet
|
||||||
|
switch decoded[0] {
|
||||||
|
case MainNetKey:
|
||||||
|
net = btcwire.MainNet
|
||||||
|
case TestNetKey:
|
||||||
|
net = btcwire.TestNet3
|
||||||
|
default:
|
||||||
|
return nil, 0, compressed, 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.
|
||||||
|
var tosum []byte
|
||||||
|
if compressed {
|
||||||
|
tosum = decoded[:32+1+1]
|
||||||
|
} else {
|
||||||
|
tosum = decoded[:32+1]
|
||||||
|
}
|
||||||
|
cksum := btcwire.DoubleSha256(tosum)[:4]
|
||||||
|
if !bytes.Equal(cksum, decoded[decodedLen-4:]) {
|
||||||
|
return nil, 0, compressed, ErrMalformedPrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
privKey := make([]byte, 32, 32)
|
||||||
|
copy(privKey[:], decoded[1:32+1])
|
||||||
|
|
||||||
|
return privKey, net, compressed, nil
|
||||||
|
}
|
||||||
|
|
|
@ -575,3 +575,49 @@ func TestAddresses(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEncodeDecodePrivateKey(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
in []byte
|
||||||
|
net btcwire.BitcoinNet
|
||||||
|
compressed bool
|
||||||
|
out string
|
||||||
|
}{
|
||||||
|
{[]byte{
|
||||||
|
0x0c, 0x28, 0xfc, 0xa3, 0x86, 0xc7, 0xa2, 0x27,
|
||||||
|
0x60, 0x0b, 0x2f, 0xe5, 0x0b, 0x7c, 0xae, 0x11,
|
||||||
|
0xec, 0x86, 0xd3, 0xbf, 0x1f, 0xbe, 0x47, 0x1b,
|
||||||
|
0xe8, 0x98, 0x27, 0xe1, 0x9d, 0x72, 0xaa, 0x1d,
|
||||||
|
}, btcwire.MainNet, false, "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ"},
|
||||||
|
{[]byte{
|
||||||
|
0xdd, 0xa3, 0x5a, 0x14, 0x88, 0xfb, 0x97, 0xb6,
|
||||||
|
0xeb, 0x3f, 0xe6, 0xe9, 0xef, 0x2a, 0x25, 0x81,
|
||||||
|
0x4e, 0x39, 0x6f, 0xb5, 0xdc, 0x29, 0x5f, 0xe9,
|
||||||
|
0x94, 0xb9, 0x67, 0x89, 0xb2, 0x1a, 0x03, 0x98,
|
||||||
|
}, btcwire.TestNet3, true, "cV1Y7ARUr9Yx7BR55nTdnR7ZXNJphZtCCMBTEZBJe1hXt2kB684q"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for x, test := range tests {
|
||||||
|
wif, err := btcutil.EncodePrivateKey(test.in, test.net, test.compressed)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%x: %v", x, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if wif != test.out {
|
||||||
|
t.Errorf("TestEncodeDecodePrivateKey failed: want '%s', got '%s'",
|
||||||
|
test.out, wif)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
key, _, compressed, err := btcutil.DecodePrivateKey(test.out)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !bytes.Equal(key, test.in) || compressed != test.compressed {
|
||||||
|
t.Errorf("TestEncodeDecodePrivateKey failed: want '%x', got '%x'",
|
||||||
|
test.out, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue