Line data Source code
1 : // Copyright (c) 2014-2021 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 :
5 : #include <key_io.h>
6 :
7 : #include <base58.h>
8 : #include <bech32.h>
9 : #include <chainparams.h>
10 : #include <util/strencodings.h>
11 :
12 : #include <algorithm>
13 : #include <assert.h>
14 : #include <string.h>
15 :
16 : namespace {
17 : class DestinationEncoder
18 : {
19 : private:
20 : const CChainParams& m_params;
21 :
22 : public:
23 676536 : explicit DestinationEncoder(const CChainParams& params) : m_params(params) {}
24 :
25 291283 : std::string operator()(const PKHash& id) const
26 : {
27 291283 : std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
28 291283 : data.insert(data.end(), id.begin(), id.end());
29 291283 : return EncodeBase58Check(data);
30 291283 : }
31 :
32 25702 : std::string operator()(const ScriptHash& id) const
33 : {
34 25702 : std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
35 25702 : data.insert(data.end(), id.begin(), id.end());
36 25702 : return EncodeBase58Check(data);
37 25702 : }
38 :
39 21283 : std::string operator()(const CNoDestination& no) const { return {}; }
40 : };
41 :
42 92550 : CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str)
43 : {
44 92550 : std::vector<unsigned char> data;
45 92550 : uint160 hash;
46 92550 : error_str = "";
47 92550 : if (DecodeBase58Check(str, data, 21)) {
48 : // base58-encoded Dash addresses.
49 : // Public-key-hash-addresses have version 76 (or 140 testnet).
50 : // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
51 92328 : const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
52 92328 : if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
53 91224 : std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
54 91224 : return PKHash(hash);
55 : }
56 : // Script-hash-addresses have version 16 (or 19 testnet).
57 : // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
58 1104 : const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
59 1104 : if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
60 1050 : std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
61 1050 : return ScriptHash(hash);
62 : }
63 :
64 : // Set potential error message.
65 54 : error_str = "Invalid prefix for Base58-encoded address";
66 54 : }
67 : // Set error message if address can't be interpreted as Base58.
68 276 : if (error_str.empty()) error_str = "Invalid address format";
69 :
70 276 : return CNoDestination();
71 92550 : }
72 : } // namespace
73 :
74 1004517 : CKey DecodeSecret(const std::string& str)
75 : {
76 1004517 : CKey key;
77 1004517 : std::vector<unsigned char> data;
78 1004517 : if (DecodeBase58Check(str, data, 34)) {
79 1004384 : const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
80 2008711 : if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
81 1004327 : std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
82 1004301 : bool compressed = data.size() == 33 + privkey_prefix.size();
83 1004301 : key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
84 1004301 : }
85 1004384 : }
86 1004517 : if (!data.empty()) {
87 1004384 : memory_cleanse(data.data(), data.size());
88 1004384 : }
89 1004517 : return key;
90 1004517 : }
91 :
92 3986 : std::string EncodeSecret(const CKey& key)
93 : {
94 3986 : assert(key.IsValid());
95 3986 : std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
96 3986 : data.insert(data.end(), key.begin(), key.end());
97 3986 : if (key.IsCompressed()) {
98 3962 : data.push_back(1);
99 3962 : }
100 3986 : std::string ret = EncodeBase58Check(data);
101 3986 : memory_cleanse(data.data(), data.size());
102 3986 : return ret;
103 3986 : }
104 :
105 2854 : CExtPubKey DecodeExtPubKey(const std::string& str)
106 : {
107 2854 : CExtPubKey key;
108 2854 : std::vector<unsigned char> data;
109 2854 : if (DecodeBase58Check(str, data, 78)) {
110 2853 : const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
111 2853 : if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
112 2579 : key.Decode(data.data() + prefix.size());
113 2579 : }
114 2853 : }
115 : return key;
116 2854 : }
117 :
118 79657 : std::string EncodeExtPubKey(const CExtPubKey& key)
119 : {
120 79657 : std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
121 79657 : size_t size = data.size();
122 79657 : data.resize(size + BIP32_EXTKEY_SIZE);
123 79657 : key.Encode(data.data() + size);
124 79657 : std::string ret = EncodeBase58Check(data);
125 79657 : return ret;
126 79657 : }
127 :
128 2854 : CExtKey DecodeExtKey(const std::string& str)
129 : {
130 2854 : CExtKey key;
131 2854 : std::vector<unsigned char> data;
132 2854 : if (DecodeBase58Check(str, data, 78)) {
133 2853 : const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
134 2853 : if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
135 285 : key.Decode(data.data() + prefix.size());
136 285 : }
137 2853 : }
138 2854 : return key;
139 2854 : }
140 :
141 247 : std::string EncodeExtKey(const CExtKey& key)
142 : {
143 247 : std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
144 247 : size_t size = data.size();
145 247 : data.resize(size + BIP32_EXTKEY_SIZE);
146 247 : key.Encode(data.data() + size);
147 247 : std::string ret = EncodeBase58Check(data);
148 247 : if (!data.empty()) {
149 247 : memory_cleanse(data.data(), data.size());
150 247 : }
151 247 : return ret;
152 247 : }
153 :
154 338268 : std::string EncodeDestination(const CTxDestination& dest)
155 : {
156 338268 : return std::visit(DestinationEncoder(Params()), dest);
157 : }
158 :
159 92270 : CTxDestination DecodeDestination(const std::string& str, std::string& error_msg)
160 : {
161 92270 : return DecodeDestination(str, Params(), error_msg);
162 : }
163 :
164 90192 : CTxDestination DecodeDestination(const std::string& str)
165 : {
166 90192 : std::string error_msg;
167 90192 : return DecodeDestination(str, error_msg);
168 90192 : }
169 :
170 280 : bool IsValidDestinationString(const std::string& str, const CChainParams& params)
171 : {
172 280 : std::string error_msg;
173 280 : return IsValidDestination(DecodeDestination(str, params, error_msg));
174 280 : }
175 :
176 280 : bool IsValidDestinationString(const std::string& str)
177 : {
178 280 : return IsValidDestinationString(str, Params());
179 : }
180 :
181 : namespace {
182 : constexpr uint8_t DIP18_TYPE_BYTE_P2PKH = 0xb0;
183 : constexpr uint8_t DIP18_TYPE_BYTE_P2SH = 0x80;
184 : constexpr size_t DIP18_PAYLOAD_SIZE = 21; // 1 type byte + 20-byte HASH160
185 :
186 8 : std::string EncodePlatformBech32m(const CChainParams& params, uint8_t type_byte, const BaseHash<uint160>& hash)
187 : {
188 8 : std::vector<uint8_t> payload;
189 8 : payload.reserve(DIP18_PAYLOAD_SIZE);
190 8 : payload.push_back(type_byte);
191 8 : payload.insert(payload.end(), hash.begin(), hash.end());
192 8 : std::vector<uint8_t> values;
193 8 : values.reserve(((DIP18_PAYLOAD_SIZE * 8) + 4) / 5);
194 280 : ConvertBits<8, 5, true>([&](uint8_t v) { values.push_back(v); }, payload.begin(), payload.end());
195 8 : return bech32::Encode(bech32::Encoding::BECH32M, params.Bech32PlatformHRP(), values);
196 8 : }
197 :
198 : class PlatformDestinationEncoder
199 : {
200 : private:
201 : const CChainParams& m_params;
202 :
203 : public:
204 16 : explicit PlatformDestinationEncoder(const CChainParams& params) : m_params(params) {}
205 :
206 6 : std::string operator()(const PlatformP2PKHDestination& id) const
207 : {
208 6 : return EncodePlatformBech32m(m_params, DIP18_TYPE_BYTE_P2PKH, id);
209 : }
210 2 : std::string operator()(const PlatformP2SHDestination& id) const
211 : {
212 2 : return EncodePlatformBech32m(m_params, DIP18_TYPE_BYTE_P2SH, id);
213 : }
214 0 : std::string operator()(const CNoDestination&) const { return {}; }
215 : };
216 : } // namespace
217 :
218 16 : bool IsValidPlatformDestination(const PlatformDestination& dest)
219 : {
220 16 : return !std::holds_alternative<CNoDestination>(dest);
221 : }
222 :
223 8 : std::string EncodePlatformDestination(const PlatformDestination& dest)
224 : {
225 8 : return std::visit(PlatformDestinationEncoder(Params()), dest);
226 : }
227 :
228 16 : PlatformDestination DecodePlatformDestination(const std::string& str, const CChainParams& params, std::string& error_str)
229 : {
230 16 : error_str.clear();
231 16 : const bech32::DecodeResult dec = bech32::Decode(str);
232 16 : if (dec.encoding == bech32::Encoding::INVALID) {
233 3 : error_str = "Invalid bech32m encoding";
234 3 : return CNoDestination();
235 : }
236 13 : if (dec.encoding != bech32::Encoding::BECH32M) {
237 1 : error_str = "DIP-18 Platform addresses require bech32m checksum";
238 1 : return CNoDestination();
239 : }
240 12 : if (dec.hrp != params.Bech32PlatformHRP()) {
241 2 : error_str = "Invalid Platform HRP for the selected network";
242 2 : return CNoDestination();
243 : }
244 10 : std::vector<uint8_t> payload;
245 10 : payload.reserve((dec.data.size() * 5) / 8);
246 219 : if (!ConvertBits<5, 8, false>([&](uint8_t b) { payload.push_back(b); }, dec.data.begin(), dec.data.end())) {
247 0 : error_str = "Invalid Platform address payload encoding";
248 0 : return CNoDestination();
249 : }
250 10 : if (payload.size() != DIP18_PAYLOAD_SIZE) {
251 1 : error_str = "Invalid Platform address payload length";
252 1 : return CNoDestination();
253 : }
254 9 : uint160 hash;
255 9 : std::copy(payload.begin() + 1, payload.end(), hash.begin());
256 9 : switch (payload[0]) {
257 : case DIP18_TYPE_BYTE_P2PKH:
258 6 : return PlatformP2PKHDestination(hash);
259 : case DIP18_TYPE_BYTE_P2SH:
260 2 : return PlatformP2SHDestination(hash);
261 : }
262 1 : error_str = "Unknown DIP-18 type byte";
263 1 : return CNoDestination();
264 16 : }
265 :
266 16 : PlatformDestination DecodePlatformDestination(const std::string& str, std::string& error_str)
267 : {
268 16 : return DecodePlatformDestination(str, Params(), error_str);
269 : }
270 :
271 0 : PlatformDestination DecodePlatformDestination(const std::string& str)
272 : {
273 0 : std::string error_str;
274 0 : return DecodePlatformDestination(str, error_str);
275 0 : }
|