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, &btcnet.MainNetParams, false) if err != nil { t.Fatal(err) } wif2, err := NewWIF(priv2, &btcnet.TestNet3Params, 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) } } }
// ECPrivKey converts the extended key to a btcec private key and returns it. // As you might imagine this is only possible if the extended key is a private // extended key (as determined by the IsPrivate function). The ErrNotPrivExtKey // error will be returned if this function is called on a public extended key. func (k *ExtendedKey) ECPrivKey() (*btcec.PrivateKey, error) { if !k.isPrivate { return nil, ErrNotPrivExtKey } privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), k.key) return privKey, nil }
// 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 } // 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 } netID := decoded[0] privKeyBytes := decoded[1 : 1+btcec.PrivKeyBytesLen] privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) return &WIF{privKey, compress, netID}, nil }