1// Copyright (c) 2013 - 2020 The btcsuite developers
2// Use of this source code is governed by an ISC
3// license that can be found in the LICENSE file.
4
5package btcutil_test
6
7import (
8	"bytes"
9	"encoding/hex"
10	"testing"
11
12	"github.com/btcsuite/btcd/btcec"
13	"github.com/btcsuite/btcd/chaincfg"
14	. "github.com/btcsuite/btcutil"
15)
16
17func TestEncodeDecodeWIF(t *testing.T) {
18	validEncodeCases := []struct {
19		privateKey []byte           // input
20		net        *chaincfg.Params // input
21		compress   bool             // input
22		wif        string           // output
23		publicKey  []byte           // output
24		name       string           // name of subtest
25	}{
26		{
27			privateKey: []byte{
28				0x0c, 0x28, 0xfc, 0xa3, 0x86, 0xc7, 0xa2, 0x27,
29				0x60, 0x0b, 0x2f, 0xe5, 0x0b, 0x7c, 0xae, 0x11,
30				0xec, 0x86, 0xd3, 0xbf, 0x1f, 0xbe, 0x47, 0x1b,
31				0xe8, 0x98, 0x27, 0xe1, 0x9d, 0x72, 0xaa, 0x1d},
32			net:      &chaincfg.MainNetParams,
33			compress: false,
34			wif:      "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ",
35			publicKey: []byte{
36				0x04, 0xd0, 0xde, 0x0a, 0xae, 0xae, 0xfa, 0xd0,
37				0x2b, 0x8b, 0xdc, 0x8a, 0x01, 0xa1, 0xb8, 0xb1,
38				0x1c, 0x69, 0x6b, 0xd3, 0xd6, 0x6a, 0x2c, 0x5f,
39				0x10, 0x78, 0x0d, 0x95, 0xb7, 0xdf, 0x42, 0x64,
40				0x5c, 0xd8, 0x52, 0x28, 0xa6, 0xfb, 0x29, 0x94,
41				0x0e, 0x85, 0x8e, 0x7e, 0x55, 0x84, 0x2a, 0xe2,
42				0xbd, 0x11, 0x5d, 0x1e, 0xd7, 0xcc, 0x0e, 0x82,
43				0xd9, 0x34, 0xe9, 0x29, 0xc9, 0x76, 0x48, 0xcb,
44				0x0a},
45			name: "encodeValidUncompressedMainNetWif",
46		},
47		{
48			privateKey: []byte{
49				0xdd, 0xa3, 0x5a, 0x14, 0x88, 0xfb, 0x97, 0xb6,
50				0xeb, 0x3f, 0xe6, 0xe9, 0xef, 0x2a, 0x25, 0x81,
51				0x4e, 0x39, 0x6f, 0xb5, 0xdc, 0x29, 0x5f, 0xe9,
52				0x94, 0xb9, 0x67, 0x89, 0xb2, 0x1a, 0x03, 0x98},
53			net:      &chaincfg.TestNet3Params,
54			compress: true,
55			wif:      "cV1Y7ARUr9Yx7BR55nTdnR7ZXNJphZtCCMBTEZBJe1hXt2kB684q",
56			publicKey: []byte{
57				0x02, 0xee, 0xc2, 0x54, 0x06, 0x61, 0xb0, 0xc3,
58				0x9d, 0x27, 0x15, 0x70, 0x74, 0x24, 0x13, 0xbd,
59				0x02, 0x93, 0x2d, 0xd0, 0x09, 0x34, 0x93, 0xfd,
60				0x0b, 0xec, 0xed, 0x0b, 0x7f, 0x93, 0xad, 0xde,
61				0xc4},
62			name: "encodeValidCompressedTestNet3Wif",
63		},
64	}
65
66	for _, validCase := range validEncodeCases {
67		t.Run(validCase.name, func(t *testing.T) {
68			priv, _ := btcec.PrivKeyFromBytes(btcec.S256(), validCase.privateKey)
69			wif, err := NewWIF(priv, validCase.net, validCase.compress)
70			if err != nil {
71				t.Fatalf("NewWIF failed: expected no error, got '%v'", err)
72			}
73
74			if !wif.IsForNet(validCase.net) {
75				t.Fatal("IsForNet failed: got 'false', want 'true'")
76			}
77
78			if gotPubKey := wif.SerializePubKey(); !bytes.Equal(gotPubKey, validCase.publicKey) {
79				t.Fatalf("SerializePubKey failed: got '%s', want '%s'",
80					hex.EncodeToString(gotPubKey), hex.EncodeToString(validCase.publicKey))
81			}
82
83			// Test that encoding the WIF structure matches the expected string.
84			got := wif.String()
85			if got != validCase.wif {
86				t.Fatalf("NewWIF failed: want '%s', got '%s'",
87					validCase.wif, got)
88			}
89
90			// Test that decoding the expected string results in the original WIF
91			// structure.
92			decodedWif, err := DecodeWIF(got)
93			if err != nil {
94				t.Fatalf("DecodeWIF failed: expected no error, got '%v'", err)
95			}
96			if decodedWifString := decodedWif.String(); decodedWifString != validCase.wif {
97				t.Fatalf("NewWIF failed: want '%v', got '%v'", validCase.wif, decodedWifString)
98			}
99		})
100	}
101
102	invalidDecodeCases := []struct {
103		name string
104		wif  string
105		err  error
106	}{
107		{
108			name: "decodeInvalidLengthWif",
109			wif:  "deadbeef",
110			err:  ErrMalformedPrivateKey,
111		},
112		{
113			name: "decodeInvalidCompressMagicWif",
114			wif:  "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sfZr2ym",
115			err:  ErrMalformedPrivateKey,
116		},
117		{
118			name: "decodeInvalidChecksumWif",
119			wif:  "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTj",
120			err:  ErrChecksumMismatch,
121		},
122	}
123
124	for _, invalidCase := range invalidDecodeCases {
125		t.Run(invalidCase.name, func(t *testing.T) {
126			decodedWif, err := DecodeWIF(invalidCase.wif)
127			if decodedWif != nil {
128				t.Fatalf("DecodeWIF: unexpectedly succeeded - got '%v', want '%v'",
129					decodedWif, nil)
130			}
131			if err != invalidCase.err {
132				t.Fatalf("DecodeWIF: expected error '%v', got '%v'",
133					invalidCase.err, err)
134			}
135		})
136	}
137
138	t.Run("encodeInvalidNetworkWif", func(t *testing.T) {
139		privateKey := []byte{
140			0x0c, 0x28, 0xfc, 0xa3, 0x86, 0xc7, 0xa2, 0x27,
141			0x60, 0x0b, 0x2f, 0xe5, 0x0b, 0x7c, 0xae, 0x11,
142			0xec, 0x86, 0xd3, 0xbf, 0x1f, 0xbe, 0x47, 0x1b,
143			0xe8, 0x98, 0x27, 0xe1, 0x9d, 0x72, 0xaa, 0x1d}
144		priv, _ := btcec.PrivKeyFromBytes(btcec.S256(), privateKey)
145
146		wif, err := NewWIF(priv, nil, true)
147
148		if wif != nil {
149			t.Fatalf("NewWIF: unexpectedly succeeded - got '%v', want '%v'",
150				wif, nil)
151		}
152		if err == nil || err.Error() != "no network" {
153			t.Fatalf("NewWIF: expected error 'no network', got '%v'", err)
154		}
155	})
156}
157