1 // Copyright (c) 2014-2016 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.
9 #include "script/script.h"
11 #include "utilstrencodings.h"
13 #include <boost/variant/apply_visitor.hpp>
14 #include <boost/variant/static_visitor.hpp>
21 /** All alphanumeric characters except for "0", "I", "O", and "l" */
22 static const char* pszBase58
= "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
24 bool DecodeBase58(const char* psz
, std::vector
<unsigned char>& vch
)
26 // Skip leading spaces.
27 while (*psz
&& isspace(*psz
))
29 // Skip and count leading '1's.
36 // Allocate enough space in big-endian base256 representation.
37 int size
= strlen(psz
) * 733 /1000 + 1; // log(58) / log(256), rounded up.
38 std::vector
<unsigned char> b256(size
);
39 // Process the characters.
40 while (*psz
&& !isspace(*psz
)) {
41 // Decode base58 character
42 const char* ch
= strchr(pszBase58
, *psz
);
45 // Apply "b256 = b256 * 58 + ch".
46 int carry
= ch
- pszBase58
;
48 for (std::vector
<unsigned char>::reverse_iterator it
= b256
.rbegin(); (carry
!= 0 || i
< length
) && (it
!= b256
.rend()); ++it
, ++i
) {
57 // Skip trailing spaces.
62 // Skip leading zeroes in b256.
63 std::vector
<unsigned char>::iterator it
= b256
.begin() + (size
- length
);
64 while (it
!= b256
.end() && *it
== 0)
66 // Copy result into output vector.
67 vch
.reserve(zeroes
+ (b256
.end() - it
));
68 vch
.assign(zeroes
, 0x00);
69 while (it
!= b256
.end())
70 vch
.push_back(*(it
++));
74 std::string
EncodeBase58(const unsigned char* pbegin
, const unsigned char* pend
)
76 // Skip & count leading zeroes.
79 while (pbegin
!= pend
&& *pbegin
== 0) {
83 // Allocate enough space in big-endian base58 representation.
84 int size
= (pend
- pbegin
) * 138 / 100 + 1; // log(256) / log(58), rounded up.
85 std::vector
<unsigned char> b58(size
);
87 while (pbegin
!= pend
) {
90 // Apply "b58 = b58 * 256 + ch".
91 for (std::vector
<unsigned char>::reverse_iterator it
= b58
.rbegin(); (carry
!= 0 || i
< length
) && (it
!= b58
.rend()); it
++, i
++) {
101 // Skip leading zeroes in base58 result.
102 std::vector
<unsigned char>::iterator it
= b58
.begin() + (size
- length
);
103 while (it
!= b58
.end() && *it
== 0)
105 // Translate the result into a string.
107 str
.reserve(zeroes
+ (b58
.end() - it
));
108 str
.assign(zeroes
, '1');
109 while (it
!= b58
.end())
110 str
+= pszBase58
[*(it
++)];
114 std::string
EncodeBase58(const std::vector
<unsigned char>& vch
)
116 return EncodeBase58(vch
.data(), vch
.data() + vch
.size());
119 bool DecodeBase58(const std::string
& str
, std::vector
<unsigned char>& vchRet
)
121 return DecodeBase58(str
.c_str(), vchRet
);
124 std::string
EncodeBase58Check(const std::vector
<unsigned char>& vchIn
)
126 // add 4-byte hash check to the end
127 std::vector
<unsigned char> vch(vchIn
);
128 uint256 hash
= Hash(vch
.begin(), vch
.end());
129 vch
.insert(vch
.end(), (unsigned char*)&hash
, (unsigned char*)&hash
+ 4);
130 return EncodeBase58(vch
);
133 bool DecodeBase58Check(const char* psz
, std::vector
<unsigned char>& vchRet
)
135 if (!DecodeBase58(psz
, vchRet
) ||
136 (vchRet
.size() < 4)) {
140 // re-calculate the checksum, ensure it matches the included 4-byte checksum
141 uint256 hash
= Hash(vchRet
.begin(), vchRet
.end() - 4);
142 if (memcmp(&hash
, &vchRet
[vchRet
.size() - 4], 4) != 0) {
146 vchRet
.resize(vchRet
.size() - 4);
150 bool DecodeBase58Check(const std::string
& str
, std::vector
<unsigned char>& vchRet
)
152 return DecodeBase58Check(str
.c_str(), vchRet
);
155 CBase58Data::CBase58Data()
161 void CBase58Data::SetData(const std::vector
<unsigned char>& vchVersionIn
, const void* pdata
, size_t nSize
)
163 vchVersion
= vchVersionIn
;
164 vchData
.resize(nSize
);
165 if (!vchData
.empty())
166 memcpy(vchData
.data(), pdata
, nSize
);
169 void CBase58Data::SetData(const std::vector
<unsigned char>& vchVersionIn
, const unsigned char* pbegin
, const unsigned char* pend
)
171 SetData(vchVersionIn
, (void*)pbegin
, pend
- pbegin
);
174 bool CBase58Data::SetString(const char* psz
, unsigned int nVersionBytes
)
176 std::vector
<unsigned char> vchTemp
;
177 bool rc58
= DecodeBase58Check(psz
, vchTemp
);
178 if ((!rc58
) || (vchTemp
.size() < nVersionBytes
)) {
183 vchVersion
.assign(vchTemp
.begin(), vchTemp
.begin() + nVersionBytes
);
184 vchData
.resize(vchTemp
.size() - nVersionBytes
);
185 if (!vchData
.empty())
186 memcpy(vchData
.data(), vchTemp
.data() + nVersionBytes
, vchData
.size());
187 memory_cleanse(vchTemp
.data(), vchTemp
.size());
191 bool CBase58Data::SetString(const std::string
& str
)
193 return SetString(str
.c_str());
196 std::string
CBase58Data::ToString() const
198 std::vector
<unsigned char> vch
= vchVersion
;
199 vch
.insert(vch
.end(), vchData
.begin(), vchData
.end());
200 return EncodeBase58Check(vch
);
203 int CBase58Data::CompareTo(const CBase58Data
& b58
) const
205 if (vchVersion
< b58
.vchVersion
)
207 if (vchVersion
> b58
.vchVersion
)
209 if (vchData
< b58
.vchData
)
211 if (vchData
> b58
.vchData
)
218 class DestinationEncoder
: public boost::static_visitor
<std::string
>
221 const CChainParams
& m_params
;
224 DestinationEncoder(const CChainParams
& params
) : m_params(params
) {}
226 std::string
operator()(const CKeyID
& id
) const
228 std::vector
<unsigned char> data
= m_params
.Base58Prefix(CChainParams::PUBKEY_ADDRESS
);
229 data
.insert(data
.end(), id
.begin(), id
.end());
230 return EncodeBase58Check(data
);
233 std::string
operator()(const CScriptID
& id
) const
235 std::vector
<unsigned char> data
= m_params
.Base58Prefix(CChainParams::SCRIPT_ADDRESS
);
236 data
.insert(data
.end(), id
.begin(), id
.end());
237 return EncodeBase58Check(data
);
240 std::string
operator()(const WitnessV0KeyHash
& id
) const
242 std::vector
<unsigned char> data
= {0};
243 ConvertBits
<8, 5, true>(data
, id
.begin(), id
.end());
244 return bech32::Encode(m_params
.Bech32HRP(), data
);
247 std::string
operator()(const WitnessV0ScriptHash
& id
) const
249 std::vector
<unsigned char> data
= {0};
250 ConvertBits
<8, 5, true>(data
, id
.begin(), id
.end());
251 return bech32::Encode(m_params
.Bech32HRP(), data
);
254 std::string
operator()(const WitnessUnknown
& id
) const
256 if (id
.version
< 1 || id
.version
> 16 || id
.length
< 2 || id
.length
> 40) {
259 std::vector
<unsigned char> data
= {(unsigned char)id
.version
};
260 ConvertBits
<8, 5, true>(data
, id
.program
, id
.program
+ id
.length
);
261 return bech32::Encode(m_params
.Bech32HRP(), data
);
264 std::string
operator()(const CNoDestination
& no
) const { return {}; }
267 CTxDestination
DecodeDestination(const std::string
& str
, const CChainParams
& params
)
269 std::vector
<unsigned char> data
;
271 if (DecodeBase58Check(str
, data
)) {
272 // base58-encoded Bitcoin addresses.
273 // Public-key-hash-addresses have version 0 (or 111 testnet).
274 // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
275 const std::vector
<unsigned char>& pubkey_prefix
= params
.Base58Prefix(CChainParams::PUBKEY_ADDRESS
);
276 if (data
.size() == hash
.size() + pubkey_prefix
.size() && std::equal(pubkey_prefix
.begin(), pubkey_prefix
.end(), data
.begin())) {
277 std::copy(data
.begin() + pubkey_prefix
.size(), data
.end(), hash
.begin());
280 // Script-hash-addresses have version 5 (or 196 testnet).
281 // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
282 const std::vector
<unsigned char>& script_prefix
= params
.Base58Prefix(CChainParams::SCRIPT_ADDRESS
);
283 if (data
.size() == hash
.size() + script_prefix
.size() && std::equal(script_prefix
.begin(), script_prefix
.end(), data
.begin())) {
284 std::copy(data
.begin() + script_prefix
.size(), data
.end(), hash
.begin());
285 return CScriptID(hash
);
289 auto bech
= bech32::Decode(str
);
290 if (bech
.second
.size() > 0 && bech
.first
== params
.Bech32HRP()) {
292 int version
= bech
.second
[0]; // The first 5 bit symbol is the witness version (0-16)
293 // The rest of the symbols are converted witness program bytes.
294 if (ConvertBits
<5, 8, false>(data
, bech
.second
.begin() + 1, bech
.second
.end())) {
297 WitnessV0KeyHash keyid
;
298 if (data
.size() == keyid
.size()) {
299 std::copy(data
.begin(), data
.end(), keyid
.begin());
304 WitnessV0ScriptHash scriptid
;
305 if (data
.size() == scriptid
.size()) {
306 std::copy(data
.begin(), data
.end(), scriptid
.begin());
310 return CNoDestination();
312 if (version
> 16 || data
.size() < 2 || data
.size() > 40) {
313 return CNoDestination();
316 unk
.version
= version
;
317 std::copy(data
.begin(), data
.end(), unk
.program
);
318 unk
.length
= data
.size();
322 return CNoDestination();
326 void CBitcoinSecret::SetKey(const CKey
& vchSecret
)
328 assert(vchSecret
.IsValid());
329 SetData(Params().Base58Prefix(CChainParams::SECRET_KEY
), vchSecret
.begin(), vchSecret
.size());
330 if (vchSecret
.IsCompressed())
331 vchData
.push_back(1);
334 CKey
CBitcoinSecret::GetKey()
337 assert(vchData
.size() >= 32);
338 ret
.Set(vchData
.begin(), vchData
.begin() + 32, vchData
.size() > 32 && vchData
[32] == 1);
342 bool CBitcoinSecret::IsValid() const
344 bool fExpectedFormat
= vchData
.size() == 32 || (vchData
.size() == 33 && vchData
[32] == 1);
345 bool fCorrectVersion
= vchVersion
== Params().Base58Prefix(CChainParams::SECRET_KEY
);
346 return fExpectedFormat
&& fCorrectVersion
;
349 bool CBitcoinSecret::SetString(const char* pszSecret
)
351 return CBase58Data::SetString(pszSecret
) && IsValid();
354 bool CBitcoinSecret::SetString(const std::string
& strSecret
)
356 return SetString(strSecret
.c_str());
359 std::string
EncodeDestination(const CTxDestination
& dest
)
361 return boost::apply_visitor(DestinationEncoder(Params()), dest
);
364 CTxDestination
DecodeDestination(const std::string
& str
)
366 return DecodeDestination(str
, Params());
369 bool IsValidDestinationString(const std::string
& str
, const CChainParams
& params
)
371 return IsValidDestination(DecodeDestination(str
, params
));
374 bool IsValidDestinationString(const std::string
& str
)
376 return IsValidDestinationString(str
, Params());