Skip to content

Commit 7d4caf0

Browse files
committed
Added basic WIF support
1 parent 016946f commit 7d4caf0

File tree

5 files changed

+322
-1
lines changed

5 files changed

+322
-1
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ View the generated [documentation](https://pkg.go.dev/github.com/bitcoinschema/g
4646
- [Create PrivateKey](private_key.go)
4747
- [Create PubKey from PrivateKey](pubkey.go)
4848
- [Script from Address](script.go)
49+
- [WIF to PrivateKey](private_key.go)
50+
- [PrivateKey to WIF](private_key.go)
4951

5052

5153
<details>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package main
2+
3+
import (
4+
"log"
5+
6+
"github.com/bitcoinschema/go-bitcoin"
7+
)
8+
9+
func main() {
10+
// Start with a private key
11+
privateKey, err := bitcoin.CreatePrivateKeyString()
12+
if err != nil {
13+
log.Fatalf("error occurred: %s", err.Error())
14+
}
15+
16+
// Create a wif
17+
var wif string
18+
if wif, err = bitcoin.PrivateKeyToWifString(privateKey); err != nil {
19+
log.Fatalf("error occurred: %s", err.Error())
20+
}
21+
22+
// Success!
23+
log.Printf("private key: %s converted to wif: %s", privateKey, wif)
24+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package main
2+
3+
import (
4+
"log"
5+
6+
"github.com/bitcoinschema/go-bitcoin"
7+
)
8+
9+
func main() {
10+
11+
// Convert the wif into a private key
12+
privateKey, err := bitcoin.WifToPrivateKeyString("5KgHn2qiftW5LQgCYFtkbrLYB1FuvisDtacax8NCvumw3UTKdcP")
13+
if err != nil {
14+
log.Fatalf("error occurred: %s", err.Error())
15+
}
16+
17+
// Success!
18+
log.Printf("private key: %s", privateKey)
19+
}

private_key.go

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"math/big"
88

99
"github.com/bitcoinsv/bsvd/bsvec"
10+
"github.com/bitcoinsv/bsvd/chaincfg"
11+
"github.com/bitcoinsv/bsvutil"
1012
)
1113

1214
// PrivateKeyFromString turns a private key (hex encoded string) into an bsvec.PrivateKey
@@ -27,7 +29,7 @@ func PrivateKeyFromString(privateKey string) (*bsvec.PrivateKey, error) {
2729
return &bsvec.PrivateKey{PublicKey: ecdsaPubKey, D: new(big.Int).SetBytes(privateKeyBytes)}, nil
2830
}
2931

30-
// CreatePrivateKey will create a new private key
32+
// CreatePrivateKey will create a new private key (*bsvec.PrivateKey)
3133
func CreatePrivateKey() (*bsvec.PrivateKey, error) {
3234
return bsvec.NewPrivateKey(bsvec.S256())
3335
}
@@ -61,3 +63,65 @@ func PrivateAndPublicKeys(privateKey string) (*bsvec.PrivateKey, *bsvec.PublicKe
6163
rawKey, publicKey := bsvec.PrivKeyFromBytes(bsvec.S256(), privateKeyBytes)
6264
return rawKey, publicKey, nil
6365
}
66+
67+
// PrivateKeyToWif will convert a private key to a WIF (*bsvutil.WIF)
68+
func PrivateKeyToWif(privateKey string) (*bsvutil.WIF, error) {
69+
70+
// Missing private key
71+
if len(privateKey) == 0 {
72+
return nil, errors.New("missing privateKey")
73+
}
74+
75+
// Decode the private key
76+
decodedKey, err := hex.DecodeString(privateKey)
77+
if err != nil {
78+
return nil, err
79+
}
80+
81+
// Get the private key from bytes
82+
rawKey, _ := bsvec.PrivKeyFromBytes(bsvec.S256(), decodedKey)
83+
84+
// Create a new WIF (error never gets hit since (net) is set correctly)
85+
return bsvutil.NewWIF(rawKey, &chaincfg.MainNetParams, false)
86+
}
87+
88+
// PrivateKeyToWifString will convert a private key to a WIF (string)
89+
func PrivateKeyToWifString(privateKey string) (string, error) {
90+
wif, err := PrivateKeyToWif(privateKey)
91+
if err != nil {
92+
return "", err
93+
}
94+
95+
return wif.String(), nil
96+
}
97+
98+
// WifToPrivateKey will convert a WIF to a private key (*bsvec.PrivateKey)
99+
func WifToPrivateKey(wif string) (*bsvec.PrivateKey, error) {
100+
101+
// Missing wif?
102+
if len(wif) == 0 {
103+
return nil, errors.New("missing wif")
104+
}
105+
106+
// Decode the wif
107+
decodedWif, err := bsvutil.DecodeWIF(wif)
108+
if err != nil {
109+
return nil, err
110+
}
111+
112+
// Return the private key
113+
return decodedWif.PrivKey, nil
114+
}
115+
116+
// WifToPrivateKeyString will convert a WIF to private key (string)
117+
func WifToPrivateKeyString(wif string) (string, error) {
118+
119+
// Convert the wif to private key
120+
privateKey, err := WifToPrivateKey(wif)
121+
if err != nil {
122+
return "", err
123+
}
124+
125+
// Return the hex (string) version of the private key
126+
return hex.EncodeToString(privateKey.Serialize()), nil
127+
}

private_key_test.go

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,215 @@ func BenchmarkPrivateAndPublicKeys(b *testing.B) {
182182
_, _, _ = PrivateAndPublicKeys(key)
183183
}
184184
}
185+
186+
// TestPrivateKeyToWif will test the method PrivateKeyToWif()
187+
func TestPrivateKeyToWif(t *testing.T) {
188+
189+
t.Parallel()
190+
191+
// Create the list of tests
192+
var tests = []struct {
193+
input string
194+
expectedWif string
195+
expectedNil bool
196+
expectedError bool
197+
}{
198+
{"", "", true, true},
199+
{"0", "", true, true},
200+
{"000000", "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAbuatmU", false, false},
201+
{"6D792070726976617465206B6579", "5HpHagT65TZzG1PH3CSu63k8DbuTZnNJf6HgyQNymvXmALAsm9s", false, false},
202+
{"54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8azz", "", true, true},
203+
{"54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8abd", "5JTHas7yTFMBLqgFogxZFf8Vc5uKEbkE7yQAQ2g3xPHo2sNG1Ei", false, false},
204+
}
205+
206+
// Run tests
207+
for _, test := range tests {
208+
if wif, err := PrivateKeyToWif(test.input); err != nil && !test.expectedError {
209+
t.Errorf("%s Failed: [%s] inputted and error not expected but got: %s", t.Name(), test.input, err.Error())
210+
} else if err == nil && test.expectedError {
211+
t.Errorf("%s Failed: [%s] inputted and error was expected", t.Name(), test.input)
212+
} else if wif == nil && !test.expectedNil {
213+
t.Errorf("%s Failed: [%s] inputted and was nil but not expected", t.Name(), test.input)
214+
} else if wif != nil && test.expectedNil {
215+
t.Errorf("%s Failed: [%s] inputted and was NOT nil but expected to be nil", t.Name(), test.input)
216+
} else if wif != nil && wif.String() != test.expectedWif {
217+
t.Errorf("%s Failed: [%s] inputted [%s] expected but failed comparison of keys, got: %s", t.Name(), test.input, test.expectedWif, wif.String())
218+
}
219+
}
220+
221+
}
222+
223+
// ExamplePrivateKeyToWif example using PrivateKeyToWif()
224+
func ExamplePrivateKeyToWif() {
225+
wif, err := PrivateKeyToWif("54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8abd")
226+
if err != nil {
227+
fmt.Printf("error occurred: %s", err.Error())
228+
return
229+
}
230+
fmt.Printf("converted wif: %s", wif.String())
231+
232+
// Output:converted wif: 5JTHas7yTFMBLqgFogxZFf8Vc5uKEbkE7yQAQ2g3xPHo2sNG1Ei
233+
}
234+
235+
// BenchmarkPrivateKeyToWif benchmarks the method PrivateKeyToWif()
236+
func BenchmarkPrivateKeyToWif(b *testing.B) {
237+
key, _ := CreatePrivateKeyString()
238+
for i := 0; i < b.N; i++ {
239+
_, _ = PrivateKeyToWif(key)
240+
}
241+
}
242+
243+
// TestPrivateKeyToWifString will test the method PrivateKeyToWifString()
244+
func TestPrivateKeyToWifString(t *testing.T) {
245+
246+
t.Parallel()
247+
248+
// Create the list of tests
249+
var tests = []struct {
250+
input string
251+
expectedWif string
252+
expectedError bool
253+
}{
254+
{"", "", true},
255+
{"0", "", true},
256+
{"000000", "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAbuatmU", false},
257+
{"6D792070726976617465206B6579", "5HpHagT65TZzG1PH3CSu63k8DbuTZnNJf6HgyQNymvXmALAsm9s", false},
258+
{"54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8azz", "", true},
259+
{"54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8abd", "5JTHas7yTFMBLqgFogxZFf8Vc5uKEbkE7yQAQ2g3xPHo2sNG1Ei", false},
260+
}
261+
262+
// Run tests
263+
for _, test := range tests {
264+
if wif, err := PrivateKeyToWifString(test.input); err != nil && !test.expectedError {
265+
t.Errorf("%s Failed: [%s] inputted and error not expected but got: %s", t.Name(), test.input, err.Error())
266+
} else if err == nil && test.expectedError {
267+
t.Errorf("%s Failed: [%s] inputted and error was expected", t.Name(), test.input)
268+
} else if wif != test.expectedWif {
269+
t.Errorf("%s Failed: [%s] inputted [%s] expected but failed comparison of keys, got: %s", t.Name(), test.input, test.expectedWif, wif)
270+
}
271+
}
272+
273+
}
274+
275+
// ExamplePrivateKeyToWifString example using PrivateKeyToWifString()
276+
func ExamplePrivateKeyToWifString() {
277+
wif, err := PrivateKeyToWifString("54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8abd")
278+
if err != nil {
279+
fmt.Printf("error occurred: %s", err.Error())
280+
return
281+
}
282+
fmt.Printf("converted wif: %s", wif)
283+
284+
// Output:converted wif: 5JTHas7yTFMBLqgFogxZFf8Vc5uKEbkE7yQAQ2g3xPHo2sNG1Ei
285+
}
286+
287+
// BenchmarkPrivateKeyToWifString benchmarks the method PrivateKeyToWifString()
288+
func BenchmarkPrivateKeyToWifString(b *testing.B) {
289+
key, _ := CreatePrivateKeyString()
290+
for i := 0; i < b.N; i++ {
291+
_, _ = PrivateKeyToWifString(key)
292+
}
293+
}
294+
295+
// TestWifToPrivateKey will test the method WifToPrivateKey()
296+
func TestWifToPrivateKey(t *testing.T) {
297+
t.Parallel()
298+
299+
// Create the list of tests
300+
var tests = []struct {
301+
input string
302+
expectedKey string
303+
expectedNil bool
304+
expectedError bool
305+
}{
306+
{"", "", true, true},
307+
{"0", "", true, true},
308+
{"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAbuatmU", "0000000000000000000000000000000000000000000000000000000000000000", false, false},
309+
{"5HpHagT65TZzG1PH3CSu63k8DbuTZnNJf6HgyQNymvXmALAsm9s", "0000000000000000000000000000000000006d792070726976617465206b6579", false, false},
310+
{"54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8azz", "", true, true},
311+
{"5JTHas7yTFMBLqgFogxZFf8Vc5uKEbkE7yQAQ2g3xPHo2sNG1Ei", "54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8abd", false, false},
312+
}
313+
314+
// Run tests
315+
for _, test := range tests {
316+
if privateKey, err := WifToPrivateKey(test.input); err != nil && !test.expectedError {
317+
t.Errorf("%s Failed: [%s] inputted and error not expected but got: %s", t.Name(), test.input, err.Error())
318+
} else if err == nil && test.expectedError {
319+
t.Errorf("%s Failed: [%s] inputted and error was expected", t.Name(), test.input)
320+
} else if privateKey == nil && !test.expectedNil {
321+
t.Errorf("%s Failed: [%s] inputted and was nil but not expected", t.Name(), test.input)
322+
} else if privateKey != nil && test.expectedNil {
323+
t.Errorf("%s Failed: [%s] inputted and was NOT nil but expected to be nil", t.Name(), test.input)
324+
} else if privateKey != nil && hex.EncodeToString(privateKey.Serialize()) != test.expectedKey {
325+
t.Errorf("%s Failed: [%s] inputted [%s] expected but failed comparison of keys, got: %s", t.Name(), test.input, test.expectedKey, hex.EncodeToString(privateKey.Serialize()))
326+
}
327+
}
328+
}
329+
330+
// ExampleWifToPrivateKey example using WifToPrivateKey()
331+
func ExampleWifToPrivateKey() {
332+
privateKey, err := WifToPrivateKey("5JTHas7yTFMBLqgFogxZFf8Vc5uKEbkE7yQAQ2g3xPHo2sNG1Ei")
333+
if err != nil {
334+
fmt.Printf("error occurred: %s", err.Error())
335+
return
336+
}
337+
fmt.Printf("private key: %s", hex.EncodeToString(privateKey.Serialize()))
338+
339+
// Output:private key: 54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8abd
340+
}
341+
342+
// BenchmarkWifToPrivateKey benchmarks the method WifToPrivateKey()
343+
func BenchmarkWifToPrivateKey(b *testing.B) {
344+
for i := 0; i < b.N; i++ {
345+
_, _ = WifToPrivateKey("5JTHas7yTFMBLqgFogxZFf8Vc5uKEbkE7yQAQ2g3xPHo2sNG1Ei")
346+
}
347+
}
348+
349+
// TestWifToPrivateKeyString will test the method WifToPrivateKeyString()
350+
func TestWifToPrivateKeyString(t *testing.T) {
351+
t.Parallel()
352+
353+
// Create the list of tests
354+
var tests = []struct {
355+
input string
356+
expectedKey string
357+
expectedError bool
358+
}{
359+
{"", "", true},
360+
{"0", "", true},
361+
{"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAbuatmU", "0000000000000000000000000000000000000000000000000000000000000000", false},
362+
{"5HpHagT65TZzG1PH3CSu63k8DbuTZnNJf6HgyQNymvXmALAsm9s", "0000000000000000000000000000000000006d792070726976617465206b6579", false},
363+
{"54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8azz", "", true},
364+
{"5JTHas7yTFMBLqgFogxZFf8Vc5uKEbkE7yQAQ2g3xPHo2sNG1Ei", "54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8abd", false},
365+
}
366+
367+
// Run tests
368+
for _, test := range tests {
369+
if privateKey, err := WifToPrivateKeyString(test.input); err != nil && !test.expectedError {
370+
t.Errorf("%s Failed: [%s] inputted and error not expected but got: %s", t.Name(), test.input, err.Error())
371+
} else if err == nil && test.expectedError {
372+
t.Errorf("%s Failed: [%s] inputted and error was expected", t.Name(), test.input)
373+
} else if privateKey != test.expectedKey {
374+
t.Errorf("%s Failed: [%s] inputted [%s] expected but failed comparison of keys, got: %s", t.Name(), test.input, test.expectedKey, privateKey)
375+
}
376+
}
377+
}
378+
379+
// ExampleWifToPrivateKeyString example using WifToPrivateKeyString()
380+
func ExampleWifToPrivateKeyString() {
381+
privateKey, err := WifToPrivateKeyString("5JTHas7yTFMBLqgFogxZFf8Vc5uKEbkE7yQAQ2g3xPHo2sNG1Ei")
382+
if err != nil {
383+
fmt.Printf("error occurred: %s", err.Error())
384+
return
385+
}
386+
fmt.Printf("private key: %s", privateKey)
387+
388+
// Output:private key: 54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8abd
389+
}
390+
391+
// BenchmarkWifToPrivateKeyString benchmarks the method WifToPrivateKeyString()
392+
func BenchmarkWifToPrivateKeyString(b *testing.B) {
393+
for i := 0; i < b.N; i++ {
394+
_, _ = WifToPrivateKeyString("5JTHas7yTFMBLqgFogxZFf8Vc5uKEbkE7yQAQ2g3xPHo2sNG1Ei")
395+
}
396+
}

0 commit comments

Comments
 (0)