Feathercoin  0.5.0
P2P Digital Currency
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
base58_tests.cpp
Go to the documentation of this file.
1 #include <boost/test/unit_test.hpp>
5 
6 #include "base58.h"
7 #include "util.h"
8 
9 using namespace json_spirit;
10 extern Array read_json(const std::string& filename);
11 
12 BOOST_AUTO_TEST_SUITE(base58_tests)
13 
14 // Goal: test low-level base58 encoding functionality
15 BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
16 {
17  Array tests = read_json("base58_encode_decode.json");
18 
19  BOOST_FOREACH(Value& tv, tests)
20  {
21  Array test = tv.get_array();
22  std::string strTest = write_string(tv, false);
23  if (test.size() < 2) // Allow for extra stuff (useful for comments)
24  {
25  BOOST_ERROR("Bad test: " << strTest);
26  continue;
27  }
28  std::vector<unsigned char> sourcedata = ParseHex(test[0].get_str());
29  std::string base58string = test[1].get_str();
30  BOOST_CHECK_MESSAGE(
31  EncodeBase58(&sourcedata[0], &sourcedata[sourcedata.size()]) == base58string,
32  strTest);
33  }
34 }
35 
36 // Goal: test low-level base58 decoding functionality
37 BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
38 {
39  Array tests = read_json("base58_encode_decode.json");
40  std::vector<unsigned char> result;
41 
42  BOOST_FOREACH(Value& tv, tests)
43  {
44  Array test = tv.get_array();
45  std::string strTest = write_string(tv, false);
46  if (test.size() < 2) // Allow for extra stuff (useful for comments)
47  {
48  BOOST_ERROR("Bad test: " << strTest);
49  continue;
50  }
51  std::vector<unsigned char> expected = ParseHex(test[0].get_str());
52  std::string base58string = test[1].get_str();
53  BOOST_CHECK_MESSAGE(DecodeBase58(base58string, result), strTest);
54  BOOST_CHECK_MESSAGE(result.size() == expected.size() && std::equal(result.begin(), result.end(), expected.begin()), strTest);
55  }
56 
57  BOOST_CHECK(!DecodeBase58("invalid", result));
58 }
59 
60 // Visitor to check address type
61 class TestAddrTypeVisitor : public boost::static_visitor<bool>
62 {
63 private:
64  std::string exp_addrType;
65 public:
66  TestAddrTypeVisitor(const std::string &exp_addrType) : exp_addrType(exp_addrType) { }
67  bool operator()(const CKeyID &id) const
68  {
69  return (exp_addrType == "pubkey");
70  }
71  bool operator()(const CScriptID &id) const
72  {
73  return (exp_addrType == "script");
74  }
75  bool operator()(const CNoDestination &no) const
76  {
77  return (exp_addrType == "none");
78  }
79 };
80 
81 // Visitor to check address payload
82 class TestPayloadVisitor : public boost::static_visitor<bool>
83 {
84 private:
85  std::vector<unsigned char> exp_payload;
86 public:
87  TestPayloadVisitor(std::vector<unsigned char> &exp_payload) : exp_payload(exp_payload) { }
88  bool operator()(const CKeyID &id) const
89  {
90  uint160 exp_key(exp_payload);
91  return exp_key == id;
92  }
93  bool operator()(const CScriptID &id) const
94  {
95  uint160 exp_key(exp_payload);
96  return exp_key == id;
97  }
98  bool operator()(const CNoDestination &no) const
99  {
100  return exp_payload.size() == 0;
101  }
102 };
103 
104 // Goal: check that parsed keys match test payload
105 BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
106 {
107  Array tests = read_json("base58_keys_valid.json");
108  std::vector<unsigned char> result;
109  CBitcoinSecret secret;
110  CBitcoinAddress addr;
111  // Save global state
112  bool fTestNet_stored = fTestNet;
113 
114  BOOST_FOREACH(Value& tv, tests)
115  {
116  Array test = tv.get_array();
117  std::string strTest = write_string(tv, false);
118  if (test.size() < 3) // Allow for extra stuff (useful for comments)
119  {
120  BOOST_ERROR("Bad test: " << strTest);
121  continue;
122  }
123  std::string exp_base58string = test[0].get_str();
124  std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
125  const Object &metadata = test[2].get_obj();
126  bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
127  bool isTestnet = find_value(metadata, "isTestnet").get_bool();
128  fTestNet = isTestnet; // Override testnet flag
129  if(isPrivkey)
130  {
131  bool isCompressed = find_value(metadata, "isCompressed").get_bool();
132  // Must be valid private key
133  // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not!
134  BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest);
135  BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest);
136  CKey privkey = secret.GetKey();
137  BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);
138  BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
139 
140  // Private key must be invalid public key
141  addr.SetString(exp_base58string);
142  BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest);
143  }
144  else
145  {
146  std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey"
147  // Must be valid public key
148  BOOST_CHECK_MESSAGE(addr.SetString(exp_base58string), "SetString:" + strTest);
149  BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest);
150  BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest);
151  CTxDestination dest = addr.Get();
152  BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest);
153 
154  // Public key must be invalid private key
155  secret.SetString(exp_base58string);
156  BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest);
157  }
158  }
159  // Restore global state
160  fTestNet = fTestNet_stored;
161 }
162 
163 // Goal: check that generated keys match test vectors
164 BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
165 {
166  Array tests = read_json("base58_keys_valid.json");
167  std::vector<unsigned char> result;
168  // Save global state
169  bool fTestNet_stored = fTestNet;
170 
171  BOOST_FOREACH(Value& tv, tests)
172  {
173  Array test = tv.get_array();
174  std::string strTest = write_string(tv, false);
175  if (test.size() < 3) // Allow for extra stuff (useful for comments)
176  {
177  BOOST_ERROR("Bad test: " << strTest);
178  continue;
179  }
180  std::string exp_base58string = test[0].get_str();
181  std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
182  const Object &metadata = test[2].get_obj();
183  bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
184  bool isTestnet = find_value(metadata, "isTestnet").get_bool();
185  fTestNet = isTestnet; // Override testnet flag
186  if(isPrivkey)
187  {
188  bool isCompressed = find_value(metadata, "isCompressed").get_bool();
189  CKey key;
190  key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
191  assert(key.IsValid());
192  CBitcoinSecret secret;
193  secret.SetKey(key);
194  BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest);
195  }
196  else
197  {
198  std::string exp_addrType = find_value(metadata, "addrType").get_str();
199  CTxDestination dest;
200  if(exp_addrType == "pubkey")
201  {
202  dest = CKeyID(uint160(exp_payload));
203  }
204  else if(exp_addrType == "script")
205  {
206  dest = CScriptID(uint160(exp_payload));
207  }
208  else if(exp_addrType == "none")
209  {
210  dest = CNoDestination();
211  }
212  else
213  {
214  BOOST_ERROR("Bad addrtype: " << strTest);
215  continue;
216  }
217  CBitcoinAddress addrOut;
218  BOOST_CHECK_MESSAGE(boost::apply_visitor(CBitcoinAddressVisitor(&addrOut), dest), "encode dest: " + strTest);
219  BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest);
220  }
221  }
222 
223  // Visiting a CNoDestination must fail
224  CBitcoinAddress dummyAddr;
225  CTxDestination nodest = CNoDestination();
226  BOOST_CHECK(!boost::apply_visitor(CBitcoinAddressVisitor(&dummyAddr), nodest));
227 
228  // Restore global state
229  fTestNet = fTestNet_stored;
230 }
231 
232 // Goal: check that base58 parsing code is robust against a variety of corrupted data
233 BOOST_AUTO_TEST_CASE(base58_keys_invalid)
234 {
235  Array tests = read_json("base58_keys_invalid.json"); // Negative testcases
236  std::vector<unsigned char> result;
237  CBitcoinSecret secret;
238  CBitcoinAddress addr;
239 
240  BOOST_FOREACH(Value& tv, tests)
241  {
242  Array test = tv.get_array();
243  std::string strTest = write_string(tv, false);
244  if (test.size() < 1) // Allow for extra stuff (useful for comments)
245  {
246  BOOST_ERROR("Bad test: " << strTest);
247  continue;
248  }
249  std::string exp_base58string = test[0].get_str();
250 
251  // must be invalid as public and as private key
252  addr.SetString(exp_base58string);
253  BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest);
254  secret.SetString(exp_base58string);
255  BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest);
256  }
257 }
258 
259 
260 BOOST_AUTO_TEST_SUITE_END()
261 
bool operator()(const CScriptID &id) const
bool IsValid() const
Definition: base58.h:296
void SetKey(const CKey &vchSecret)
Definition: base58.h:407
bool IsScript() const
Definition: base58.h:380
CKey GetKey()
Definition: base58.h:415
BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
bool DecodeBase58(const char *psz, std::vector< unsigned char > &vchRet)
Definition: base58.h:77
bool operator()(const CScriptID &id) const
Array read_json(const std::string &filename)
std::string exp_addrType
bool operator()(const CKeyID &id) const
bool operator()(const CNoDestination &no) const
bool IsValid() const
Definition: base58.h:422
CTxDestination Get() const
Definition: base58.h:345
Config::Object_type Object
const Array & get_array() const
bool IsValid() const
Definition: key.h:226
bool SetString(const char *pszSecret)
Definition: base58.h:440
bool fTestNet
Definition: util.cpp:81
bool operator()(const CNoDestination &no) const
A base58-encoded secret key.
Definition: base58.h:398
TestAddrTypeVisitor(const std::string &exp_addrType)
const Object_type::value_type::Value_type & find_value(const Object_type &obj, const String_type &name)
std::string ToString() const
Definition: base58.h:229
Config::Array_type Array
DBTest * test
Definition: db_test.cc:1701
void Set(const T pbegin, const T pend, bool fCompressedIn)
Definition: key.h:206
TestPayloadVisitor(std::vector< unsigned char > &exp_payload)
bool operator()(const CKeyID &id) const
Value_type::String_type write_string(const Value_type &value, bool pretty)
std::vector< unsigned char > exp_payload
A reference to a CKey: the Hash160 of its serialized public key.
Definition: key.h:24
160-bit unsigned integer
Definition: uint256.h:422
bool SetString(const char *psz)
Definition: base58.h:206
std::string EncodeBase58(const unsigned char *pbegin, const unsigned char *pend)
Definition: base58.h:29
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: key.h:32
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: script.h:62
An encapsulated private key.
Definition: key.h:172
std::string get_str(std::string::const_iterator begin, std::string::const_iterator end)
int id
Definition: db_test.cc:1709
vector< unsigned char > ParseHex(const char *psz)
Definition: util.cpp:500