Skip to content

Commit d9d3ec0

Browse files
committed
Consolidate XOnlyPubKey lookup hack
The places where we need to lookup information for a XOnlyPubKey currently implement a hack which makes both serializations of the full pubkey in order to try the CKeyIDs for the lookup functions. Instead of duplicating this everywhere it is needed, we can consolidate the CKeyID generation into a function, and then have wrappers around GetPubKey, GetKey, and GetKeyOrigin which takes the XOnlyPubKey, retrieves all of the CKeyIDs (using the new GetKeyIDs() function in XOnlyPubKey), and tries their respective underlying lookup function.
1 parent dbcb574 commit d9d3ec0

File tree

5 files changed

+48
-23
lines changed

5 files changed

+48
-23
lines changed

src/pubkey.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,23 @@ XOnlyPubKey::XOnlyPubKey(Span<const unsigned char> bytes)
180180
std::copy(bytes.begin(), bytes.end(), m_keydata.begin());
181181
}
182182

183+
std::vector<CKeyID> XOnlyPubKey::GetKeyIDs() const
184+
{
185+
std::vector<CKeyID> out;
186+
// For now, use the old full pubkey-based key derivation logic. As it is indexed by
187+
// Hash160(full pubkey), we need to return both a version prefixed with 0x02, and one
188+
// with 0x03.
189+
unsigned char b[33] = {0x02};
190+
std::copy(m_keydata.begin(), m_keydata.end(), b + 1);
191+
CPubKey fullpubkey;
192+
fullpubkey.Set(b, b + 33);
193+
out.push_back(fullpubkey.GetID());
194+
b[0] = 0x03;
195+
fullpubkey.Set(b, b + 33);
196+
out.push_back(fullpubkey.GetID());
197+
return out;
198+
}
199+
183200
bool XOnlyPubKey::IsFullyValid() const
184201
{
185202
secp256k1_xonly_pubkey pubkey;

src/pubkey.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,11 @@ class XOnlyPubKey
267267
/** Construct a Taproot tweaked output point with this point as internal key. */
268268
std::optional<std::pair<XOnlyPubKey, bool>> CreateTapTweak(const uint256* merkle_root) const;
269269

270+
/** Returns a list of CKeyIDs for the CPubKeys that could have been used to create this XOnlyPubKey.
271+
* This is needed for key lookups since keys are indexed by CKeyID.
272+
*/
273+
std::vector<CKeyID> GetKeyIDs() const;
274+
270275
const unsigned char& operator[](int pos) const { return *(m_keydata.begin() + pos); }
271276
const unsigned char* data() const { return m_keydata.begin(); }
272277
static constexpr size_t size() { return decltype(m_keydata)::size(); }

src/script/descriptor.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,14 +1242,8 @@ std::unique_ptr<PubkeyProvider> InferXOnlyPubkey(const XOnlyPubKey& xkey, ParseS
12421242
CPubKey pubkey(full_key);
12431243
std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0, pubkey, true);
12441244
KeyOriginInfo info;
1245-
if (provider.GetKeyOrigin(pubkey.GetID(), info)) {
1245+
if (provider.GetKeyOriginByXOnly(xkey, info)) {
12461246
return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
1247-
} else {
1248-
full_key[0] = 0x03;
1249-
pubkey = CPubKey(full_key);
1250-
if (provider.GetKeyOrigin(pubkey.GetID(), info)) {
1251-
return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
1252-
}
12531247
}
12541248
return key_provider;
12551249
}

src/script/sign.cpp

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,7 @@ bool MutableTransactionSignatureCreator::CreateSchnorrSig(const SigningProvider&
6060
assert(sigversion == SigVersion::TAPROOT || sigversion == SigVersion::TAPSCRIPT);
6161

6262
CKey key;
63-
{
64-
// For now, use the old full pubkey-based key derivation logic. As it is indexed by
65-
// Hash160(full pubkey), we need to try both a version prefixed with 0x02, and one
66-
// with 0x03.
67-
unsigned char b[33] = {0x02};
68-
std::copy(pubkey.begin(), pubkey.end(), b + 1);
69-
CPubKey fullpubkey;
70-
fullpubkey.Set(b, b + 33);
71-
CKeyID keyid = fullpubkey.GetID();
72-
if (!provider.GetKey(keyid, key)) {
73-
b[0] = 0x03;
74-
fullpubkey.Set(b, b + 33);
75-
CKeyID keyid = fullpubkey.GetID();
76-
if (!provider.GetKey(keyid, key)) return false;
77-
}
78-
}
63+
if (!provider.GetKeyByXOnly(pubkey, key)) return false;
7964

8065
// BIP341/BIP342 signing needs lots of precomputed transaction data. While some
8166
// (non-SIGHASH_DEFAULT) sighash modes exist that can work with just some subset

src/script/signingprovider.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,30 @@ class SigningProvider
2626
virtual bool HaveKey(const CKeyID &address) const { return false; }
2727
virtual bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { return false; }
2828
virtual bool GetTaprootSpendData(const XOnlyPubKey& output_key, TaprootSpendData& spenddata) const { return false; }
29+
30+
bool GetKeyByXOnly(const XOnlyPubKey& pubkey, CKey& key) const
31+
{
32+
for (const auto& id : pubkey.GetKeyIDs()) {
33+
if (GetKey(id, key)) return true;
34+
}
35+
return false;
36+
}
37+
38+
bool GetPubKeyByXOnly(const XOnlyPubKey& pubkey, CPubKey& out) const
39+
{
40+
for (const auto& id : pubkey.GetKeyIDs()) {
41+
if (GetPubKey(id, out)) return true;
42+
}
43+
return false;
44+
}
45+
46+
bool GetKeyOriginByXOnly(const XOnlyPubKey& pubkey, KeyOriginInfo& info) const
47+
{
48+
for (const auto& id : pubkey.GetKeyIDs()) {
49+
if (GetKeyOrigin(id, info)) return true;
50+
}
51+
return false;
52+
}
2953
};
3054

3155
extern const SigningProvider& DUMMY_SIGNING_PROVIDER;

0 commit comments

Comments
 (0)