1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package libkb
5
6import (
7	"encoding/hex"
8	"testing"
9)
10
11func doBase58Test(t *testing.T, startingHex, expectedBase58 string) {
12	startingBytes, err := hex.DecodeString(startingHex)
13	if err != nil {
14		t.Fatalf("Not valid hex: '%s'", startingHex)
15	}
16	base58 := Base58.EncodeToString(startingBytes)
17	if base58 != expectedBase58 {
18		t.Fatalf("'%s' was converted to '%s' instead of '%s'", startingHex, base58, expectedBase58)
19	}
20	backToBytes, err := Base58.DecodeString(base58)
21	if err != nil {
22		t.Fatalf("Not valid base58: '%s'", base58)
23	}
24	backToHex := hex.EncodeToString(backToBytes)
25	if backToHex != startingHex {
26		t.Fatalf("'%s' round tripped to '%s'", startingHex, backToHex)
27	}
28}
29
30func TestBase58(t *testing.T) {
31	doBase58Test(t, "", "")
32	doBase58Test(t, "00", "1")
33	doBase58Test(t, "0000", "11")
34	doBase58Test(t, "01", "2")
35	doBase58Test(t, "00ff00", "1LQX")
36}
37
38var testVectors = []struct {
39	address    string
40	wantedType CryptocurrencyType
41}{
42	{"zcCk6rKzynC4tT1Rmg325A5Xw81Ck3S6nD6mtPWCXaMtyFczkyU4kYjEhrcz2QKfF5T2siWGyJNxWo43XWT3qk5YpPhFGj2", CryptocurrencyTypeZCashShielded},
43	{"zcCk6rKzynC4tT1Rmg325A5Xw81Ck3S6nD6mtPWCXaMtyFczkyU4kYjEhrcz2QKfF5T2siWGyJNxWo43XWT3qk5YpPhFGj2x", CryptocurrencyTypeNone},
44	{"zcCk6rKzynC4tT1Rmg325A5Xw81Ck3S6nD6mtPWCXaMtyFczkyU4kYjEhrcz2QKfF5T2siWGyJNxWo43XWT3qk5YpPhFGj3", CryptocurrencyTypeNone},
45	{"t1c3Ebc6FBbWuirNrjJ6HbS4KHLb6Dbh5xL", CryptocurrencyTypeZCashTransparentP2PKH},
46	{"t1c3Ebc6FBbWuirNrjJ6HbS4KHLb6Dbh5xLx", CryptocurrencyTypeNone},
47	{"t1c3Ebc6FBbWuirNrjJ6HbS4KHLb6Dbh5xx", CryptocurrencyTypeNone},
48	{"3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy", CryptocurrencyTypeBTCMultiSig},
49	{"3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLyx", CryptocurrencyTypeNone},
50	{"3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLx", CryptocurrencyTypeNone},
51	{"zs165czn4y5jfa552kux7yl3y5l8ge4cl6af45y9dh3yzfnkgd68vajyjdlkht54ve958qx693jjak", CryptocurrencyTypeZCashSapling},
52	{"zs1x2q4pej08shm9pd5fx8jvl97f8f7t8sej8lsgp08jsczxsucr5gkff0yasc0gc43dtv3wczerv5", CryptocurrencyTypeZCashSapling},
53	{"zs1fw4tgx9gccv2f8af6ugu727slx7pq0nc46yflcuqyluruxtcmg20hxh3r4d9ec9yejj6gfrf2hc", CryptocurrencyTypeZCashSapling},
54	{"ZS1FW4TGX9GCCV2F8AF6UGU727SLX7PQ0NC46YFLCUQYLURUXTCMG20HXH3R4D9EC9YEJJ6GFRF2HC", CryptocurrencyTypeZCashSapling},
55	{"zs1fw4tgx9gccv2f8af6ugu727slx7pq0nc46yflcuqyluruxtcmg20hxh3r4d9ec9yejj6gfrf2hd", CryptocurrencyTypeNone},
56	{"bc1qcerjvfmt8qr8xlp6pv4htjhwlj2wgdjnayc3cc", CryptocurrencyTypeBTCSegwit},
57}
58
59func TestCryptocurrencyParseAndCheck(t *testing.T) {
60	for i, v := range testVectors {
61		typ, _, err := CryptocurrencyParseAndCheck(v.address)
62		if typ != v.wantedType {
63			t.Fatalf("Address %s (%d): got wrong CryptocurrencyTyp: %d != %d (%v)", v.address, i, typ, v.wantedType, err)
64		}
65	}
66}
67
68func TestAddressValidation(t *testing.T) {
69	btcTestAddrs := []struct {
70		address string
71		valid   bool
72	}{
73		{"3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy", true},
74		{"4J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy", false}, // changed first digit
75		{"bc1qcerjvfmt8qr8xlp6pv4htjhwlj2wgdjnayc3cc", true},
76		{"bc1qcerjvfmt8qr8xlp6pv4htjhwlj2wgdjnaycccc", false}, // bad checksum
77		{"bc11cerjvfmt8qr8xlp6pv4htjhwlj2wgdjnayc3cc", false},
78		{"bc20cerjvfmt8qr8xlp6pv4htjhwlj2wgdjnayc3cc", false},
79		{"bc1q7k78aepp3epmlzvxwvvhc4up849efeg7r5j0xk", true},
80		{"BC1QCERJVFMT8QR8XLP6PV4HTJHWLJ2WGDJNAYC3CC", true}, // uppercase is accepted
81		{"bc1qc7slrfxkknqcq2jevvvkdgvrt8080852dfjewde450xdlk4ugp7szw5tk9", true},
82	}
83	for _, testAddr := range btcTestAddrs {
84		_, _, err := BtcAddrCheck(testAddr.address, nil)
85		if testAddr.valid && err != nil {
86			t.Fatalf("Failed to validate a good address %s.", testAddr.address)
87		}
88		if !testAddr.valid && err == nil {
89			t.Fatalf("Failed to catch a bad address %s.", testAddr.address)
90		}
91	}
92}
93