You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

base58_tests.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. // Copyright (c) 2011-2014 The Bitcoin Core developers
  2. // Distributed under the MIT software license, see the accompanying
  3. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4. #include "base58.h"
  5. #include "data/base58_encode_decode.json.h"
  6. #include "data/base58_keys_invalid.json.h"
  7. #include "data/base58_keys_valid.json.h"
  8. #include "key.h"
  9. #include "script/script.h"
  10. #include "uint256.h"
  11. #include "util.h"
  12. #include "utilstrencodings.h"
  13. #include "test/test_bitcoin.h"
  14. #include <boost/foreach.hpp>
  15. #include <boost/test/unit_test.hpp>
  16. #include "json/json_spirit_reader_template.h"
  17. #include "json/json_spirit_utils.h"
  18. #include "json/json_spirit_writer_template.h"
  19. using namespace json_spirit;
  20. extern Array read_json(const std::string& jsondata);
  21. BOOST_FIXTURE_TEST_SUITE(base58_tests, BasicTestingSetup)
  22. // Goal: test low-level base58 encoding functionality
  23. BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
  24. {
  25. Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
  26. BOOST_FOREACH(Value& tv, tests)
  27. {
  28. Array test = tv.get_array();
  29. std::string strTest = write_string(tv, false);
  30. if (test.size() < 2) // Allow for extra stuff (useful for comments)
  31. {
  32. BOOST_ERROR("Bad test: " << strTest);
  33. continue;
  34. }
  35. std::vector<unsigned char> sourcedata = ParseHex(test[0].get_str());
  36. std::string base58string = test[1].get_str();
  37. BOOST_CHECK_MESSAGE(
  38. EncodeBase58(begin_ptr(sourcedata), end_ptr(sourcedata)) == base58string,
  39. strTest);
  40. }
  41. }
  42. // Goal: test low-level base58 decoding functionality
  43. BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
  44. {
  45. Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
  46. std::vector<unsigned char> result;
  47. BOOST_FOREACH(Value& tv, tests)
  48. {
  49. Array test = tv.get_array();
  50. std::string strTest = write_string(tv, false);
  51. if (test.size() < 2) // Allow for extra stuff (useful for comments)
  52. {
  53. BOOST_ERROR("Bad test: " << strTest);
  54. continue;
  55. }
  56. std::vector<unsigned char> expected = ParseHex(test[0].get_str());
  57. std::string base58string = test[1].get_str();
  58. BOOST_CHECK_MESSAGE(DecodeBase58(base58string, result), strTest);
  59. BOOST_CHECK_MESSAGE(result.size() == expected.size() && std::equal(result.begin(), result.end(), expected.begin()), strTest);
  60. }
  61. BOOST_CHECK(!DecodeBase58("invalid", result));
  62. // check that DecodeBase58 skips whitespace, but still fails with unexpected non-whitespace at the end.
  63. BOOST_CHECK(!DecodeBase58(" \t\n\v\f\r skip \r\f\v\n\t a", result));
  64. BOOST_CHECK( DecodeBase58(" \t\n\v\f\r skip \r\f\v\n\t ", result));
  65. std::vector<unsigned char> expected = ParseHex("971a55");
  66. BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
  67. }
  68. // Visitor to check address type
  69. class TestAddrTypeVisitor : public boost::static_visitor<bool>
  70. {
  71. private:
  72. std::string exp_addrType;
  73. public:
  74. TestAddrTypeVisitor(const std::string &exp_addrType) : exp_addrType(exp_addrType) { }
  75. bool operator()(const CKeyID &id) const
  76. {
  77. return (exp_addrType == "pubkey");
  78. }
  79. bool operator()(const CScriptID &id) const
  80. {
  81. return (exp_addrType == "script");
  82. }
  83. bool operator()(const CNoDestination &no) const
  84. {
  85. return (exp_addrType == "none");
  86. }
  87. };
  88. // Visitor to check address payload
  89. class TestPayloadVisitor : public boost::static_visitor<bool>
  90. {
  91. private:
  92. std::vector<unsigned char> exp_payload;
  93. public:
  94. TestPayloadVisitor(std::vector<unsigned char> &exp_payload) : exp_payload(exp_payload) { }
  95. bool operator()(const CKeyID &id) const
  96. {
  97. uint160 exp_key(exp_payload);
  98. return exp_key == id;
  99. }
  100. bool operator()(const CScriptID &id) const
  101. {
  102. uint160 exp_key(exp_payload);
  103. return exp_key == id;
  104. }
  105. bool operator()(const CNoDestination &no) const
  106. {
  107. return exp_payload.size() == 0;
  108. }
  109. };
  110. // Goal: check that parsed keys match test payload
  111. BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
  112. {
  113. Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
  114. std::vector<unsigned char> result;
  115. CBitcoinSecret secret;
  116. CBitcoinAddress addr;
  117. SelectParams(CBaseChainParams::MAIN);
  118. BOOST_FOREACH(Value& tv, tests)
  119. {
  120. Array test = tv.get_array();
  121. std::string strTest = write_string(tv, false);
  122. if (test.size() < 3) // Allow for extra stuff (useful for comments)
  123. {
  124. BOOST_ERROR("Bad test: " << strTest);
  125. continue;
  126. }
  127. std::string exp_base58string = test[0].get_str();
  128. std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
  129. const Object &metadata = test[2].get_obj();
  130. bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
  131. bool isTestnet = find_value(metadata, "isTestnet").get_bool();
  132. if (isTestnet)
  133. SelectParams(CBaseChainParams::TESTNET);
  134. else
  135. SelectParams(CBaseChainParams::MAIN);
  136. if(isPrivkey)
  137. {
  138. bool isCompressed = find_value(metadata, "isCompressed").get_bool();
  139. // Must be valid private key
  140. // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not!
  141. BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest);
  142. BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest);
  143. CKey privkey = secret.GetKey();
  144. BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);
  145. BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
  146. // Private key must be invalid public key
  147. addr.SetString(exp_base58string);
  148. BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest);
  149. }
  150. else
  151. {
  152. std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey"
  153. // Must be valid public key
  154. BOOST_CHECK_MESSAGE(addr.SetString(exp_base58string), "SetString:" + strTest);
  155. BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest);
  156. BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest);
  157. CTxDestination dest = addr.Get();
  158. BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest);
  159. // Public key must be invalid private key
  160. secret.SetString(exp_base58string);
  161. BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest);
  162. }
  163. }
  164. }
  165. // Goal: check that generated keys match test vectors
  166. BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
  167. {
  168. Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
  169. std::vector<unsigned char> result;
  170. BOOST_FOREACH(Value& tv, tests)
  171. {
  172. Array test = tv.get_array();
  173. std::string strTest = write_string(tv, false);
  174. if (test.size() < 3) // Allow for extra stuff (useful for comments)
  175. {
  176. BOOST_ERROR("Bad test: " << strTest);
  177. continue;
  178. }
  179. std::string exp_base58string = test[0].get_str();
  180. std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
  181. const Object &metadata = test[2].get_obj();
  182. bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
  183. bool isTestnet = find_value(metadata, "isTestnet").get_bool();
  184. if (isTestnet)
  185. SelectParams(CBaseChainParams::TESTNET);
  186. else
  187. SelectParams(CBaseChainParams::MAIN);
  188. if(isPrivkey)
  189. {
  190. bool isCompressed = find_value(metadata, "isCompressed").get_bool();
  191. CKey key;
  192. key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
  193. assert(key.IsValid());
  194. CBitcoinSecret secret;
  195. secret.SetKey(key);
  196. BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest);
  197. }
  198. else
  199. {
  200. std::string exp_addrType = find_value(metadata, "addrType").get_str();
  201. CTxDestination dest;
  202. if(exp_addrType == "pubkey")
  203. {
  204. dest = CKeyID(uint160(exp_payload));
  205. }
  206. else if(exp_addrType == "script")
  207. {
  208. dest = CScriptID(uint160(exp_payload));
  209. }
  210. else if(exp_addrType == "none")
  211. {
  212. dest = CNoDestination();
  213. }
  214. else
  215. {
  216. BOOST_ERROR("Bad addrtype: " << strTest);
  217. continue;
  218. }
  219. CBitcoinAddress addrOut;
  220. BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest);
  221. BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest);
  222. }
  223. }
  224. // Visiting a CNoDestination must fail
  225. CBitcoinAddress dummyAddr;
  226. CTxDestination nodest = CNoDestination();
  227. BOOST_CHECK(!dummyAddr.Set(nodest));
  228. SelectParams(CBaseChainParams::MAIN);
  229. }
  230. // Goal: check that base58 parsing code is robust against a variety of corrupted data
  231. BOOST_AUTO_TEST_CASE(base58_keys_invalid)
  232. {
  233. Array tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
  234. std::vector<unsigned char> result;
  235. CBitcoinSecret secret;
  236. CBitcoinAddress addr;
  237. BOOST_FOREACH(Value& tv, tests)
  238. {
  239. Array test = tv.get_array();
  240. std::string strTest = write_string(tv, false);
  241. if (test.size() < 1) // Allow for extra stuff (useful for comments)
  242. {
  243. BOOST_ERROR("Bad test: " << strTest);
  244. continue;
  245. }
  246. std::string exp_base58string = test[0].get_str();
  247. // must be invalid as public and as private key
  248. addr.SetString(exp_base58string);
  249. BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest);
  250. secret.SetString(exp_base58string);
  251. BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest);
  252. }
  253. }
  254. BOOST_AUTO_TEST_SUITE_END()