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 77396 : explicit DestinationEncoder(const CChainParams& params) : m_params(params) {}
24 :
25 32065 : std::string operator()(const PKHash& id) const
26 : {
27 32065 : std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
28 32065 : data.insert(data.end(), id.begin(), id.end());
29 32065 : return EncodeBase58Check(data);
30 32065 : }
31 :
32 53 : std::string operator()(const ScriptHash& id) const
33 : {
34 53 : std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
35 53 : data.insert(data.end(), id.begin(), id.end());
36 53 : return EncodeBase58Check(data);
37 53 : }
38 :
39 6580 : std::string operator()(const CNoDestination& no) const { return {}; }
40 : };
41 :
42 6476 : CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str)
43 : {
44 6476 : std::vector<unsigned char> data;
45 6476 : uint160 hash;
46 6476 : error_str = "";
47 6476 : 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 6312 : const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
52 6312 : if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
53 6246 : std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
54 6246 : 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 66 : const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
59 66 : if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
60 26 : std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
61 26 : return ScriptHash(hash);
62 : }
63 :
64 : // Set potential error message.
65 40 : error_str = "Invalid prefix for Base58-encoded address";
66 40 : }
67 : // Set error message if address can't be interpreted as Base58.
68 204 : if (error_str.empty()) error_str = "Invalid address format";
69 :
70 204 : return CNoDestination();
71 6476 : }
72 : } // namespace
73 :
74 267 : CKey DecodeSecret(const std::string& str)
75 : {
76 267 : CKey key;
77 267 : std::vector<unsigned char> data;
78 267 : if (DecodeBase58Check(str, data, 34)) {
79 154 : const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
80 251 : if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
81 97 : std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
82 71 : bool compressed = data.size() == 33 + privkey_prefix.size();
83 71 : key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
84 71 : }
85 154 : }
86 267 : if (!data.empty()) {
87 154 : memory_cleanse(data.data(), data.size());
88 154 : }
89 267 : return key;
90 267 : }
91 :
92 66 : std::string EncodeSecret(const CKey& key)
93 : {
94 66 : assert(key.IsValid());
95 66 : std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
96 66 : data.insert(data.end(), key.begin(), key.end());
97 66 : if (key.IsCompressed()) {
98 42 : data.push_back(1);
99 42 : }
100 66 : std::string ret = EncodeBase58Check(data);
101 66 : memory_cleanse(data.data(), data.size());
102 66 : return ret;
103 66 : }
104 :
105 162 : CExtPubKey DecodeExtPubKey(const std::string& str)
106 : {
107 162 : CExtPubKey key;
108 162 : std::vector<unsigned char> data;
109 162 : if (DecodeBase58Check(str, data, 78)) {
110 161 : const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
111 161 : if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
112 119 : key.Decode(data.data() + prefix.size());
113 119 : }
114 161 : }
115 : return key;
116 162 : }
117 :
118 11499 : std::string EncodeExtPubKey(const CExtPubKey& key)
119 : {
120 11499 : std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
121 11499 : size_t size = data.size();
122 11499 : data.resize(size + BIP32_EXTKEY_SIZE);
123 11499 : key.Encode(data.data() + size);
124 11499 : std::string ret = EncodeBase58Check(data);
125 11499 : return ret;
126 11499 : }
127 :
128 162 : CExtKey DecodeExtKey(const std::string& str)
129 : {
130 162 : CExtKey key;
131 162 : std::vector<unsigned char> data;
132 162 : if (DecodeBase58Check(str, data, 78)) {
133 161 : const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
134 161 : if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
135 53 : key.Decode(data.data() + prefix.size());
136 53 : }
137 161 : }
138 162 : return key;
139 162 : }
140 :
141 83 : std::string EncodeExtKey(const CExtKey& key)
142 : {
143 83 : std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
144 83 : size_t size = data.size();
145 83 : data.resize(size + BIP32_EXTKEY_SIZE);
146 83 : key.Encode(data.data() + size);
147 83 : std::string ret = EncodeBase58Check(data);
148 83 : if (!data.empty()) {
149 83 : memory_cleanse(data.data(), data.size());
150 83 : }
151 83 : return ret;
152 83 : }
153 :
154 38698 : std::string EncodeDestination(const CTxDestination& dest)
155 : {
156 38698 : return std::visit(DestinationEncoder(Params()), dest);
157 : }
158 :
159 6476 : CTxDestination DecodeDestination(const std::string& str, std::string& error_msg)
160 : {
161 6476 : return DecodeDestination(str, Params(), error_msg);
162 : }
163 :
164 6474 : CTxDestination DecodeDestination(const std::string& str)
165 : {
166 6474 : std::string error_msg;
167 6474 : return DecodeDestination(str, error_msg);
168 6474 : }
169 :
170 0 : bool IsValidDestinationString(const std::string& str, const CChainParams& params)
171 : {
172 0 : std::string error_msg;
173 0 : return IsValidDestination(DecodeDestination(str, params, error_msg));
174 0 : }
175 :
176 0 : bool IsValidDestinationString(const std::string& str)
177 : {
178 0 : 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 : }
|