/root/bitcoin/src/key_io.cpp
Line | Count | Source (jump to first uncovered line) |
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 <script/interpreter.h> |
10 | | #include <script/solver.h> |
11 | | #include <tinyformat.h> |
12 | | #include <util/strencodings.h> |
13 | | |
14 | | #include <algorithm> |
15 | | #include <assert.h> |
16 | | #include <string.h> |
17 | | |
18 | | /// Maximum witness length for Bech32 addresses. |
19 | | static constexpr std::size_t BECH32_WITNESS_PROG_MAX_LEN = 40; |
20 | | |
21 | | namespace { |
22 | | class DestinationEncoder |
23 | | { |
24 | | private: |
25 | | const CChainParams& m_params; |
26 | | |
27 | | public: |
28 | 0 | explicit DestinationEncoder(const CChainParams& params) : m_params(params) {} |
29 | | |
30 | | std::string operator()(const PKHash& id) const |
31 | 0 | { |
32 | 0 | std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); |
33 | 0 | data.insert(data.end(), id.begin(), id.end()); |
34 | 0 | return EncodeBase58Check(data); |
35 | 0 | } |
36 | | |
37 | | std::string operator()(const ScriptHash& id) const |
38 | 0 | { |
39 | 0 | std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); |
40 | 0 | data.insert(data.end(), id.begin(), id.end()); |
41 | 0 | return EncodeBase58Check(data); |
42 | 0 | } |
43 | | |
44 | | std::string operator()(const WitnessV0KeyHash& id) const |
45 | 0 | { |
46 | 0 | std::vector<unsigned char> data = {0}; |
47 | 0 | data.reserve(33); |
48 | 0 | ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.begin(), id.end()); |
49 | 0 | return bech32::Encode(bech32::Encoding::BECH32, m_params.Bech32HRP(), data); |
50 | 0 | } |
51 | | |
52 | | std::string operator()(const WitnessV0ScriptHash& id) const |
53 | 0 | { |
54 | 0 | std::vector<unsigned char> data = {0}; |
55 | 0 | data.reserve(53); |
56 | 0 | ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.begin(), id.end()); |
57 | 0 | return bech32::Encode(bech32::Encoding::BECH32, m_params.Bech32HRP(), data); |
58 | 0 | } |
59 | | |
60 | | std::string operator()(const WitnessV1Taproot& tap) const |
61 | 0 | { |
62 | 0 | std::vector<unsigned char> data = {1}; |
63 | 0 | data.reserve(53); |
64 | 0 | ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, tap.begin(), tap.end()); |
65 | 0 | return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data); |
66 | 0 | } |
67 | | |
68 | | std::string operator()(const WitnessUnknown& id) const |
69 | 0 | { |
70 | 0 | const std::vector<unsigned char>& program = id.GetWitnessProgram(); |
71 | 0 | if (id.GetWitnessVersion() < 1 || id.GetWitnessVersion() > 16 || program.size() < 2 || program.size() > 40) { |
72 | 0 | return {}; |
73 | 0 | } |
74 | 0 | std::vector<unsigned char> data = {(unsigned char)id.GetWitnessVersion()}; |
75 | 0 | data.reserve(1 + (program.size() * 8 + 4) / 5); |
76 | 0 | ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, program.begin(), program.end()); |
77 | 0 | return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data); |
78 | 0 | } |
79 | | |
80 | 0 | std::string operator()(const CNoDestination& no) const { return {}; } |
81 | 0 | std::string operator()(const PubKeyDestination& pk) const { return {}; } |
82 | | }; |
83 | | |
84 | | CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str, std::vector<int>* error_locations) |
85 | 0 | { |
86 | 0 | std::vector<unsigned char> data; |
87 | 0 | uint160 hash; |
88 | 0 | error_str = ""; |
89 | | |
90 | | // Note this will be false if it is a valid Bech32 address for a different network |
91 | 0 | bool is_bech32 = (ToLower(str.substr(0, params.Bech32HRP().size())) == params.Bech32HRP()); |
92 | |
|
93 | 0 | if (!is_bech32 && DecodeBase58Check(str, data, 21)) { |
94 | | // base58-encoded Bitcoin addresses. |
95 | | // Public-key-hash-addresses have version 0 (or 111 testnet). |
96 | | // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. |
97 | 0 | const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); |
98 | 0 | if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) { |
99 | 0 | std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin()); |
100 | 0 | return PKHash(hash); |
101 | 0 | } |
102 | | // Script-hash-addresses have version 5 (or 196 testnet). |
103 | | // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. |
104 | 0 | const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); |
105 | 0 | if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) { |
106 | 0 | std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin()); |
107 | 0 | return ScriptHash(hash); |
108 | 0 | } |
109 | | |
110 | | // If the prefix of data matches either the script or pubkey prefix, the length must have been wrong |
111 | 0 | if ((data.size() >= script_prefix.size() && |
112 | 0 | std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) || |
113 | 0 | (data.size() >= pubkey_prefix.size() && |
114 | 0 | std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin()))) { |
115 | 0 | error_str = "Invalid length for Base58 address (P2PKH or P2SH)"; |
116 | 0 | } else { |
117 | 0 | error_str = "Invalid or unsupported Base58-encoded address."; |
118 | 0 | } |
119 | 0 | return CNoDestination(); |
120 | 0 | } else if (!is_bech32) { |
121 | | // Try Base58 decoding without the checksum, using a much larger max length |
122 | 0 | if (!DecodeBase58(str, data, 100)) { |
123 | 0 | error_str = "Invalid or unsupported Segwit (Bech32) or Base58 encoding."; |
124 | 0 | } else { |
125 | 0 | error_str = "Invalid checksum or length of Base58 address (P2PKH or P2SH)"; |
126 | 0 | } |
127 | 0 | return CNoDestination(); |
128 | 0 | } |
129 | | |
130 | 0 | data.clear(); |
131 | 0 | const auto dec = bech32::Decode(str); |
132 | 0 | if (dec.encoding == bech32::Encoding::BECH32 || dec.encoding == bech32::Encoding::BECH32M) { |
133 | 0 | if (dec.data.empty()) { |
134 | 0 | error_str = "Empty Bech32 data section"; |
135 | 0 | return CNoDestination(); |
136 | 0 | } |
137 | | // Bech32 decoding |
138 | 0 | if (dec.hrp != params.Bech32HRP()) { |
139 | 0 | error_str = strprintf("Invalid or unsupported prefix for Segwit (Bech32) address (expected %s, got %s).", params.Bech32HRP(), dec.hrp); |
140 | 0 | return CNoDestination(); |
141 | 0 | } |
142 | 0 | int version = dec.data[0]; // The first 5 bit symbol is the witness version (0-16) |
143 | 0 | if (version == 0 && dec.encoding != bech32::Encoding::BECH32) { |
144 | 0 | error_str = "Version 0 witness address must use Bech32 checksum"; |
145 | 0 | return CNoDestination(); |
146 | 0 | } |
147 | 0 | if (version != 0 && dec.encoding != bech32::Encoding::BECH32M) { |
148 | 0 | error_str = "Version 1+ witness address must use Bech32m checksum"; |
149 | 0 | return CNoDestination(); |
150 | 0 | } |
151 | | // The rest of the symbols are converted witness program bytes. |
152 | 0 | data.reserve(((dec.data.size() - 1) * 5) / 8); |
153 | 0 | if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, dec.data.begin() + 1, dec.data.end())) { |
154 | |
|
155 | 0 | std::string_view byte_str{data.size() == 1 ? "byte" : "bytes"}; |
156 | |
|
157 | 0 | if (version == 0) { |
158 | 0 | { |
159 | 0 | WitnessV0KeyHash keyid; |
160 | 0 | if (data.size() == keyid.size()) { |
161 | 0 | std::copy(data.begin(), data.end(), keyid.begin()); |
162 | 0 | return keyid; |
163 | 0 | } |
164 | 0 | } |
165 | 0 | { |
166 | 0 | WitnessV0ScriptHash scriptid; |
167 | 0 | if (data.size() == scriptid.size()) { |
168 | 0 | std::copy(data.begin(), data.end(), scriptid.begin()); |
169 | 0 | return scriptid; |
170 | 0 | } |
171 | 0 | } |
172 | | |
173 | 0 | error_str = strprintf("Invalid Bech32 v0 address program size (%d %s), per BIP141", data.size(), byte_str); |
174 | 0 | return CNoDestination(); |
175 | 0 | } |
176 | | |
177 | 0 | if (version == 1 && data.size() == WITNESS_V1_TAPROOT_SIZE) { |
178 | 0 | static_assert(WITNESS_V1_TAPROOT_SIZE == WitnessV1Taproot::size()); |
179 | 0 | WitnessV1Taproot tap; |
180 | 0 | std::copy(data.begin(), data.end(), tap.begin()); |
181 | 0 | return tap; |
182 | 0 | } |
183 | | |
184 | 0 | if (CScript::IsPayToAnchor(version, data)) { |
185 | 0 | return PayToAnchor(); |
186 | 0 | } |
187 | | |
188 | 0 | if (version > 16) { |
189 | 0 | error_str = "Invalid Bech32 address witness version"; |
190 | 0 | return CNoDestination(); |
191 | 0 | } |
192 | | |
193 | 0 | if (data.size() < 2 || data.size() > BECH32_WITNESS_PROG_MAX_LEN) { |
194 | 0 | error_str = strprintf("Invalid Bech32 address program size (%d %s)", data.size(), byte_str); |
195 | 0 | return CNoDestination(); |
196 | 0 | } |
197 | | |
198 | 0 | return WitnessUnknown{version, data}; |
199 | 0 | } else { |
200 | 0 | error_str = strprintf("Invalid padding in Bech32 data section"); |
201 | 0 | return CNoDestination(); |
202 | 0 | } |
203 | 0 | } |
204 | | |
205 | | // Perform Bech32 error location |
206 | 0 | auto res = bech32::LocateErrors(str); |
207 | 0 | error_str = res.first; |
208 | 0 | if (error_locations) *error_locations = std::move(res.second); |
209 | 0 | return CNoDestination(); |
210 | 0 | } |
211 | | } // namespace |
212 | | |
213 | | CKey DecodeSecret(const std::string& str) |
214 | 0 | { |
215 | 0 | CKey key; |
216 | 0 | std::vector<unsigned char> data; |
217 | 0 | if (DecodeBase58Check(str, data, 34)) { |
218 | 0 | const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY); |
219 | 0 | if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) && |
220 | 0 | std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) { |
221 | 0 | bool compressed = data.size() == 33 + privkey_prefix.size(); |
222 | 0 | key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed); |
223 | 0 | } |
224 | 0 | } |
225 | 0 | if (!data.empty()) { |
226 | 0 | memory_cleanse(data.data(), data.size()); |
227 | 0 | } |
228 | 0 | return key; |
229 | 0 | } |
230 | | |
231 | | std::string EncodeSecret(const CKey& key) |
232 | 0 | { |
233 | 0 | assert(key.IsValid()); |
234 | 0 | std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY); |
235 | 0 | data.insert(data.end(), UCharCast(key.begin()), UCharCast(key.end())); |
236 | 0 | if (key.IsCompressed()) { |
237 | 0 | data.push_back(1); |
238 | 0 | } |
239 | 0 | std::string ret = EncodeBase58Check(data); |
240 | 0 | memory_cleanse(data.data(), data.size()); |
241 | 0 | return ret; |
242 | 0 | } |
243 | | |
244 | | CExtPubKey DecodeExtPubKey(const std::string& str) |
245 | 0 | { |
246 | 0 | CExtPubKey key; |
247 | 0 | std::vector<unsigned char> data; |
248 | 0 | if (DecodeBase58Check(str, data, 78)) { |
249 | 0 | const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY); |
250 | 0 | if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) { |
251 | 0 | key.Decode(data.data() + prefix.size()); |
252 | 0 | } |
253 | 0 | } |
254 | 0 | return key; |
255 | 0 | } |
256 | | |
257 | | std::string EncodeExtPubKey(const CExtPubKey& key) |
258 | 0 | { |
259 | 0 | std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY); |
260 | 0 | size_t size = data.size(); |
261 | 0 | data.resize(size + BIP32_EXTKEY_SIZE); |
262 | 0 | key.Encode(data.data() + size); |
263 | 0 | std::string ret = EncodeBase58Check(data); |
264 | 0 | return ret; |
265 | 0 | } |
266 | | |
267 | | CExtKey DecodeExtKey(const std::string& str) |
268 | 0 | { |
269 | 0 | CExtKey key; |
270 | 0 | std::vector<unsigned char> data; |
271 | 0 | if (DecodeBase58Check(str, data, 78)) { |
272 | 0 | const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY); |
273 | 0 | if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) { |
274 | 0 | key.Decode(data.data() + prefix.size()); |
275 | 0 | } |
276 | 0 | } |
277 | 0 | return key; |
278 | 0 | } |
279 | | |
280 | | std::string EncodeExtKey(const CExtKey& key) |
281 | 0 | { |
282 | 0 | std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY); |
283 | 0 | size_t size = data.size(); |
284 | 0 | data.resize(size + BIP32_EXTKEY_SIZE); |
285 | 0 | key.Encode(data.data() + size); |
286 | 0 | std::string ret = EncodeBase58Check(data); |
287 | 0 | memory_cleanse(data.data(), data.size()); |
288 | 0 | return ret; |
289 | 0 | } |
290 | | |
291 | | std::string EncodeDestination(const CTxDestination& dest) |
292 | 0 | { |
293 | 0 | return std::visit(DestinationEncoder(Params()), dest); |
294 | 0 | } |
295 | | |
296 | | CTxDestination DecodeDestination(const std::string& str, std::string& error_msg, std::vector<int>* error_locations) |
297 | 0 | { |
298 | 0 | return DecodeDestination(str, Params(), error_msg, error_locations); |
299 | 0 | } |
300 | | |
301 | | CTxDestination DecodeDestination(const std::string& str) |
302 | 0 | { |
303 | 0 | std::string error_msg; |
304 | 0 | return DecodeDestination(str, error_msg); |
305 | 0 | } |
306 | | |
307 | | bool IsValidDestinationString(const std::string& str, const CChainParams& params) |
308 | 0 | { |
309 | 0 | std::string error_msg; |
310 | 0 | return IsValidDestination(DecodeDestination(str, params, error_msg, nullptr)); |
311 | 0 | } |
312 | | |
313 | | bool IsValidDestinationString(const std::string& str) |
314 | 0 | { |
315 | 0 | return IsValidDestinationString(str, Params()); |
316 | 0 | } |