Introduce better WIF API.
The old functions DecodePrivateKey and EncodePrivateKey have been removed in favor of the DecodeWIF function and the String method of the new WIF type. ok @davecgh
This commit is contained in:
parent
973174daa4
commit
bff18e5a93
5 changed files with 294 additions and 166 deletions
100
address.go
100
address.go
|
@ -23,11 +23,6 @@ var (
|
|||
// 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
|
||||
// to a bad checksum.
|
||||
ErrChecksumMismatch = errors.New("checksum mismatch")
|
||||
|
@ -46,12 +41,6 @@ const (
|
|||
// 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
|
||||
|
||||
|
@ -511,92 +500,3 @@ func (a *AddressPubKey) AddressPubKeyHash() *AddressPubKeyHash {
|
|||
func (a *AddressPubKey) PubKey() *btcec.PublicKey {
|
||||
return a.pubKey
|
||||
}
|
||||
|
||||
// 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++
|
||||
}
|
||||
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
|
||||
}
|
||||
|
|
|
@ -589,49 +589,3 @@ 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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,60 +2,65 @@
|
|||
github.com/conformal/btcutil/base58.go Base58Decode 100.00% (20/20)
|
||||
github.com/conformal/btcutil/base58.go Base58Encode 100.00% (15/15)
|
||||
github.com/conformal/btcutil/block.go Block.Tx 100.00% (12/12)
|
||||
github.com/conformal/btcutil/wif.go WIF.String 100.00% (11/11)
|
||||
github.com/conformal/btcutil/block.go Block.Transactions 100.00% (11/11)
|
||||
github.com/conformal/btcutil/address.go encodeAddress 100.00% (9/9)
|
||||
github.com/conformal/btcutil/amount.go NewAmount 100.00% (9/9)
|
||||
github.com/conformal/btcutil/amount.go AmountUnit.String 100.00% (8/8)
|
||||
github.com/conformal/btcutil/block.go NewBlockFromBytes 100.00% (7/7)
|
||||
github.com/conformal/btcutil/tx.go NewTxFromBytes 100.00% (7/7)
|
||||
github.com/conformal/btcutil/tx.go Tx.Sha 100.00% (5/5)
|
||||
github.com/conformal/btcutil/block.go Block.Sha 100.00% (5/5)
|
||||
github.com/conformal/btcutil/tx.go Tx.Sha 100.00% (5/5)
|
||||
github.com/conformal/btcutil/address.go checkBitcoinNet 100.00% (5/5)
|
||||
github.com/conformal/btcutil/hash160.go calcHash 100.00% (2/2)
|
||||
github.com/conformal/btcutil/amount.go Amount.Format 100.00% (2/2)
|
||||
github.com/conformal/btcutil/address.go NewAddressScriptHash 100.00% (2/2)
|
||||
github.com/conformal/btcutil/block.go OutOfRangeError.Error 100.00% (1/1)
|
||||
github.com/conformal/btcutil/block.go NewBlockFromBlockAndBytes 100.00% (1/1)
|
||||
github.com/conformal/btcutil/amount.go Amount.ToUnit 100.00% (1/1)
|
||||
github.com/conformal/btcutil/amount.go Amount.String 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go AddressPubKeyHash.String 100.00% (1/1)
|
||||
github.com/conformal/btcutil/block.go Block.MsgBlock 100.00% (1/1)
|
||||
github.com/conformal/btcutil/block.go NewBlock 100.00% (1/1)
|
||||
github.com/conformal/btcutil/block.go Block.SetHeight 100.00% (1/1)
|
||||
github.com/conformal/btcutil/block.go Block.Height 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go AddressPubKeyHash.EncodeAddress 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go AddressPubKeyHash.ScriptAddress 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go AddressPubKeyHash.Hash160 100.00% (1/1)
|
||||
github.com/conformal/btcutil/tx.go NewTx 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go AddressScriptHash.EncodeAddress 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go AddressScriptHash.ScriptAddress 100.00% (1/1)
|
||||
github.com/conformal/btcutil/tx.go Tx.SetIndex 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go AddressScriptHash.String 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go AddressScriptHash.Hash160 100.00% (1/1)
|
||||
github.com/conformal/btcutil/tx.go Tx.Index 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go AddressPubKey.EncodeAddress 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go AddressPubKey.ScriptAddress 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go AddressPubKey.String 100.00% (1/1)
|
||||
github.com/conformal/btcutil/amount.go Amount.ToUnit 100.00% (1/1)
|
||||
github.com/conformal/btcutil/amount.go Amount.String 100.00% (1/1)
|
||||
github.com/conformal/btcutil/block.go Block.MsgBlock 100.00% (1/1)
|
||||
github.com/conformal/btcutil/block.go Block.Height 100.00% (1/1)
|
||||
github.com/conformal/btcutil/block.go Block.SetHeight 100.00% (1/1)
|
||||
github.com/conformal/btcutil/block.go NewBlock 100.00% (1/1)
|
||||
github.com/conformal/btcutil/block.go NewBlockFromBlockAndBytes 100.00% (1/1)
|
||||
github.com/conformal/btcutil/hash160.go Hash160 100.00% (1/1)
|
||||
github.com/conformal/btcutil/tx.go Tx.MsgTx 100.00% (1/1)
|
||||
github.com/conformal/btcutil/tx.go Tx.Index 100.00% (1/1)
|
||||
github.com/conformal/btcutil/tx.go Tx.SetIndex 100.00% (1/1)
|
||||
github.com/conformal/btcutil/tx.go NewTx 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go AddressPubKeyHash.String 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go AddressPubKey.String 100.00% (1/1)
|
||||
github.com/conformal/btcutil/hash160.go Hash160 100.00% (1/1)
|
||||
github.com/conformal/btcutil/block.go OutOfRangeError.Error 100.00% (1/1)
|
||||
github.com/conformal/btcutil/address.go DecodeAddress 95.65% (22/23)
|
||||
github.com/conformal/btcutil/appdata.go appDataDir 92.00% (23/25)
|
||||
github.com/conformal/btcutil/address.go NewAddressPubKeyHash 91.67% (11/12)
|
||||
github.com/conformal/btcutil/address.go NewAddressScriptHashFromHash 91.67% (11/12)
|
||||
github.com/conformal/btcutil/address.go EncodePrivateKey 90.91% (20/22)
|
||||
github.com/conformal/btcutil/block.go Block.TxLoc 88.89% (8/9)
|
||||
github.com/conformal/btcutil/block.go Block.Bytes 88.89% (8/9)
|
||||
github.com/conformal/btcutil/address.go AddressPubKey.serialize 85.71% (6/7)
|
||||
github.com/conformal/btcutil/address.go DecodePrivateKey 83.33% (20/24)
|
||||
github.com/conformal/btcutil/address.go NewAddressPubKey 83.33% (15/18)
|
||||
github.com/conformal/btcutil/wif.go DecodeWIF 81.82% (18/22)
|
||||
github.com/conformal/btcutil/wif.go NewWIF 75.00% (3/4)
|
||||
github.com/conformal/btcutil/block.go Block.TxSha 75.00% (3/4)
|
||||
github.com/conformal/btcutil/wif.go paddedAppend 66.67% (2/3)
|
||||
github.com/conformal/btcutil/address.go AddressPubKey.IsForNet 60.00% (3/5)
|
||||
github.com/conformal/btcutil/address.go AddressScriptHash.IsForNet 60.00% (3/5)
|
||||
github.com/conformal/btcutil/address.go AddressPubKeyHash.IsForNet 60.00% (3/5)
|
||||
github.com/conformal/btcutil/address.go AddressPubKey.IsForNet 60.00% (3/5)
|
||||
github.com/conformal/btcutil/certgen.go NewTLSCertPair 0.00% (0/50)
|
||||
github.com/conformal/btcutil/wif.go WIF.SerializePubKey 0.00% (0/4)
|
||||
github.com/conformal/btcutil/wif.go WIF.IsForNet 0.00% (0/4)
|
||||
github.com/conformal/btcutil/address.go AddressPubKey.AddressPubKeyHash 0.00% (0/3)
|
||||
github.com/conformal/btcutil/address.go AddressPubKey.Format 0.00% (0/1)
|
||||
github.com/conformal/btcutil/appdata.go AppDataDir 0.00% (0/1)
|
||||
github.com/conformal/btcutil/address.go AddressPubKey.Format 0.00% (0/1)
|
||||
github.com/conformal/btcutil/address.go AddressPubKey.SetFormat 0.00% (0/1)
|
||||
github.com/conformal/btcutil ------------------------------- 78.89% (299/379)
|
||||
github.com/conformal/btcutil/address.go AddressPubKey.PubKey 0.00% (0/1)
|
||||
github.com/conformal/btcutil ------------------------------- 76.70% (293/382)
|
||||
|
||||
|
|
198
wif.go
Normal file
198
wif.go
Normal file
|
@ -0,0 +1,198 @@
|
|||
// 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/btcec"
|
||||
"github.com/conformal/btcwire"
|
||||
)
|
||||
|
||||
// ErrMalformedPrivateKey describes an error where a WIF-encoded private
|
||||
// key cannot be decoded due to being improperly formatted. This may occur
|
||||
// if the byte length is incorrect or an unexpected magic number was
|
||||
// encountered.
|
||||
var ErrMalformedPrivateKey = errors.New("malformed private key")
|
||||
|
||||
// These constants define the magic numbers used for identifing components
|
||||
// of a WIF-encoded private key and the bitcoin address associated with it.
|
||||
const (
|
||||
// mainNetKey is the magic number identifying a WIF private key for
|
||||
// the MainNet bitcoin network.
|
||||
mainNetKey byte = 0x80
|
||||
|
||||
// testNetKey is the magic number identifying a WIF private key for
|
||||
// the regression test and TestNet3 bitcoin networks.
|
||||
testNetKey byte = 0xef
|
||||
|
||||
// compressMagic is the magic byte used to identify a WIF encoding for
|
||||
// an address created from a compressed serialized public key.
|
||||
compressMagic byte = 0x01
|
||||
)
|
||||
|
||||
// WIF contains the individual components described by the Wallet Import Format
|
||||
// (WIF). A WIF string is typically used to represent a private key and its
|
||||
// associated address in a way that may be easily copied and imported into or
|
||||
// exported from wallet software. WIF strings may be decoded into this
|
||||
// structure by calling DecodeWIF or created with a user-provided private key
|
||||
// by calling NewWIF.
|
||||
type WIF struct {
|
||||
// PrivKey is the private key being imported or exported.
|
||||
PrivKey *btcec.PrivateKey
|
||||
|
||||
// CompressPubKey specifies whether the address controlled by the
|
||||
// imported or exported private key was created by hashing a
|
||||
// compressed (33-byte) serialized public key, rather than an
|
||||
// uncompressed (65-byte) one.
|
||||
CompressPubKey bool
|
||||
|
||||
// netID is the bitcoin network identifier byte used when
|
||||
// WIF encoding the private key.
|
||||
netID byte
|
||||
}
|
||||
|
||||
// NewWIF creates a new WIF structure to export an address and its private key
|
||||
// as a string encoded in the Wallet Import Format. The net argument must be
|
||||
// either btcwire.MainNet, btcwire.TestNet3 or btcwire.TestNet. The compress
|
||||
// argument specifies whether the address intended to be imported or exported
|
||||
// was created by serializing the public key compressed rather than
|
||||
// uncompressed.
|
||||
func NewWIF(privKey *btcec.PrivateKey, net btcwire.BitcoinNet, compress bool) (*WIF, error) {
|
||||
// Determine the key's network identifier byte. The same byte is
|
||||
// shared for TestNet3 and TestNet (the regression test network).
|
||||
switch net {
|
||||
case btcwire.MainNet:
|
||||
return &WIF{privKey, compress, mainNetKey}, nil
|
||||
case btcwire.TestNet, btcwire.TestNet3:
|
||||
return &WIF{privKey, compress, testNetKey}, nil
|
||||
default:
|
||||
return nil, ErrUnknownNet
|
||||
}
|
||||
}
|
||||
|
||||
// IsForNet returns whether or not the decoded WIF structure is associated
|
||||
// with the passed bitcoin network.
|
||||
func (w *WIF) IsForNet(net btcwire.BitcoinNet) bool {
|
||||
switch net {
|
||||
case btcwire.MainNet:
|
||||
return w.netID == mainNetKey
|
||||
case btcwire.TestNet, btcwire.TestNet3:
|
||||
return w.netID == testNetKey
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// DecodeWIF creates a new WIF structure by decoding the string encoding of
|
||||
// the import format.
|
||||
//
|
||||
// The WIF string must be a base58-encoded string of the following byte
|
||||
// sequence:
|
||||
//
|
||||
// * 1 byte to identify the network, must be 0x80 for mainnet or 0xef for
|
||||
// either testnet3 or the regression test network
|
||||
// * 32 bytes of a binary-encoded, big-endian, zero-padded private key
|
||||
// * Optional 1 byte (equal to 0x01) if the address being imported or exported
|
||||
// was created by taking the RIPEMD160 after SHA256 hash of a serialized
|
||||
// compressed (33-byte) public key
|
||||
// * 4 bytes of checksum, must equal the first four bytes of the double SHA256
|
||||
// of every byte before the checksum in this sequence
|
||||
//
|
||||
// If the base58-decoded byte sequence does not match this, DecodeWIF will
|
||||
// return a non-nil error. ErrMalformedPrivateKey is returned when the WIF
|
||||
// is of an impossible length or the expected compressed pubkey magic number
|
||||
// does not equal the expected value of 0x01. ErrChecksumMismatch is returned
|
||||
// if the expected WIF checksum does not match the calculated checksum.
|
||||
func DecodeWIF(wif string) (*WIF, error) {
|
||||
decoded := Base58Decode(wif)
|
||||
decodedLen := len(decoded)
|
||||
var compress bool
|
||||
|
||||
// Length of base58 decoded WIF must be 32 bytes + an optional 1 byte
|
||||
// (0x01) if compressed, plus 1 byte for netID + 4 bytes of checksum.
|
||||
switch decodedLen {
|
||||
case 1 + btcec.PrivKeyBytesLen + 1 + 4:
|
||||
if decoded[33] != compressMagic {
|
||||
return nil, ErrMalformedPrivateKey
|
||||
}
|
||||
compress = true
|
||||
case 1 + btcec.PrivKeyBytesLen + 4:
|
||||
compress = false
|
||||
default:
|
||||
return nil, ErrMalformedPrivateKey
|
||||
}
|
||||
|
||||
netID := decoded[0]
|
||||
if netID != mainNetKey && netID != testNetKey {
|
||||
return nil, 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 compress {
|
||||
tosum = decoded[:1+btcec.PrivKeyBytesLen+1]
|
||||
} else {
|
||||
tosum = decoded[:1+btcec.PrivKeyBytesLen]
|
||||
}
|
||||
cksum := btcwire.DoubleSha256(tosum)[:4]
|
||||
if !bytes.Equal(cksum, decoded[decodedLen-4:]) {
|
||||
return nil, ErrChecksumMismatch
|
||||
}
|
||||
|
||||
privKeyBytes := decoded[1 : 1+btcec.PrivKeyBytesLen]
|
||||
privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes)
|
||||
return &WIF{privKey, compress, netID}, nil
|
||||
}
|
||||
|
||||
// String creates the Wallet Import Format string encoding of a WIF structure.
|
||||
// See DecodeWIF for a detailed breakdown of the format and requirements of
|
||||
// a valid WIF string.
|
||||
func (w *WIF) String() string {
|
||||
// Precalculate size. Maximum number of bytes before base58 encoding
|
||||
// is one byte for the network, 32 bytes of private key, possibly one
|
||||
// extra byte if the pubkey is to be compressed, and finally four
|
||||
// bytes of checksum.
|
||||
encodeLen := 1 + btcec.PrivKeyBytesLen + 4
|
||||
if w.CompressPubKey {
|
||||
encodeLen++
|
||||
}
|
||||
|
||||
a := make([]byte, 0, encodeLen)
|
||||
a = append(a, w.netID)
|
||||
// Pad and append bytes manually, instead of using Serialize, to
|
||||
// avoid another call to make.
|
||||
a = paddedAppend(btcec.PrivKeyBytesLen, a, w.PrivKey.D.Bytes())
|
||||
if w.CompressPubKey {
|
||||
a = append(a, compressMagic)
|
||||
}
|
||||
cksum := btcwire.DoubleSha256(a)[:4]
|
||||
a = append(a, cksum...)
|
||||
return Base58Encode(a)
|
||||
}
|
||||
|
||||
// SerializePubKey serializes the associated public key of the imported or
|
||||
// exported private key in either a compressed or uncompressed format. The
|
||||
// serialization format chosen depends on the value of w.CompressPubKey.
|
||||
func (w *WIF) SerializePubKey() []byte {
|
||||
pk := (*btcec.PublicKey)(&w.PrivKey.PublicKey)
|
||||
if w.CompressPubKey {
|
||||
return pk.SerializeCompressed()
|
||||
}
|
||||
return pk.SerializeUncompressed()
|
||||
}
|
||||
|
||||
// paddedAppend appends the src byte slice to dst, returning the new slice.
|
||||
// If the length of the source is smaller than the passed size, leading zero
|
||||
// bytes are appended to the dst slice before appending src.
|
||||
func paddedAppend(size uint, dst, src []byte) []byte {
|
||||
for i := 0; i < int(size)-len(src); i++ {
|
||||
dst = append(dst, 0)
|
||||
}
|
||||
return append(dst, src...)
|
||||
}
|
71
wif_test.go
Normal file
71
wif_test.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
// 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 (
|
||||
"testing"
|
||||
|
||||
"github.com/conformal/btcec"
|
||||
. "github.com/conformal/btcutil"
|
||||
"github.com/conformal/btcwire"
|
||||
)
|
||||
|
||||
func TestEncodeDecodeWIF(t *testing.T) {
|
||||
priv1, _ := btcec.PrivKeyFromBytes(btcec.S256(), []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})
|
||||
|
||||
priv2, _ := btcec.PrivKeyFromBytes(btcec.S256(), []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})
|
||||
|
||||
wif1, err := NewWIF(priv1, btcwire.MainNet, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wif2, err := NewWIF(priv2, btcwire.TestNet3, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
wif *WIF
|
||||
encoded string
|
||||
}{
|
||||
{
|
||||
wif1,
|
||||
"5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ",
|
||||
},
|
||||
{
|
||||
wif2,
|
||||
"cV1Y7ARUr9Yx7BR55nTdnR7ZXNJphZtCCMBTEZBJe1hXt2kB684q",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
// Test that encoding the WIF structure matches the expected string.
|
||||
s := test.wif.String()
|
||||
if s != test.encoded {
|
||||
t.Errorf("TestEncodeDecodePrivateKey failed: want '%s', got '%s'",
|
||||
test.encoded, s)
|
||||
continue
|
||||
}
|
||||
|
||||
// Test that decoding the expected string results in the original WIF
|
||||
// structure.
|
||||
w, err := DecodeWIF(test.encoded)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
if got := w.String(); got != test.encoded {
|
||||
t.Errorf("NewWIF failed: want '%v', got '%v'", test.wif, got)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue