Parse a public key that excludes origin information. */
| 930 | |
| 931 | /** Parse a public key that excludes origin information. */ |
| 932 | std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error) |
| 933 | { |
| 934 | using namespace spanparsing; |
| 935 | |
| 936 | bool permit_uncompressed = ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH; |
| 937 | auto split = Split(sp, '/'); |
| 938 | std::string str(split[0].begin(), split[0].end()); |
| 939 | if (str.size() == 0) { |
| 940 | error = "No key provided"; |
| 941 | return nullptr; |
| 942 | } |
| 943 | if (split.size() == 1) { |
| 944 | if (IsHex(str)) { |
| 945 | std::vector<unsigned char> data = ParseHex(str); |
| 946 | CPubKey pubkey(data); |
| 947 | if (pubkey.IsFullyValid()) { |
| 948 | if (permit_uncompressed || pubkey.IsCompressed()) { |
| 949 | return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, false); |
| 950 | } else { |
| 951 | error = "Uncompressed keys are not allowed"; |
| 952 | return nullptr; |
| 953 | } |
| 954 | } else if (data.size() == 32 && ctx == ParseScriptContext::P2TR) { |
| 955 | unsigned char fullkey[33] = {0x02}; |
| 956 | std::copy(data.begin(), data.end(), fullkey + 1); |
| 957 | pubkey.Set(std::begin(fullkey), std::end(fullkey)); |
| 958 | if (pubkey.IsFullyValid()) { |
| 959 | return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, true); |
| 960 | } |
| 961 | } |
| 962 | error = strprintf("Pubkey '%s' is invalid", str); |
| 963 | return nullptr; |
| 964 | } |
| 965 | CKey key = DecodeSecret(str); |
| 966 | if (key.IsValid()) { |
| 967 | if (permit_uncompressed || key.IsCompressed()) { |
| 968 | CPubKey pubkey = key.GetPubKey(); |
| 969 | out.keys.emplace(pubkey.GetID(), key); |
| 970 | return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, ctx == ParseScriptContext::P2TR); |
| 971 | } else { |
| 972 | error = "Uncompressed keys are not allowed"; |
| 973 | return nullptr; |
| 974 | } |
| 975 | } |
| 976 | } |
| 977 | CExtKey extkey = DecodeExtKey(str); |
| 978 | CExtPubKey extpubkey = DecodeExtPubKey(str); |
| 979 | if (!extkey.key.IsValid() && !extpubkey.pubkey.IsValid()) { |
| 980 | error = strprintf("key '%s' is not valid", str); |
| 981 | return nullptr; |
| 982 | } |
| 983 | KeyPath path; |
| 984 | DeriveType type = DeriveType::NO; |
| 985 | if (split.back() == Span{"*"}.first(1)) { |
| 986 | split.pop_back(); |
| 987 | type = DeriveType::UNHARDENED; |
| 988 | } else if (split.back() == Span{"*'"}.first(2) || split.back() == Span{"*h"}.first(2)) { |
| 989 | split.pop_back(); |
no test coverage detected