Base58 decoding is currently done without checking that the input size is reasonable.

This can lead to excessive decoding run time if an attacker can control the base58 input being decoded.

`DecodeBase58/DecodeBase58Check(…)` run time sampled with varying input sizes:

* 1 000 bytes: 1 ms
* 10 000 bytes: 97 ms
* 100 000 bytes: 8 865 ms (9 seconds)
* 1 000 000 bytes: 857 440 ms (14 minutes)
* 10 000 000 bytes: too long :)

`DecodeBase58/DecodeBase58Check(…)` is reachable via the RPC interface using the following code paths:

```
addmultisigaddress(JSONRPCRequest const&) → AddrToPubKey(CKeyStore*, std::string const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
createpsbt(JSONRPCRequest const&) → ConstructTransaction(UniValue const&, UniValue const&, UniValue const&, UniValue const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
createrawtransaction(JSONRPCRequest const&) → ConstructTransaction(UniValue const&, UniValue const&, UniValue const&, UniValue const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
createwallet(JSONRPCRequest const&) → CWallet::CreateWalletFromFile(interfaces::Chain&, WalletLocation const&, unsigned long) → CWallet::LoadWallet(bool&) → WalletBatch::LoadWallet(CWallet*) → ReadKeyValue(CWallet*, CDataStream&, CDataStream&, CWalletScanState&, std::string&, std::string&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
deriveaddresses(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
deriveaddresses(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtPubKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
deriveaddresses(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
deriveaddresses(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
dumpprivkey(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
fundrawtransaction(JSONRPCRequest const&) → FundTransaction(CWallet*, CMutableTransaction&, long&, int&, UniValue) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
generatetoaddress(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
getaddressinfo(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
getdescriptorinfo(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
getdescriptorinfo(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtPubKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
getdescriptorinfo(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
getdescriptorinfo(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
getreceivedbyaddress(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importaddress(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtPubKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → ProcessImportLegacy(ImportData&, std::map<CKeyID, CPubKey, std::less<CKeyID>, std::allocator<std::pair<CKeyID const, CPubKey> > >&, std::map<CKeyID, CKey, std::less<CKeyID>, std::allocator<std::pair<CKeyID const, CKey> > >&, std::set<CScript, std::less<CScript>, std::allocator<CScript> >&, bool&, UniValue const&, std::vector<CKeyID>&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → ProcessImportLegacy(ImportData&, std::map<CKeyID, CPubKey, std::less<CKeyID>, std::allocator<std::pair<CKeyID const, CPubKey> > >&, std::map<CKeyID, CKey, std::less<CKeyID>, std::allocator<std::pair<CKeyID const, CKey> > >&, std::set<CScript, std::less<CScript>, std::allocator<CScript> >&, bool&, UniValue const&, std::vector<CKeyID>&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importprivkey(JSONRPCRequest const&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importwallet(JSONRPCRequest const&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
listreceivedbyaddress(JSONRPCRequest const&) → ListReceived(interfaces::Chain::Lock&, CWallet*, UniValue const&, bool) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
listreceivedbylabel(JSONRPCRequest const&) → ListReceived(interfaces::Chain::Lock&, CWallet*, UniValue const&, bool) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
listunspent(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
loadwallet(JSONRPCRequest const&) → LoadWallet(interfaces::Chain&, WalletLocation const&, std::string&, std::string&) → CWallet::CreateWalletFromFile(interfaces::Chain&, WalletLocation const&, unsigned long) → CWallet::LoadWallet(bool&) → WalletBatch::LoadWallet(CWallet*) → ReadKeyValue(CWallet*, CDataStream&, CDataStream&, CWalletScanState&, std::string&, std::string&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
scantxoutset(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
scantxoutset(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtPubKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
scantxoutset(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
scantxoutset(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
sendmany(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
sendtoaddress(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
sethdseed(JSONRPCRequest const&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
setlabel(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
signmessage(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
signmessagewithprivkey(JSONRPCRequest const&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
signrawtransactionwithkey(JSONRPCRequest const&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
validateaddress(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
verifymessage(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
walletcreatefundedpsbt(JSONRPCRequest const&) → ConstructTransaction(UniValue const&, UniValue const&, UniValue const&, UniValue const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
walletcreatefundedpsbt(JSONRPCRequest const&) → FundTransaction(CWallet*, CMutableTransaction&, long&, int&, UniValue) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
```

Other code paths involving base58-decoding:

```
IsValidDestinationString(std::string const&, CChainParams const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
LoadWallet(interfaces::Chain&, std::string const&, std::string&, std::string&) → LoadWallet(interfaces::Chain&, WalletLocation const&, std::string&, std::string&) → CWallet::CreateWalletFromFile(interfaces::Chain&, WalletLocation const&, unsigned long) → CWallet::LoadWallet(bool&) → WalletBatch::LoadWallet(CWallet*) → ReadKeyValue(CWallet*, CDataStream&, CDataStream&, CWalletScanState&, std::string&, std::string&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
LoadWallets(interfaces::Chain&, std::vector<std::string, std::allocator<std::string > > const&) → CWallet::CreateWalletFromFile(interfaces::Chain&, WalletLocation const&, unsigned long) → CWallet::LoadWallet(bool&) → WalletBatch::LoadWallet(CWallet*) → ReadKeyValue(CWallet*, CDataStream&, CDataStream&, CWalletScanState&, std::string&, std::string&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
WalletBatch::RecoverKeysOnlyFilter(void*, CDataStream, CDataStream) → ReadKeyValue(CWallet*, CDataStream&, CDataStream&, CWalletScanState&, std::string&, std::string&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
```
{
    std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
    size_t size = data.size();
    data.resize(size + BIP32_EXTKEY_SIZE);
    key.Encode(data.data() + size);
    std::string ret = EncodeBase58Check(data);
    return ret;
}
CExtKey DecodeExtKey(const std::string& str)
{
    CExtKey key;
    std::vector<unsigned char> data;
    if (DecodeBase58Check(str, data)) {
        const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
        if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
            key.Decode(data.data() + prefix.size());
        }
    }
    return key;
}
std::string EncodeExtKey(const CExtKey& key)