block index checking on load, extra redundant checks, misc refactoring
[novacoin.git] / base58.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto\r
2 // Distributed under the MIT/X11 software license, see the accompanying\r
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.\r
4 \r
5 \r
6 //\r
7 // Why base-58 instead of standard base-64 encoding?\r
8 // - Don't want 0OIl characters that look the same in some fonts and\r
9 //      could be used to create visually identical looking account numbers.\r
10 // - A string with non-alphanumeric characters is not as easily accepted as an account number.\r
11 // - E-mail usually won't line-break if there's no punctuation to break at.\r
12 // - Doubleclicking selects the whole number as one word if it's all alphanumeric.\r
13 //\r
14 \r
15 \r
16 static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";\r
17 \r
18 \r
19 inline string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)\r
20 {\r
21     CAutoBN_CTX pctx;\r
22     CBigNum bn58 = 58;\r
23     CBigNum bn0 = 0;\r
24 \r
25     // Convert big endian data to little endian\r
26     // Extra zero at the end make sure bignum will interpret as a positive number\r
27     vector<unsigned char> vchTmp(pend-pbegin+1, 0);\r
28     reverse_copy(pbegin, pend, vchTmp.begin());\r
29 \r
30     // Convert little endian data to bignum\r
31     CBigNum bn;\r
32     bn.setvch(vchTmp);\r
33 \r
34     // Convert bignum to string\r
35     string str;\r
36     str.reserve((pend - pbegin) * 138 / 100 + 1);\r
37     CBigNum dv;\r
38     CBigNum rem;\r
39     while (bn > bn0)\r
40     {\r
41         if (!BN_div(&dv, &rem, &bn, &bn58, pctx))\r
42             throw bignum_error("EncodeBase58 : BN_div failed");\r
43         bn = dv;\r
44         unsigned int c = rem.getulong();\r
45         str += pszBase58[c];\r
46     }\r
47 \r
48     // Leading zeroes encoded as base58 zeros\r
49     for (const unsigned char* p = pbegin; p < pend && *p == 0; p++)\r
50         str += pszBase58[0];\r
51 \r
52     // Convert little endian string to big endian\r
53     reverse(str.begin(), str.end());\r
54     return str;\r
55 }\r
56 \r
57 inline string EncodeBase58(const vector<unsigned char>& vch)\r
58 {\r
59     return EncodeBase58(&vch[0], &vch[0] + vch.size());\r
60 }\r
61 \r
62 inline bool DecodeBase58(const char* psz, vector<unsigned char>& vchRet)\r
63 {\r
64     CAutoBN_CTX pctx;\r
65     vchRet.clear();\r
66     CBigNum bn58 = 58;\r
67     CBigNum bn = 0;\r
68     CBigNum bnChar;\r
69     while (isspace(*psz))\r
70         psz++;\r
71 \r
72     // Convert big endian string to bignum\r
73     for (const char* p = psz; *p; p++)\r
74     {\r
75         const char* p1 = strchr(pszBase58, *p);\r
76         if (p1 == NULL)\r
77         {\r
78             while (isspace(*p))\r
79                 p++;\r
80             if (*p != '\0')\r
81                 return false;\r
82             break;\r
83         }\r
84         bnChar.setulong(p1 - pszBase58);\r
85         if (!BN_mul(&bn, &bn, &bn58, pctx))\r
86             throw bignum_error("DecodeBase58 : BN_mul failed");\r
87         bn += bnChar;\r
88     }\r
89 \r
90     // Get bignum as little endian data\r
91     vector<unsigned char> vchTmp = bn.getvch();\r
92 \r
93     // Trim off sign byte if present\r
94     if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80)\r
95         vchTmp.erase(vchTmp.end()-1);\r
96 \r
97     // Restore leading zeros\r
98     int nLeadingZeros = 0;\r
99     for (const char* p = psz; *p == pszBase58[0]; p++)\r
100         nLeadingZeros++;\r
101     vchRet.assign(nLeadingZeros + vchTmp.size(), 0);\r
102 \r
103     // Convert little endian data to big endian\r
104     reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size());\r
105     return true;\r
106 }\r
107 \r
108 inline bool DecodeBase58(const string& str, vector<unsigned char>& vchRet)\r
109 {\r
110     return DecodeBase58(str.c_str(), vchRet);\r
111 }\r
112 \r
113 \r
114 \r
115 \r
116 \r
117 inline string EncodeBase58Check(const vector<unsigned char>& vchIn)\r
118 {\r
119     // add 4-byte hash check to the end\r
120     vector<unsigned char> vch(vchIn);\r
121     uint256 hash = Hash(vch.begin(), vch.end());\r
122     vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);\r
123     return EncodeBase58(vch);\r
124 }\r
125 \r
126 inline bool DecodeBase58Check(const char* psz, vector<unsigned char>& vchRet)\r
127 {\r
128     if (!DecodeBase58(psz, vchRet))\r
129         return false;\r
130     if (vchRet.size() < 4)\r
131     {\r
132         vchRet.clear();\r
133         return false;\r
134     }\r
135     uint256 hash = Hash(vchRet.begin(), vchRet.end()-4);\r
136     if (memcmp(&hash, &vchRet.end()[-4], 4) != 0)\r
137     {\r
138         vchRet.clear();\r
139         return false;\r
140     }\r
141     vchRet.resize(vchRet.size()-4);\r
142     return true;\r
143 }\r
144 \r
145 inline bool DecodeBase58Check(const string& str, vector<unsigned char>& vchRet)\r
146 {\r
147     return DecodeBase58Check(str.c_str(), vchRet);\r
148 }\r
149 \r
150 \r
151 \r
152 \r
153 \r
154 \r
155 static const unsigned char ADDRESSVERSION = 0;\r
156 \r
157 inline string Hash160ToAddress(uint160 hash160)\r
158 {\r
159     // add 1-byte version number to the front\r
160     vector<unsigned char> vch(1, ADDRESSVERSION);\r
161     vch.insert(vch.end(), UBEGIN(hash160), UEND(hash160));\r
162     return EncodeBase58Check(vch);\r
163 }\r
164 \r
165 inline bool AddressToHash160(const char* psz, uint160& hash160Ret)\r
166 {\r
167     vector<unsigned char> vch;\r
168     if (!DecodeBase58Check(psz, vch))\r
169         return false;\r
170     if (vch.empty())\r
171         return false;\r
172     unsigned char nVersion = vch[0];\r
173     if (vch.size() != sizeof(hash160Ret) + 1)\r
174         return false;\r
175     memcpy(&hash160Ret, &vch[1], sizeof(hash160Ret));\r
176     return (nVersion <= ADDRESSVERSION);\r
177 }\r
178 \r
179 inline bool AddressToHash160(const string& str, uint160& hash160Ret)\r
180 {\r
181     return AddressToHash160(str.c_str(), hash160Ret);\r
182 }\r
183 \r
184 inline bool IsValidBitcoinAddress(const char* psz)\r
185 {\r
186     uint160 hash160;\r
187     return AddressToHash160(psz, hash160);\r
188 }\r
189 \r
190 inline bool IsValidBitcoinAddress(const string& str)\r
191 {\r
192     return IsValidBitcoinAddress(str.c_str());\r
193 }\r
194 \r
195 \r
196 \r
197 \r
198 inline string PubKeyToAddress(const vector<unsigned char>& vchPubKey)\r
199 {\r
200     return Hash160ToAddress(Hash160(vchPubKey));\r
201 }\r